Oplatform.Class.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: phperstar
  5. * Date: 2019/12/2
  6. * Time: 3:30 PM
  7. */
  8. namespace Util\WeiXin;
  9. use Mall\Framework\Core\ResultWrapper;
  10. use Mall\Framework\Core\ErrorCode;
  11. use Mall\Framework\Factory;
  12. class Oplatform
  13. {
  14. // 第三方平台 appId
  15. private $appid;
  16. // 第三方平台 appsecret
  17. private $appsecret;
  18. // 第三方平台接收消息的校验token
  19. private $token;
  20. // 第三方平台接收消息的加密symmetric_key
  21. private $encodingAesKey;
  22. // 验证票据(component_verify_ticket)缓存
  23. private $component_verify_ticket = 'componentVerifyTicket';
  24. // 调用令牌(component_access_token)缓存
  25. private $component_access_token = 'componentAccessToken';
  26. // 预授权码(pre_auth_code)缓存
  27. private $pre_auth_code = 'preAuthCode';
  28. // 接口调用令牌(authorizer_access_token)缓存
  29. private $authorizer_access_token = 'authorizerAccessToken';
  30. // 刷新令牌 (authorizer_refresh_token) 缓存
  31. private $authorizer_refresh_token = 'authorizerRefreshToken';
  32. // 接口主域名
  33. private $baseUrl = 'https://api.weixin.qq.com/cgi-bin/component/';
  34. // 小程序
  35. private $wxUrl = 'https://api.weixin.qq.com/wxa/';
  36. // 微信认证域名
  37. private $wxverifyUrl = 'https://api.weixin.qq.com/cgi-bin/wxverify/';
  38. //微信账户
  39. private $wxAccount = 'https://api.weixin.qq.com/cgi-bin/account/';
  40. public function __construct($appid, $token, $encodingAesKey, $appsecret)
  41. {
  42. $this->appid = $appid;
  43. $this->token = $token;
  44. $this->encodingAesKey = $encodingAesKey;
  45. $this->appsecret = $appsecret;
  46. }
  47. /**
  48. * 获取平台令牌 component_access_token
  49. * 官方文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/component_access_token.html
  50. */
  51. public function componentAccessToken()
  52. {
  53. $authorizer_access_token = Factory::cache('default')->get($this->component_access_token . ':' . $this->appid);
  54. if (!empty($authorizer_access_token)) {
  55. return ResultWrapper::success($authorizer_access_token);
  56. }
  57. $component_verify_ticket = Factory::cache('default')->get($this->component_verify_ticket . ':' . $this->appid);
  58. // if (empty($component_verify_ticket)) {
  59. // return ResultWrapper::fail('component_verify_ticket验证票据为空', ErrorCode::$contentNotExists);
  60. // }
  61. $postData = [
  62. 'component_appid' => $this->appid,
  63. 'component_appsecret' => $this->appsecret,
  64. 'component_verify_ticket' => $component_verify_ticket,
  65. ];
  66. $url = $this->baseUrl . 'api_component_token';
  67. $response = request($url, json_encode($postData), 10);
  68. $result = self::commonResponse($response);
  69. if (!$result->isSuccess()) {
  70. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  71. }
  72. $authorizer_access_token = $result->getData();
  73. Factory::cache('default')->set($this->component_access_token . ':' . $this->appid, $authorizer_access_token['component_access_token'], 7000);
  74. return ResultWrapper::success($authorizer_access_token['component_access_token']);
  75. }
  76. /**
  77. * 公共处理返回结果函数
  78. * https://developers.weixin.qq.com/doc/oplatform/Return_codes/Return_code_descriptions_new.html
  79. */
  80. public function commonResponse($response, $isBinary = false)
  81. {
  82. if ($response['httpcode'] != 200) {
  83. return ResultWrapper::fail('请求外部系统接口报错', ErrorCode::$apiNotResult);
  84. }
  85. if (!is_object($response['content']) && $isBinary) {
  86. return ResultWrapper::success($response['content']);
  87. }
  88. $responseData = json_decode($response['content'], true);
  89. if (isset($responseData['errcode']) && $responseData['errcode'] != 0) {
  90. return ResultWrapper::fail($responseData['errmsg'], $responseData['errcode']);
  91. }
  92. return ResultWrapper::success($responseData);
  93. }
  94. /**
  95. * 创建小程序接口
  96. * 官网文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Fast_Registration_Interface_document.html
  97. */
  98. public function fastregisterweappCreate($registerData)
  99. {
  100. $result = self::componentAccessToken();
  101. if (!$result->isSuccess()) {
  102. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  103. }
  104. $component_access_token = $result->getData();
  105. $postData = [
  106. 'name' => $registerData['name'],
  107. 'code' => $registerData['code'],
  108. 'code_type' => $registerData['code_type'],
  109. 'legal_persona_wechat' => $registerData['legal_persona_wechat'],
  110. 'legal_persona_name' => $registerData['legal_persona_name'],
  111. 'component_phone' => $registerData['component_phone'],
  112. ];
  113. $url = $this->baseUrl . 'fastregisterweapp?action=create&component_access_token=' . $component_access_token;
  114. $response = request($url, json_encode($postData, JSON_UNESCAPED_UNICODE), 10);
  115. $result = self::commonResponse($response);
  116. if (!$result->isSuccess()) {
  117. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  118. }
  119. return ResultWrapper::success($result->getData());
  120. }
  121. /**
  122. * 查询创建状态
  123. */
  124. public function fastregisterweappSearch($registerData)
  125. {
  126. $result = self::componentAccessToken();
  127. if (!$result->isSuccess()) {
  128. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  129. }
  130. $component_access_token = $result->getData();
  131. $postData = [
  132. 'name' => $registerData['name'],
  133. 'legal_persona_wechat' => $registerData['legal_persona_wechat'],
  134. 'legal_persona_name' => $registerData['legal_persona_name'],
  135. ];
  136. $url = $this->baseUrl . 'fastregisterweapp?action=search&component_access_token=' . $component_access_token;
  137. $response = request($url, json_encode($postData), 10);
  138. $result = self::commonResponse($response);
  139. if (!$result->isSuccess()) {
  140. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  141. }
  142. return ResultWrapper::success($result->getData());
  143. }
  144. /**
  145. * 微信认证名称检测
  146. * 官网文档地址: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/wxverify_checknickname.html
  147. */
  148. public function checkwxverifynickname($authorizer_appid, $nickName)
  149. {
  150. $result = self::apiAuthorizerToken($authorizer_appid);
  151. if (!$result->isSuccess()) {
  152. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  153. }
  154. $authorizer_access_token = $result->getData();
  155. $postData = [
  156. 'nick_name' => $nickName,
  157. ];
  158. $url = $this->wxverifyUrl . 'checkwxverifynickname?access_token=' . $authorizer_access_token;
  159. $response = request($url, json_encode($postData, JSON_UNESCAPED_UNICODE), 10);
  160. $result = self::commonResponse($response);
  161. if (!$result->isSuccess()) {
  162. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  163. }
  164. return ResultWrapper::success($result->getData());
  165. }
  166. /**
  167. * 设置名称
  168. * 官网文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/setnickname.html
  169. */
  170. public function setnickname($authorizer_appid, $nickName)
  171. {
  172. $result = self::apiAuthorizerToken($authorizer_appid);
  173. if (!$result->isSuccess()) {
  174. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  175. }
  176. $authorizer_access_token = $result->getData();
  177. $postData = [
  178. 'nick_name' => $nickName,
  179. ];
  180. $url = $this->wxUrl . 'setnickname?access_token=' . $authorizer_access_token;
  181. $response = request($url, json_encode($postData, JSON_UNESCAPED_UNICODE), 10);
  182. $result = self::commonResponse($response);
  183. if (!$result->isSuccess()) {
  184. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  185. }
  186. return ResultWrapper::success($result->getData());
  187. }
  188. /**
  189. * 获取预授权码 pre_auth_code
  190. * 官网文档地址: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/pre_auth_code.html
  191. */
  192. public function preAuthCode()
  193. {
  194. $pre_auth_code = Factory::cache('default')->get($this->pre_auth_code . ':' . $this->appid);
  195. if (!empty($pre_auth_code)) {
  196. return ResultWrapper::success($pre_auth_code);
  197. }
  198. $result = self::componentAccessToken();
  199. if (!$result->isSuccess()) {
  200. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  201. }
  202. $component_access_token = $result->getData();
  203. $postData = [
  204. 'component_access_token' => $component_access_token,
  205. 'component_appid' => $this->appid,
  206. ];
  207. $url = $this->baseUrl . 'api_create_preauthcode?component_access_token=' . $component_access_token;
  208. $response = request($url, json_encode($postData), 10);
  209. $result = self::commonResponse($response);
  210. if (!$result->isSuccess()) {
  211. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  212. }
  213. $pre_auth_code = $result->getData();
  214. Factory::cache('default')->set($this->pre_auth_code . ':' . $this->appid, $pre_auth_code['pre_auth_code'], 500);
  215. return ResultWrapper::success($pre_auth_code['pre_auth_code']);
  216. }
  217. /**
  218. * 获取授权信息 authorizer_refresh_token
  219. */
  220. public function apiQueryAuth($authorization_code)
  221. {
  222. $result = self::componentAccessToken();
  223. if (!$result->isSuccess()) {
  224. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  225. }
  226. $component_access_token = $result->getData();
  227. $postData = [
  228. 'component_access_token' => $component_access_token, // 令牌
  229. 'component_appid' => $this->appid, // 第三方平台appid
  230. 'authorization_code' => $authorization_code, // 授权码
  231. ];
  232. $url = $this->baseUrl . 'api_query_auth?component_access_token=' . $component_access_token;
  233. $response = request($url, json_encode($postData), 10);
  234. $result = self::commonResponse($response);
  235. if (!$result->isSuccess()) {
  236. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  237. }
  238. $authorization_info = $result->getData();
  239. $authorization_info = $authorization_info['authorization_info'];
  240. Factory::cache('default')->set($this->authorizer_access_token . ':' . $authorization_info['authorizer_appid'], $authorization_info['authorizer_access_token'], 6000);
  241. Factory::cache('default')->set($this->authorizer_refresh_token . ':' . $authorization_info['authorizer_appid'], $authorization_info['authorizer_refresh_token'], 7000);
  242. Factory::cache('default')->del($this->pre_auth_code . ':' . $this->appid);
  243. return ResultWrapper::success($authorization_info);
  244. }
  245. /**
  246. * 拉取所有已授权的帐号信息 https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/api_get_authorizer_list.html
  247. * @param $authorizer_appid
  248. * @return ResultWrapper
  249. * @throws \Exception
  250. */
  251. public function apiGetAuthorizerList()
  252. {
  253. $result = self::componentAccessToken();
  254. if (!$result->isSuccess()) {
  255. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  256. }
  257. $component_access_token = $result->getData();
  258. $postData = [
  259. 'component_access_token' => $component_access_token, // 令牌
  260. 'component_appid' => $this->appid, // 第三方平台appid
  261. 'offset' => 0,
  262. 'count' => 500,
  263. ];
  264. $url = $this->baseUrl . 'api_get_authorizer_list?component_access_token=' . $component_access_token;
  265. $response = request($url, json_encode($postData), 10);
  266. $result = self::commonResponse($response);
  267. if (!$result->isSuccess()) {
  268. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  269. }
  270. $auth_list = $result->getData();
  271. return ResultWrapper::success($auth_list);
  272. }
  273. /**
  274. * 获取/刷新接口调用令牌 authorizer_access_token
  275. * 官网文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/api_authorizer_token.html
  276. */
  277. public function apiAuthorizerToken($authorizer_appid, $authorizer_refresh_token = null)
  278. {
  279. $authorizer_access_token = Factory::cache('default')->get($this->authorizer_access_token . ':' . $authorizer_appid);
  280. if (!empty($authorizer_access_token)) {
  281. return ResultWrapper::success($authorizer_access_token);
  282. }
  283. $result = self::componentAccessToken();
  284. if (!$result->isSuccess()) {
  285. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  286. }
  287. $component_access_token = $result->getData();
  288. //如果有刷新token,则使用返回的刷新token
  289. if (empty($authorizer_refresh_token)) {
  290. $authorizer_refresh_token = Factory::cache('default')->get($this->authorizer_refresh_token . ':' . $authorizer_appid);
  291. if (empty($authorizer_refresh_token)) {
  292. return ResultWrapper::fail('微信开发平台授权过期,请重新授权', ErrorCode::$notAllowAccess);
  293. }
  294. }
  295. $postData = [
  296. 'component_access_token' => $component_access_token, // 令牌
  297. 'component_appid' => $this->appid, // 第三方平台appid
  298. 'authorizer_appid' => $authorizer_appid,
  299. 'authorizer_refresh_token' => $authorizer_refresh_token,
  300. ];
  301. $url = $this->baseUrl . 'api_authorizer_token?component_access_token=' . $component_access_token;
  302. $response = request($url, json_encode($postData), 10);
  303. $result = self::commonResponse($response);
  304. if (!$result->isSuccess()) {
  305. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  306. }
  307. $authorizer_access_token = $result->getData();
  308. Factory::cache('default')->set($this->authorizer_access_token . ':' . $authorizer_appid, $authorizer_access_token['authorizer_access_token'], 6000);
  309. Factory::cache('default')->set($this->authorizer_refresh_token . ':' . $authorizer_appid, $authorizer_access_token['authorizer_refresh_token'], 7000);
  310. return ResultWrapper::success($authorizer_access_token['authorizer_access_token']);
  311. }
  312. /**
  313. * 设置服务器域名
  314. * 官方文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Server_Address_Configuration.html
  315. */
  316. public function modifyDomain($authorizer_appid, $requestDomain)
  317. {
  318. $result = self::apiAuthorizerToken($authorizer_appid);
  319. if (!$result->isSuccess()) {
  320. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  321. }
  322. $authorizer_access_token = $result->getData();
  323. $postData = [
  324. 'action' => 'set',
  325. 'requestdomain' => ['https://' . $requestDomain, 'https://restapi.amap.com'],
  326. 'wsrequestdomain' => ['wss://' . $requestDomain],
  327. 'uploaddomain' => [QINIU_UPLOAD],
  328. 'downloaddomain' => ['https://' . $requestDomain, QINIU_IMAGE, 'https://upload.' . DOMAIN],
  329. ];
  330. $url = $this->wxUrl . 'modify_domain?access_token=' . $authorizer_access_token;
  331. $response = request($url, json_encode($postData), 10);
  332. $result = self::commonResponse($response);
  333. if (!$result->isSuccess()) {
  334. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  335. }
  336. return ResultWrapper::success($result->getData());
  337. }
  338. /**
  339. * 设置业务域名
  340. * 官方文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/setwebviewdomain.html
  341. */
  342. public function setwebviewdomain($authorizer_appid, $webviewDomain)
  343. {
  344. $result = self::apiAuthorizerToken($authorizer_appid);
  345. if (!$result->isSuccess()) {
  346. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  347. }
  348. $authorizer_access_token = $result->getData();
  349. $postData = [
  350. 'action' => 'add',
  351. 'webviewdomain' => ['https://' . $webviewDomain],//增加业务域名
  352. ];
  353. $url = $this->wxUrl . 'setwebviewdomain?access_token=' . $authorizer_access_token;
  354. $response = request($url, json_encode($postData), 10);
  355. $result = self::commonResponse($response);
  356. if (!$result->isSuccess()) {
  357. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  358. }
  359. return ResultWrapper::success($result->getData());
  360. }
  361. /**
  362. * Doc: (des="获取小程序账号基本信息")
  363. * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Mini_Program_Information_Settings.html
  364. * User: XMing
  365. * Date: 2020/11/9
  366. * Time: 3:47 下午
  367. * @param $authorizer_appid
  368. * @return ResultWrapper
  369. * @deprecated 仅限api快递创建的小程序使用
  370. */
  371. public function getAccountBasicInfo($authorizer_appid)
  372. {
  373. $result = self::apiAuthorizerToken($authorizer_appid);
  374. if (!$result->isSuccess()) {
  375. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  376. }
  377. $authorizer_access_token = $result->getData();
  378. $url = $this->wxAccount . 'getaccountbasicinfo?access_token=' . $authorizer_access_token;
  379. $response = request($url);
  380. $result = self::commonResponse($response);
  381. if (!$result->isSuccess()) {
  382. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  383. }
  384. return ResultWrapper::success($result->getData());
  385. }
  386. /**
  387. * Doc: (des="获取小程序账户信息")
  388. * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/api_get_authorizer_info.html
  389. * User: XMing
  390. * Date: 2020/11/9
  391. * Time: 5:04 下午
  392. */
  393. public function apiGetAuthorizerInfo($authorizer_appid)
  394. {
  395. $result = self::componentAccessToken();
  396. if (!$result->isSuccess()) {
  397. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  398. }
  399. $component_access_token = $result->getData();
  400. $url = $this->baseUrl . 'api_get_authorizer_info?component_access_token=' . $component_access_token;
  401. $postData = [
  402. 'component_appid' => $this->appid,
  403. 'authorizer_appid' => $authorizer_appid,
  404. ];
  405. $response = request($url,json_encode($postData), 10);
  406. $result = self::commonResponse($response);
  407. if (!$result->isSuccess()) {
  408. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  409. }
  410. return ResultWrapper::success($result->getData());
  411. }
  412. /**
  413. * 上传小程序代码
  414. * 官方文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/commit.html
  415. */
  416. public function commit($authorizer_appid, $template_id, $ext_json, $user_version, $user_desc)
  417. {
  418. $result = self::apiAuthorizerToken($authorizer_appid);
  419. if (!$result->isSuccess()) {
  420. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  421. }
  422. $authorizer_access_token = $result->getData();
  423. $postData = [
  424. 'template_id' => $template_id,
  425. 'ext_json' => json_encode($ext_json),
  426. 'user_version' => $user_version,
  427. 'user_desc' => $user_desc
  428. ];
  429. $url = $this->wxUrl . 'commit?access_token=' . $authorizer_access_token;
  430. $response = request($url, json_encode($postData), 10);
  431. $result = self::commonResponse($response);
  432. if (!$result->isSuccess()) {
  433. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  434. }
  435. return ResultWrapper::success($result->getData());
  436. }
  437. /**
  438. * 获取已上传的代码的页面列表
  439. */
  440. public function getPage($authorizer_appid)
  441. {
  442. $result = self::apiAuthorizerToken($authorizer_appid);
  443. if (!$result->isSuccess()) {
  444. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  445. }
  446. $authorizer_access_token = $result->getData();
  447. $url = $this->wxUrl . 'get_page?access_token=' . $authorizer_access_token;
  448. $response = request($url, null, 10);
  449. $result = self::commonResponse($response);
  450. if (!$result->isSuccess()) {
  451. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  452. }
  453. $page_list = $result->getData();
  454. return ResultWrapper::success($page_list['page_list']);
  455. }
  456. /**
  457. * 获取体验版二维码
  458. */
  459. public function getQrcode($authorizer_appid, $path)
  460. {
  461. $result = self::apiAuthorizerToken($authorizer_appid);
  462. if (!$result->isSuccess()) {
  463. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  464. }
  465. $authorizer_access_token = $result->getData();
  466. $url = $this->wxUrl . 'get_qrcode?access_token=' . $authorizer_access_token . '&path=' . urlencode($path);
  467. $response = request($url, null, 10);
  468. $result = self::commonResponse($response, true);
  469. if (!$result->isSuccess()) {
  470. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  471. }
  472. return ResultWrapper::success($result->getData());
  473. }
  474. /**
  475. * 获取审核时可填写的类目信息
  476. */
  477. public function getCategory($authorizer_appid)
  478. {
  479. $result = self::apiAuthorizerToken($authorizer_appid);
  480. if (!$result->isSuccess()) {
  481. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  482. }
  483. $authorizer_access_token = $result->getData();
  484. $url = $this->wxUrl . 'get_category?access_token=' . $authorizer_access_token;
  485. $response = request($url, null, 10);
  486. $result = self::commonResponse($response);
  487. if (!$result->isSuccess()) {
  488. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  489. }
  490. $categoryData = $result->getData();
  491. return ResultWrapper::success($categoryData['category_list']);
  492. }
  493. /**
  494. * 提交审核A
  495. */
  496. public function submitAudit($authorizer_appid)
  497. {
  498. $result = self::apiAuthorizerToken($authorizer_appid);
  499. if (!$result->isSuccess()) {
  500. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  501. }
  502. $authorizer_access_token = $result->getData();
  503. unset($result);
  504. $result = self::getCategory($authorizer_appid);
  505. if (!$result->isSuccess()) {
  506. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  507. }
  508. $categoryData = $result->getData();
  509. $item_list = [
  510. [
  511. 'address' => 'pages/index/index',
  512. 'tag' => '商城',
  513. 'first_class' => $categoryData[0]['first_class'],
  514. 'second_class' => $categoryData[0]['second_class'],
  515. 'first_id' => $categoryData[0]['first_id'],
  516. 'second_id' => $categoryData[0]['second_id'],
  517. 'title' => '首页',
  518. ]
  519. ];
  520. $postData = [
  521. 'item_list' => $item_list,
  522. ];
  523. $url = $this->wxUrl . 'submit_audit?access_token=' . $authorizer_access_token;
  524. $response = request($url, json_encode($postData, JSON_UNESCAPED_UNICODE), 10);
  525. $result = self::commonResponse($response);
  526. if (!$result->isSuccess()) {
  527. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  528. }
  529. return ResultWrapper::success($result->getData()['auditid']);
  530. }
  531. /**
  532. * 查询审核状态
  533. */
  534. public function getAuditstatus($authorizer_appid, $auditid)
  535. {
  536. $result = self::apiAuthorizerToken($authorizer_appid);
  537. if (!$result->isSuccess()) {
  538. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  539. }
  540. $authorizer_access_token = $result->getData();
  541. $postData = [
  542. 'auditid' => $auditid,
  543. ];
  544. $url = $this->wxUrl . 'get_auditstatus?access_token=' . $authorizer_access_token;
  545. $response = request($url, json_encode($postData, JSON_UNESCAPED_UNICODE), 10);
  546. $result = self::commonResponse($response);
  547. if (!$result->isSuccess()) {
  548. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  549. }
  550. return ResultWrapper::success($result->getData());
  551. }
  552. /**
  553. * 小程序审核撤回
  554. * 官网文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/undocodeaudit.html
  555. */
  556. public function undocodeaudit($authorizer_appid)
  557. {
  558. $result = self::apiAuthorizerToken($authorizer_appid);
  559. if (!$result->isSuccess()) {
  560. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  561. }
  562. $authorizer_access_token = $result->getData();
  563. $url = $this->wxUrl . 'undocodeaudit?access_token=' . $authorizer_access_token;
  564. $response = request($url, null, 10);
  565. $result = self::commonResponse($response);
  566. if (!$result->isSuccess()) {
  567. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  568. }
  569. return ResultWrapper::success($result->getData());
  570. }
  571. /**
  572. * 发布已通过审核的小程序
  573. * 官网文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/release.html
  574. */
  575. public function release($authorizer_appid)
  576. {
  577. $result = self::apiAuthorizerToken($authorizer_appid);
  578. if (!$result->isSuccess()) {
  579. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  580. }
  581. $authorizer_access_token = $result->getData();
  582. $url = $this->wxUrl . 'release?access_token=' . $authorizer_access_token;
  583. $response = request($url, '{}', 10);
  584. $result = self::commonResponse($response);
  585. if (!$result->isSuccess()) {
  586. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  587. }
  588. return ResultWrapper::success($result->getData());
  589. }
  590. /**
  591. * 将公众平台回复用户的消息加密打包.
  592. * <ol>
  593. * <li>对要发送的消息进行AES-CBC加密</li>
  594. * <li>生成安全签名</li>
  595. * <li>将消息密文和安全签名打包成xml格式</li>
  596. * </ol>
  597. *
  598. * @param $replyMsg string 公众平台待回复用户的消息,xml格式的字符串
  599. * @param $timeStamp string 时间戳,可以自己生成,也可以用URL参数的timestamp
  600. * @param $nonce string 随机串,可以自己生成,也可以用URL参数的nonce
  601. * 当return返回0时有效
  602. *
  603. * @return ResultWrapper
  604. */
  605. public function encryptMsg($replyMsg, $timeStamp, $nonce)
  606. {
  607. //加密
  608. $return = self::encrypt($replyMsg, $this->appid);
  609. if (!$return->isSuccess()) {
  610. return ResultWrapper::fail($return->getData(), $return->getErrorCode());
  611. }
  612. $encrypt = $return->getData();
  613. if ($timeStamp == null) {
  614. $timeStamp = time();
  615. }
  616. //生成安全签名
  617. unset($return);
  618. $return = self::getSHA1($this->token, $timeStamp, $nonce, $encrypt);
  619. if (!$return->isSuccess()) {
  620. return ResultWrapper::fail($return->getData(), $return->getErrorCode());
  621. }
  622. $signature = $return->getData();
  623. //生成发送的xml
  624. $encryptMsg = self::generate($encrypt, $signature, $timeStamp, $nonce);
  625. return ResultWrapper::success($encryptMsg);
  626. }
  627. /**
  628. * 官方文档地址: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Message_Encryption/Message_encryption_and_decryption.html
  629. * 检验消息的真实性,并且获取解密后的明文.
  630. * <ol>
  631. * <li>利用收到的密文生成安全签名,进行签名验证</li>
  632. * <li>若验证通过,则提取xml中的加密消息</li>
  633. * <li>对消息进行解密</li>
  634. * </ol>
  635. *
  636. * @param $msgSignature string 签名串,对应URL参数的msg_signature
  637. * @param $timestamp string 时间戳 对应URL参数的timestamp
  638. * @param $nonce string 随机串,对应URL参数的nonce
  639. * @param $postData string 密文,对应POST请求的数据
  640. * @param &$msg string 解密后的原文,当return返回0时有效
  641. *
  642. * @return ResultWrapper
  643. */
  644. public function decryptMsg($msgSignature, $timestamp, $nonce, $postData)
  645. {
  646. if (strlen($this->encodingAesKey) != 43) {
  647. return ResultWrapper::fail('无效的加密encodingAesKey', ErrorCode::$paramError);
  648. }
  649. //验证安全签名
  650. $return = self::getSHA1($this->token, $timestamp, $nonce, $postData['Encrypt']);
  651. if (!$return->isSuccess()) {
  652. return ResultWrapper::fail($return->getData(), $return->getErrorCode());
  653. }
  654. $signature = $return->getData();
  655. if ($signature != $msgSignature) {
  656. return ResultWrapper::fail('签名验证错误', ErrorCode::$notAllowAccess);
  657. }
  658. $result = self::decrypt($postData['Encrypt'], $this->appid);
  659. if (!$result->isSuccess()) {
  660. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  661. }
  662. return ResultWrapper::success($result->getData());
  663. }
  664. /**
  665. * 用SHA1算法生成安全签名
  666. * @param string $token 票据
  667. * @param string $timestamp 时间戳
  668. * @param string $nonce 随机字符串
  669. * @param string $encrypt_msg 密文消息
  670. */
  671. public function getSHA1($token, $timestamp, $nonce, $encrypt_msg)
  672. {
  673. //排序
  674. try {
  675. $array = array($encrypt_msg, $token, $timestamp, $nonce);
  676. sort($array, SORT_STRING);
  677. $str = implode($array);
  678. return ResultWrapper::success(sha1($str));
  679. } catch (\Exception $e) {
  680. return ResultWrapper::fail('sha加密生成签名失败', ErrorCode::$notAllowAccess);
  681. }
  682. }
  683. /**
  684. * 对解密后的明文进行补位删除
  685. * @param decrypted 解密后的明文
  686. * @return 删除填充补位后的明文
  687. */
  688. function PKCS7decode($text)
  689. {
  690. $pad = ord(substr($text, -1));
  691. if ($pad < 1 || $pad > 32) {
  692. $pad = 0;
  693. }
  694. return substr($text, 0, (strlen($text) - $pad));
  695. }
  696. /**
  697. * 对需要加密的明文进行填充补位
  698. * @param string $text 需要进行填充补位操作的明文
  699. * @return string 补齐明文字符串
  700. */
  701. function PKCS7encode($text)
  702. {
  703. $block_size = 32;
  704. $text_length = strlen($text);
  705. //计算需要填充的位数
  706. $amount_to_pad = $block_size - ($text_length % $block_size);
  707. if ($amount_to_pad == 0) {
  708. $amount_to_pad = $block_size;
  709. }
  710. //获得补位所用的字符
  711. $pad_chr = chr($amount_to_pad);
  712. $tmp = "";
  713. for ($index = 0; $index < $amount_to_pad; $index++) {
  714. $tmp .= $pad_chr;
  715. }
  716. return $text . $tmp;
  717. }
  718. /**
  719. * 对密文进行解密
  720. * @param string $encrypted 需要解密的密文
  721. * @return ResultWrapper 解密得到的明文
  722. */
  723. public function decrypt($encrypted, $appid)
  724. {
  725. try {
  726. $asekey = base64_decode($this->encodingAesKey . '=');
  727. $aesIV = substr($asekey, 0, 16);
  728. $decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', $asekey, OPENSSL_ZERO_PADDING, $aesIV);
  729. } catch (\Exception $e) {
  730. return ResultWrapper::fail('aes 解密失败', ErrorCode::$notAllowAccess);
  731. }
  732. try {
  733. //去除补位字符
  734. $result = self::PKCS7decode($decrypted);
  735. //去除16位随机字符串,网络字节序和AppId
  736. if (strlen($result) < 16) {
  737. return ResultWrapper::fail('解密出来数据长度小于16位', ErrorCode::$notAllowAccess);
  738. }
  739. $content = substr($result, 16, strlen($result));
  740. $len_list = unpack("N", substr($content, 0, 4));
  741. $xml_len = $len_list[1];
  742. $xml_content = substr($content, 4, $xml_len);
  743. $from_appid = substr($content, $xml_len + 4);
  744. } catch (\Exception $e) {
  745. return ResultWrapper::fail('解密后得到的buffer非法', ErrorCode::$notAllowAccess);
  746. }
  747. if ($from_appid != $appid) {
  748. return ResultWrapper::fail('appid 校验错误', ErrorCode::$notAllowAccess);
  749. }
  750. return ResultWrapper::success($xml_content);
  751. }
  752. /**
  753. * 对明文进行加密
  754. * @param string $text 需要加密的明文
  755. * @return ResultWrapper
  756. */
  757. public function encrypt($text, $appid)
  758. {
  759. try {
  760. //获得16位随机字符串,填充到明文之前
  761. $random = getRandomStr();
  762. $text = $random . pack("N", strlen($text)) . $text . $appid;
  763. $asekey = base64_decode($this->encodingAesKey . '=');
  764. $aesIV = substr($asekey, 0, 16);
  765. $text = self::PKCS7encode($text);
  766. $encrypted = openssl_encrypt($text, 'AES-256-CBC', $asekey, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $aesIV);
  767. $encrypt_msg = base64_encode($encrypted);
  768. return ResultWrapper::success($encrypt_msg);
  769. } catch (\Exception $e) {
  770. return ResultWrapper::fail('aes 加密失败', ErrorCode::$notAllowAccess);
  771. }
  772. }
  773. /**
  774. * 生成xml消息
  775. * @param string $encrypt 加密后的消息密文
  776. * @param string $signature 安全签名
  777. * @param string $timestamp 时间戳
  778. * @param string $nonce 随机字符串
  779. */
  780. public function generate($encrypt, $signature, $timestamp, $nonce)
  781. {
  782. $format = "<xml>
  783. <Encrypt><![CDATA[%s]]></Encrypt>
  784. <MsgSignature><![CDATA[%s]]></MsgSignature>
  785. <TimeStamp>%s</TimeStamp>
  786. <Nonce><![CDATA[%s]]></Nonce>
  787. </xml>";
  788. return sprintf($format, $encrypt, $signature, $timestamp, $nonce);
  789. }
  790. }