微信公众平台开发:消息推送
先分析一下回复消息的逻辑流程:用户发送消息给公众号,微信服务器接收的消息,立即对消息进行编码,并以一个xml格式发给开发者的服务器,开发者的服务器就响应一个编辑好的消息,也以xml格式发回给微信服务器,之后微信服务器解析xml发回给微信服务器。(现支持回复文本、图片、图文、语音、视频、音乐)。
消息推送也是在控制器中-index-方法中写的:
由于消息推送同关注和定位一样以xml数据包推送的,故此也要先对xml解析处理
// 微信推送事件 public function index(){ //获取xml数据包,并对数据包解析处理 $xmldata = file_get_contents("php://input");、 $postObj = simplexml_load_string($xmldata, 'SimpleXMLElement', LIBXML_NOCDATA); $data = (array)$postObj; if(isset($data['MsgType']) && $data['MsgType'] == 'text'){ $this->robot($data); exit('success'); } exit(input('get.echostr')); }
当服务器判断用户的信息为text文本格式时,就调用机器人接口进行回复
// 机器人接口 private function robot($data){ //判断是否含有设定好的关键字 if($data['Content'] == '图文消息'){ $response = $this->model->img_article_msg($data); exit($response); } if($data['Content'] == '附近'){ $response = $this->model->near_shops($data['ToUserName'],$data['FromUserName']); exit($response); } // 调用器机人智能聊天 $response = $this->model->robot($data); exit($response); }
机器人接口也会对消息内容进行判断,如果消息中包含了设定好的关键字,就会回复相应图文信息,如果没有包含的关键,就开启智能聊天功能:调用模型中的机器人robot方法:
消息推送:机器人自动回复
调用php中文网写好的机器人API,先配置APPID和KEY
return [ //微信配置 'token' => 'aMCikdpelconEk1omMjK4', 'appid' => 'wxc68d8ac1d6fe2201', 'appsecret' => 'ca719e7b9270e24afa511ef0858f0516', // 机器人API 'robot' => [ 'appid' => '10001', 'key' => '4fa92702a0633127d26ba957d97680ab', ], ];
由于对接微信平台也有个APPID 所以我们需要在机器人API配置中,包个robot配置,在模型中调用方法如下:
// 机器人聊天 public function robot($data){ //1. 调用机器人配置参数 $config = config('app.robot'); $params['appid'] = $config['appid']; $key = $config['key']; //2. 生成签名和消息内容处理 $params['timestamp'] = time();//生成时间戳 $params['msg'] = $data['Content'];//用户发送的消息 ksort($params);//排序数组 $str = http_build_query($params);//拼接数组 $sign = sha1($str.$key);//加密生成签名 //3. 请求机器人智能回复服务 $url = 'http://www.php.cn/index.php/weixintest/robot?'.$str.'&sign='.$sign; $res = http_get($url); $res = json_decode($res,true);//解析机器人返回的消息 $res['msg'] = str_replace('{br}', "\n", $res['msg']);//替换掉特殊字符串和强制换行 //4. 打包成xml数据包 返回给微信服务器 $response = '<xml> <ToUserName>'.$data['FromUserName'].'</ToUserName> <FromUserName>'.$data['ToUserName'].'</FromUserName> <CreateTime>'.time().'</CreateTime> <MsgType>text</MsgType> <Content>'.$res['msg'].'</Content> </xml>'; return $response; }
当微信服务器接收机器人回复的消息,就原样返回给微信客户端,效果如下:
消息推送:图文信息
图文消息推送比较简单的,当用户发送的消息中包含了设定好的关键字,就会回复已编辑好的图文信息给用户浏览即可:
控制器判断和调用模型中的 img_article_msg 方法:关键词content可以自定义
private function robot($data){ if($data['Content'] == '图文消息'){ $response = $this->model->img_article_msg($data); exit($response); }
我们先看看官方的示例和各项参数:
<xml> <ToUserName>< ![CDATA[toUser]接收方帐号(收到的OpenID) ]></ToUserName> <FromUserName>< ![CDATA[fromUser]开发者微信号 ]></FromUserName> <CreateTime>12345678 消息创建时间 (整型)</CreateTime> <MsgType>< ![CDATA[news] ]>消息类型:新闻/活动</MsgType> <ArticleCount>2 图文消息个数,限制为8条以内</ArticleCount> <Articles 多条图文消息信息,注意,如果图文数超过8,则将会无响应> <item 默认第一个item为大图,> <Title>< ![CDATA[title1]图文消息标题 ]></Title> <Description>< ![CDATA[description1] 图文消息描述]></Description> 类似于新闻简介 <PicUrl>< ![CDATA[picurl] 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200 ]></PicUrl> <Url>< ![CDATA[url] 点击图文消息跳转链接 ]></Url> </item> <item> <Title>< ![CDATA[title] ]></Title> <Description>< ![CDATA[description] ]></Description> <PicUrl>< ![CDATA[picurl] ]></PicUrl> <Url>< ![CDATA[url] ]></Url> </item> </Articles> </xml>
这里我们需要注意一下:每一个图文消息都由2个标签包住1.Articles,类似于div或ul标签 >2. item标签类似于li标签
而图文消息有三步形成:
1.编辑好图文消息内容:用数组方法包含节点方式读取图文消息
// 被动回复用户图文消息 public function img_article_msg($data){ // 真实环境下是由后台编辑内容,再从数据库读取图文消息,此处我们直接拉取PHP中文网的新闻链接 $articles = array( array('title'=>'从php招聘要求看php程序员应该会什么?','description'=>'目前在国内有很多知名公司都采用PHP 作为主要的开发 Web 开发语言,php中文网小编就从专业的IT招聘网站拉钩网挑选几条php招聘要','picurl'=>'https://img.php.cn/upload/article/000/000/164/58a56f51f0d4c979.jpg','url'=>'http://www.php.cn/toutiao-352287.html'), array('title'=>'全球php开发框架排行榜','description'=>'在PHP开发中,选择合适的框架有助于加快软件开发,节约宝贵的项目时间,让开发者专注于功能的实现上。由于流行的框架经过了大量项','picurl'=>'https://img.php.cn/upload/article/000/000/002/82ff85191adbac932aec043cbf901727.jpg','url'=>'http://www.php.cn/toutiao-380795.html'), );
读取数据库的图文消息:
public function img_article_msg($data){ // 数据库读取图文消息 $res = \think\Db::name('news')->field('id,title,newsmi,img,url')->select(); foreach ($res as $key => $value){ $articles[] = array('title'=>$value['title'],'description'=>$value['newsmi'],'picurl'=>$value['img'],'url'=>$value['url']); } }
2. 用一个构造方法 【build_img_text_msg 】对图文消息进行重组成 xml数据包
//构造图文消息 private function build_img_text_msg($from,$to,$data){ $str = '<xml><ToUserName>'.$from.'</ToUserName><FromUserName>'.$from.'</FromUserName><CreateTime>'.time().'</CreateTime><MsgType>news</MsgType><ArticleCount>2</ArticleCount><Articles>'; foreach ($data as $item) { $str .= '<item><Title>'.$item['title'].'</Title> <Description>'.$item['description'].'</Description><PicUrl>'.$item['picurl】'].'</PicUrl><Url>'.$item['url'].'</Url></item>'; } $str .= '</Articles></xml>'; return $str; }
构造图文消息需要几个参数:1. $from 谁发的 2. $to 发给谁的 $data:发送的数据
由于图文消息可以有几段,所以我们对图文消息进行拼接组装:
先将头部标签参数写出来:count($data) 表示计算取出多少条数据
$str = '<xml><ToUserName>'.$from.'</ToUserName><FromUserName>'.$to.'</FromUserName><CreateTime>'.time().'</CreateTime><MsgType>news</MsgType><ArticleCount>'.count($data).'</ArticleCount><Articles>';
再将标题内容进行循环出来:foreach ($data as $item)
$str .= '<item><Title>'.$item['title'].'</Title> <Description>'.$item['description'].'</Description><PicUrl>'.$item['picurl'].'</PicUrl><Url>'.$item['url'].'</Url></item>';
最后把尾部标签拼接上,最后 return $str;
$str .= '</Articles></xml>'; return $str;
3. 回复图文消息 xml 数据包给微信服务器
$xml = $this->build_img_text_msg($data['FromUserName'],$data['ToUserName'],$articles); return $xml;
这样一段图文消息就能成功推送出来了 效果如下:
消息推送:推送附近店铺 根据记录用户的经纬度坐标进行推荐附近店铺,增强营销。。
推送附近店铺跟推送图文消息方法一样,只是推送的内容参数不一样,下面我们看看实现的步骤:
1. 先对用户发送的信息进行判断,是否包含关键字,附近,有就在控制器中调用near_shops的方法:
private function robot($data){ if($data['Content'] == '附近'){ $response = $this->model->near_shops($data['ToUserName'],$data['FromUserName']); exit($response); }
2. 设定需推送的店铺经纬度坐标位置:
先创建店铺数据库表shop,创建六个字段:id title 店铺名称 address 地址 img 店铺图片 lat 经度 lng纬度
可以利用百度地图的拾取坐标系统,或高德地图的高德云图功能来获取地图的经纬度坐标参数,创建店铺数据
创建好店铺数据后,就可以在模型中写方法:
public function near_shops($from,$to,$distance = 10){ //先用openid值查找到用户信息 $user = Db::name('user')->where(array('openid'=>$to))->find(); //取出经纬度值 $lat = $user['lat']; $lng = $user['lng']; //查询计算排序用户群的经纬度 $res = \think\Db::name('shop')->field('id,title,address,(6371*acos(cos(radians('.$lat.'))*cos(radians(lat))*cos(radians(lng)-radians('.$lng.'))+sin(radians('.$lat.'))*sin(radians(lat)))) AS distance')->having('distance < '.$distance)->order('distance')->select(); $shop_list = []; //循环读取数组的值 foreach ($res as $key => $value) { $shop_list[] = array('title'=>$value['title'],'description'=>$value['address'].' 距离:'.$value['distance'].'公里','picurl'=>$value['img'],'url'=>'/'); }
这里需要注意几个参数 $lat 经度 $lng 纬度 $distance 距离 HAVING 对由sum或其它集合函数运算结果的输出进行限制。
// 回复图文消息 $xml = $this->build_img_text_msg($to,$from,$shop_list); return $xml;
看看效果: