代码参考自慕课网视频https://www.imooc.com/learn/509
本文实现的是微信公众被关注和被动回复用户的文本消息的纯文本和图文消息
不多BB,先上完整代码!下面再分块讲解!
完整代码
<?php
$nonce = $_GET['nonce'];
$token = '******';
$timestamp = $_GET['timestamp'];
$echostr = $_GET['echostr'];
$signature = $_GET['signature'];
//形成数组,然后按字典序排序
$array = array();
$array = array($nonce, $timestamp, $token);
sort($array);
//拼接成字符串,sha1加密 ,然后与signature进行校验
$str = sha1( implode( $array ) );
if( $str == $signature && $echostr ){
//第一次接入weixin api接口的时候
echo $echostr;
exit;
}
responseMsg();
//消息回复
function responseMsg() {
//1.获取到微信推送过来post数据(xml格式)
$postArr = file_get_contents("php://input");
//2.处理消息类型,并设置回复类型和内容
$postObj = simplexml_load_string($postArr, 'SimpleXMLElement', LIBXML_NOCDATA);
//判断该数据包是否是订阅的事件推送
if (strtolower($postObj->MsgType) == 'event') {
//如果是关注 subscribe事件
if (strtolower($postObj->Event) == 'subscribe') {
$info = array(
'toUser' => $postObj->FromUserName,
'fromUser' => $postObj->ToUserName,
'time' => time(),
'msgType' => 'text',
'content' => '欢迎关注我的微信公众号!'
);
res_text($info);
}// if end
}//if end
// 判断该数据是否是图文消息
if (strtolower($postObj->MsgType) == 'text'){
res_user_msg($postObj);
}// if end
}// responseMsg() end
// 消息函数
/*<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>*/
function res_user_msg($postObj){
$info = array(
'toUser' => $postObj->FromUserName,
'fromUser' => $postObj->ToUserName,
'time' => time()
);
// 发送纯文本消息
$res_text_msg = array(
'1' => '<a href="http://www.xiaoxiaoming.net/">个人博客,欢迎阅读!</a>'
);
// 发送图文消息
$res_article = array(
'article_test' => array(
array(
'title'=>'MongoDB的优劣势',
'description'=>"什么情况下选择MongoDB?",
'picUrl'=>'https://mmbiz.qpic.cn/mmbiz_jpg/evOoWdxqPS3FabKwKqfhR86sibicEB5ZYUqVpmVo9L3kpXdjgPbicplZBiblUQ42jgONLbE8E4MM27av1IqibqwHQCg/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1',
'url'=>'https://mp.weixin.qq.com/s/O2R0X-3hw7K3deEXGDdBLA',
),
),
);
// 文本消息遍历
foreach($res_text_msg as $key=>$value){
if(trim($postObj->Content) == $key){
$info['content'] = $value;
$info['msgType'] = 'text';
res_text($info);
}
}// foreach end
// 图文消息
foreach($res_article as $key=>$value){
if(trim($postObj->Content) == $key){
$info['msgType'] = 'news';
$info['content'] = $value;
res_article($info);
}
}//foreach end
}// res_user_msg() end
// 发送纯文本信息
function res_text($info){
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$res = sprintf($template, $info['toUser'], $info['fromUser'], $info['time'], $info['msgType'], $info['content']);
echo $res;
}// res_text() end
// 回复图文消息
function res_article($info){
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<ArticleCount>".count($info['content'])."</ArticleCount>
<Articles>";
foreach($info['content'] as $key=>$value){
$template .="<item>
<Title><![CDATA[".$value['title']."]]></Title>
<Description><![CDATA[".$value['description']."]]></Description>
<PicUrl><![CDATA[".$value['picUrl']."]]></PicUrl>
<Url><![CDATA[".$value['url']."]]></Url>
</item>";
}
$template .= "</Articles>
</xml>";
$res = sprintf($template, $info['toUser'], $info['fromUser'], $info['time'], $info['msgType']);
echo $res;
}// res_article end
服务器配置初始化连接
$nonce = $_GET['nonce'];
$token = '******'; // 换成自己公众号的token
$timestamp = $_GET['timestamp'];
$echostr = $_GET['echostr'];
$signature = $_GET['signature'];
//形成数组,然后按字典序排序
$array = array();
$array = array($nonce, $timestamp, $token);
sort($array);
//拼接成字符串,sha1加密 ,然后与signature进行校验
$str = sha1( implode( $array ) );
if( $str == $signature && $echostr ){
//第一次接入weixin api接口的时候
echo $echostr;
exit;
}
responseMsg();
这段代码的功能是初始化配置连接,在公众号管理中打开,如果不知道为什么这样连接,可以稍微花点时间看下文档 ,我觉得配合文档应该可以理解;文档url:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
微信平台在向服务器发送连接的时候,初始化配置连接会带有echostr,所以如果不是初始化配置连接,这执行responseMsg()函数,连接完成之后再来看下如何回复消息吧!
被关注纯文本回复
//消息回复
function responseMsg() {
//1.获取到微信推送过来post数据(xml格式)
$postArr = file_get_contents("php://input");
//2.处理消息类型,并设置回复类型和内容
$postObj = simplexml_load_string($postArr, 'SimpleXMLElement', LIBXML_NOCDATA);
//判断该数据包是否是订阅的事件推送
if (strtolower($postObj->MsgType) == 'event') {
//如果是关注 subscribe事件
if (strtolower($postObj->Event) == 'subscribe') {
$info = array(
'toUser' => $postObj->FromUserName,
'fromUser' => $postObj->ToUserName,
'time' => time(),
'msgType' => 'text',
'content' => '欢迎关注我的微信公众号!'
);
res_text($info);
}// if end
}//if end
// 判断该数据是否是图文消息
if (strtolower($postObj->MsgType) == 'text'){
res_user_msg($postObj);
}// if end
}// responseMsg() end
在代码中有比较详细的解释,但是这里需要说的我踩过的坑是
$postArr = file_get_contents("php://input");
就是接收微信平台发过来的数据的时候,在教程中是这样的
$postArr = $GLOBALS['HTTP_RAW_POST_DATA'];
然而这样的方式在PHP7.0中不能接收到数据
接收到的是一个xml格式的数据,如这样
<xml>
<ToUserName>< ![CDATA[toUser] ]></ToUserName>
<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType>< ![CDATA[text] ]></MsgType>
<Content>< ![CDATA[this is a test] ]></Content>
<MsgId>1234567890123456</MsgId>
</xml>
$postObj = simplexml_load_string($postArr, 'SimpleXMLElement', LIBXML_NOCDATA);
simplexml_load_string()可以将xml装换成对象进行调用
if (strtolower($postObj->MsgType) == 'event') {
//如果是关注 subscribe事件
if (strtolower($postObj->Event) == 'subscribe') {
$info = array(
'toUser' => $postObj->FromUserName,
'fromUser' => $postObj->ToUserName,
'time' => time(),
'msgType' => 'text',
'content' => '欢迎关注我的微信公众号!'
);
res_text($info);
}// if end
}//if end
xml中的MsgType包含消息的类型,用户在订阅公众号的时候,开启开发配置的情况下会向服务器发送一个事件,如果是事件还会包含有Event的xml,会显示时间的类型,被订阅公众号的时间类型是subscribe;官方 文档url:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140454
在判断是被关注的消息后根据接收的消息就可以进行消息发送了,我们通过info获取xml的信息,然后传递到函数中进行相应格式的消息进行发送,其实就想发送邮件差不多;
// 发送纯文本信息
function res_text($info){
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$res = sprintf($template, $info['toUser'], $info['fromUser'], $info['time'], $info['msgType'], $info['content']);
echo $res;
}// res_text() end
函数传递info参数后,我们返回消息需要发送一个xml的固定格式的数据,如上是一个发送纯文本数据的格式,官方文档url:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140543
官方文档的格式是这样:
<xml>
<ToUserName>< ![CDATA[toUser] ]></ToUserName>
<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType>< ![CDATA[text] ]></MsgType>
<Content>< ![CDATA[你好] ]></Content>
</xml>
这个和我们代码template不同的就是替换了%s,但是我才到的坑是复制这个官方的替换,结果因为中间的空格导致回复失败!(我感觉这个非常操蛋,但是在别人的框架下开发唠叨一下就好了,该学还是得学);
被动回复用户消息
// 判断该数据是否是图文消息
if (strtolower($postObj->MsgType) == 'text'){
res_user_msg($postObj);
}// if end
在responseMsg()中还有上面这样一段话,这个就是当接收到消息类型是文本“text"消息的时候进行的相应处理
function res_user_msg($postObj){
$info = array(
'toUser' => $postObj->FromUserName,
'fromUser' => $postObj->ToUserName,
'time' => time()
);
// 发送纯文本消息
$res_text_msg = array(
'1' => '<a href="http://www.xiaoxiaoming.net/">个人博客,欢迎阅读!</a>'
);
// 发送图文消息
$res_article = array(
'article_test' => array(
array(
'title'=>'MongoDB的优劣势',
'description'=>"什么情况下选择MongoDB?",
'picUrl'=>'https://mmbiz.qpic.cn/mmbiz_jpg/evOoWdxqPS3FabKwKqfhR86sibicEB5ZYUqVpmVo9L3kpXdjgPbicplZBiblUQ42jgONLbE8E4MM27av1IqibqwHQCg/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1',
'url'=>'https://mp.weixin.qq.com/s/O2R0X-3hw7K3deEXGDdBLA',
),
),
);
// 文本消息遍历
foreach($res_text_msg as $key=>$value){
if(trim($postObj->Content) == $key){
$info['content'] = $value;
$info['msgType'] = 'text';
res_text($info);
}
}// foreach end
// 图文消息
foreach($res_article as $key=>$value){
if(trim($postObj->Content) == $key){
$info['msgType'] = 'news';
$info['content'] = $value;
res_article($info);
}
}//foreach end
}// res_user_msg() end
在接收到纯文本消息后,我们能回复纯文本,语言,图片,视频,图文;纯文本我们基本和前面被动关注回复消息的差不多;还有用的比较多的是回复图文消息;
在我们代码中,res_text_msg中的关联数组,key值是我们检测到用户发送的相应纯文本消息,$value就是我们需要回应的纯文本消息,只需通过便利查看用户回复的消息是否对应即可!
回复图文消息
/ 回复图文消息
function res_article($info){
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<ArticleCount>".count($info['content'])."</ArticleCount>
<Articles>";
foreach($info['content'] as $key=>$value){
$template .="<item>
<Title><![CDATA[".$value['title']."]]></Title>
<Description><![CDATA[".$value['description']."]]></Description>
<PicUrl><![CDATA[".$value['picUrl']."]]></PicUrl>
<Url><![CDATA[".$value['url']."]]></Url>
</item>";
}
$template .= "</Articles>
</xml>";
$res = sprintf($template, $info['toUser'], $info['fromUser'], $info['time'], $info['msgType']);
echo $res;
}// res_article end
回复图文消息,其实就是 xml消息结构不同,同时msgType是news类型;这里可能会疑惑为什么这里是不是 多了一层数组没必要,因为在2018、10、12之前同时回复的图文消息可以是多个的,包括客服消息接口;
好了!文章就到这里了!这个算是微信公众号开发的开始了!接下来继续学习!在开发模式下就这2个功能在编辑模式下可以轻松实现,但是学习总是从简单的开始,当业务逻辑复杂的服务号下,当然就是只能靠开发模式下进行了!