GzhMsgsController.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. <?php
  2. namespace App\Http\Controllers\Wechat\GzhMsg;
  3. use App\Http\Controllers\Wechat\Template\TemplatesController;
  4. use App\Http\Controllers\Wechat\Staff\StaffsController;
  5. use App\Http\Controllers\Wechat\Material\MaterialsController;
  6. use App\Http\Controllers\Wechat\User\UserInfosController;
  7. use App\Http\Requests;
  8. use App\Http\Controllers\WechatController;
  9. use App\Modules\OfficialAccount\Services\ForceSubscribeDelayMsgService;
  10. use EasyWeChat\Message\Text;
  11. use Illuminate\Http\Request;
  12. use Illuminate\Support\Facades\Redis;
  13. use EasyWeChat\Foundation\Application;
  14. use App\Modules\OfficialAccount\Services\ForceSubscribeService;
  15. use App\Modules\WechatMaterial\Services\WechatMaterialSendMsgService;
  16. /**
  17. * 普通公众号接收消息类
  18. * @author zhoulingjie
  19. *
  20. */
  21. class GzhMsgsController extends WechatController
  22. {
  23. public $param;
  24. public $official_account;
  25. public function __construct()
  26. {
  27. v('gzh_msgs_construct');
  28. // 提取gzh_app_id,回调格式domain/$APPID$/callback
  29. preg_match('/\/(.*)?\/callback/i',$_SERVER['REQUEST_URI'],$data);
  30. isset($data[1]) && !empty($data[1]) && $this->gzh_app_id=$data[1];
  31. v('$this->gzh_app_id');v($this->gzh_app_id);
  32. // 如果redis没有公众号信息,则直接返回,防止被刷
  33. $redis_offcial_account_key = env('redis_offcial_account_key');
  34. if(!empty($redis_offcial_account_key)){
  35. $redis_offcial_account_key = $redis_offcial_account_key.$this->gzh_app_id;
  36. $official_account = Redis::hGet($redis_offcial_account_key,'official_account_info');
  37. $official_account = objectToArray(json_decode($official_account));
  38. if(empty($official_account)){
  39. v('construct_not_has_redis_official_account_return:'.$this->gzh_app_id);
  40. die('');
  41. }else{
  42. v('construct_has_redis_official_account:'.$this->gzh_app_id);
  43. }
  44. }
  45. v('construct_check_end:'.$this->gzh_app_id);
  46. parent::__construct($this->gzh_app_id);
  47. $this->Staff = new StaffsController($this->param);
  48. $this->Material = new MaterialsController($this->param);
  49. $this->UserInfo = new UserInfosController($this->param);
  50. }
  51. /**
  52. * 接收微信回调
  53. http://zydy/wxdbc486f1b4f6a8c3/callback?signature=7aa9eb2a2fd0a0b4c4b4b7acd45f4b77ed990165&timestamp=1506838034&nonce=244404927&openid=oAcqg1LRHNKN2jaEkJ5v56HOwPEQ&encrypt_type=aes&msg_signature=8599ff0fec541a4dfe5ccdd3e50a85d56514a5e6
  54. */
  55. public function index(Request $request)
  56. {
  57. v('gzh_msg_index_start');
  58. if(!$this->checkSignature($request)){
  59. v('return_fail:');
  60. // exit;
  61. }else{
  62. v('return_success:');
  63. }
  64. v('start_setmessagehander:'.env('DEVELOP_MODE'));
  65. if(env('DEVELOP_MODE') == 'local'){
  66. v('local_test');
  67. $message = $this->get_fake_data();
  68. $res = $this->deal_callback($message);
  69. }else{
  70. v('start-server');
  71. $this->app->server->setMessageHandler(function ($message) {
  72. v('start_deal_callback');
  73. return $this->deal_callback($message);
  74. });
  75. }
  76. v('last_echo');
  77. $response = $this->app->server->serve();
  78. // 将响应输出
  79. return $response;
  80. }
  81. function deal_callback($message){
  82. // 开关
  83. $wechat_callback_switch = Redis::get('wechat_callback_switch');
  84. if($wechat_callback_switch){
  85. v('wechat_callback_switch_direct_return:');
  86. return '';
  87. }
  88. try{
  89. v('gzh_start_setmessagehander_in');
  90. // 微信全网发布公众号,在第三方框架里面已经做了回应检测了,这里需要直接返回不然有bug
  91. if($this->gzh_app_id == 'wx570bc396a51b8ff8'){
  92. v('deal_callback_wxtest_direct_return:'.$this->gzh_app_id);
  93. return '';
  94. }
  95. v($message);
  96. if(isset($this->official_account) && in_array($this->official_account['official_account_type'],array('third_platform_default_login','third_platform_pay'))){
  97. v('deal_callback_myown_direct_return:'.$this->gzh_app_id);
  98. return '';
  99. }
  100. $openid = isset($message->FromUserName)?$message->FromUserName:'';
  101. $this->param['openid'] = $openid;
  102. $distribution_channel_id = isset($this->official_account['distribution_channel_id'])?$this->official_account['distribution_channel_id']:'';
  103. // 模板消息发送成功,微信回调直接Return
  104. if($message->Event == 'TEMPLATESENDJOBFINISH'){
  105. v('event_template_send_job_finish_return:'.$openid);
  106. return '';
  107. }
  108. $wx_user = $this->WechatApi->get_force_wx_user($this->gzh_app_id,$openid);
  109. //增加客服消息实际可送达用户记录
  110. try {
  111. ForceSubscribeService::updateGzhUserCustomActive(['openid' => $openid, 'appid' => $this->gzh_app_id, 'distribution_channel_id' => $distribution_channel_id, 'force_user' => $wx_user]);
  112. }catch (\Exception $e)
  113. {
  114. //\Log::error('custom active error:'.$e->getMessage().':'.$e->getFile().':'.$e->getLine());
  115. }
  116. switch ($message->MsgType) {
  117. case 'event':
  118. // 如果关注,则判断是否保存user
  119. if($message->Event == 'subscribe'){
  120. v('subscribe:'.$openid);
  121. // 如果是微信素材直接进来的关注,则要先判断有没有建立强关场景值映射关系,有的话,直接赋值下EventKey
  122. $material_force_subscribe_mapping = $this->WechatApi->get_material_force_subscribe_mapping($this->official_account['distribution_channel_id'],$openid);
  123. v('material_force_subscribe_mapping:'.json_encode($material_force_subscribe_mapping));
  124. if(isset($material_force_subscribe_mapping['uid']) && !empty($material_force_subscribe_mapping['uid'])){
  125. $message->EventKey = 'qrscene_'.$material_force_subscribe_mapping['uid'];
  126. v('material_force_subscribe_mapping_eventkey:'.$message->EventKey);
  127. }
  128. // {"ToUserName":"gh_0fdfe1e4f56c","FromUserName":"ovuI01FHKJuIR8wNkJ_7qj1o9_gY","CreateTime":"1507710568","MsgType":"event","Event":"subscribe","EventKey":"qrscene_999","Ticket":"gQF78DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyWUs2UlZsLXljUWsxNVB5NXhxMUsAAgRz1d1ZAwQAjScA"}
  129. // 强制关注 qrscene_osCoL1iAhr_htstSO6XIKvguBs34
  130. $force_subscribe_sceneId = '';
  131. if(!empty($message->EventKey) && strpos($message->EventKey,'qrscene_') === 0){
  132. $force_subscribe_sceneId = str_replace('qrscene_','',$message->EventKey);
  133. v('subscribe_openid:'.$openid.' force_subscribe_sceneId:'.$force_subscribe_sceneId);
  134. }
  135. // 先判断存在性
  136. if(!empty($wx_user)){
  137. v('exist:'.$openid);
  138. v('subscribe:'.$openid);
  139. $this->WechatApi->subscribe_wx_user($this->gzh_app_id,$openid);
  140. }
  141. // 还没访问我们网站,直接关注公众号,TODO暂时原则是要访问了才记录用户信息
  142. else{
  143. v('not_exist:'.$openid);
  144. // 有场景值才更新,强制关注新的公众号的时候,肯定是空的
  145. // 站外推广
  146. if(strpos($force_subscribe_sceneId,'outer') > -1){
  147. v('outer_subscribe:'.$openid.' sceneId:'.$force_subscribe_sceneId);
  148. }
  149. // 如果场景值是其他类型的,则用户不保存
  150. else{
  151. if(!empty($force_subscribe_sceneId)){
  152. v('not_exist_user_save_force_subscribe:'.$openid.' $force_subscribe_sceneId:'.$force_subscribe_sceneId);
  153. $data = $this->UserInfo->get_oauth_user_info($openid,$force_subscribe_sceneId);
  154. // 保存用户信息
  155. $this->WechatApi->save_force_wx_user($data);
  156. }
  157. }
  158. }
  159. ForceSubscribeDelayMsgService::queue($distribution_channel_id,$this->gzh_app_id,$openid);
  160. }
  161. elseif($message->Event == 'unsubscribe'){
  162. v('unsubscribe:'.$openid);
  163. $this->WechatApi->unsubscribe_wx_user($this->gzh_app_id,$openid);
  164. ForceSubscribeDelayMsgService::dequeue($openid);
  165. }
  166. // 扫描事件
  167. elseif($message->Event == 'SCAN'){
  168. $force_subscribe_sceneId = $message->EventKey;
  169. v('event_scan:'.$openid.' force_subscribe_sceneId:'.$force_subscribe_sceneId);
  170. // {"ToUserName":"gh_0fdfe1e4f56c","FromUserName":"ovuI01FHKJuIR8wNkJ_7qj1o9_gY","CreateTime":"1507710445","MsgType":"event","Event":"SCAN","EventKey":"999","Ticket":"gQF78DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyWUs2UlZsLXljUWsxNVB5NXhxMUsAAgRz1d1ZAwQAjScA"}
  171. if(!empty($message->EventKey)){
  172. // 强制关注,提前关注的老用户,存储下
  173. if(empty($wx_user)){
  174. v('scan_not_exist_user_save_force_subscribe');
  175. $data = $this->UserInfo->get_oauth_user_info($openid,$force_subscribe_sceneId);
  176. // 保存用户信息
  177. $this->WechatApi->save_force_wx_user($data);
  178. }
  179. // FIXME 针对扫错二维码的用户,强制更新uid,防止一直扫描,对h5的uid还是自己的不影响
  180. else{
  181. $origin_uid = isset($wx_user['uid'])?$wx_user['uid']:'';
  182. v('scan_exist_user_update_uid:'.$openid.' scenid:'.$force_subscribe_sceneId.' origin_uid:'.$origin_uid);
  183. $this->WechatApi->update_force_wx_user($openid,$force_subscribe_sceneId);
  184. }
  185. }
  186. }
  187. // 点击事件
  188. elseif($message->Event == 'CLICK'){
  189. v('event_click:'.$openid);
  190. }
  191. // 点击事件
  192. elseif($message->Event == 'TEMPLATESENDJOBFINISH'){
  193. v('event_template_send_job_finish:'.$openid);
  194. return '';
  195. }
  196. // 点击view
  197. elseif($message->Event == 'VIEW' || $message->Event == 'view'){
  198. v('event_view_direct_return:'.$openid);
  199. return '';
  200. }
  201. // 群发消息,返回成功人数
  202. elseif($message->Event == 'MASSSENDJOBFINISH'){
  203. v('event_msg_job_finish:'.$openid);
  204. WechatMaterialSendMsgService::update_wechat_material_send_msg_info($message);
  205. return '';
  206. }
  207. // 统一推送消息
  208. $send_event_content = $this->WechatApi->get_event_content($message->Event,$message->EventKey,$this->gzh_app_id,$openid);
  209. v('$send_event_content');v($send_event_content);
  210. return $this->Staff->batch_send_wechat_content($openid,$send_event_content,'direct_return');
  211. return '';
  212. break;
  213. case 'text':
  214. try{
  215. if ($message->Content === '0') $message->Content = '签到';
  216. if ($message->Content === '00') $message->Content = '最近阅读';
  217. if(!empty($message->Content)){
  218. if($message->Content == 't'){
  219. $send_event_content = array();
  220. $send_event_content['text'] = $openid;
  221. return $this->Staff->batch_send_wechat_content($openid,$send_event_content,'direct_return');
  222. }else{
  223. // 兼容图片和文字
  224. $send_event_content = $this->WechatApi->get_event_content($message->MsgType,$message->Content,$this->gzh_app_id,$openid);
  225. return $this->Staff->batch_send_wechat_content($openid,$send_event_content,'direct_return');
  226. }
  227. }
  228. }
  229. catch(\Exception $e){
  230. v('text_ept:'.$openid.' info:'.$e->getMessage());
  231. }
  232. return '';
  233. break;
  234. case 'image':
  235. $encode_distribution_channel_id = encodeDistributionChannelId($distribution_channel_id);
  236. $WECHAT_CUSTOM_HOST = env('WECHAT_CUSTOM_HOST');
  237. $feedback_content = '未找到相关小说,'."\n".'您可以试试:'."\n"."\n".'<a href="'.env('PROTOCOL').'://site'.$encode_distribution_channel_id.'.'.$WECHAT_CUSTOM_HOST.'.com/recent">查看阅读记录 >> </a> '."\n"."\n".'<a href="'.env('PROTOCOL').'://site'.$encode_distribution_channel_id.'.'.$WECHAT_CUSTOM_HOST.'.com">去书城首页看看 >> </a> '."\n"."\n".'点此<a href="https://help.wd.amanbook.com/?distribution_channel_id='.$encode_distribution_channel_id.'&down=1">联系客服</a>';
  238. $send_event_content = array();
  239. $send_event_content['text'] = $feedback_content;
  240. return $this->Staff->batch_send_wechat_content($openid,$send_event_content,'direct_return');
  241. return '';
  242. break;
  243. case 'voice':
  244. return '';
  245. break;
  246. case 'media':
  247. return '';
  248. break;
  249. case 'location':
  250. return '';
  251. break;
  252. case 'link':
  253. return '';
  254. break;
  255. // ... 其它消息
  256. default:
  257. return '';
  258. break;
  259. }
  260. return '';
  261. }
  262. catch(\Exception $e){
  263. v('deal_call_ept:'.$this->gzh_app_id.' info:'.$e->getMessage());
  264. }
  265. return '';
  266. }
  267. private function checkSignature($request)
  268. {
  269. v('checksign_start');v($request->all());
  270. $signature = $request->get('signature');
  271. $timestamp = $request->get('timestamp');
  272. $nonce = $request->get('nonce');
  273. $echostr = $request->get('echostr');
  274. // $msg = '';
  275. // $errCode = $pc->decryptMsg($msg_sign, $timeStamp, $nonce, $from_xml, $msg);
  276. // $token = 'd4352c0225d5da500b176cf3464e9822';
  277. $tmpArr = array($this->token, $timestamp, $nonce);
  278. sort($tmpArr, SORT_STRING);
  279. $tmpStr = implode( $tmpArr );
  280. $tmpStr = sha1( $tmpStr );
  281. v('tmpStr:'.$tmpStr.' signature:'.$signature);
  282. if( $tmpStr == $signature ){
  283. return true;
  284. }else{
  285. return false;
  286. }
  287. }
  288. function get_fake_data(){
  289. $message = new \stdClass();
  290. $test = 'daily_sign';
  291. $openid = 'oTsZb0cLT7kg3RnxGkfabuRapxMA';
  292. $openid = 'oAcqg1LRHNKN2jaEkJ5v56HOwPEQ';
  293. // $openid = 'oTsZb0cLT7kg3RnxGkfabuRapxMA--9';
  294. if($test == 'subscribe'){
  295. // <xml><ToUserName><![CDATA[gh_9432cc91c481]]></ToUserName>
  296. // <FromUserName><![CDATA[osCoL1gMD06xkuz-ZkYZlK7lbIaU]]></FromUserName>
  297. // <CreateTime>1497423859</CreateTime>
  298. // <MsgType><![CDATA[event]]></MsgType>
  299. // <Event><![CDATA[subscribe]]></Event>
  300. // <EventKey><![CDATA[qrscene_osCoL1iAhr_htstSO6XIKvguBs34]]></EventKey>
  301. // <Ticket><![CDATA[gQHB8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyMnU1XzlHTUdjYm0xMDAwMDAwN08AAgSY30BZAwQAAAAA]]></Ticket>
  302. // </xml>
  303. $message->ToUserName = 'gh_0fdfe1e4f56c';
  304. $message->FromUserName =$openid;
  305. $message->Event = 'subscribe';
  306. $message->EventKey= 'qrscene_outer:1564_752019';
  307. // $message->Event = 'click';
  308. $message->MsgType = 'event';
  309. }elseif($test == 'unsubscribe'){
  310. // <xml><ToUserName><![CDATA[gh_9432cc91c481]]></ToUserName>
  311. // <FromUserName><![CDATA[osCoL1gMD06xkuz-ZkYZlK7lbIaU]]></FromUserName>
  312. // <CreateTime>1497423859</CreateTime>
  313. // <MsgType><![CDATA[event]]></MsgType>
  314. // <Event><![CDATA[subscribe]]></Event>
  315. // <EventKey><![CDATA[qrscene_osCoL1iAhr_htstSO6XIKvguBs34]]></EventKey>
  316. // <Ticket><![CDATA[gQHB8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyMnU1XzlHTUdjYm0xMDAwMDAwN08AAgSY30BZAwQAAAAA]]></Ticket>
  317. // </xml>
  318. $message->ToUserName = 'gh_0fdfe1e4f56c';
  319. $message->FromUserName = $openid;
  320. $message->Event = 'unsubscribe';
  321. $message->EventKey= 'unsubscribe';
  322. // $message->Event = 'click';
  323. $message->MsgType = 'event';
  324. }elseif($test == 'recent_read'){
  325. $message->ToUserName = 'gh_0fdfe1e4f56c';
  326. $message->FromUserName = $openid;
  327. $message->EventKey= 'recent_read';
  328. $message->Event = 'click';
  329. $message->MsgType = 'event';
  330. }elseif($test == 'daily_sign'){
  331. $message->ToUserName = 'gh_0fdfe1e4f56c';
  332. $message->FromUserName = $openid;
  333. $message->EventKey= 'daily_sign';
  334. $message->Event = 'click';
  335. $message->MsgType = 'event';
  336. }elseif($test == 'contact_customer'){
  337. $message->FromUserName = $openid;
  338. $message->Event = 'CLICK';
  339. $message->MsgType = 'event';
  340. $message->EventKey= 'contact_customer';
  341. // $message->Content = '获取我的推广卡';
  342. }elseif($test == 'text'){
  343. $message->FromUserName = $openid;
  344. $message->Event = 'text';
  345. $message->MsgType = 'text';
  346. $message->EventKey= 'text';
  347. $message->Content = '我123';
  348. }
  349. // 扫描进来,判断来源
  350. elseif($test == 'scan'){
  351. // <xml><ToUserName><![CDATA[gh_9432cc91c481]]></ToUserName>
  352. // <FromUserName><![CDATA[osCoL1gMD06xkuz-ZkYZlK7lbIaU]]></FromUserName>
  353. // <CreateTime>1497423781</CreateTime>
  354. // <MsgType><![CDATA[event]]></MsgType>
  355. // <Event><![CDATA[SCAN]]></Event>
  356. // <EventKey><![CDATA[osCoL1iAhr_htstSO6XIKvguBs34]]></EventKey>
  357. // <Ticket><![CDATA[gQHB8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyMnU1XzlHTUdjYm0xMDAwMDAwN08AAgSY30BZAwQAAAAA]]></Ticket>
  358. // </xml>
  359. // gh_b31f44e696d8
  360. $message->FromUserName = $openid;
  361. $message->Event = 'SCAN';
  362. $message->MsgType = 'event';
  363. $message->EventKey= '6';
  364. }
  365. return $message;
  366. }
  367. }