`

来一个腾讯开平的工具类

    博客分类:
  • 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_TEST = '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;

    /**
     * 玩家信息
     */
    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';

    /**
     * 取得包月礼包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;
    }


    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 '<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);
            $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;
    }
}

 

 

分享到:
评论

相关推荐

    腾讯邮件发送工具类

    【腾讯邮件发送工具类】是基于Java编程语言开发的一个实用工具,主要目的是简化通过腾讯邮箱发送邮件的过程。这个工具类通常包含了一系列方法,用于设置邮件的收件人、主题、正文,以及添加附件等操作。它可能依赖于...

    腾讯云对象存储静态工具类(CosUtils.java),快速上手!!!

    腾讯云对象存储静态工具类,满足日常工作使用,每个方法都有注释,快速上手!记得先引入Maven依赖,在配置文件中配置对象存储所属参数!

    C#腾讯AI 接口签名工具及Demo

    C#腾讯AI 接口签名工具 在工具类中有个完整的语音合成的Demo 具体接口文档地址参照...并不是所有的接口都是一样的 ,所以本demo 和工具类希望能给开发者和各位同学提供一个思路,感谢,有问题留言提出!

    腾讯云COS桌面工具(64位)

    【腾讯云COS桌面工具(64位)】是一款专为Windows操作系统设计的客户端软件,旨在简化用户在腾讯云COS(Cloud Object Storage)对象存储服务中的数据管理任务。这款64位版本的工具提供了直观的图形用户界面,让用户...

    腾讯优图-图片扫描,获取卡号和密码工具类

    使用这个工具类时,首先需要调用腾讯优图提供的API接口,将待处理的图片作为输入。这些API可能包括上传图片、设置识别区域、指定识别模式等功能。在调用API时,通常需要提供API密钥和访问令牌,以确保安全性和合法性...

    android app调用高德百度腾讯路线规划导航工具类

    android app集成调用第三方地图(高德,百度,腾讯)路线规划导航工具类

    微信小程序支付工具类

    微信小程序支付工具类是开发者为了简化微信支付流程而编写的代码模块,它的主要目标是提供一个易用且可定制的接口,以便在微信小...总的来说,这个工具类的存在大大降低了微信小程序支付的开发难度,提高了开发效率。

    微信小程序的常用功能整理(封装的wx.request请求方法,腾讯地图定位+位置选择+距离计算,utils工具类(常用方法的封装))

    其次,腾讯地图在微信小程序中的应用是一个重要部分。通过引入腾讯地图SDK,我们可以实现定位、位置选择以及距离计算等功能。例如,`wx.getLocation`可以获取用户当前的经纬度信息,然后通过`TMap`的定位接口进行高...

    腾讯AI人脸融合jar包和工具类

    "腾讯AI人脸融合jar包和工具类"是一个专门用于人脸融合的Java开发工具包,它包含了必要的库文件和源码,便于开发者集成到自己的项目中,实现人脸识别和融合功能。 1. **Java接口**:这个jar包提供了Java接口,使得...

    腾讯截图工具

    腾讯截图工具是一款由腾讯公司开发的高效屏幕截图软件,它为用户提供了一种简便快捷的方式,以捕获并编辑计算机屏幕上的任何区域。该工具在日常办公、学习和娱乐中广泛使用,尤其对于需要频繁分享屏幕内容的用户来说...

    Java地图工具类计算地球上两点之间的距离

    在Java中,我们可以创建一个名为`MapUtils`的工具类,包含一个静态方法来执行此计算。以下是一个简单的实现: ```java public class MapUtils { private static final double EARTH_RADIUS_KM = 6371.0; public ...

    发送邮件工具类,支持QQ邮箱

    总的来说,这个“发送邮件工具类,支持QQ邮箱”为开发者提供了一个高效、安全且方便的途径来发送邮件,尤其是当需要发送多附件时,它的价值更加突出。通过熟练掌握此类工具,开发者可以轻松地将邮件功能集成到各种...

    腾讯GT工具

    腾讯GT工具,全称为“腾讯优测通用测试框架”(Generic Testing Framework),是由腾讯公司推出的一款专业级移动应用性能测试工具。它主要针对Android和iOS平台的应用程序,为开发者和测试工程师提供了全面、深入的...

    腾讯小工具 腾讯小工具 腾讯小工具

    【腾讯小工具】是腾讯公司推出的一系列实用小软件的统称,这些工具通常轻量级、便捷,旨在解决用户在日常使用电脑时遇到的各种问题。"DeskGo_3.1.1420.127.exe" 文件很可能是其中的一款应用,根据命名规则,我们可以...

    腾讯云签名工具

    腾讯云签名工具是一款用于在腾讯云服务中进行安全通信的重要组件。它支持多种编程语言,如Java、Node.js、C#、PHP和C++,确保开发者可以方便地集成到自己的应用环境中,实现高效且安全的云签名功能。下面将详细阐述...

    腾讯通讯工具

    用户可以创建不同的讨论组,根据项目或任务来组织成员,这样就能让相关人员在一个平台上集中讨论,提高了沟通的针对性和效率。群组内还支持设置管理员,以便管理成员权限和消息通知,保持群组秩序。 除了基础功能,...

    C#腾讯AI 接口签名工具及语音合成Demo(适合小白)

    在demo中将标注的字段改为你自己注册的相应字段即可,语音合成的demo就能跑起来,工具类和demo仅提供学习和参考使用,并不是所有的接口都是一样的 ,所以本demo 和工具类希望能给开发者和各位同学提供一个思路,感谢...

    腾讯精品课视频解析批量下载工具助手

    总的来说,【腾讯精品课视频解析批量下载工具助手】为学习者提供了一个方便的途径,使他们可以更加灵活地管理和学习腾讯课堂的课程内容。然而,合理、合法使用这些工具至关重要,尊重版权并保护个人信息是每个互联网...

    腾讯云COS的Java版SDK测试Demo(增删改查)

    COS中的每个对象都包含一个对象键、内容和元信息,如内容类型、存储类等。 对于Java开发者,腾讯云提供了Java SDK,使得我们可以方便地在Java应用中调用COS的相关功能。在开始之前,确保已经安装了JDK,并配置了...

Global site tag (gtag.js) - Google Analytics