JSSDK.php
4.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php namespace common\exts\wechat;
use common\exts\wechat\Http;
use common\exts\wechat\AccessToken;
use common\services\redis\RedisConfig;
use yii;
use Redis;
use common\exts\wechat\Log as WxLog;
/**
* Class JSSDK
* @package common\exts\wechat
*/
class JSSDK
{
private $appId;
private $appSecret;
private $redis;
//const CACHE_TICKET_ID = 'WECHAT_TICKET';
/**
* @param $options
*/
public function __construct($options)
{
$this->redis = \yii::$app->redis;
$this->appId = isset($options['appid'])?$options['appid']:'';
$this->appSecret = isset($options['appsecret'])?$options['appsecret']:'';
}
/**
* @return array
*/
public function getSignContext($url = false)
{
$jsapiTicket = $this->getJsApiTicket();
// 注意 URL 一定要动态获取,不能 hardcode.
if (!$url) {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
}
$timestamp = time();
$nonceStr = $this->createNonceStr();
// 这里参数的顺序要按照 key 值 ASCII 码升序排序
$string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url";
$signature = sha1($string);
$signContext = new \stdClass();
$signContext->appId = $this->appId;
$signContext->nonceStr = $nonceStr;
$signContext->timestamp = $timestamp;
$signContext->url = $url;
$signContext->signature = $signature;
$signContext->rawString = $string;
return $signContext;
}
/**
* @param int $length
* @return string
*/
public 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;
}
/**
* @return mixed
*/
public function getJsApiTicket()
{
// 跟踪日志
WxLog::init();
// jsapi_ticket
$data = null;
$cacheTicketKey = RedisConfig::WECHAT_TICKET_PREFIX . $this->appId;
if($this->redis->exists($cacheTicketKey)){
$data = json_decode($this->redis->get($cacheTicketKey));
}
if(!$data){
$data = new \stdClass();
$data->expire_time = null;
$data->access_token = null;
}
//WxLog::DEBUG("getJsApiTicket: cacheTicketKey[" . $cacheTicketKey . "]: " . json_encode($data));
if ($data->expire_time < time()) {
$accessToken = AccessToken::get($this->appId, $this->appSecret);//API 的access token
// 如果是企业号用以下 URL 获取 ticket
// $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
$res = json_decode(Http::get($url));
//WxLog::DEBUG("getJsApiTicket: result=>" . json_encode($res));
// 检测到40001access_token失效错误立刻强制刷新,纠正错误[weigong-2016-06-16 16:25:27]
if(isset($res->errcode) && $res->errcode == 40001) {
WxLog::WARN("getJsApiTicket: access_token失效, 自动恢复!");
$accessToken = AccessToken::get($this->appId, $this->appSecret, true); // 强制刷新access_token
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
$res = json_decode(Http::get($url));
}
$ticket = null;
if (isset($res->ticket)) {
$ticket = $res->ticket;
$data->expire_time = time() + 7000;
$data->jsapi_ticket = $ticket;
$this->redis->set($cacheTicketKey, json_encode($data));
$this->redis->expireat($cacheTicketKey, $data->expire_time); // 到期自动删除
WxLog::DEBUG("jsapi_ticket刷新: jsapi_ticket=[" . $data->jsapi_ticket . "], expire_time=["
. $data->expire_time . "], 修改时间=[" . date("Y-m-d H:i:s", time()) . "], cacheTicketKey["
. $cacheTicketKey . "]");
}
} else {
$ticket = $data->jsapi_ticket;
}
return $ticket;
}
}