由于一直做各种对接工作,所以也总结了下常用的接口,适用于目前黄钻、蓝钻的页游对接,有兴趣的朋友可以来指点。
$openid, 'openkey'=>$openkey, 'pf'=>$pf, 'pfkey'=>$pfkey, 'tokentype'=>$tokentype, 'ts'=>$_SERVER['REQUEST_TIME'], 'discountid'=>$discountid, 'zoneid'=>0, 'version' => 'v3', ); return self::api(self::S_QQ_API_GET_TOKEN, $params, $method, $protocol); } /** * 取得完整的联盟PF * @param string $appid * @param string $openid * @return string $pf */ static function unionPf($openid=''){ $url = 'http://union.tencentlog.com/cgi-bin/Query.cgi?appid=' . self::$appid . '&opopenid=' . $openid; $ret = Utils::get($url, '', false); $ret = iconv('gb2312', 'utf-8', $ret); $result = json_decode($ret, 1); if ($result['iRet'] == 0) { return $result['sPf']; } else { return ''; } } /** * 取得联盟的pfkey * @param string $openid * @param string $openkey * @param string $pf * @return string */ static function unionPfkey($openid, $openkey, $pf){ $url = 'http://union.tencentlog.com/control/GetPfkey.php?app=' . self::$appid . '&pf=' . $pf . '&openid=' . $openid . '&openkey=' . $openkey; $ret = Utils::get($url, '', false); $ret = iconv('gb2312', 'utf-8', $ret); $result = json_decode($ret, 1); if ($result['ret'] == 0) { return $result['pfkey']; } else { return ''; } } static function pfkey($openid, $openkey, $pf, $method = 'GET', $protocol = 'http'){ $params = array( 'openid' => $openid, 'openkey' => $openkey, 'pf' => $pf, ); /** * 返回值 * ret 返回码 0 成功 * pfkey * is_lost 忽略此值 */ $ret = self::api(self::S_QQ_API_GET_PFKEY, $params, $method, $protocol, self::OPEN_API_GET_PFKEY); if ( $openid == '5A86F5B031580BBA67945EC315F78A4A'){ var_dump($ret); } return $ret['pfkey'] ? : ''; } CONST S_QQ_API_GET_PFKEY_BY_OPENID = 'http://apps.game.qq.com/wan/box/App/GetPfkeyByOpenid.php'; /** * 根据OPENID取得pfkey * @param $openid * @param $openkey * @param $pf * @return array|mixed */ static function getPfkeyByOpenid($openid, $openkey, $pf){ $params = array( 'appid'=>self::$appid, 'openid'=>$openid, 'openkey'=>$openkey, 'pf'=>$pf, ); $ret = Utils::get(self::S_QQ_API_GET_PFKEY_BY_OPENID, $params, false); $ret = str_ireplace('var GetPfkeyByOpenid_JSON = ', '', $ret); $json = json_decode($ret, 1); if ( $json ){ if ( $json['ret'] == 0 ){ return $json['pfkey']; } } return ''; } /** * 获取交易TOKEN * @param array $params 应该包含如下字段: * pfkey: 必须 * amt: 交易总价 Q点为单位 1Q币=10Q点 * amttype: 支付方式:coin:仅允许使用游戏币支付,不传为Q点 * ts: 必须 时间戳 * payitem: 必须 ID*Price*Num,单价最少不能少于2Q点 * appmode: 购买数量类型 1:不可选 2:可选 * max_num: 购买数量上限 appmode:2时有效 * goodsmeta: 必须 商品描述信息 256字符内utf8编码 * goodsurl: 必须 商品图片URL 116x116px * zoneid: 必须 分区ID,默认0 * manyouid: 视情况,详见文档 * present: 是否是礼物 0或不传给自己 1:送给好友 2:索要 * paymode: 忽略 * cee_extend: 忽略 * @return array */ static function buyGoods($params=array()){ /** * 参考 http://wiki.open.qq.com/wiki/v3/pay/buy_goods * ret 返回码 * msg 错误信息 * is_lost 是否有数据丢失(忽略此值) * token ret=0时为临时订单号 * url_params ret=0时为真正购买物品的url参数,获取此值后传给前端有js唤起支付接口 */ return self::api(self::S_QQ_API_BUY_GOODS, $params, 'post', 'https'); } /** * 获得用户信息 * @param string $openid * @param string $openkey * @param string $pf * @param string $pfkey * @param int $flag 当pf为蓝钻时,flag为要获取的数据类型。1:昵称性别 2:蓝钻等级 3:昵称和蓝钻等级 4:照片秀标识 * @param string $method * @param string $protocol * @return array */ static function getUserInfo($openid, $openkey, $pf, $pfkey, $flag = 1, $method = 'GET', $protocol = 'http') { /** * 参考 http://wiki.open.qq.com/wiki/v3/user/get_info * ret 返回码 * msg 错误信息 * is_lost 判断是否有数据丢失。如果应用不使用cache,不需要关心此参数。 0或者不返回:没有数据丢失,可以缓存。 1:有部分数据丢失或错误,不要缓存。 * nickname 昵称。 * gender 性别。 * country 国家(当pf=qzone、pengyou或qplus时返回)。 * province 省(当pf=qzone、pengyou或qplus时返回)。 * city 市(当pf=qzone、pengyou或qplus时返回)。 * figureurl 头像URL。详见:前端页面规范#6. 关于用户头像的获取和尺寸说明。 * openid 用户QQ号码转化得到的ID(当pf=qplus时返回)。 * qq_level 用户QQ等级(当pf=qplus时返回)。 * qq_vip_level 用户QQ会员等级(当pf=qplus时返回)。 * qplus_level 用户Q+等级(当pf=qplus时返回)。 * is_yellow_vip 是否为黄钻用户(0:不是; 1:是)。(当pf=qzone、pengyou或qplus时返回) * is_yellow_year_vip 是否为年费黄钻用户(0:不是; 1:是)。 (当pf=qzone、pengyou或qplus时返回) * yellow_vip_level 黄钻等级,目前最高级别为黄钻8级(如果是黄钻用户才返回此参数)。(当pf=qzone、pengyou或qplus时返回) * is_yellow_high_vip 是否为豪华版黄钻用户(0:不是; 1:是)。(当pf=qzone、pengyou或qplus时返回) * is_blue_vip 是否为蓝钻用户(0:不是; 1:是)。(当pf=qqgame或3366时返回) * is_blue_year_vip 是否为年费蓝钻用户(0:不是; 1:是)。(当pf=qqgame或3366时返回) * blue_vip_level 蓝钻等级(如果是蓝钻用户才返回此参数)。(当pf=qqgame或3366时返回) * 3366_level 3366用户的大等级。(当pf=3366时返回) * 3366_level_name 3366用户的等级名,如小游游、小游仙。(当pf=3366时返回) * 3366_grow_level 3366用户的成长等级。(当pf=3366时返回) * 3366_grow_value 3366用户的成长值。(当pf=3366时返回) * is_super_blue_vip 是否是豪华蓝钻。(当pf=qqgame或3366时返回) */ $params = array( 'openid' => $openid, 'openkey' => $openkey, 'pfkey' => $pfkey, 'pf' => $pf, ); if ('qqgame' == $pf) { $params['flag'] = $flag; } return self::api(self::S_QQ_API_USER_INFO, $params, $method, $protocol); } /** * 判断用户是否登录 * @param string $openid * @param string $openkey * @param string $pf * @param string $pfkey * @param string $method * @param string $protocol * @return array */ static function isLogin($openid, $openkey, $pf, $pfkey, $method = 'GET', $protocol = 'http') { /** * 参考 http://wiki.open.qq.com/wiki/v3/user/is_login * ret 返回码 * msg 错误信息 */ return self::api(self::S_QQ_API_IS_LOGIN, array( 'openid' => $openid, 'openkey' => $openkey, 'pfkey' => $pfkey, 'pf' => $pf, ), $method, $protocol); } /** * 获得防沉迷信息 * @param string $openid * @param string $openkey * @param string $pf * @param string $pfkey * @param int $cmd_type * @param string $method * @param string $protocol */ static function getAntiaddiction($openid, $openkey, $pf, $pfkey, $cmd_type = 2, $method = 'GET', $protocol = 'http') { /** * 参考 http://open.qqgame.qq.com/inside/lodyapi/get_antiaddiction_info.htm * ret 返回码 * msg 错误描述 * audit 身份信息: 0:未成年 1:成年 2:无身份证验证(1时gametime无意义) * gametime 在线时长 */ return self::api(self::S_QQ_API_IS_LOGIN, array( 'openid' => $openid, 'openkey' => $openkey, 'pfkey' => $pfkey, 'pf' => $pf, 'cmd_type' => $cmd_type, ), $method, $protocol); } /** * 检测蓝钻状态 * @param string $openid * @param string $openkey * @param string $pf * @param string $pfkey * @return mixed */ static function isBlueVip($openid, $openkey, $pf, $pfkey, $method = 'GET', $protocol = 'http') { /** * 此接口返回值 * is_blue_vip int 是否蓝钻, 1 表示是,0 表示不是 * is_blue_year_vip int 是否年费蓝钻;1 表示是,0 表示不是 * is_super_blue_vip int 是否豪华蓝钻;1 表示是,0 表示不是 * is_expand_blue_vip int 是否超级蓝钻;1 表示是,0 表示不是 * blue_vip_level int 蓝钻等级 * is_have_growth int 蓝钻是否具备成长值,1 表示是,0 表示不是 * is_mobile_blue_vip int 是否手机蓝钻;1 表示是,0 表示不是 * server_time int 服务器时间,用于比较蓝钻开通时间和到期时间,unix 时间戳,单位为秒 * vip_reg_time int 蓝钻开通时间,unix 时间戳,单位为秒 * year_vip_reg_time int 年费蓝钻开通时间,unix 时间戳,单位为秒 * super_vip_reg_time int 豪华蓝钻开通时间,unix 时间戳,单位为秒 * expand_vip_reg_time int 超级蓝钻开通时间,unix 时间戳,单位为秒 * vip_valid_time int 蓝钻到期时间,unix 时间戳,单位为秒 * year_vip_valid_time int 年费蓝钻到期时间,unix 时间戳,单位为秒 * super_vip_valid_time int 豪华蓝钻到期时间,unix 时间戳,单位为秒 * expand_vip_valid_time int 超级蓝钻到期时间,unix 时间戳,单位为秒 */ return self::api(self::S_QQ_API_BLUE_VIP, array( 'openid' => $openid, 'openkey' => $openkey, 'pfkey' => $pfkey, 'pf' => $pf, ), $method, $protocol); } /** * 检测黄钻状态 * @param string $openid * @param string $openkey * @param string $pf * @param string $pfkey * @return mixed */ static function isYellowVip($openid, $openkey, $pf, $pfkey, $method = 'GET', $protocol = 'http') { /** * 此接口返回值 http://wiki.open.qq.com/wiki/v3/user/is_vip * ret 返回码 * msg 消息 * is_lost 1:有部分数据丢失或错误,不要缓存。 * is_yellow_vip 是否为黄钻用户(0:不是; 1:是) * is_yellow_year_vip 是否为年费黄钻用户(0:不是; 1:是) * yellow_vip_level 黄钻等级。目前最高级别为黄钻8级(如果是黄钻用户才返回此字段) * is_yellow_high_vip 是否为豪华版黄钻用户(0:不是; 1:是)。(当pf=qzone、pengyou或qplus时返回) * yellow_vip_pay_way 用户的付费类型。0:非预付费用户(先开通业务后付费,一般指通过手机开通黄钻的用户);1:预付费用户(先付费后开通业务,一般指通过Q币Q点、财付通或网银付费开通黄钻的用户)。 */ return self::api(self::S_QQ_API_YELLOW_VIP, array( 'openid' => $openid, 'openkey' => $openkey, 'pfkey' => $pfkey, 'pf' => $pf, ), $method, $protocol); } /** * 返回是否心悦用户 * @param string $openid * @param string $openkey * @param string $pf * @param string $pfkey * @param string $method * @param string $protocol * @return array */ static function isXinyue($openid, $openkey, $pf, $pfkey, $method = 'GET', $protocol = 'http') { /** * 心悦接口:非普通API * xy_type: 心悦会员类型,1为普通心悦,2为蓝悦,3为财悦(目前暂时只支持1)。 * xy_level: 心悦会员等级。 */ return self::api(self::S_QQ_API_XINYUE_INFO, array( 'openid' => $openid, 'openkey' => $openkey, 'pfkey' => $pfkey, 'pf' => $pf, ), $method, $protocol); } /** * 返回腾讯所有VIP信息 * @param string $openid * @param string $openkey * @param string $pf * @param string $pfkey * @param string $method * @param string $protocol * @return array */ static function totalVIP($openid, $openkey, $pf, $pfkey, $method = 'GET', $protocol = 'http') { /** * 参考 http://wiki.open.qq.com/wiki/v3/user/total_vip_info * member_vip string 是否查询QQ会员信息,1为查询,0或者不写为不查询。 * blue_vip string 是否查询蓝钻信息,1为查询,0或者不写为不查询。 * yellow_vip string 是否查询黄钻信息,1为查询,0或者不写为不查询。 * red_vip string 是否查询红钻信息,1为查询,0或者不写为不查询。 * green_vip string 是否查询绿钻信息,1为查询,0或者不写为不查询。 * pink_vip string 是否查询粉钻信息,1为查询,0或者不写为不查询。 * superqq string 是否查询超级qq信息,1为查询,0或者不写为不查询。 * is_3366 string 是否查询3366信息,1为查询,0或者不写为不查询。 */ return self::api(self::S_QQ_API_TOTAL_VIP, array( 'openid' => $openid, 'openkey' => $openkey, 'pfkey' => $pfkey, 'pf' => $pf, ), $method, $protocol); } /** * 初始化QQApi(必须在调用本类其他方法前调用) * * @param int $appid 应用的ID * @param string $appkey 应用的密钥 * @param bool $sandbox 服务器ID */ static function init($appid, $appkey, $sandbox = false) { self::$appid = $appid; self::$appkey = $appkey; self::isSandbox($sandbox); } /** * 设置服务器域名(并不考虑$debug值) * @param $server_name */ static function setServerName($server_name) { return self::$server_name = $server_name; } static function setStatUrl($stat_url) { self::$stat_url = $stat_url; } /** * 设置调试模式(设置后URL也会根据$debug值判断) * @param bool $debug * @return bool */ static function isSandbox($debug = false) { self::$sandbox = $debug; self::$server_name = !!self::$sandbox ? self::OPEN_API_TENCENTYUN_TEST : self::OPEN_API_TENCENTYUN; return self::$sandbox; } CONST S_QQ_API_CONFIRM_DELIVERY = '/v3/pay/confirm_delivery'; /** * 提交反馈信息 * @param array $params * @param string $method * @param string $protocol * @return array */ static function confirmDelivery($params=array(), $method = 'GET', $protocol = 'http'){ $params = array( 'openid'=>$params['openid'], 'pf'=>$params['pf'], 'ts' => $params['openid'], 'payitem' => $params['payitemde'], 'provide_errno' => 0, 'token_id' => $params['token_id'], 'billno' => $params['billno'], 'amt' => $params['amt'], 'payamt_coins' => $params['payamt_coins'], 'providetype'=>0, 'zoneid' => $params['zoneid'] ? : 0, ); //file_put_contents('/tmp/order_delivery.txt', print_r($params, 1)."\r\n".self::$appid.'-'.self::$appkey.'-'.self::$sandbox."\r\n", FILE_APPEND); return self::api(self::S_QQ_API_CONFIRM_DELIVERY, $params, $method, $protocol); } /** * 执行API调用,返回结果数组 * * @param string $script_name 调用的API方法,比如/v3/user/get_info,参考 http://wiki.open.qq.com/wiki/API_V3.0%E6%96%87%E6%A1%A3 * @param array $params 调用API时带的参数 * @param string $method 请求方法 post / get * @param string $protocol 协议类型 http / https * @return array 结果数组 */ static function api($script_name, $params, $method = 'post', $protocol = 'http', $server_name='') { // 检查 openid 是否为空 if (!isset($params['openid']) || empty($params['openid'])) { return array( 'ret' => 'OPENAPI_ERROR_REQUIRED_PARAMETER_EMPTY', 'msg' => 'openid is empty'); } // 检查 openid 是否合法 if (!self::isOpenId($params['openid'])) { return array( 'ret' => 'OPENAPI_ERROR_REQUIRED_PARAMETER_INVALID', 'msg' => 'openid is invalid'); } // 无需传sig, 会自动生成 unset($params['sig']); // 添加一些参数 $params['appid'] = self::$appid; $params['format'] = self::$format; // 生成签名 $secret = self::$appkey . '&'; $sig = self::makeSig($method, $script_name, $params, $secret); $params['sig'] = $sig; $url = $protocol . '://' .( $server_name ? : self::$server_name ). $script_name; $cookie = array(); //记录接口调用开始时间 $start_time = self::getTime(); // 发起请求 $ret = self::makeRequest($url, $params, $cookie, $method, $protocol); if (false === $ret['result']) { return array( 'ret' => 'OPENAPI_ERROR_CURL ' . +$ret['errno'], 'msg' => $ret['msg'], ); } $result_array = json_decode($ret['msg'], true); // 远程返回的不是 json 格式, 说明返回包有问题 if (is_null($result_array)) { $result_array = array( 'ret' => 'OPENAPI_ERROR_RESPONSE_DATA_INVALID', 'msg' => $ret['msg'] ); } return $result_array; } static public function getTime() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } /** * 检查 openid 的格式 * * @param string $openid openid * @return bool (true|false) */ static private function isOpenId($openid) { return preg_match('/^[0-9a-fA-F]{32}$/i', $openid); } /** * 执行一个 HTTP 请求 * * @param string $url 执行请求的URL * @param mixed $params 表单参数 * 可以是array, 也可以是经过url编码之后的string * @param mixed $cookie cookie参数 * 可以是array, 也可以是经过拼接的string * @param string $method 请求方法 post / get * @param string $protocol http协议类型 http / https * @return array 结果数组 */ static public function makeRequest($url, $params, $cookie, $method = 'post', $protocol = 'http') { $query_string = self::makeQueryString($params); $cookie_string = self::makeCookieString($cookie); $ch = curl_init(); if ('GET' == strtoupper($method)) { curl_setopt($ch, CURLOPT_URL, "$url?$query_string"); } else { curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $query_string); } curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); // disable 100-continue curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); if (!empty($cookie_string)) { curl_setopt($ch, CURLOPT_COOKIE, $cookie_string); } if ('https' == $protocol) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } $ret = curl_exec($ch); $err = curl_error($ch); if (false === $ret || !empty($err)) { $errno = curl_errno($ch); $info = curl_getinfo($ch); curl_close($ch); return array( 'result' => false, 'errno' => $errno, 'msg' => $err, 'info' => $info, ); } curl_close($ch); return array( 'result' => true, 'msg' => $ret, ); } /** * 执行一个 HTTP 请求,以post方式,multipart/form-data的编码类型上传文件 * * @param string $url 执行请求的URL * @param mixed $params 表单参数,必须是array, 对于文件表单项 直接传递文件的全路径, 并在前面增加'@'符号 * 举例: array('upload_file'=>'@/home/xxx/hello.jpg', 'field1'=>'value1'); * @param mixed $cookie cookie参数 * 可以是array, 也可以是经过拼接的string * @param string $protocol http协议类型 http / https * @return array 结果数组 */ static public function makeRequestWithFile($url, $params, $cookie, $protocol = 'http') { $cookie_string = self::makeCookieString($cookie); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $params); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); // disable 100-continue curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); if (!empty($cookie_string)) { curl_setopt($ch, CURLOPT_COOKIE, $cookie_string); } if ('https' == $protocol) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } $ret = curl_exec($ch); $err = curl_error($ch); if (false === $ret || !empty($err)) { $errno = curl_errno($ch); $info = curl_getinfo($ch); curl_close($ch); return array( 'result' => false, 'errno' => $errno, 'msg' => $err, 'info' => $info, ); } curl_close($ch); return array( 'result' => true, 'msg' => $ret, ); } static public function makeQueryString($params) { if (is_string($params)) return $params; $query_string = array(); foreach ($params as $key => $value) { array_push($query_string, rawurlencode($key) . '=' . rawurlencode($value)); } $query_string = join('&', $query_string); return $query_string; } static public function makeCookieString($params) { if (is_string($params)) return $params; $cookie_string = array(); foreach ($params as $key => $value) { array_push($cookie_string, $key . '=' . $value); } $cookie_string = join('; ', $cookie_string); return $cookie_string; } /** * 生成签名 * * @param string $method 请求方法 "get" or "post" * @param string $url_path * @param array $params 表单参数 * @param string $secret 密钥 */ static public function makeSig($method, $url_path, $params, $secret) { $mk = self::makeSource($method, $url_path, $params); $my_sign = hash_hmac("sha1", $mk, strtr($secret, '-_', '+/'), true); $my_sign = base64_encode($my_sign); return $my_sign; } static private function makeSource($method, $url_path, $params) { $strs = strtoupper($method) . '&' . rawurlencode($url_path) . '&'; ksort($params); $query_string = array(); foreach ($params as $key => $val) { array_push($query_string, $key . '=' . $val); } $query_string = join('&', $query_string); return $strs . str_replace('~', '%7E', rawurlencode($query_string)); } /** * 验证回调发货URL的签名 (注意和普通的OpenAPI签名算法不一样,详见@refer的说明) * * @param string $method 请求方法 "get" or "post" * @param string $url_path * @param array $params 腾讯调用发货回调URL携带的请求参数 * @param string $secret 密钥 * @param string $sig 腾讯调用发货回调URL时传递的签名 * * @refer * http://wiki.open.qq.com/wiki/%E5%9B%9E%E8%B0%83%E5%8F%91%E8%B4%A7URL%E7%9A%84%E5%8D%8F%E8%AE%AE%E8%AF%B4%E6%98%8E_V3 */ static public function verifySig($method, $url_path, $params, $secret, $sig) { unset($params['sig']); // 先使用专用的编码规则对value编码 foreach ($params as $k => $v) { $params[$k] = self::encodeValue($v); } // 再计算签名 $sig_new = self::makeSig($method, $url_path, $params, $secret); return $sig_new == $sig; } /** * 回调发货URL专用的编码算法 * 编码规则为:除了 0~9 a~z A~Z !*()之外其他字符按其ASCII码的十六进制加%进行表示,例如"-"编码为"%2D" * @refer * http://wiki.open.qq.com/wiki/%E5%9B%9E%E8%B0%83%E5%8F%91%E8%B4%A7URL%E7%9A%84%E5%8D%8F%E8%AE%AE%E8%AF%B4%E6%98%8E_V3 */ static private function encodeValue($value) { $rst = ''; $len = strlen($value); for ($i = 0; $i < $len; $i++) { $c = $value[$i]; if (preg_match("/[a-zA-Z0-9!\(\)*]{1,1}/", $c)) { $rst .= $c; } else { $rst .= ("%" . sprintf("%02X", ord($c))); } } return $rst; } public function market($params, $method = 'get') { echo ''; var_dump($params); echo '
'; echo $sig = $params['sig']; $url_path = '/qqjz/Market'; //$url_path = '/cgi-bin/check_award'; unset($params['sig']);//验证用 unset($params['app_user_source']);// unset($params['app_contract_id']);// unset($params['app_custom']);// echo '
'; // 生成签名 echo $secret = $this->appkey . '&'; //$secret = '111222333'. '&'; $strs = strtoupper($method) . '&' . rawurlencode($url_path) . '&'; ksort($params); $query_string = array(); foreach ($params as $key => $val) { $value = self::encodeValue($val); array_push($query_string, $key . '=' . $value); } $query_string = join('&', $query_string); //var_dump($query_string); //echo $newGet = $strs . str_replace('~', '%7E', rawurlencode($query_string)); $my_sign = hash_hmac("sha1", $newGet, strtr($secret, '-_', '+/'), true); echo $my_sign = base64_encode($my_sign); die; } // *********** QQ罗盘上报相关 *********** // // QQ罗盘上报相关 /** * QQ 罗盘上报地址-充值 */ const QQ_COMPASS_URL_REPORT_CHARGE = 'http://tencentlog.com/stat/report_recharge.php'; /** * QQ 罗盘上报地址-主动注册登录 */ const QQ_COMPASS_URL_REPORT_REGISTER = 'http://tencentlog.com/stat/report_register.php'; /** * 支付充值:用户通过Q点/Q币兑换游戏内等值货币(例如“点券/金币/元宝”)的行为。 * 必填字段: * @param int $modifyfee 如果没有变化,则填0, 上报单位为Q分(100Q分 = 10Q点 = 1Q币)) * 推荐项: * $touid, toopenid, source, itemid, itemtype, itemcnt, modifyexp, totalexp, modifycoin, totalcoin, totalfee, level */ public function reportCharge($opuid, $opopenid, $gold = 0, $domain = 1) { // 必填项目 return self::compassReport($opuid, $opopenid, 2, array('modifyfee'), $gold, $domain); } /** * 默认的构建接口 * 必选: * @param string $version 若未上报,则自动补齐为:1 * @param string $appid 应用ID * @param string $userip 若未上报,则自动补齐为:http请求头里的客户机ip * @param string $svrip 若未上报,则自动补齐为:该cgi所在server的ip * @param int $time 若未上报,则自动补齐为:服务器当前时间 * @param string $domain 域 * @param string $worldid 若未上报,则自动补齐为:1 * @param string $opuid * @param string $opopenid */ static function compassReport($opuid, $opopenid, $report_flag = 1, $params = array(), $gold=0, $domain=1) { $req = Yii::app()->request; // 必填项目 $version = $req->getParam('version'); // 由调用接口传 $appid = self::$appid; // 由调用接口传 $userip = $req->userHostAddress; $svrip = $req->getParam('srvip'); // 由调用接口传 $time = time(); $worldid = $req->getParam('worldid'); // 由调用接口传 // $opuid = $req->getParam('opuid'); // 由调用接口传 // $opopenid = $req->getParam('opopenid'); // 构建默认必选参数表 $params_str = <<getParam($v); if ($tmp_v) { $params_str .= "&{$v}=" . $tmp_v; } } $params_str.="&modifyfee=$gold"; switch ($report_flag) { case 1: $url = self::QQ_COMPASS_URL_REPORT_REGISTER; break; case 2: $url = self::QQ_COMPASS_URL_REPORT_CHARGE; break; default: $url = ''; } if ( $url ) { file_put_contents('/tmp/compass.txt', $url.'?'.$params); return Utils::get($url, $params_str, false); } return 0; } // *********** open.qq.com 服务器列表获取工具 *********** // /** * 取得腾讯开平的服务器配置 * @return mixed */ static function getServerlist() { $cacheKey = '__CACHE_OPEN_QQ_SERVER_LIST__'.self::$appid; $data = Cache::cache_get($cacheKey); if ( !$data || BOSS_NO_CACHE){ $str = Utils::get('http://openwebgame.qq.com/app/RecentServerInfo.php?appid=' . self::$appid, null, false); $str = str_replace('var user_all_servers = ', '', $str); $tmp_array = explode('var user_recent_servers', $str); $str = str_replace(';', '', $tmp_array[0]); // 处理服务器列表去掉历史记录 $data = json_decode($str, 1); // 给一个300秒的缓存 Cache::cache_set($cacheKey, $data, 300); } return $data; } /** * 取得推荐服列表 * @return mixed */ static function getRecommendServers(){ $cacheKey = $cacheKey = '__CACHE_OPEN_QQ_SERVER_RECOMMEND__'.self::$appid; $recommends = Cache::cache_get($cacheKey); if ( !$recommends || BOSS_NO_CACHE){ $data = self::getServerlist(); if (empty($data) || !is_array($data)){ return $recommends; } $recommends = array(); $lastServer = null; foreach($data as $zone){ if ( empty($zone['subcat'])){ continue; } foreach($zone['subcat'] as $srv){ if ( $srv['sAttrValue']['iIsRecommend'] > 0 ){ $recommends[] = $srv; } if ( !$lastServer ) $lastServer = $srv; } } if ( count($recommends) > 0 ){ // 找到1个以上的推荐服就缓存300秒 Cache::cache_set($cacheKey, $recommends, 300); } else if ( $lastServer ){ // 不存在推荐服时就取得一个最新的服务器, 即openqq服务器列表中最上面的那个服 $recommends[] = $lastServer; Cache::cache_set($cacheKey, $recommends, 60); } else { // 尚未添加任意服务器也要缓存5秒防刷 Cache::cache_set($cacheKey, $recommends, 5); } } return $recommends; } }