2016/03/24

对接微信公众号卡卷发放


之前在微信公众号里对接过H5游戏,获取微信用户的基本信息和行为进行入库。写完就忘记了,这周需要在新的公众号里做一个卡卷发放的功能对接,又跑去公众号里看了一遍文档。

玩法需求:微信打开链接,用户同意授权公众号获取基本信息,然后跳转到HTML,玩家填写姓名号码提交,即可获得卡卷。


拉取用户基本信息

1.配置授权回调域名

开发-->接口权限-->网页服务-->网页账号-->网页授权获取用户基本信息

2.配置用户同意授权后的回调地址url

https://open.weixin.qq.com/connect/oauth2/authorize?appid=`APPID`&redirect_uri=`REDIRECT_URI`&response_type=code&scope=SCOPE&state=`STATE`#wechat_redirect

APPID:          微信appid
REDIRECT_URI:   回调url,需要进行urlencode
STATE:          标识码

3.回调回来后可获得code,state参数。通过这code参数可获取用户openid和用户access_token,紧接着就可以获取用户基本信息。简单的PHP例子:

//微信appid
$appId = "wx11a11e1faea111111";
//微信appsecret
$appSecret = "bd11cf1df1e11b11ffefff1f11d11b11";

//获得code,state参数
$code = $_GET['code'];
$state = $_GET['state'];
if ($state != "STATE") return;

//获取用户openid和用户access_token
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appId&secret=$appSecret&code=$code&grant_type=authorization_code";
$result = json_decode(file_get_contents($url), TRUE);
if (isset($result['errcode'])) return;

//获取用户信息
$openid = $result['openid'];
$access_token = $result['access_token'];
$info_url = "https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid";
$result = json_decode(file_get_contents($info_url), TRUE);

return $result;

拉取用户信息就算完成,官网文档地址:http://mp.weixin.qq.com/wiki/4/9ac2e7b1f1d22e9e57260f6553822520.html


获取微信公众号相关token

1.获取公众号 access_token,access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。

官网文档地址:http://mp.weixin.qq.com/wiki/14/9f9c82c1af308e3b14ba9b973f99a8ba.html

2.获取公众号 jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过第一步的 access_token 来获取。

官网文档地址:http://mp.weixin.qq.com/wiki/11/74ad127cc054f6b80759c40f77ec03db.html 附录1-JS-SDK使用权限签名算法

3.获取公众号卡卷 api_ticket,api_ticket 是用于调用卡券相关接口的临时票据,有效期为7200秒,通过第一步的 access_token 来获取。

官网文档地址:http://mp.weixin.qq.com/wiki/11/74ad127cc054f6b80759c40f77ec03db.html 附录4-卡券扩展字段及签名生成算法

//微信appid
$appId = "wx11a11e1faea111111";
//微信appsecret
$appSecret = "bd11cf1df1e11b11ffefff1f11d11b11";

//获取access_token
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appId&secret=$appSecret";
$result = json_decode(file_get_contents($url), TRUE);
$access_token = $result["access_token"];

//获取jsapi_ticket
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$access_token";
$result = json_decode(file_get_contents($url), TRUE);
$jsapi_ticket = $result["ticket"];

//获取api_ticket
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card&access_token=$access_token";
$result = json_decode(file_get_contents($url), TRUE);
$api_ticket = $result["ticket"];

以上3个票据调用次数非常有限,所以必须将它们缓存起来,可以入库,也可以文件落地。


获取相关签名

1.设置JS接口安全域名后,公众号开发者可在该域名下调用微信开放的JS接口

设置-->公共号设置-->功能设置-->JS接口安全域名

2.获取JS-SDK签名,用于js初始化配置

//随机字符串 用于签名
function createNonceStr($length = 16) {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $str = "";
    for ($i = 0; $i < $length; $i++) {
        $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    }
    return $str;
}

//js_api_ticket签名内容
function getJsApiSignPackage() {
    // 注意 URL 一定要动态获取,不能 hardcode.
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
    $timestamp = time();
    $nonceStr = createNonceStr();
    // 这里参数的顺序要按照 key 值 ASCII 码升序排序
    $string = "jsapi_ticket=$jsapi_ticket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

    $signature = sha1($string);
    $signPackage = array(
        "appId"     => $appId, //公共号 appid
        "nonceStr"  => $nonceStr, //随机字符串
        "timestamp" => $timestamp, //时间戳
        "url"       => $url, //完整url #打后除掉
        "signature" => $signature, //sha1签名
        "rawString" => $string //签名前原文字符串
    );
    return $signPackage;
}

官网文档地址:http://mp.weixin.qq.com/wiki/11/74ad127cc054f6b80759c40f77ec03db.html 附录1-JS-SDK使用权限签名算法

3.获取卡卷签名,用于卡卷发放

//api_ticket签名内容
function getApiSignPackage($card_id="", $code="", $openid="") {
    $timestamp = time();
    $nonceStr = $createNonceStr();

    //字符串的字典序排序
    $string = array((string)$card_id, (string)$code, (string)$openid, (string)$timestamp, (string)$api_ticket, (string)$nonceStr);
    sort($string, SORT_STRING);
    $signature = sha1(implode($string));

    $signPackage = array(
        "appId" => $appId, //公共号 appid
        "cardId" => $card_id, //卡卷id
        "code" => $code, //指定的卡券code码
        "nonceStr"  => $nonceStr, //随机字符串
        "timestamp" => $timestamp, //时间戳
        "signature" => $signature, //sha1签名
        "rawString" => $string, //签名前原文字符串
    );

    return $signPackage;
}

js文件配置

我这边用了PHP的twig模板

wx.config({
    debug: false,
    appId: "{{appid}}",
    timestamp: {{jsapi.timestamp}},
    nonceStr: "{{jsapi.nonceStr}}",
    signature: "{{jsapi.signature}}",
    jsApiList: [
        // 所有要调用的 API 都要加到这个列表中
        'checkJsApi',
        'addCard',
        'chooseCard',
        'openCard'
    ]
});

wx.error(function(res) {
    alert("error>>>>>"+res.errMsg);
});

wx.ready(function () {
    // 在这里调用 API

    //用户提交数据领取卡卷
    $('#getcard').click(function(){
        var post_data = {
            "pname":"c2s_card_give",
            "name":$("#name").val(),
            "phone":$("#phone").val()
        };
        function post_func(data, status) {
            var obj = JSON.parse(data);
            if (obj.pname == "s2c_card_give") {
                    //校验成功给予卡卷
                    wx.addCard({
                        cardList: [{
                        cardId: "{{api.cardId}}",
                        cardExt: '{"code": "", "openid": "", "timestamp": "{{api.timestamp}}", "signature":"{{api.signature}}", "nonce_str": "{{api.nonceStr}}"}'
                    }],
                    //微信发放卡卷成功回调
                    success: function (res) {
                        alert("success");
                    }
                });
            }
        }
        $.post("/card_give", post_data, post_func);
    });
});