WechatGetTicketController.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\modules\common\controllers;
  8. use app\models\AggregateQrcode;
  9. use app\models\MerchantInfo;
  10. use app\models\Option;
  11. use app\models\Store;
  12. use app\models\WechatConfig;
  13. use app\models\StoreMini;
  14. use app\models\StoreMiniAuth;
  15. use app\models\StoreMiniAuthIcp;
  16. use app\modules\admin\models\WechatThirdForm;
  17. use app\utils\WechatMerchant\Merchant;
  18. use yii\log\Logger;
  19. use yii\web\Controller;
  20. use EasyWeChat\Factory;
  21. use EasyWeChat\OpenPlatform\Server\Guard;
  22. use Symfony\Component\HttpFoundation\HeaderBag;
  23. use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
  24. use app\modules\admin\models\AdminForm;
  25. use app\models\Admin;
  26. use yii\web\Response;
  27. include_once "./utils/Wechat/crypt/wxBizMsgCrypt.php";
  28. class WechatGetTicketController extends Controller
  29. {
  30. public function beforeAction($action) {
  31. if (parent::beforeAction($action)) {
  32. $params = all_params();
  33. if(isset($params['echostr'])){
  34. \Yii::$app->response->format = Response::FORMAT_RAW;
  35. \Yii::$app->response->content = $params['echostr'];
  36. return false;
  37. }
  38. return true;
  39. }
  40. }
  41. //从服务市场登陆
  42. public function actionFuwuBuyerLogin(){
  43. $code = input_params('code', '');
  44. $cacheK = 'actionFuwuBuyerLogin_' . $code;
  45. $cacheV = cache()->get($cacheK);
  46. if($cacheV){
  47. echo '登陆太频繁,请等待一分钟后重试。';
  48. return;
  49. }
  50. cache()->set($cacheK, 1, 60);
  51. $form = new WechatThirdForm();
  52. $res = $form->servicemarketAuthCode($code);
  53. if($res['code'] != 0){
  54. echo '登陆失败,' . $res['msg'];
  55. return;
  56. }
  57. $mini = $res['data']['mini'];
  58. $store_id = $mini['store_id'];
  59. if(!$store_id){
  60. echo '登陆失败,店铺查找失败';
  61. return;
  62. }
  63. $admin = Admin::findOne(['type' => 'store', 'type_id' => $store_id, 'is_enable' => 1, 'is_delete' => 0]);
  64. if(!$admin){
  65. echo '登陆失败,管理员查找失败';
  66. return;
  67. }
  68. $model = new AdminForm();
  69. $model->username = $admin['username'];
  70. $model->loginType = 'username';
  71. $token = $model->generateToken(86400 * 100, $store_id);
  72. $data = [
  73. 'access_token' => $token,
  74. 'is_saas' => \Yii::$app->isSaas(),
  75. ];
  76. $cyy_code = 'cyy_code_login_' . $store_id . md5(time());
  77. cache()->set($cyy_code, $data, 60 * 3);
  78. $this->redirect(\Yii::$app->request->hostInfo . \Yii::$app->params['module_admin_login_uri'] . '?cyy_code=' . $cyy_code . '&redirect=' . urlencode(\Yii::$app->params['module_admin_login_uri'].'videoMarketing/manage'));
  79. }
  80. public function actionIndex(){
  81. $config = [
  82. 'app_id' => Option::get("platform_third_appid",0,'saas')['value'],
  83. 'secret' => Option::get("platform_third_secret",0,'saas')['value'],
  84. 'token' =>Option::get("platform_token",0,'saas')['value'],
  85. 'aes_key' => Option::get("platform_encodingAesKey",0,'saas')['value']
  86. ];
  87. $openPlatform = Factory::openPlatform($config);
  88. $request = \Yii::$app->req;
  89. if (\RUN_MODE == 'wokerman') {
  90. $symfony_request = new SymfonyRequest($request->get(), $request->post(), [], $request->cookie(), [], [], $request->rawBody());
  91. $symfony_request->headers = new HeaderBag($request->header());
  92. $openPlatform->rebind('request', $symfony_request);
  93. }
  94. $server = $openPlatform->server;
  95. $msg = $server->getMessage();
  96. \Yii::error($msg, '小程序审核通过回调');
  97. debug_log(['小程序审核通过回调', $msg], __CLASS__ . '.log');
  98. $server->push(function($msg) {
  99. if ($msg['InfoType'] == 'authorized' || $msg['InfoType'] == 'updateauthorized') {
  100. $appid = $msg['AuthorizerAppid'] ;
  101. $auth_code = $msg['AuthorizationCode'] ;
  102. $ExpiredTime = $msg['AuthorizationCodeExpiredTime'] ;
  103. $mini = StoreMini::find()->where(['appid'=>$appid])->one();
  104. $mini->auth_code = json_encode([
  105. 'authorization_code'=>$auth_code,
  106. 'end_time'=>time()*1 + $ExpiredTime*1
  107. ]);
  108. $mini->save();
  109. }
  110. if ($msg['InfoType'] == 'unauthorized') {
  111. $appid = $msg['AuthorizerAppid'];
  112. $mini = StoreMini::find()->where(['appid' => $appid])->one();
  113. $mini->is_cancle = 1;
  114. $mini->save();
  115. }
  116. // 小程序备案信息也会发送在这里
  117. // 小程序管理员人脸核身完成事件
  118. if ($msg['InfoType'] == 'notify_icpfiling_verify_result') {
  119. $storeMiniAuthIcp = StoreMiniAuthIcp::findOne(['task_id' => $msg['task_id']]);
  120. if (!intval($storeMiniAuthIcp->face_is_finish)) {
  121. if (in_array($msg['result'], [StoreMiniAuthIcp::FACE_STATUS_SUCCESS, StoreMiniAuthIcp::FACE_STATUS_FAIL])) {
  122. $storeMiniAuthIcp->face_status = $msg['result'];
  123. } elseif (intval($msg['result']) == StoreMiniAuthIcp::FACE_STATUS_INIT) {//超时未完成核验 需要重新提交
  124. $storeMiniAuthIcp->task_id = '';
  125. }
  126. if (isset($msg['along_with_auth_result'])) {
  127. $storeMiniAuthIcp->face_along_with_auth_result = $msg['along_with_auth_result'];
  128. }
  129. $storeMiniAuthIcp->save();
  130. }
  131. }
  132. //小程序认证审核费用支付完成的事件
  133. if ($msg['InfoType'] == 'notify_3rd_wxa_auth_and_icp') {
  134. if (isset($msg['procedure_id'])) {
  135. $storeMiniAuthIcp = StoreMiniAuthIcp::findOne(['procedure_id' => $msg['procedure_id']]);
  136. }
  137. if (isset($msg['taskid'])) {
  138. $storeMiniAuthIcp = StoreMiniAuthIcp::findOne(['task_id' => $msg['taskid']]);
  139. }
  140. if (!empty($storeMiniAuthIcp)) {
  141. //兼容提交时候报错 但是微信已经提交成功
  142. $storeMiniAuthIcp->procedure_status = $msg['procedure_status'];
  143. $storeMiniAuthIcp->save();
  144. } else {
  145. //兼容提交时候报错 但是微信已经提交成功
  146. if (isset($msg['appid'])) {
  147. $mini_id_list = StoreMini::find()->where(['appid' => $msg['appid'], 'is_cancle' => 0])
  148. ->select('id')->column();
  149. if ($mini_id_list) {
  150. StoreMiniAuthIcp::updateAll(['procedure_status' => $msg['procedure_status'], 'procedure_id' => $msg['procedure_id']], ['mini_id' => $mini_id_list]);
  151. }
  152. }
  153. }
  154. }
  155. });
  156. $server->push(function($msg) {
  157. $code = $msg['info']['code'];
  158. $mini = StoreMini::find()->where([
  159. 'code'=>$code
  160. ])->orderBy(['id' => SORT_DESC])->one();
  161. $mini->status = $msg['status'] == 0 ? 1 : 2;
  162. $mini->auth_code = json_encode([
  163. 'authorization_code' => $msg['auth_code'],
  164. 'end_time' => time() * 1 + 3600 * 1
  165. ]);
  166. $mini->msg = '状态码:'.$msg['status'].' 状态信息:'.$msg['msg'];
  167. $mini->fail_time = time();
  168. $mini->appid = $msg['appid'];
  169. \Yii::error([__METHOD__, $mini->status, $msg]);
  170. $mini->save();
  171. \Yii::error([__METHOD__, $mini]);
  172. if($msg['status'] == "0"){
  173. $form = new WechatThirdForm();
  174. $form->authorization_code = $msg['auth_code'];
  175. $form->mini_id = $mini->id;
  176. $form->store_id = $mini->store_id;
  177. $res = $form->getAuthorization_info($msg['auth_code']);
  178. $qrcode = AggregateQrcode::find()->where(['store_id' => $mini->store_id ])->one();
  179. if ($qrcode) {
  180. $qrcode->wx_mini_id = $mini->id;
  181. $res = $qrcode->save();
  182. }
  183. }
  184. \app\modules\alliance\models\store\SalesmanNewStoreForm::wechatPush($msg, $mini);
  185. }, Guard::EVENT_THIRD_FAST_REGISTERED);
  186. try {
  187. $server->push(function($msg) {
  188. if ($msg['InfoType'] == 'notify_3rd_wxa_auth') {
  189. $taskid = $msg['taskid'];
  190. $task_status = $msg['task_status'];
  191. $apply_status = $msg['apply_status'];
  192. $message = $msg['message'];
  193. $dispatch_info = $msg['dispatch_info'];
  194. $store_mini_auth = \app\models\StoreMiniAuth::findOne(['task_id' => $taskid]);
  195. $store_mini_auth->task_status = $task_status;
  196. if ($apply_status) {
  197. $store_mini_auth->apply_status = $apply_status;
  198. }
  199. if (in_array($task_status, [1, 2, 5, 8, 11, 14]) || in_array($apply_status, [3, 5])) {
  200. if ($store_mini_auth->is_use_service) {
  201. $store_mini_auth->is_use_service = 0;
  202. $store = Store::findOne($store_mini_auth->store_id);
  203. if (!$store) {
  204. throw new \Exception('店铺不存在');
  205. }
  206. $store->mini_auth_num += 1;
  207. if (!$store->save()) {
  208. throw new \Exception(json_encode($store->errors, JSON_UNESCAPED_UNICODE));
  209. }
  210. }
  211. }
  212. if ($dispatch_info) {
  213. $provider = $dispatch_info['provider'];
  214. $contact = $dispatch_info['contact'];
  215. $dispatch_time = $dispatch_info['dispatch_time'];
  216. $store_mini_auth->provider = $provider;
  217. $store_mini_auth->contact = $contact;
  218. $store_mini_auth->dispatch_time = $dispatch_time;
  219. $message = $message . ":" . $provider . ";" . $contact . ";" . date('Y-m-d H:i:s', $dispatch_time) . ";";
  220. }
  221. $store_mini_auth->task_message = $message;
  222. $store_mini_auth->save();
  223. }
  224. //测试数据
  225. if (isset($msg['Event'])) {
  226. debug_log($msg, 'event.log');
  227. }
  228. });
  229. } catch (\Throwable $e) {
  230. debug_log(['code' => $e->getCode(), 'message' => $e->getMessage()], 'event.log');
  231. }
  232. $server->push(function($msg) {
  233. //判断是否解密成功 成功则存储设置component_verify_ticket
  234. $ticket = $msg['ComponentVerifyTicket'];
  235. Option::set("component_verify_ticket",$ticket,0,'saas');
  236. }, Guard::EVENT_COMPONENT_VERIFY_TICKET);
  237. $server->serve();
  238. return 'success';
  239. }
  240. //消息与事件接收
  241. public function actionCallback(){
  242. if(\Yii::$app->prod_is_duli()){
  243. $app = \app\utils\Wechat\WechatMini::getWechatConfig(1);
  244. // $app->config->set('token', 'weixin');
  245. // $app->config->set('aes_key', '2XJmAod7fTYTjQ9rr4vw730VsKlr7DYOYr9IacLEi6a');
  246. // var_dump($app->getConfig(), $app->access_token->getToken(), get_params(), post_params());die;
  247. }else{
  248. $config = [
  249. 'app_id' => Option::get("platform_third_appid",0,'saas')['value'],
  250. 'secret' => Option::get("platform_third_secret",0,'saas')['value'],
  251. 'token' =>Option::get("platform_token",0,'saas')['value'],
  252. 'aes_key' => Option::get("platform_encodingAesKey",0,'saas')['value']
  253. ];
  254. $app = Factory::openPlatform($config);
  255. }
  256. $request = \Yii::$app->req;
  257. if (\RUN_MODE == 'wokerman') {
  258. $symfony_request = new SymfonyRequest($request->get(), $request->post(), [], $request->cookie(), [], [], $request->rawBody());
  259. $symfony_request->headers = new HeaderBag($request->header());
  260. $app->rebind('request', $symfony_request);
  261. }
  262. $server = $app->server;
  263. try{
  264. $msg = $server->getMessage();
  265. } catch (\Exception $e){
  266. \Yii::error($e);
  267. return 'err0';
  268. }
  269. $appid = get_params('appid');
  270. $file_name = \Yii::$app->runtimePath . '/logs/app_wechat.log';
  271. file_put_contents($file_name, "\r\n" . '[审核事件接受][' . date('Y-m-d H:i:s') . $appid . ']' . json_encode($msg), FILE_APPEND);
  272. // if (\RUN_MODE == 'wokerman') {
  273. // $text = $request->rawBody();
  274. // } else {
  275. // $text = file_get_contents("php://input");
  276. // }
  277. // $res = $this->base($text);
  278. // file_put_contents($file_name, "\r\n" . '[审核事件接受-old][' . date('Y-m-d H:i:s') . $appid . ']' . json_encode($res), FILE_APPEND);
  279. // if($res['errCode'] === 0){
  280. // $xml_tree = new \DOMDocument();
  281. // $xml_tree->loadXML($res['msg']);
  282. // $array_Event = $xml_tree->getElementsByTagName('Event');
  283. // $Event = $array_Event->item(0)->nodeValue;
  284. $Event = $msg['Event'];
  285. if ($Event == "weapp_audit_success") {//代码上传审核通过
  286. StoreMini::updateAll(['mini_up' => 2], ['appid'=>$appid]);
  287. } elseif ($Event == "weapp_audit_fail") {//代码上传审核不通过
  288. // $array_Reason = $xml_tree->getElementsByTagName('Reason');
  289. // $Reason = $array_Reason->item(0)->nodeValue;
  290. StoreMini::updateAll(['mini_up' => 3, 'mini_up_error' => $msg['Reason']], ['appid'=>$appid]);
  291. } elseif($Event == "weapp_audit_delay") {//代码上传审核延后
  292. StoreMini::updateAll(['mini_up' => 4], ['appid'=>$appid]);
  293. } elseif($Event == "retail_pay_notify") {
  294. \app\utils\Wechat\B2b\B2bPay::notify($msg);
  295. } elseif($Event == "retail_refund_notify") {
  296. return 'success';
  297. } elseif($Event == "wxa_nickname_audit") {//名称审核结果推送
  298. // $ret = $xml_tree->getElementsByTagName('ret')->item(0)->nodeValue;
  299. if ($msg['ret'] == 3) {
  300. StoreMini::updateAll(['apply_name_status' => 3, 'apply_name_error' => ''], ['appid'=>$appid]);
  301. $wechat = new WechatThirdForm();
  302. $wechat->getMiniInfo("",$appid);
  303. }
  304. if ($msg['ret'] == 2) {
  305. // $reason = $xml_tree->getElementsByTagName('reason')->item(0)->nodeValue;
  306. StoreMini::updateAll(['apply_name_status' => 2, 'mini_up' => 2, 'mini_up_error' => $msg['reason'], 'apply_name_error' => $msg['reason']], ['appid'=>$appid]);
  307. }
  308. }else{
  309. return 'err1';
  310. }
  311. // }
  312. }
  313. public function base($text){
  314. \Yii::getLogger()->log($text,Logger::LEVEL_ERROR);
  315. $token = Option::get("platform_token",0,'saas')['value'];
  316. $encodingAesKey = Option::get("platform_encodingAesKey",0,'saas')['value'];
  317. $appid = Option::get("platform_third_appid",0,'saas')['value'];
  318. if(!empty(get_params())){
  319. $getParam = get_params();
  320. }else{
  321. $getParam = post_params();
  322. }
  323. //解密
  324. $wx = new \WXBizMsgCrypt($token,$encodingAesKey,$appid);
  325. $xml_tree = new \DOMDocument();
  326. $xml_tree->loadXML($text);
  327. $array_e = $xml_tree->getElementsByTagName('Encrypt');
  328. $encrypt = $array_e->item(0)->nodeValue;
  329. $format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
  330. $from_xml = sprintf($format, $encrypt);
  331. $msg = "";
  332. $errCode = $wx->decryptMsg($getParam['msg_signature'],$getParam['timestamp'],$getParam['nonce'],$from_xml,$msg);
  333. return [
  334. 'errCode'=>$errCode,
  335. 'msg'=>$msg
  336. ];
  337. }
  338. }