This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Wechat\API; |
||
3 | |||
4 | use Wechat\Api; |
||
5 | use Wechat\Utils\Code\WXBizMsgCrypt; |
||
6 | |||
7 | /** |
||
8 | * 微信接收回调相关接口. |
||
9 | * |
||
10 | * @author Tian. |
||
11 | */ |
||
12 | class ServerApi extends BaseApi |
||
13 | { |
||
14 | private static $XML_OBJECT; |
||
15 | |||
16 | /** |
||
17 | * 监听 |
||
18 | * |
||
19 | * @param string $target |
||
20 | * @param string|callable $event |
||
21 | * @param callable $callback |
||
22 | * |
||
23 | * @return bool Server |
||
24 | */ |
||
25 | |||
26 | public function on($target, $event, $callback = null) |
||
0 ignored issues
–
show
|
|||
27 | { |
||
28 | $echostr = isset($_GET['echostr']) ? $_GET['echostr'] : null; |
||
29 | $checkSignature = $this->checkSignature(); |
||
30 | |||
31 | if (!$checkSignature) { |
||
32 | exit("签名验证失败"); |
||
0 ignored issues
–
show
The method
on() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
33 | } |
||
34 | |||
35 | if (!empty($echostr)) { |
||
36 | echo $echostr; |
||
37 | exit; |
||
0 ignored issues
–
show
The method
on() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
38 | } |
||
39 | |||
40 | if (is_null($callback)) { |
||
41 | $callback = $event; |
||
42 | $event = '*'; |
||
43 | } |
||
44 | |||
45 | if (!is_callable($callback)) { |
||
46 | exit("$callback 不是一个可调用的函数或方法"); |
||
0 ignored issues
–
show
The method
on() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
47 | } |
||
48 | |||
49 | $rest = $this->$target($event); |
||
50 | |||
51 | $datas = []; |
||
52 | $datas['data'] = $rest; |
||
53 | |||
54 | if (!empty($rest)) { |
||
55 | $rest_user = []; |
||
56 | $rest_user['ToUserName'] = $rest['FromUserName']; |
||
57 | $rest_user['FromUserName'] = $rest['ToUserName']; |
||
58 | $rest_msg = call_user_func_array($callback, $datas); |
||
59 | |||
60 | if ($rest_msg == 'success') { |
||
61 | exit('success'); |
||
0 ignored issues
–
show
The method
on() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
62 | } |
||
63 | |||
64 | $rest_array = array_merge($rest_user, $rest_msg); |
||
65 | |||
66 | $rest_xml = $this->arrayToXml($rest_array); |
||
67 | |||
68 | $msg_signature = isset($_GET['msg_signature']) ? $_GET['msg_signature'] : null; |
||
69 | if (!empty($msg_signature) && $msg_signature != '') { |
||
70 | $rest_xml = $this->encryptMsg($rest_xml); |
||
71 | } |
||
72 | |||
73 | exit($rest_xml); |
||
0 ignored issues
–
show
The method
on() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
74 | } else { |
||
75 | return false; |
||
76 | } |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * 验证签名 |
||
81 | * |
||
82 | * string $signature [签名] |
||
83 | * int $timestamp [时间戳] |
||
84 | * string $nonce [随机字符串] |
||
85 | * |
||
86 | * @param string $token [token] |
||
87 | * |
||
88 | * @return mixed|bool |
||
89 | */ |
||
90 | public function checkSignature($token = null) |
||
0 ignored issues
–
show
checkSignature uses the super-global variable $_GET which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
91 | { |
||
92 | $config_token = Api::getToken(); |
||
93 | $signature = isset($_GET['signature']) ? $_GET['signature'] : null; |
||
94 | $timestamp = isset($_GET['timestamp']) ? $_GET['timestamp'] : null; |
||
95 | $nonce = isset($_GET['nonce']) ? $_GET['nonce'] : null; |
||
96 | $token = empty($token) ? $config_token : $token; |
||
97 | $tmpArr = [$token, $timestamp, $nonce]; |
||
98 | sort($tmpArr, SORT_STRING); |
||
99 | $tmpStr = implode($tmpArr); |
||
100 | $tmpStr = sha1($tmpStr); |
||
101 | |||
102 | if ($tmpStr == $signature && $signature != null) { |
||
103 | return $this; |
||
104 | } |
||
105 | |||
106 | return false; |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * 生成签名 - 用作 转发到第三方 |
||
111 | * |
||
112 | * @param string $token |
||
113 | * @param string $time |
||
114 | * @param string $nonce |
||
115 | * |
||
116 | * @return bool|string |
||
117 | */ |
||
118 | public function makeSignature($token = null, $time = null, $nonce = null) |
||
0 ignored issues
–
show
makeSignature uses the super-global variable $_GET which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
119 | { |
||
120 | if (!is_string($token) || empty($token)) { |
||
121 | exit("$token 参数错误"); |
||
0 ignored issues
–
show
The method
makeSignature() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
122 | } |
||
123 | |||
124 | $timestamp = !empty($time) ? $time : $_GET['timestamp']; |
||
125 | $nonce = !empty($nonce) ? $nonce : $_GET['nonce']; |
||
126 | $tmpArr = [$token, $timestamp, $nonce]; |
||
127 | sort($tmpArr, SORT_STRING); |
||
128 | $tmpStr = implode($tmpArr); |
||
129 | $tmpStr = sha1($tmpStr); |
||
130 | |||
131 | return $tmpStr; |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * 推送到第三方 |
||
136 | * |
||
137 | * @param string $url [地址] |
||
138 | * @param string $token [token] |
||
139 | * @param string $xml [XML] |
||
140 | * @param bool $encipher [是否加密] |
||
141 | * |
||
142 | * @return array|bool XML |
||
143 | */ |
||
144 | public function receiveAgent($url = '', $token = '', $xml = '', $encipher = false) |
||
145 | { |
||
146 | $object = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); |
||
147 | |||
148 | $object = json_decode(json_encode($object), true); |
||
149 | |||
150 | if (isset($object['Encrypt']) && !empty($object['Encrypt']) && $object['Encrypt'] != '') { |
||
151 | $xml = $this->decryptMsg($xml); |
||
152 | } |
||
153 | |||
154 | if ($encipher) { |
||
155 | $xml = $this->encryptMsg($xml); |
||
156 | |||
157 | $object_enc = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); |
||
158 | $object_enc = json_decode(json_encode($object_enc), true); |
||
159 | $postQueryStr = []; |
||
160 | $postQueryStr['timestamp'] = $object_enc['TimeStamp']; |
||
161 | $postQueryStr['nonce'] = $object_enc['Nonce']; |
||
162 | $postQueryStr['signature'] = $this->makeSignature($token, $postQueryStr['timestamp'], $postQueryStr['nonce']); |
||
163 | $postQueryStr['msg_signature'] = $object_enc['MsgSignature']; |
||
164 | |||
165 | $array = []; |
||
166 | $array['ToUserName'] = $object['ToUserName']; |
||
167 | $array['Encrypt'] = $object_enc['Encrypt']; |
||
168 | |||
169 | $xml = $this->arrayToXml($array); |
||
170 | } else { |
||
171 | $postQueryStr['timestamp'] = time(); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$postQueryStr was never initialized. Although not strictly required by PHP, it is generally a good practice to add $postQueryStr = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
172 | $postQueryStr['nonce'] = $this->getRandomStr(); |
||
173 | $postQueryStr['signature'] = $this->makeSignature($token, $postQueryStr['timestamp'], $postQueryStr['nonce']); |
||
174 | } |
||
175 | |||
176 | asort($postQueryStr); |
||
177 | $postQueryStr = http_build_query($postQueryStr); |
||
178 | |||
179 | $rest = $this->https_xml($url . '?' . $postQueryStr, $xml); |
||
180 | |||
181 | if ($rest) { |
||
182 | $object_rest = simplexml_load_string($rest, 'SimpleXMLElement', LIBXML_NOCDATA); |
||
183 | $object_rest = json_decode(json_encode($object_rest), true); |
||
184 | |||
185 | if (!empty($object_rest['MsgSignature']) && !empty($object_rest['TimeStamp']) && !empty($object_rest['Nonce']) && !empty($object_rest['Encrypt'])) { |
||
186 | $rest = $this->decryptMsg($rest, $object_rest['MsgSignature'], $object_rest['TimeStamp'], $object_rest['Nonce']); |
||
187 | } |
||
188 | $object_rest = simplexml_load_string($rest, 'SimpleXMLElement', LIBXML_NOCDATA); |
||
189 | $rest_array = json_decode(json_encode($object_rest), true); |
||
190 | |||
191 | return $rest_array; |
||
192 | } |
||
193 | |||
194 | return false; |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * 加密XML |
||
199 | * |
||
200 | * @param $xml |
||
201 | * |
||
202 | * @return string |
||
203 | */ |
||
204 | public function encryptMsg($xml) |
||
205 | { |
||
206 | $appId = Api::getAppId(); |
||
207 | $token = Api::getToken(); |
||
208 | $encodingAesKey = Api::getEncoding_Aes_Key(); |
||
209 | |||
210 | if (empty($token) || !$token || empty($encodingAesKey) || !$encodingAesKey) { |
||
211 | return $xml; |
||
212 | } |
||
213 | |||
214 | $timeStamp = time(); |
||
215 | $nonce = $this->getRandomStr(); |
||
216 | |||
217 | $pc = new WXBizMsgCrypt($token, $encodingAesKey, $appId); |
||
218 | $encryptMsg = ''; |
||
219 | $errCode = $pc->encryptMsg($xml, $timeStamp, $nonce, $encryptMsg); |
||
220 | if ($errCode == 0) { |
||
221 | return $encryptMsg; |
||
222 | } else { |
||
223 | exit($errCode); |
||
0 ignored issues
–
show
The method
encryptMsg() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
224 | } |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * 解密XML |
||
229 | * |
||
230 | * @param $xml |
||
231 | * @param null $msg_signature |
||
232 | * @param null $timeStamp |
||
233 | * @param null $nonce |
||
234 | * |
||
235 | * @return string |
||
236 | */ |
||
237 | public function decryptMsg($xml, $msg_signature = null, $timeStamp = null, $nonce = null) |
||
0 ignored issues
–
show
decryptMsg uses the super-global variable $_GET which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
238 | { |
||
239 | $appId = Api::getAppId(); |
||
240 | $token = Api::getToken(); |
||
241 | $encodingAesKey = Api::getEncoding_Aes_Key(); |
||
242 | |||
243 | $msg_signature = !empty($msg_signature) ? $msg_signature : $_GET['msg_signature']; |
||
244 | $timeStamp = !empty($timeStamp) ? $timeStamp : $_GET['timestamp']; |
||
245 | $nonce = !empty($nonce) ? $nonce : $_GET['nonce']; |
||
246 | |||
247 | $pc = new WXBizMsgCrypt($token, $encodingAesKey, $appId); |
||
248 | $msg = ''; |
||
249 | |||
250 | $errCode = $pc->decryptMsg($msg_signature, $timeStamp, $nonce, $xml, $msg); |
||
251 | |||
252 | if ($errCode == 0) { |
||
253 | return $msg; |
||
254 | } else { |
||
255 | exit($errCode); |
||
0 ignored issues
–
show
The method
decryptMsg() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
256 | } |
||
257 | } |
||
258 | |||
259 | /** |
||
260 | * 魔术方法 处理 返回结果 |
||
261 | * |
||
262 | * @param string $target [事件] |
||
263 | * @param $event |
||
264 | * |
||
265 | * @return string $event [类型] |
||
266 | * @return array $xml [xml] |
||
267 | */ |
||
268 | public function __call($target, $event) |
||
0 ignored issues
–
show
__call uses the super-global variable $_GET which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
269 | { |
||
270 | $object = self::$XML_OBJECT; |
||
271 | if (!$object || !is_object($object) || empty($object)) { |
||
272 | $xml = file_get_contents('php://input'); |
||
273 | |||
274 | $msg_signature = isset($_GET['msg_signature']) ? $_GET['msg_signature'] : null; |
||
275 | |||
276 | if (!empty($msg_signature) && $msg_signature != '') { |
||
277 | $xml = $this->decryptMsg($xml); |
||
278 | } |
||
279 | |||
280 | $object = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); |
||
281 | self::$XML_OBJECT = $object; |
||
282 | } |
||
283 | |||
284 | $target = strtolower(trim($target)); |
||
285 | |||
286 | $event = strtolower(trim(reset($event))); |
||
287 | |||
288 | $rx_target = strtolower(trim($object->MsgType)); |
||
289 | $rx_event = strtolower(trim($object->Event)); |
||
290 | |||
291 | if ($target == $rx_target) { |
||
292 | if ($event == '*') { |
||
293 | $array = json_decode(json_encode($object), true); |
||
294 | } elseif ($event == $rx_event) { |
||
295 | $array = json_decode(json_encode($object), true); |
||
296 | } else { |
||
297 | $array = false; |
||
298 | } |
||
299 | } else { |
||
300 | $array = false; |
||
301 | } |
||
302 | |||
303 | return $array; |
||
304 | } |
||
305 | |||
306 | /** |
||
307 | * array转xml. |
||
308 | * |
||
309 | * @param array $arr |
||
310 | * @param bool $flag |
||
311 | * @param bool $especial |
||
312 | * |
||
313 | * @return string |
||
314 | */ |
||
315 | public function arrayToXml($arr = [], $flag = true, $especial = false) |
||
316 | { |
||
317 | if ($flag) { |
||
318 | $xml = '<xml>'; |
||
319 | } else { |
||
320 | $xml = ''; |
||
321 | } |
||
322 | |||
323 | foreach ($arr as $key => $val) { |
||
324 | if (is_numeric($val)) { |
||
325 | $xml .= '<' . $key . '>' . $val . '</' . $key . '>'; |
||
326 | } elseif (is_array($val)) { |
||
327 | if (strtolower($key) == 'item') { |
||
328 | $xml .= $this->arrayToXml($val, false, true); |
||
329 | } elseif ($especial == true) { |
||
0 ignored issues
–
show
|
|||
330 | $xml .= '<item>'; |
||
331 | $xml .= $this->arrayToXml($val, false, true); |
||
332 | $xml .= '</item>'; |
||
333 | } else { |
||
334 | $xml .= !is_numeric($key) ? '<' . ucfirst($key) . '>' : ''; |
||
335 | $xml .= $this->arrayToXml($val, false); |
||
336 | $xml .= !is_numeric($key) ? '</' . ucfirst($key) . '>' : ''; |
||
337 | } |
||
338 | } else { |
||
339 | $xml .= '<' . $key . '><![CDATA[' . $val . ']]></' . $key . '>'; |
||
340 | } |
||
341 | } |
||
342 | |||
343 | if ($flag) { |
||
344 | $xml .= '</xml>'; |
||
345 | } |
||
346 | |||
347 | return $xml; |
||
348 | } |
||
349 | |||
350 | public function getXmlObject() |
||
351 | { |
||
352 | return self::$XML_OBJECT; |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * 第三方 post 推送 |
||
357 | * |
||
358 | * @param $url |
||
359 | * @param null $xml |
||
360 | * |
||
361 | * @return mixed |
||
362 | */ |
||
363 | public function https_xml($url, $xml = null) |
||
364 | { |
||
365 | $ch = curl_init($url); |
||
366 | curl_setopt($ch, CURLOPT_URL, $url); |
||
367 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
||
368 | //curl_setopt($ch, CURLOPT_HTTPHEADER, $header); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
64% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
369 | curl_setopt($ch, CURLOPT_POST, 1); |
||
370 | curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); |
||
371 | $response = curl_exec($ch); |
||
372 | if (curl_errno($ch)) { |
||
373 | print curl_error($ch); |
||
374 | } |
||
375 | curl_close($ch); |
||
376 | |||
377 | return $response; |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * 随机生成16位字符串 |
||
382 | * |
||
383 | * @return string 生成的字符串 |
||
384 | */ |
||
385 | View Code Duplication | public function getRandomStr() |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
386 | { |
||
387 | $str = ""; |
||
388 | $str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; |
||
389 | $max = strlen($str_pol) - 1; |
||
390 | for ($i = 0; $i < 16; $i++) { |
||
391 | $str .= $str_pol[mt_rand(0, $max)]; |
||
392 | } |
||
393 | |||
394 | return $str; |
||
395 | } |
||
396 | } |
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: