调用扫一扫功能有几个步骤
简单而言:
1 获取accesstoken
2 获取jsapi_ticket
3 生成签名signature
调用wx.config wx.ready wx.error
三个function
=======我个人的代码在最后面,只是部分代码。具体的需要你们自己写,我用的是LaneWechat
(1和2都需要自己把它存储起来,ticket的调用次数比较少,所以更要注意,记住要写一个中转器自动检查更新这两个数据,而不是主动请求的时候才去生成新的凭据,否则在会出现延迟,页面出现错误,需要再次刷新才正常)
============================详细介绍:
在这里要说的是,我之前提示的是invaild signature 结果用官方的接口调试工具发现我生成的加密数据和官方生成的不同,调试工具:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
结果发现,是因为我的timestramp 和 noncsrt 用的不是同一个,他们分别执行了两次,对不上号所以出错了。大家要注意
- 参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):../15/54ce45d8d30b6bf6758f68d2e95bc627.html
- 用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回如下JSON:
{ "errcode":0, "errmsg":"ok", "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA", "expires_in":7200 }
获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。
签名算法
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
即signature=sha1(string1)。 示例:
- noncestr=Wm3WZYTPz0wzccnW
- jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
- timestamp=1414587457
- url=http://mp.weixin.qq.com?params=value
步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步骤2. 对string1进行sha1签名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事项
- 签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
- 签名用的url必须是调用JS接口页面的完整URL。
- 出于安全考虑,开发者必须在服务器端实现签名的逻辑。
class JsapiTicket{
public static function getJsapiTicket(){
$jsapi_ticket = self::_checkJsapiTicket();
if($jsapi_ticket === false){
$jsapi_ticket = self::_getJsapiTicket();
}
return $jsapi_ticket['ticket'];
}
private static function _getJsapiTicket(){
$accessToken=AccessToken::getAccessToken();//获取access_token
//通过获取的accessToken请求 jsapi Ticket
//请求地址: https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
//GET方式请求
// print_r('get_accesstoken====>'.$accessToken);
$ticket_url='https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='.$accessToken.'&type=jsapi';
$jsapi_ticket = Curl::callWebServer($ticket_url, '', 'GET');
// print_r('JsapiTicket:====>>>'.$jsapi_ticket);
$jsapi_ticket['time'] = time();//设置时间戳
$jsapi_ticketJson = json_encode($jsapi_ticket);
$f = fopen('jsapi_ticket', 'w+');//将ticket保存下来。它也是有效期为7200S,而且接口的调用次数比accesstoken少
fwrite($f, $jsapi_ticketJson);
fclose($f);
// print_r('jsapi_ticket====>'.$jsapi_ticketJson);
return $jsapi_ticketJson;
}
/**
* @descrpition 检测微信ticket是否过期
*
* @return bool
*/
private static function _checkJsapiTicket(){
$data = file_get_contents('jsapi_ticket');
//print_r('从文件中读取的accesstoken,data是 :'.$data);
$jsapi_ticket['value'] = $data;
if(!empty($jsapi_ticket['value'])){
$jsapi_ticket = json_decode($jsapi_ticket['value'], true);
if(time() - $jsapi_ticket['time'] < $jsapi_ticket['expires_in']-200){//200为缓冲期
return $jsapi_ticket;
}
}
return false;//无论是ACCESSTOKEN过期了还是没有ACCESSTOKEN,都返回FALSE
}
}
$randNumber=getRandChar(10);//随机字符串,这个是必要的
$curtime=time();//生成一个时间戳
function ticket(){
$ticket=JsapiTicket::getJsapiTicket();//获取ticket
//print_r($ticket);
return $ticket;
}
function getRandChar($length){
$str = null;
$strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
$max = strlen($strPol)-1;
for($i=0;$i<$length;$i++){
$str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
}
return $str;
}
function getSignature(){
//获取SHA1加密后的字符串(官方有个加密检测工具,如果生成的最后数据跟你的生成的不一样,就说明是错的,其中有可能错的就是,你生成了两次的随机数或者两次的时间戳,所以务必确认你生成的参数和你提交的参数是相同的)
global $randNumber;
global $curtime;
$str="jsapi_ticket=".ticket()."&noncestr=".$randNumber."×tamp=".$curtime."&url=http://weixin.ittun.com/huayuanWechat/saomiao.php";
//echo $str;
$signature=sha1($str);
return $signature;
//return $str;
}
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appid, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: signature,// 必填,签名,见附录1
jsApiList: ['scanQRCode'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
mui.alert('微信接口准备就绪');
mui.alert('开始调用扫一扫接口');
wx.scanQRCode({
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
}
});
});
});
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
mui.alert('微信接口调用失败');
});
测试完成后再wx.config方法中的debug参数设置为false,这样alert窗口的提示就不会弹出来了