1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the slince/smartqq package. |
5
|
|
|
* |
6
|
|
|
* (c) Slince <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Slince\SmartQQ; |
13
|
|
|
|
14
|
|
|
use GuzzleHttp\Cookie\CookieJar; |
15
|
|
|
use Slince\SmartQQ\Exception\RuntimeException; |
16
|
|
|
|
17
|
|
|
class CredentialResolver |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* 客户端id(固定值). |
21
|
|
|
* |
22
|
|
|
* @var int |
23
|
|
|
*/ |
24
|
|
|
protected static $clientId = 53999199; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var CookieJar |
28
|
|
|
*/ |
29
|
|
|
protected $cookies; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* 获取ptwebqq的地址 |
33
|
|
|
* |
34
|
|
|
* @var string |
35
|
|
|
*/ |
36
|
|
|
protected $certificationUrl; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var Client |
40
|
|
|
*/ |
41
|
|
|
protected $client; |
42
|
|
|
|
43
|
|
|
public function __construct(Client $client) |
44
|
|
|
{ |
45
|
|
|
$this->client = $client; |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* 获取授权凭据. |
50
|
|
|
* |
51
|
|
|
* @param callable $qrCallback |
52
|
|
|
* @return Credential |
53
|
|
|
*/ |
54
|
|
|
public function resolve($qrCallback) |
55
|
|
|
{ |
56
|
|
|
$this->cookies = new CookieJar(); |
57
|
|
|
|
58
|
|
|
//获取二维码资源 |
59
|
|
|
$response = $this->sendRequest(new Request\GetQrCodeRequest()); |
60
|
|
|
$qrCallback((string)$response->getBody()); |
61
|
|
|
|
62
|
|
|
//查找"qrsig"参数 |
63
|
|
|
$qrSign = $this->findQRSign(); |
64
|
|
|
//计算ptqrtoken |
65
|
|
|
$ptQrToken = Utils::hash33($qrSign); |
66
|
|
|
|
67
|
|
|
//验证状态 |
68
|
|
|
while (true) { |
69
|
|
|
//查看二维码状态 |
70
|
|
|
$status = $this->getQrCodeStatus($ptQrToken); |
71
|
|
|
|
72
|
|
|
// 认证成功 |
73
|
|
|
if (Request\VerifyQrCodeRequest::STATUS_CERTIFICATION === $status) { |
74
|
|
|
//授权成功跳出状态检查 |
75
|
|
|
break; |
76
|
|
|
} elseif (Request\VerifyQrCodeRequest::STATUS_EXPIRED == $status) { |
77
|
|
|
//查找"qrsig"参数 |
78
|
|
|
$qrSign = $this->findQRSign($this->cookies); |
|
|
|
|
79
|
|
|
//计算ptqrtoken |
80
|
|
|
$ptQrToken = Utils::hash33($qrSign); |
81
|
|
|
} |
82
|
|
|
//暂停1秒 |
83
|
|
|
usleep(1000000); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
$ptWebQQ = $this->getPtWebQQ(); |
87
|
|
|
$vfWebQQ = $this->getVfWebQQ($ptWebQQ); |
88
|
|
|
list($uin, $pSessionId) = $this->getUinAndPSessionId($ptWebQQ); |
89
|
|
|
|
90
|
|
|
$credential = new Credential( |
91
|
|
|
$ptWebQQ, |
92
|
|
|
$vfWebQQ, |
93
|
|
|
$pSessionId, |
94
|
|
|
$uin, |
95
|
|
|
static::$clientId, |
96
|
|
|
$this->cookies |
97
|
|
|
); |
98
|
|
|
|
99
|
|
|
return $credential; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* 从cookie中查找 "qrsig" 参数 |
104
|
|
|
* |
105
|
|
|
* @return string |
106
|
|
|
*/ |
107
|
|
|
protected function findQRSign() |
108
|
|
|
{ |
109
|
|
|
foreach ($this->cookies as $cookie) { |
110
|
|
|
if (0 === strcasecmp($cookie->getName(), 'qrsig')) { |
111
|
|
|
return $cookie->getValue(); |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
throw new RuntimeException('Can not find parameter [qrsig]'); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* 验证二维码状态 |
119
|
|
|
* |
120
|
|
|
* @param int $ptQrToken qr token |
121
|
|
|
* |
122
|
|
|
* @return int |
123
|
|
|
*/ |
124
|
|
|
protected function getQrCodeStatus($ptQrToken) |
125
|
|
|
{ |
126
|
|
|
$request = new Request\VerifyQrCodeRequest($ptQrToken); |
127
|
|
|
$response = $this->client->sendRequest($request); |
128
|
|
|
if (false !== strpos($response->getBody(), '未失效')) { |
129
|
|
|
$status = Request\VerifyQrCodeRequest::STATUS_UNEXPIRED; |
130
|
|
|
} elseif (false !== strpos($response->getBody(), '已失效')) { |
131
|
|
|
$status = Request\VerifyQrCodeRequest::STATUS_EXPIRED; |
132
|
|
|
} elseif (false !== strpos($response->getBody(), '认证中')) { |
133
|
|
|
$status = Request\VerifyQrCodeRequest::STATUS_ACCREDITATION; |
134
|
|
|
} else { |
135
|
|
|
$status = Request\VerifyQrCodeRequest::STATUS_CERTIFICATION; |
136
|
|
|
//找出认证url |
137
|
|
|
if (preg_match("#'(http.+)'#U", strval($response->getBody()), $matches)) { |
138
|
|
|
$this->certificationUrl = trim($matches[1]); |
139
|
|
|
} else { |
140
|
|
|
throw new RuntimeException('Can not find certification url'); |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
return $status; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* 获取ptwebqq的参数值 |
149
|
|
|
* |
150
|
|
|
* @return string |
151
|
|
|
*/ |
152
|
|
|
protected function getPtWebQQ() |
153
|
|
|
{ |
154
|
|
|
$request = new Request\GetPtWebQQRequest(); |
155
|
|
|
$request->setUri($this->certificationUrl); |
156
|
|
|
$this->sendRequest($request); |
157
|
|
|
foreach ($this->cookies as $cookie) { |
158
|
|
|
if (0 === strcasecmp($cookie->getName(), 'ptwebqq')) { |
159
|
|
|
return $cookie->getValue(); |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
throw new RuntimeException('Can not find parameter [ptwebqq]'); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* @param string $ptWebQQ |
167
|
|
|
* |
168
|
|
|
* @return string |
169
|
|
|
*/ |
170
|
|
|
protected function getVfWebQQ($ptWebQQ) |
171
|
|
|
{ |
172
|
|
|
$request = new Request\GetVfWebQQRequest($ptWebQQ); |
173
|
|
|
$response = $this->sendRequest($request); |
174
|
|
|
|
175
|
|
|
return Request\GetVfWebQQRequest::parseResponse($response); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* 获取pessionid和uin. |
180
|
|
|
* |
181
|
|
|
* @param string $ptWebQQ |
182
|
|
|
* |
183
|
|
|
* @return array |
184
|
|
|
*/ |
185
|
|
|
protected function getUinAndPSessionId($ptWebQQ) |
186
|
|
|
{ |
187
|
|
|
$request = new Request\GetUinAndPsessionidRequest([ |
188
|
|
|
'ptwebqq' => $ptWebQQ, |
189
|
|
|
'clientid' => static::$clientId, |
190
|
|
|
'psessionid' => '', |
191
|
|
|
'status' => 'online', |
192
|
|
|
]); |
193
|
|
|
$response = $this->sendRequest($request); |
194
|
|
|
|
195
|
|
|
return Request\GetUinAndPsessionidRequest::parseResponse($response); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
protected function sendRequest(Request\RequestInterface $request) |
199
|
|
|
{ |
200
|
|
|
return $this->client->sendRequest($request, [ |
201
|
|
|
'cookies' => $this->cookies |
202
|
|
|
]); |
203
|
|
|
} |
204
|
|
|
} |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.