微信用户向你的微信公众号发送信息以后,微信的服务器会把用户发送的信息转发到你在微信公众平台的后台提供的地址上。你的应用程序会接收到微信发过来的信息,这些信息里包含信息是哪个微信用户发过来的,创建的时间是什么时候,信息是什么类型的(文本,图片,语音 ... ),信息的 id 号,还有信息的具体的内容。根据这些东西我们可以决定怎么样做出回应,比如返回一些帮助信息,最近发布的文章,用户最近的订单等等。回复给用户的信息可以是文本,图片,语音,视频,图文。
前言
这篇文章我们来看一下怎么样接收并且处理微信用户发送过来的信息,还有怎么样给用户回复信息。首先你可以参考《
使用 Laravel 框架:成为微信开发者》,使用 Laravel 框架创建一个与
微信沟通的接口。
接收文本类型的微信消息
你的微信公众帐号的订阅用户,向你发微信,微信的服务器会把用户发送给你的微信打包转发到你提供的地址上。其实就是使用 POST 方法去请求你的应用地址,请求里面会包含使用 XML 格式包装的信息。你的应用接收到这个信息以后,需要做出回应,微信服务器会等你一会儿(5秒),看你没搭理他,他就会断开连接,不过他又会重新再把信息发给你,还没搭理他,他会再试一次,一共会试三回。
信息格式
微信服务器发给你的是 XML 格式的数据,不同类型的信息这个 XML 的结构是不一样的,下面是一个普通的文本信息的格式:
<xml>
<ToUserName><![CDATA[53166188@qq.com]]></ToUserName>
<FromUserName><![CDATA[osbKLjtJPw...]]></FromUserName>
<CreateTime>1401495511</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[我叫王皓]]></Content>
<MsgId>1235567891123956</MsgId>
</xml>
上面这个 XML 文档里面有一些标签,不同的标签包装着不同的内容,比如
<Content>
,它里面的东西就是用户发送的微信的具体的内容。一般我们可以忽略掉标签里面的
![CDATA[...]]
,在这个奇怪的东西的里面,才是你想要的真正的内容。
文本类型的信息包含下面这几样东西:
- ToUserName - 你的公众平台微信帐号
- FromUserName - 微信用户的 ID
- CreateTime - 信息创建的时间
- MsgType - 信息的类型
- Content - 信息里面包含的具体内容
- MsgId - 信息的 ID
ToUserName
它表示信息发送到的那个微信帐号,如果是微信用户给你的公众平台发的信息,那么这个
ToUserName 就表示你的微信公众平台的帐号。
FromUserName
它表示消息是来自哪个微信用户,微信会用一种叫 OpenID 的东西来表示微信用户,这个 OpenID 看起来像这样:
osbKLjtJPwZzfMea7X7Q_q7tH_EU
就是一串很长的字符串,它表示的就是某个微信用户。我们的应用在收到信息以后,在给用户回复信息的时候,可以把
ToUserName 设置成接收到的信息里面的这个
FromUserName 里的值。
CreateTime
表示消息的创建的信息,也就是微信用户给你发这条信息那时候的时间。这个时间是用时间戳(Timestamp)的形式表示的,你会看到一串数字,它表示的是其实就是从 1970 年 1 月 1 号到现在这个时间的秒数。
MsgType
表示信息的类型。用户如果发送的是文本类型的内容,那么这个
MsgType 应该就是
text(文本)。
Content
在
Content 里面的东西就是用户发送的信息的具体的内容。在我们的应用里可以去分析一下这个
Content 里的内容,然后再决定怎么样去回复用户。比如你可以根据这个内容,从数据库里查询出一些东西来,再用文本或者图文的形式回复给用户。
MsgId
表示信息身份的 ID 号。在我们自己的应用里面,可以使用这个信息的 ID 号来确定处理的信息不是重复的。因为微信服务器向你发送信息的时候,如果你没有及时响应,它会重复试三次。
处理文本类型的微信消息
下面要做的就是让我们的应用去处理微信服务器发送过来的信息。首先可以使用 PHP 的代码获取到发送过来的 POST 请求里面的原始的内容,获取到的内容应该就是前面介绍过的一个特定结构的 XML 文档,我们需要解析一下这个 XML 文档,然后得到里面具体的内容。
获取原始内容
在 PHP 的程序里面接收到 POST 请求里的原始数据,可以访问
$HTTP_RAW_POST_DATA 这个全局变量,或者,也可以通过
php://input 得到。
$HTTP_RAW_POST_DATA
在微信公众平台的文档里提供的演示代码里,用到了这个方法。
$message = $GLOBALS['HTTP_RAW_POST_DATA'];
这样可以把接收到的 POST 请求里的原始的主体内容交给
$message 这个变量。不过使用这个方法可能需要设置一条 PHP 指令,也就是把
always_populate_raw_post_data 设置成
On 。不然这个变量可能不会包含原始的 POST 数据。我在测试的时候,没有开启这个选项,一样可以接收到微信服务器 POST 过来的数据。如果你不能正常接收到数据,可以去开启这个选项再试一下。打开 PHP 的配置文件
php.ini ,我用的是 CentOS 系统,这个配置文件的位置是在:
/etc/php.ini
打开以后,找到:
;always_populate_raw_post_data = On
去掉这行代码前面的分号,可以让它起作用:
always_populate_raw_post_data = On
修改完成以后,保存配置文件并重新启动 Web 服务器。
php://input
在 PHP 官方的文档里面,推荐接收 POST 原始数据的方法是用
php://input,使用它不需要去修改 PHP 的配置。这种方法不支持
enctype="multipart/form-data" 。
可以让它与
file_get_contents 函数放到一块儿用:
$message = file_get_contents(php://input);
上面这行代码也会把得到的 POST 请求的原始数据交给
$message 这个变量。
处理请求里的数据
用前面介绍的两个方法其中的一个,你应该可以成功的获取到微信发过来的数据。因为这个数据的格式是 XML,所以我们得去处理一下它,这样才能得到里面的具体的某项内容(发送人,信息类型,信息)。
使用
simplexml_load_string(),可以把 XML 数据转换成一个对象。你可以在本地的环境里面去试一下,新建一个 PHP 文档,把下面这些代码放到里面:
// 定义一个 xml
$message = <<<MESSAGE
<xml>
<ToUserName><![CDATA[53166188@qq.com]]></ToUserName>
<FromUserName><![CDATA[osbKLjtJPw...]]></FromUserName>
<CreateTime>1401495511</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[我叫王皓]]></Content>
<MsgId>1235567891123956</MsgId>
</xml>
MESSAGE;
// 把 xml 数据转换成 PHP 的对象
$message = simplexml_load_string($message, 'SimpleXMLElement', LIBXML_NOCDATA);
print_r($message);
在浏览器里打开这个这个 PHP 文档,查看一下这个文档的源代码,你应该会看到类似这样的结果:
SimpleXMLElement Object
(
[ToUserName] => 53166188@qq.com
[FromUserName] => osbKLjtJPw...
[CreateTime] => 1401495511
[MsgType] => text
[Content] => 我叫王皓
[MsgId] => 1235567891123956
)
使用
simplexml_load_string ,我们把一个 XML 结构的数据转换成了一个 PHP 对象,这样在代码里面,可以很容易得到对象的属性的值。比如,你想得到
FromUserName 这个属性的值,可以这样:
$message->FromUserName;
xml 扩展
你发现不能正常使用
simplexml_load_string ,可以去安装一下 PHP 的 xml 扩展:
yum install php55u-xml
上面的代码适用于 CentOS 服务器上,可以安装一个 php5.5 版本的 xml 扩展。
Laravel
现在我们已经知道了微信发过来的数据的格式,怎么样接收到这个数据,怎么样处理这个数据然后得到自己想要的内容。下面,我们可以把这些东西结合到一块儿,应用到 Laravel 框架里面。
处理 POST 请求
在之前的文章里,我们在 Laravel 框架里面创建了一个 Resource 类型的
控制器。在这个控制器里,处理 POST 请求到路由地址上的方法是
store() ,比如我们创建的控制器的
路由是
api/v1,这样,用 POST 请求到
api/v1 这个地址上,处理这个请求用到的就是
store() 。
在这个方法里, 可以接收到微信服务器发过来的数据。打开这个控制器,找到
store 这个方法,像下面这样去改造一下这个方法:
public function store()
{
$message = file_get_contents('php://input');
$message = simplexml_load_string($message, 'SimpleXMLElement', LIBXML_NOCDATA);
return $message->Content;
}
现在,如果有用 POST 的形式请求
api/v1 这个地址,会把请求里的原始数据处理成一个 PHP 的对象,然后再返回这个对象的内容。
测试
下面去验证一下 Laravel 能不能正常处理使用 POST 请求发过来的 XML 数据。可以使用 Chrome 浏览器,然后再安装一个
Postman 插件。在测试之前,先注释掉在
WeixinController 控制器里面应用的
过滤器。
- 打开 Chrome 浏览器的 Postman 插件。
- 选择 Normal 选项卡。
- 输入把请求发送到的地址,类型选择 POST。
- 选择请求带的数据。点击 raw ,格式选择 XML(text/html),然后把请求里带的数据粘贴到下面。
- 点击 Send 按钮。
- 点击下面的 Body 选项卡,可以查看服务器响应回来的内容。
回复用户
向用户回复信息,需要使用跟接收到的同样结构的 XML 数据。只不过,在回复的时候,我们需要把
ToUserName 设置成给你发信息的微信用户的 ID 。
在 Laravel 框架里面,可以去创建一个视图来包含这个要回复的 XML 数据的结构。先修改一下
WeixinController 这个控制器的
store 方法。
public function store()
{
$message = file_get_contents('php://input');
$message = simplexml_load_string($message, 'SimpleXMLElement', LIBXML_NOCDATA);
return View::make('weixin.index')->with('message', $message);
}
注意,这次返回的是一个视图。使用的是 Laravel 的
View::make 方法。在这个
make 方法里面的
weixin.index 就是我们要使用的视图文件,它表示这个视图是在 weixin 目录下面,名字是
index.php 或
index.blade.php 。Blade 是 Laravel 框架使用的模板引擎。
在
make 的方法的后面,又使用了一个
with 方法,把处理好的数据传递给视图,传递过去以后,这个数据的名字叫
message,要传递的数据是在
$message 这个变量里面,这里面的东西就是接收到微信发过来的数据,并且转换成的那个 PHP 对象。
再解释一下
store 这个方法做的事。首先得到微信发过来的 XML 数据(用户发的微信信息以及相关的内容),然后把这个 XML 数据处理成一个 PHP 对象,接着把请求带着处理好的数据交给
weixin 目录下面的
index.blade.php 这个视图去处理。
创建视图
下面,我们再去创建这个视图文件,Laravel 的视图文件是在
app/views 下面。在这个目录里先新建一个目录叫
weixin,然后在这个
weixin 目录的下面再新建一个 PHP 文件,叫
index.blade.php 。
再把下面这几行代码粘贴到这个文件里面:
<xml>
<ToUserName><![CDATA[{{ $message->FromUserName }}]]></ToUserName>
<FromUserName><![CDATA[{{ $message->ToUserName }}]]></FromUserName>
<CreateTime>{{ time() }}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[{{ $message->Content }}]]></Content>
</xml>
上面是微信要求的给用户回复文本信息的格式。在这里,你会看到像这样的东西:
{{ $message->FromUserName }}
在 Laravel 的 Blade 模板引擎里面,输出东西可以使用
{{ ... }} ,两组花括号,里面再加上要输出的东西。
$message->FromUserName 表示的就是之前给我们发微信的那个用户,在给这个用户回复信息的时候,就可以把
ToUserName 里面的东西设置成这个用户。
最终显示在用户微信上的内容是在
Content 标签里面的东西,在这里, 我用了一个
$message->Content ,它表示的是用户给我们发的信息的内容。你能想到这是什么样的结果,也就是,当用户向我们的微信公众号上发一条文本内容,我们会回复给他同样的内容:)
测试
可以使用 Postman 再测试一下:
确定应用会返回正确结构的 XML 数据以后, 我们就可以在公众平台帐户的后台,启用
开发模式 去试一下了。
功能 - 高级功能 - 开发模式,点击
开启。于是有了下面这样的对话 :)
扫描下面的二维码,订阅宁皓网的微信,可以测试一下上面的对话。嘿嘿。
总结
这篇文章的主要目的就是让您了解怎么样去处理微信发送过来的信息,怎么样去回复信息。实现的功能只是用户发过来什么就回复给他什么。但是你可以去做一些复杂的事情,根据用户发来的信息做出判断,再回应合适的信息。你可以创建多个视图,不同的视图里面包含特定的信息的格式。
微信 Laravel
评论
沙发......看到滚那个啥,雷暴了,哈哈
10 年 6 个月 以前
微信这一块什么时候也出个视频呀,怎么做微信的网站,怎么做接口,怎么收发信息,怎么使用微信平台的功能,这个现在热门呀
10 年 6 个月 以前
得出完 PHP 教程之后再回来看看吧。
10 年 6 个月 以前
PHP要到年底了吧,微信现在这样热门,老王你可以弄弄,这个挺有钱途,对我们大家,是个机会,做网站,现在市场成熟度高,大家的机会少呀。微信会的人本身就不多,我们大家有机会呀。呵呵。对了,你也可以弄个什么投票什么的,看看大家都想学些什么样的课程,民主些,也收集点信息,不是挺好的吗
10 年 6 个月 以前
皓哥,我也需要啊,现在微信开发势不可挡,这两篇博文很及时,建站同样有需求啊!!!
10 年 5 个月 以前
在 Laravel 里面或许可以用这个获取 post 数据
Request::instance()->getContent();
10 年 5 个月 以前