weixin['account']['appid']) || !$this->weixin['account']['appid']) { exit('插件AppId未配置(如果后台已经配置,请更新缓存后,才会生效)'); } elseif (!isset($this->weixin['account']['token']) || !$this->weixin['account']['token']) { exit('插件Token未配置(如果后台已经配置,请更新缓存后,才会生效)'); } elseif ($this->checkSignature()) { // 判读是不是只是验证 $echostr = \Phpcmf\Service::L('Input')->get('echostr', true); if ($echostr) { echo $echostr;exit; } else { // 实际处理用户消息 $content = file_get_contents('php://input'); if (isset($this->weixin['account']['log']) && $this->weixin['account']['log']) { file_put_contents(WRITEPATH.'app/weixin.log', dr_date(SYS_TIME, 'Y-m-d H:i:s').' - '.$content.PHP_EOL.'==================================='.PHP_EOL, FILE_APPEND); } //file_put_contents(APPPATH."wx.txt", var_export($content, true)); if ($content) { // 解析微信传过来的 XML 内容 转化为数组 $this->data = dr_object2array(simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA)); if (!$this->data['EventKey']) { $this->data['EventKey'] = ''; } $this->token = $this->data['ToUserName']; $rt = weixin_get_access_token(); $rt['code'] && $this->access_token = $rt['msg']; // 微信消息钩子 \Phpcmf\Hooks::trigger('weixin_msg', $this); // 存储和分析请求 switch ($this->data['MsgType']) { case 'text': # 文本消息 // 初始化用户 将其加入到粉丝组里面 $this->_init_user(); \Phpcmf\Service::M('Weixin', 'Weixin')->save_message($this->data); // // 搜索自定义回复 $kws = $this->get_cache('weixin-kws'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : '')); if ($kws) { foreach ($kws as $kw => $id) { if (strpos($this->data['Content'], (string)$kw) !== false) { $data = \Phpcmf\Service::M()->table(weixin_wxtable('reply'))->get($id); if ($data) { // 记录 \Phpcmf\Service::M()->table(weixin_wxtable('reply'))->update($data['id'], [ 'counts' => $data['counts'] + 1, 'updatetime' => SYS_TIME, ]); if ($data['tid']) { // 回复素材 return $this->_to_weixin_content($data['content']); } else { // 回复文本 return $this->_to_weixin_text($data['content']); } break; } } } } // 用于自定义开发回复 if (is_file(APPPATH.'Plugins/AutoReply/Run.php')) { require APPPATH.'Plugins/AutoReply/Run.php'; } // 搜索模块内容回复 if ($this->weixin['config']['ss']) { // 搜索模块内容回复 if ($this->weixin['config']['ss_dir']) { // 搜索模块内容 foreach ($this->weixin['config']['ss_dir'] as $dirname) { foreach ($this->site as $siteid) { $table = dr_module_table_prefix($dirname, $siteid); // 判断是否存在表 if (!\Phpcmf\Service::M()->is_table_exists($table)) { continue; } // 查询 关键 词 $kw = dr_safe_replace($this->data['Content']); $data = \Phpcmf\Service::M()->db->table($table)->where('`title` LIKE "%'.$kw.'%"')->orderBy('id desc')->limit(1)->get()->getResultArray(); #log_message('error', ''.\Phpcmf\Service::M()->get_sql_query()); if ($data) { // 查询成功,回复他们 $cdata = [ 'tid' => 'index', 'content' => [], ]; foreach ($data as $ii => $t) { $i = 10 + $ii; $cdata['content'][$i] = [ 'title_'.$i => $t['title'], 'author_'.$i => $t['author'], 'thumb_'.$i => $t['thumb'] ? dr_get_file($t['thumb']) : SITE_LOGO, 'description_'.$i => $t['description'], 'url_'.$i => dr_url_prefix($t['url']), ]; if ($t['thumb'] && !isset($cdata['content'][1])) { $cdata['content'][1] = [ 'title_1' => $t['title'], 'author_1' => $t['author'], 'thumb_1' => dr_get_file($t['thumb']), 'description_1' => $t['description'], 'url_1' => dr_url_prefix($t['url']), ]; unset($cdata['content'][$i]); } } ksort($cdata['content']); // 回复内容 return $this->_to_weixin_content_data($cdata); } } } } // 没有找到回复内容 if ($this->weixin['config']['ss_type']) { // 回复素材 return $this->_to_weixin_content($this->weixin['config']['ss_value_1']); } else { // 回复文本 return $this->_to_weixin_text($this->weixin['config']['ss_value_0']); } } break; case 'image': # 图片消息 case 'voice': # 语音消息 case 'video': # 视频消息 case 'shortvideo': # 小视频消息 case 'link': # 链接消息 // 初始化用户 将其加入到粉丝组里面 $this->_init_user(); \Phpcmf\Service::M('Weixin', 'Weixin')->save_message($this->data); break; case 'location': # 地理位置消息 break; case 'event': # 事件推送 switch ($this->data['Event']) { case 'PUBLISHJOBFINISH': // 发布内容推送 \Phpcmf\Service::M()->table(weixin_wxtable('content')) ->where('publish_id', $this->data['PublishEventInfo']['publish_id'])->update(0, [ 'status' => $this->data['PublishEventInfo']['publish_status'], 'article_id' => $this->data['PublishEventInfo']['article_id'], ]); break; case 'subscribe': // 关注时 // 统计数据 /* $fans = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->where('date', date('Ymd'))->getRow(); if (!$fans) { // 今日新关注 $usercount = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts(); $rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->insert([ 'new' => 1, 'cancel' => 0, 'cumulate' => $usercount, 'date' => date('Ymd'), ]); } else { $rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->update($fans['id'], [ 'new' => $fans['new'] + 1, 'cumulate' => $fans['cumulate'] + 1, ]); }*/ if (strpos($this->data['EventKey'], 'qrscene_bang-') === 0) { // 表示通过扫描二维码关注微信公众号 $this->_gz_bang_user(); } else { // 初始化用户 将其加入到粉丝组里面 $user = $this->_init_user(); $this->_gz_login_user(); // 回复关注信息 if ($this->weixin['config']['gz']) { if ($this->weixin['config']['gz_type']) { // 回复素材 if ($this->weixin['config']['gz_value_1']) { $this->_to_weixin_content($this->weixin['config']['gz_value_1']); } } else { // 回复文本 if ($this->weixin['config']['gz_value_0']) { $this->_to_weixin_text($this->_gz_msg($this->weixin['config']['gz_value_0'], $user)); } } } } break; case 'unsubscribe': // 取消关注时 /* $fans = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->where('date', date('Ymd'))->getRow(); if (!$fans) { // 今日新取消关注 $usercount = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts(); $rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->insert([ 'new' => 0, 'cancel' => 1, 'cumulate' => $usercount, 'date' => date('Ymd'), ]); } else { $rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->update($fans['id'], [ 'cancel' => $fans['new'] + 1, 'cumulate' => max(0, $fans['cumulate'] - 1), ]); }*/ // 删除各种记录 \Phpcmf\Service::M()->db->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->delete(); \Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->where('openid', $this->data['FromUserName'])->delete(); \Phpcmf\Service::M()->db->table(weixin_wxtable('message'))->where('openid', $this->data['FromUserName'])->delete(); \Phpcmf\Service::M()->db->table('member_oauth')->where('oauth', 'wechat')->where('oid', $this->data['FromUserName'])->delete(); break; default: if (strpos($this->data['EventKey'], 'App::') === 0) { // 表示执行插件控制器 $file = APPPATH.'Plugins/'.ucfirst(substr($this->data['EventKey'], 5)).'/Run.php'; if (!is_file($file)) { log_message('error', '微信小插件运行程序不存在:'.$file); } else { require $file; } // 初始化用户 将其加入到粉丝组里面 $this->_init_user(); } elseif (strpos($this->data['EventKey'], 'bang-') === 0 || strpos($this->data['EventKey'], 'qrscene_bang-') === 0) { // 表示通过扫描二维码关注微信公众号 $this->_gz_bang_user(); } elseif (strpos($this->data['EventKey'], 'login-') === 0 || strpos($this->data['EventKey'], 'qrscene_login-') === 0) { // 表示通过扫描二维码关注微信公众号 $this->_gz_login_user(); } break; } break; default: # code... // 初始化用户 将其加入到粉丝组里面 $this->_init_user(); break; } } } } exit; } // 表示通过扫描二维码关注微信公众号 private function _gz_bang_user() { list($s, $uid) = explode('-', $this->data['EventKey']); $member = $uid ? dr_member_info($uid) : []; if ($member) { // 绑定账号 $rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']); if (!$rt['code']) { return; } elseif (!$rt['data']['openid']) { return; } \Phpcmf\Service::M('member')->insert_oauth($uid, 'login', [ 'oid' => $rt['data']['openid'], 'oauth' => 'wechat', 'avatar' => (string)$rt['data']['headimgurl'], 'unionid' => (string)$rt['data']['unionid'], 'nickname' => dr_emoji2html($rt['data']['nickname']?$rt['data']['nickname']:'微信用户'), 'expire_at' => SYS_TIME, 'access_token' => 0, 'refresh_token' => 0, ], ''); \Phpcmf\Service::M()->db->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->update([ 'uid' => (int)$member['uid'], 'username' => (string)$member['username'], ]); if ( $this->weixin['config']['gz']) { if ($this->weixin['config']['gz_type']) { // 回复素材 $this->_to_weixin_content($this->weixin['config']['gz_value_1']); } else { // 回复文本 $this->_to_weixin_text($this->_gz_msg($this->weixin['config']['gz_value_0'], $member)); } } } } // 表示通过扫描二维码关注微信公众号 private function _gz_login_user() { list($s, $ep) = explode('-', $this->data['EventKey']); if ($ep) { // 登录或注册账号 $rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']); if (!$rt['code']) { return; } $user = \Phpcmf\Service::M()->table('member_oauth')->where('oid', $rt['data']['openid'])->where('oauth', 'wechat')->getRow(); if (!$user && isset($rt['data']['unionid']) && $rt['data']['unionid']) { $user = \Phpcmf\Service::M()->table('member_oauth')->where('unionid', $rt['data']['unionid'])->getRow(); } if ($user['uid']) { // 已经关注,就登录 \Phpcmf\Service::M()->table('member_oauth')->update($user['id'], [ 'refresh_token' => 'login-'.$ep, ]); if ($this->weixin['config']['gz_login']) { $user = dr_member_info($user['uid']); $this->_to_weixin_text(str_replace(['{user}', '{time}', '{name}'], [$user['username'], dr_date(SYS_TIME), $user['name']], $this->weixin['config']['gz_login'])); } else { $this->_to_weixin_text('通过扫描二维码在PC登录成功'); } return; } if ($this->member_cache['oauth']['login']) { // 直接注册 $oauth = [ 'oid' => $rt['data']['openid'], 'oauth' => 'wechat', 'avatar' => $rt['data']['headimgurl'], 'unionid' => (string)$rt['data']['unionid'], 'nickname' => dr_emoji2html($rt['data']['nickname']?$rt['data']['nickname']:'微信用户'), 'expire_at' => SYS_TIME, 'access_token' => 0, 'refresh_token' => 'login-'.$ep, ]; $rt2 = \Phpcmf\Service::M('member')->insert_oauth(0, 'register', $oauth, ''); if (!$rt2['code']) { $this->_to_weixin_text($rt2['msg']); } $oauth['id'] = $rt2['code']; $groupid = (int)$this->member_cache['register']['groupid']; if (!$groupid) { $this->_to_weixin_text('系统没有设置默认注册的用户组'); } $rt = \Phpcmf\Service::M('member')->register_oauth($groupid, $oauth); if ($rt['code']) { // 登录成功 if ($this->weixin['config']['gz_reg']) { $user = $rt['data']['member']; $this->_to_weixin_text(str_replace(['{user}', '{time}', '{name}'], [$user['username'], dr_date(SYS_TIME), $user['name']], $this->weixin['config']['gz_reg'])); } else { $this->_to_weixin_text('通过扫描二维码在PC注册成功,随机账号为:'.$rt['data']['member']['username']); } } else { $this->_to_weixin_text($rt['msg']); } } else { // 绑定账号 $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode(SITE_URL.'index.php?s=weixin&c=member&ep=login-'.$ep).'&response_type=code&scope=snsapi_base&state=member#wechat_redirect'; $txt = $this->weixin['config']['bang_text'] ? $this->weixin['config']['bang_text'] : '您还没有绑定本站账号,点我立即绑定账号'; $this->_to_weixin_text(''.$txt.''); } } } // 替换返回值 private function _gz_msg($tpl, $user) { if (!isset($user['username']) || !$user['username']) { $user['username'] = $user['nickname']; } return str_replace('{username}', $user['username'], (string)$tpl); } // 初始化用户情况 private function _init_user() { $rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']); if (!$rt['code']) { return; } $user = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->getRow(); if (!$user) { // 入库粉丝表 $user = \Phpcmf\Service::M('User', APP_DIR)->insert_user($rt['data']); } else { // 更新 $user = \Phpcmf\Service::M('User', APP_DIR)->update_user($user, $rt['data']);; } // 判断当用户没有绑定会员的情况时 if (!$user['uid']) { // 判断是否绑定过公众号 $bang = \Phpcmf\Service::M()->table('member_oauth')->where('oauth', 'wechat')->where('oid', $this->data['FromUserName'])->getRow(); if (!$bang && isset($user['unionid']) && $user['unionid']) { $bang = \Phpcmf\Service::M()->table('member_oauth')->where('unionid', $user['unionid'])->getRow(); } if ($bang && $bang['uid']) { $member = dr_member_info($bang['uid']); \Phpcmf\Service::M()->table(weixin_wxtable('user'))->update($user['id'], [ 'uid' => (int)$bang['uid'], 'username' => (string)$member['username'], ]); } else { if ($this->weixin['config']['bang']) { // 提醒用户绑定会员 $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode(SITE_URL.'index.php?s=weixin&c=member').'&response_type=code&scope=snsapi_base&state=member#wechat_redirect'; $txt = $this->weixin['config']['bang_text'] ? $this->weixin['config']['bang_text'] : '您还没有绑定本站账号,点我立即绑定账号'; $this->_to_weixin_text(''.$txt.''); } return $user; } } // 存储cookie $this->uid = $user['uid']; $this->member = \Phpcmf\Service::M('member')->get_member($this->uid); \Phpcmf\Service::M('member')->save_cookie($this->member); return $this->member; } // 验证微信请求 private function checkSignature() { $nonce = (string)$_GET["nonce"]; $signature = (string)$_GET["signature"]; $timestamp = (string)$_GET["timestamp"]; $token = $this->weixin['account']['token']; $tmpArr = [$token, $timestamp, $nonce]; sort($tmpArr, SORT_STRING); $tmpStr = implode( $tmpArr ); $tmpStr = sha1( $tmpStr ); if ($tmpStr == $signature){ return true; } else{ return false; } } // ================================================ // 回复文本 public function _to_weixin_text($text) { if (!$text) { return; } echo ' data['FromUserName'].']]> data['ToUserName'].']]> '.(SYS_TIME+2).' ';exit; } // 回复素材 public function _to_weixin_content($id) { $id = (int)substr($id, 5); if (!$id) { return; } // 查询内容 $data = \Phpcmf\Service::M()->table(weixin_wxtable('content'))->get($id); if (!$data) { return; } $value = dr_string2array($data['content']); $data['content'] = []; if ($value) { for ($i = 1; $i<=9; $i++) { if (!$value['thumb_'.$i] || !$value['title_'.$i]) { break; } $data['content'][$i] = [ "title_".$i => $value['title_'.$i], "thumb_".$i => dr_get_file($value['thumb_'.$i]), "description_".$i => $value['description_'.$i], "url_".$i => html_entity_decode(dr_url_prefix($value['url_'.$i])) ]; } } #file_put_contents(WRITEPATH."weixin/wx.txt", var_export($data, true)); return $this->_to_weixin_content_data($data); } // 开始回复 public function _to_weixin_content_data($cdata) { if (!$cdata['tid']) { $cdata['tid'] = 'index'; } switch ($cdata['tid']) { case 'index': // 回复图文 $count = 0; $text = ''; foreach ($cdata['content'] as $i => $t) { if ($t['title_'.$i]) { $count ++; $text.= ' <![CDATA['.$t['title_'.$i].']]> '; } } if (!$count) { $this->_to_weixin_text('没有找到相关内容'); return; } exit(' data['FromUserName'].']]> data['ToUserName'].']]> '.(SYS_TIME+2).' '.$count.' '.$text.' '); break; case 'image': if (!$cdata['media_id']) { $this->_to_weixin_text('没有找到相关内容'); return; } exit(' data['FromUserName'].']]> data['ToUserName'].']]> '.(SYS_TIME+2).' '); break; case 'voice': if (!$cdata['media_id']) { $this->_to_weixin_text('没有找到相关内容'); return; } exit(' data['FromUserName'].']]> data['ToUserName'].']]> '.(SYS_TIME+2).' '); break; case 'video': if (!$cdata['media_id']) { $this->_to_weixin_text('没有找到相关内容'); return; } exit(' data['FromUserName'].']]> data['ToUserName'].']]> '.(SYS_TIME+2).' '); break; case 'link': exit(' data['FromUserName'].']]> data['ToUserName'].']]> '.(SYS_TIME+2).' <![CDATA['.$cdata['title'].']]> '); break; } $this->_to_weixin_text('没有找到相关内容'); } /* 组装xml数据 */ private function _data2xml($xml, $data, $item = 'item') { foreach ( $data as $key => $value ) { is_numeric ( $key ) && ($key = $item); if (is_array ( $value ) || is_object ( $value )) { $child = $xml->addChild ( $key ); $this->_data2xml ( $child, $value, $item ); } else { if (is_numeric ( $value )) { $child = $xml->addChild ( $key, $value ); } else { $child = $xml->addChild ( $key ); $node = dom_import_simplexml ( $child ); $node->appendChild ( $node->ownerDocument->createCDATASection ( $value ) ); } } } } }