最近做了几个微信公众号自动回复的小程序,时间紧促,代码写的非常混乱。
近期闲下来,把代码重构了,按这个模式就可以 以非常优雅的方式 处理微信消息。只需要 继承 消息类,重构类的方法(比如:onTextMessage),就可以处理 接收到的文本信息。根据用户回复,返回 textMessage 即可将文本信息发送给用户。
现在已经将 相关代码开源,访问 https://gitee.com/mqycn/WechatMessage 即可下载,简单的使用例子如下:
<?php class WechatMessageApp extends WechatMessageCommon { protected function onSubscribeEvent() { $msg = "你好,非常感谢您的订阅。\n\n"; return $this->textMessage($msg); } protected function onTextMessage($content) { return $this->textMessage("[自动回复]${content}"); } protected function onImageMessage($image, $media_id) { return $this->imageMessage($media_id); } }
消息类型和对应的方法
消息事件 | 需要重写的方法 |
---|---|
用户订阅 | onSubscribeEvent() |
文字消息 | onTextMessage($content) |
图片消息 | onImageMessage($image,$media_id) |
语音消息 | onVoiceMessage($media_id,$format,$to_text) |
视频消息 | onVideoMessage($media_id,$media_thumb_id) |
分享消息 | onLinkMessage($title,$desc,$url) |
文件上传 | onFileMessage($filename,$desc,$file_key,$file_md5,$file_size) |
位置信息 | onLocationMessage($address,$lat,$lng,$scale) |
进入客服界面(小程序) | onUserEnterTempsessionEvent() |
回复类型 | 回复的方法 |
---|---|
文字消息 | textMessage($content) |
图片消息 | imageMessage($media_id) |
语音消息 | voiceMessage($media_id) |
视频消息 | videoMessage($media_id,$title = '',$desc = '') |
分享消息 | linkMessage($articles = array()) |
核心代码:
<?php /** * 类名:WechatMessageCommon * 作者:mqycn * 博客:http://www.miaoqiyuan.cn * 源码:https://gitee.com/mqycn/WechatMessage * 说明:微信消息处理核心类,使用时直接 继承此类,重写 on[事件] 即可,使用 $this->textMessage 可以输出回复 */ abstract class WechatMessageCommon { protected $fromUsername; protected $toUsername; protected $msgId; protected $msgTime; /** * 验证消息事件 */ protected function onValid($request) {} /** * 原始消息事件 */ protected function onMessage($request) {} /** * 回复事件 */ protected function onSendMessage($body) {} /** * 文字消息事件 */ protected function onTextMessage($content) { return $this->onOtherMessage('文字消息', array($content)); } /** * 图片消息事件 */ protected function onImageMessage($image, $media_id) { return $this->onOtherMessage('图片消息', array($image, $media_id)); } /** * 语音消息事件 */ protected function onVoiceMessage($media_id, $format, $to_text) { return $this->onOtherMessage('语音消息', array($media_id, $format, $to_text)); } /** * 视频消息事件 */ protected function onVideoMessage($media_id, $media_thumb_id) { return $this->onOtherMessage('视频消息', array($media_id, $media_thumb_id)); } /** * 分享事件 */ protected function onLinkMessage($title, $desc, $url) { return $this->onOtherMessage('分享消息', array($title, $desc, $url)); } /** * 上传事件 */ protected function onFileMessage($file_name, $desc, $file_key, $file_md5, $file_size) { return $this->onOtherMessage('文件上传', array($file_name, $desc, $file_key, $file_md5, $file_size)); } /** * 位置信息事件 */ protected function onLocationMessage($address, $lat, $lng, $scale) { return $this->onOtherMessage('位置信息', array($address, $lat, $lng, $scale)); } /** * 其他消息事件 */ protected function onOtherMessage($event_type, $argument = array()) { return $this->textMessage('暂时不支持的消息' . $event_type . ',参数(' . join($argument, ', ') . ')'); } /** * 订阅事件 */ protected function onSubscribeEvent() { return $this->textMessage('您好,请问有什么可以帮助您?'); } /** * 客服事件 */ protected function onUserEnterTempsessionEvent() { return $this->textMessage('您好,请问有什么可以帮助您?'); } /** * 其他消息事件 */ protected function onOtherEvent($event_type, $argument = array()) { return $this->textMessage('暂时不支持的事件' . $event_type . ',参数(' . join($argument, ', ') . ')'); } /** * 处理一个请求 */ public function auto() { if (!isset($HTTP_RAW_POST_DATA)) { $HTTP_RAW_POST_DATA = file_get_contents('php://input'); } if (!empty($HTTP_RAW_POST_DATA)) { return $this->answer($HTTP_RAW_POST_DATA); } else { return $this->valid(); } } /** * 验证 */ public function valid() { $this->onValid($_SERVER['QUERY_STRING']); return isset($_GET["echostr"]) ? $_GET["echostr"] : ''; } /** * 自动应答 */ public function answer($post_raw = false) { if ($post_raw === false) { if (!isset($HTTP_RAW_POST_DATA)) { $HTTP_RAW_POST_DATA = file_get_contents('php://input'); } $post_raw = $HTTP_RAW_POST_DATA; } $this->onMessage($post_raw); if (empty($post_raw)) { die("Error"); } else { $message_request = simplexml_load_string($post_raw, 'SimpleXMLElement', LIBXML_NOCDATA); //提取公共参数 $this->fromUsername = trim($message_request->FromUserName); $this->toUsername = trim($message_request->ToUserName); $this->msgId = (int) $message_request->MsgId; $this->msgTime = (int) $message_request->CreateTime; switch (trim($message_request->MsgType)) { case 'text': return $this->onTextMessage($message_request->Content); break; case 'image': return $this->onImageMessage($message_request->PicUrl, $message_request->MediaId); break; case 'voice': return $this->onVoiceMessage($message_request->MediaId, $message_request->Format, $message_request->Recognition); break; case 'video': return $this->onVideoMessage($message_request->MediaId, $message_request->ThumbMediaId); break; case 'link': return $this->onLinkMessage($message_request->Title, $message_request->Description, $message_request->Url); break; case 'file': return $this->onFileMessage($message_request->Title, $message_request->Description, $message_request->FileKey, $message_request->FileMd5, $message_request->FileTotalLen); break; case 'location': return $this->onLocationMessage($message_request->Label, $message_request->Location_X, $message_request->Location_Y, $message_request->Scale); break; case 'event': return $this->onEvent($message_request); break; default: return $this->onOtherMessage($message_request->Event); break; } } } /** * 事件 */ protected function onEvent($message_request) { switch (trim($message_request->Event)) { case "subscribe": return $this->onSubscribeEvent(); case "user_enter_tempsession": return $this->onUserEnterTempsessionEvent(); default: return $this->onOtherEvent($message_request->Event); } } /** * 回复消息 */ protected function sendMessage($message_body) { $tpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime>%s</xml>"; $body = sprintf($tpl, $this->fromUsername, $this->toUsername, time(), $message_body); $this->onSendMessage($body); return $body; } /** * 回复文本信息 */ protected function textMessage($content) { return $this->sendMessage("<MsgType><![CDATA]></MsgType><Content><![CDATA[${content}]]></Content>"); } /** * 回复图片消息 */ protected function imageMessage($media_id) { return $this->sendMessage("<MsgType><![CDATA[image]]></MsgType><Image><MediaId><![CDATA[${media_id}]]></MediaId></Image>"); } /** * 回复语音消息 */ protected function voiceMessage($media_id) { return $this->sendMessage("<MsgType><![CDATA[voice]]></MsgType><Voice><MediaId><![CDATA[${media_id}]]></MediaId></Voice>"); } /** * 回复视频消息 */ protected function videoMessage($media_id, $title = '', $desc = '') { return $this->sendMessage("<MsgType><![CDATA]></MsgType><Video><MediaId><![CDATA[${media_id}]]></MediaId><Title><![CDATA[${title}]]></Title><Description>< ![CDATA[${desc}] ]></Description></Video>"); } /** * 回复分享信息 */ protected function linkMessage($articles = array()) { $content = "<MsgType><![CDATA[news]]></MsgType><ArticleCount>" . count($articles) . "</ArticleCount><Articles>"; foreach ($articles as $article) { list($title, $url, $image, $desc) = $this->linkMessageArticleInfo($article); $content .= "<item><Title><![CDATA[${title}]]></Title><Description><![CDATA[${desc}]]></Description><PicUrl><![CDATA[${image}]]></PicUrl><Url><![CDATA[${url}]]></Url></item>"; } $content .= "</Articles>"; return $this->sendMessage($content); } /** * 获取分享信息记录 */ protected function linkMessageArticleInfo($article) { if (!is_array($article)) { $article = array(); } $title = isset($article['title']) ? $article['title'] : ''; $url = isset($article['url']) ? $article['url'] : ''; $image = isset($article['image']) ? $article['image'] : ''; $desc = isset($article['desc']) ? $article['desc'] : ''; return array($title, $url, $image, $desc); } /** * 生成单条分享信息记录 */ protected function linkMessageArticleItem($title, $url, $image, $desc) { return array( 'title' => $title, 'url' => $url, 'image' => $image, 'desc' => $desc, ); } }
使用说明(使用测试工具)
**1、下载本源码并部署到PHP的WEB环境 **
将下载的脚本安装到服务器后,比如:http://您的域名/安装路径/
测试工具的地址为: http://您的域名/安装路径/test/index.html
如果 仅 需要测试,可以直接访问在线测试地址:http://wechatmessage.demo.miaoqiyuan.cn/test/
**2、选择消息类型,填写参数,点击立即测试,即可看到服务器执行的信息 **
这样 就可以不使用微信,直接开发了。
使用说明(真机测试)
1、申请测试帐号
打开测试接口页面,https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
点击 登录 按钮,使用微信扫码登陆。
**2、填写 测试脚本的URL **
将下载的脚本安装到服务器后,比如:http://您的域名/安装路径/
在 接口配置信息中,填写 测试地址为: http://您的域名/安装路径/demo/message.php 访问
如果不想自己配置,可以使用 在线测试地址:http://wechatmessage.demo.miaoqiyuan.cn/demo/message.php
**3、关注 测试号二维码 **
关注 测试号二维码,进入 公众号 聊天窗口,输入内容即可测试。
默认 不支持的消息模式,会如下图显示: