在上一篇文章中我们介绍了微信开发的准备工作接下来就是正式开发了
以自动回复为例
要实现自动回复,我们首先的获取用户输入的消息,那么怎么获取用户输入的数据 根据文档,“消息管理”----“接收普通消息” 注意这样一句话
“当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
当普通用户发送消息到公众号时,微信服务器会发送POST请求到我们的服务器,包含一个XML的数据包
XML
和JSON
一样都是通用的数据类型 既然是发送POST请求,那我们是不是可以用$_POST
接收数据?
尝试一下 首先关注我们这个测试公众号 “开发者工具----公众平台测试账号”,下拉鼠标有个测试二维码,扫码并关注 接下来的开发都基于此账号
本地服务器接收数据
$txt = $_POST['Content'];
//这里我们只接收用户发送的消息,并将其存放到1.txt文件
file_put_contents('./1.txt', $txt);
打开1.txt发现什么也没有
什么原因?原来$_POST
是不能接收test/xml的数据类型(具体为什么不能可参照POST和$GLOBALS[‘HTTP_RAW_POST_DATA’] 的区别,在前面我们提到,微信服务器将用户的消息,以xml的格式发送给本地服务器。
在php5.6以前我们可以通过GLOBALS['HTTP_RAW_POST_DATA']
接收POST不能接受的数据,但在php7.0后这个方法被废弃,php7.0后我们可以使用
file_get_contents('php://input')
获取原生的POST数据。
了解了这个后修改我们的代码
$txt = file_get_contents('php://input');
file_put_contents('./1.txt', $txt);
打开1.txt发现被写入了一段xml数据
<xml><ToUserName><![CDATA[gh_811767743479]]></ToUserName>
<FromUserName><![CDATA[oYRMeuO7pFQP-jXLTE2YmEVCAhPg]]></FromUserName>
<CreateTime>1580781691</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[热]]></Content>//用户发送的消息
<MsgId>22631351498653850</MsgId>
</xml>
Content
就是用户发送的消息
虽然获取到了,但我们怎么处理他?在php看来上面这些就是一字符串,这里我们就要像使用json数据那样,将xml数据转换为php对象 php为我们提供了函数将xml数据转换为php对象
simplexml_load_string($postStr,'SimpleXMLElement',LIBXML_NOCDATA);
修改我们的代码
$txt = file_get_contents('php://input');
//XML数据转换为php对象
$txtObj = simplexml_load_string($txt,'SimpleXMLElement',LIBXML_NOCDATA);
file_put_contents('./1.txt', $txtObj->Content);
发送消息
打开1.txt文件
接受用户信息成功 接受信息之后我们设置自动回复返回给用户消息 查看文档“消息管理----被动回复用户消息”`
当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。
既然接受是xml数据包,那回复肯定也是xml数据 编辑我们的代码,判断用户回复消息
<?php
//服务器验证
//接收参数
$txt = file_get_contents('php://input');
$txtObj = simplexml_load_string($txt,'SimpleXMLElement',LIBXML_NOCDATA);
//消息发送模板
$txtModel = "
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$toUserName = $txtObj->FromUserName;//接受方等于发送此消息的用户名
$fromUserName = $txtObj->ToUserName;//发送方等用户发送消息的ToUserName
$time = time();
if($txtObj->MsgType = 'text'){
//如果用户回复的是文本消息
$msgType = 'text';
if($txtObj->Content == '1'){
//如果用户回复的是文本“1”
$content = '测试回复【发送1】!!!';
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}else{
$content = '测试回复【常规】!!!';
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}
}
上述代码通过sprintf
进行字符串格式化,这样做的好处是不用重复的写xml格式的数据包,直接将其定义成模板留出占位符,直接调用sprintf
填充数据
到此已经完成了简单的自动回复功能
我们还可以根据不同的数据类型进行不同的消息回复
<?php
//服务器验证
//接收参数
$txt = file_get_contents('php://input');
$txtObj = simplexml_load_string($txt,'SimpleXMLElement',LIBXML_NOCDATA);
//消息发送模板
$txtModel = "
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$toUserName = $txtObj->FromUserName;//接受方等于发送此消息的用户名
$fromUserName = $txtObj->ToUserName;//发送方等用户发送消息的ToUserName
$time = time();
$msgType = 'text';
if($txtObj->MsgType == 'text'){
//如果用户回复的是文本消息
if($txtObj->Content == '1'){
//如果用户回复的是文本“1”
$content = '测试回复【发送1】!!!';
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}else{
$content = '测试回复【常规】!!!';
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}
}elseif($txtObj->MsgType == 'image'){
$content = '您发送了一张图片安';
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}elseif($txtObj->MsgType == 'voice'){
$content = '您发送了一条语音安';
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}elseif($txtObj->MsgType == 'video'){
$content = '您发送了一条视频安';
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}elseif($txtObj->MsgType == 'location'){
$content = '您发送了一条位置信息s安';
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}
完成上述操作后我们已经知道如何获取用户消息,设置自动回复了 接下来完成一个案例 用户发送位置信息查询地图上距离用户当前位置的银行信息 要完成这个案例,肯定的调用第三方地图接口,如百度地图
注册/登录成为其用户,并按照提示邮箱激活 激活后我们选择“控制台”---“应用管理”---“创建应用”
这里我们只需要地点检索 创建完成后,会生成一个“AK”;这个“AK”用于调用接口 点击开发文档-----“web服务API”
选择地点检索服务
服务文档选择找到”圆型区域“
阅读参数,进行相关设置 浏览器地址栏测试访问接口
成功访问,不过这里我们将返回的数据类型设置为‘json’通过设置参数output=json
,同时使其返回详细地址通过设置参数scope=2
接下来我们就可以通过php发送get请求到百度地图,使其返回对应的位置信息
http://api.map.baidu.com/place/v2/search?query=%E9%93%B6%E8%A1%8C&location=39.915,116.404&radius=2000&output=json&scope=2&ak=这里键入你的“Ak”
通过file_get_contents
函数
if($txtObj->MsgType == 'location'){
//如果用户发送位置信息
$latitude = $txtObj->Location_X;//纬度
$longitude = $txtObj->Location_Y;//经度
$url = 'http://api.map.baidu.com/place/v2/search?query=银行&location='.$latitude.','.$longitude.'&radius=2000&output=json&scope=2&ak='.$ak
$arr = file_get_contents($url);//发送get请求
$arrPosition = json_decode($arr,true)['results'];//将获取到的结果转换为数组
$content ="共有".count($arrPosition)."条关于银行的记录\n\n";
foreach($arrPosition as $key => $value){
$content.= $value['name'].'在'.$value['province'].$value['city'].$value['area'].$value['address'].'距离你'.$value['detail_info']['distance']."米\n\n";
}
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
}
案例二,人脸识别评估
同样这里要调用第三方接口,通过第三方分析人脸数据并将其返回给用户
1.注册旷视
注册登录后,创建一个应用,生APIKey与APISecret,用于调用他的接口
查看API文档
这里我们选择DeleteApi 仔细阅读文档,查看调用api必选参数与可选参数
调用URL https://api-cn.faceplusplus.com/facepp/v3/detect 调用方法 POST 请求体格式 multipart/form-data
由于要用post的方式请求它,这里我们就用curl
先来测试一下能否访问
<?php
$data = [
'api_key'=>'dut2DHBMm8reohiFo_Kx17GwIfx0EkW3',
'api_secret'=>'xBHyvcOxMtXrRwZrNzVAlcU2_mW7bT_Y',
'image_url'=>'http://590c1c9e.nat123.cc/2.jpg',//图片地址
'return_landmark'=>'1',
'return_attributes'=>'gender,age,emotion,beauty'//请求返回数据包含性别,年龄,情绪,颜值
];
$url = 'https://api-cn.faceplusplus.com/facepp/v3/detect';
//1,初始化
$curl = curl_init();
//设置参数
curl_setopt($curl, CURLOPT_URL,$url);
curl_setopt($curl, CURLOPT_HEADER,0);//不返回header头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//数据返回而不是输出
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);//使用ssl证书加密
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);//post提交
//发送请求信息
$data = curl_exec($curl);
//关闭请求资源
curl_close($curl);
$arr = json_decode($data,true)['faces'];//将返回的数据转换为php数组
print_r($arr);
数据返回成功,接下来对需要的数据进行处理
$data = [
'api_key'=>'你的APIKEY',
'api_secret'=>'你的Secret',
'image_url'=>'http://590c1c9e.nat123.cc/2.jpg',//图片地址
'return_landmark'=>'1',
'return_attributes'=>'gender,age,emotion,beauty'//请求返回数据包含性别,年龄,情绪,颜值
];
$url = 'https://api-cn.faceplusplus.com/facepp/v3/detect';
//1,初始化
$curl = curl_init();
//设置参数
curl_setopt($curl, CURLOPT_URL,$url);
curl_setopt($curl, CURLOPT_HEADER,0);//不返回header头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//数据返回而不是输出
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);//不使用ssl证书加密
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);//post提交
//发送请求信息
$data = curl_exec($curl);
//关闭请求资源
curl_close($curl);
$arr = json_decode($data,true)['faces'];//将返回的数据转换为php数组
$content = "一共检测到".count($arr)."个人物\n";
foreach ($arr as $key => $value) {
$gender = $value['attributes']['gender']['value']=='Male'?'男':'女';
$content .= '第'.($key+1)."个的性别为:".$gender.";年龄为:".$value['attributes']['age']['value'].";颜值为:".$value['attributes']['beauty']['male_score']."\n\n";
}
echo $content;
这里能显示正常,但放微信上就不行了,估计问题是请求时间过长,超时请求,所以出现了如下问题
$data = [
'api_key'=>$key,
'api_secret'=>$secret,
'image_url'=>'http://590c1c9e.nat123.cc/2.jpg',//图片地址
'return_landmark'=>'1',
'return_attributes'=>'gender,age,emotion,beauty'//请求返回数据包含性别,年龄,情绪,颜值
];
$url = 'https://api-cn.faceplusplus.com/facepp/v3/detect';
//1,初始化
$curl = curl_init();
//设置参数
curl_setopt($curl, CURLOPT_URL,$url);
curl_setopt($curl, CURLOPT_HEADER,0);//不返回header头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//数据返回而不是输出
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);//使用ssl证书加密
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);//post提交
//发送请求信息
$data = curl_exec($curl);
//关闭请求资源
curl_close($curl);
$arr = json_decode($data,true)['faces'];//将返回的数据转换为php数组
foreach ($arr as $key => $value) {
$gender = $value['attributes']['gender']['value']=='Male'?'男':'女';
$content .= '第'.($key+1)."个的性别为:".$gender.";年龄为:".$value['attributes']['age']['value'].";颜值为:".$value['attributes']['beauty']['male_score']."\n\n";
$sendText = sprintf($txtModel,$toUserName,$fromUserName,$time,$msgType,$content);
echo $sendText;
浏览器直接打开都行,但是访问时间太长
尝试了很多次还是不行......放弃了,但正常情况上面的代码的data
数组的image_url
应该改成 $txtObj->PicUrl
获取用户上传的图片地址,根据图片分析信息并传递给用户