做PHP对接很久了,也总结了一些常用的工具类。希望给大家带来方便。
<?php
/**
* 腾讯接口统一API 此接口应该先调用init方法后再执行其他操作.即 QqApi::init($appid, $appkey, $server_name);
*/
class QqApi
{
private static $sandbox = true;
private static $appid = 0;
private static $appkey = '';
private static $server_name = '';
private static $format = 'json';
private static $stat_url = "apistat.tencentyun.com";
CONST OPEN_API_TENCENTYUN = 'openapi.tencentyun.com';
CONST OPEN_API_TENCENTYUN_NEW = 'openapi.minigame.qq.com';
CONST OPEN_API_TENCENTYUN_TEST = 'openapi.sparta.html5.qq.com'; // 119.147.19.43
CONST OPEN_API_GET_PFKEY = '113.108.20.23';
// 腾讯PF常量
CONST PID_TENCENT = 'tencent';
CONST PF_QQGAME = 'qqgame';
CONST PF_QZONE = 'qzone';
CONST PF_WEBSITE = 'website';
CONST PF_OPENAPP = 'qqopenapp';
CONST PF_TGP = 'tgp';
CONST PF_UNION = 'union';
CONST PF_XINYUE = 'xinyue';
// **************** 集市任务cmd码 ****************
/**
* 开发者仅需要查询任务步骤是否完成,返回步骤完成状态。
*/
CONST TASK_MARKET_CMD_CHECK = 'check';
/**
* 开发者需要查询任务步骤是否完成,若步骤已完成,直接给用户发货(payitem),并返回发货是否成功。
*/
CONST TASK_MARKET_CMD_CHECK_AWARD = 'check_award';
/**
* 平台通知开发者直接给给用户发货,开发者返回发货是否成功。
*/
CONST TASK_MARKET_CMD_AWARD = 'award';
/**
* 反馈给腾讯任务集市的状态码
* !!沙箱联调时,ret返回码仅能返回0和3!!
*/
/**
* 步骤已完成 或 奖励发放成功
*/
CONST TASK_MARKET_RET_OK = 0;
/**
* 用户尚未在应用内创建角色
*/
CONST TASK_MARKET_RET_NO_ROLE = 1;
/**
* 用户尚未完成本步骤
*/
CONST TASK_MARKET_RET_NOT_FINISHED = 2;
/**
* 该步骤奖励已发放过
*/
CONST TASK_MARKET_RET_HAS_AWARDED = 3;
/**
* token已过期
*/
CONST TASK_MARKET_RET_TOKEN_EXPIRE = 100;
/**
* token不存在
*/
CONST TASK_MARKET_RET_TOKEN_NOT_FOUND = 101;
/**
* 奖励发放失败
*/
CONST TASK_MARKET_RET_AWARD_FAILS = 102;
/**
* 请求参数错误
*/
CONST TASK_MARKET_RET_PARAM_ERROR = 103;
/**
* @param string $pf
* @param string $script_name
* @return string
*/
static function parseServerName($pf, $script_name = '')
{
return $pf == 'qqgame' && in_array($script_name, [
self::S_QQ_API_USER_INFO,
self::S_QQ_API_BLUE_VIP,
self::S_QQ_API_IS_LOGIN,
]) ? self::OPEN_API_TENCENTYUN_NEW : self::OPEN_API_TENCENTYUN;
}
/**
* 玩家信息
*/
CONST S_QQ_API_USER_INFO = '/v3/user/get_info';
/**
* 取得PFKEY
*/
CONST S_QQ_API_GET_PFKEY = '/v3/user/get_pfkey';
/**
* QQ API 蓝钻信息
*/
CONST S_QQ_API_BLUE_VIP = '/v3/user/blue_vip_info';
/**
* QQ API 黄钻信息
*/
CONST S_QQ_API_YELLOW_VIP = '/v3/user/is_vip';
/**
* QQ API 各类腾讯增值服务信息
*/
CONST S_QQ_API_TOTAL_VIP = '/v3/user/total_vip_info';
/**
* QQ API 心悦信息
*/
CONST S_QQ_API_XINYUE_INFO = '/v3/user/get_xinyue_info';
/**
* QQ API 是否登录
*/
CONST S_QQ_API_IS_LOGIN = '/v3/user/is_login';
/**
* QQ API 防沉迷接口
*/
CONST S_QQ_API_ANTIADDICTION_INFO = '/v3/user/get_antiaddiction_info';
/**
* QQ API 获取交易TOKEN
*/
CONST S_QQ_API_BUY_GOODS = '/v3/pay/buy_goods';
/**
* 取得包月礼包
*/
CONST S_QQ_API_GET_TOKEN = '/v3/pay/get_token';
/**
* 实名认证查询
*/
CONST S_QQ_API_REAL_NAME_QUERY = '/v3/user/gameapi_real_name_query';
/**
* 实名认证查询
* 本接口需要申请才能用!返回格式:{"ret":0, "msg":"OK"}其中附加返回参数有:
* int age:年龄
* int real_name_flag:实名标识:0=未认证 1=认证中 2=已认证 3=认证失败 4=无认证
* int is_adult:1=成年 0=未成年
* @param string $openid
* @param string $openkey
* @param string $method
* @param string $protocol
* @return array
*/
static function realNameQuery($openid, $openkey, $method='GET', $protocol='http'){
$params = [
'openid'=>$openid,
'openkey'=>$openkey,
];
return self::api(self::S_QQ_API_REAL_NAME_QUERY, $params, $method, $protocol, 'openapi.minigame.qq.com');
}
/**
* 实名认证
*/
CONST S_QQ_API_REAL_NAME_REGISTER = '/v3/user/gameapi_real_name_register';
/**
* 实名认证
* 本接口需要申请才能用!返回格式:{"ret":0, "msg":"OK"}其中ret为:
* 0:请求成功
* 1:系统错误
* 2:没有权限
* 3:访问频限
* 4:该用户没有实名认证
* 5:用户已注册
* 6:证件绑定超过限制
* 7:用户没注册(修改时可能返回)
* 8:证件没有绑定openid
* 100:非法参数输入
* 101:非法的身份证
* 102:非法的生日
* 103:非法的中文名字
* 104:token过期或openid不合法
* 返回值:{"ret":0,"msg":"OK","uin":0,"reg_result":0,"seq":0,"pf":}
* @param string $openid
* @param string $openkey
* @param string $idnumber
* @param string $name
* @return mixed
*/
static function realNameRegister($openid, $openkey, $idnumber, $name, $method='GET', $protocol='http'){
$params = [
'openid'=>$openid,
'openkey'=>$openkey,
'idnumber'=>$idnumber,
'name'=>$name,
];
return self::api(self::S_QQ_API_REAL_NAME_REGISTER, $params, $method, $protocol, 'openapi.minigame.qq.com');
}
/**
* 取得包月礼包token
* 参考 http://wiki.open.qq.com/wiki/v3/pay/get_token
* @param string $openid
* @param string $openkey
* @param string $pf
* @param string $pfkey
* @param string $discountid
* @param int $tokentype
* @param string $method
* @param string $protocol
* @return array
*/
static function getToken($openid, $openkey, $pf, $pfkey, $discountid, $tokentype = 1, $method = 'GET', $protocol = 'http')
{
$params = array(
'openid' => $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;
}
/**
* 设置API域名
* @param string $domain
* @return string
*/
static function setDomain($domain)
{
return self::$server_name = $domain;
}
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;
self::$server_name = $server_name ?: self::parseServerName($params['pf'], $script_name);
$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)) {
Yii::info($url . '?' . $query_string);
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:'));
/// $cookie_string = 'session_id=openid;session_type=openkey;org_loc=%2Fmpay%2Fget_balance_m';
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 '<pre>';
var_dump($params);
echo '<br><br>';
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 '<br>';
// 生成签名
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 = <<<EOT
version={$version}&appid={$appid}&userip={$userip}&svrip={$svrip}&time={$time}&domain={$domain}&worldid={$worldid}&opuid={$opuid}&opopenid={$opopenid}
EOT;
// 构造附加字段
foreach ($params as $v) {
$tmp_v = $req->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);
$path = Yii::getPathOfAlias('application.config');
$str = file_get_contents($path.'/RecentServerInfo.txt');
$str = str_replace('var user_all_servers = ', '', $str);
$str = str_replace('var user_all_servers = ', '', $str);
$str = substr($str, 0, strrpos($str, '}}]}];') +5);
// 处理服务器列表去掉历史记录
$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;
}
}
网友评论