php中引入facebook的messenger消息接口
前一段时间需要开发一个messenger的消息接口,但是facebook的官方文档似是而非,而且由于在国内比较小众,之前也没有另外的人写过中文的开发教程,只好自己进行了一番研究并完成了一个demo,希望给后来的人能带来一点方便。
一.创建Facebook应用和主页
https://developers.facebook.com/docs/messenger-platform/guides/quick-start
直接按照官方文档的第一步去完成即可
二.设置webhook
这里的webhook实际上就是你的第三方服务器,这里facebook的主页类似于微信的公众号。其中webhook的callback url就是回调函数的地址。类似于微信的服务器验证方式,这里的webhook也需要返回给facebook服务器指定的信息。
在 webhook 网址中,添加身份验证代码。此代码应对应上述验证口令,并以验证请求中发送的 challenge 为响应。点击“新建主页订阅”窗口中的“验证并保存”,以便通过 GET 请求调用 Webhook
然后给了一个官方案例,返回信息
app.get('/webhook', function(req, res) {
if (req.query['hub.mode'] === 'subscribe' &&
req.query['hub.verify_token'] === <VERIFY_TOKEN>) {
console.log("Validating webhook");
res.status(200).send(req.query['hub.challenge']);
} else {
console.error("Failed validation. Make sure the validation tokens match.");
res.sendStatus(403);
}
});
我不是很熟悉node.js,发现get[‘hub.verify_token’]并不能拿到并返回验证的信息,这里贴出我的php的验证方式
private function setupWebhook()
{
if(isset($_REQUEST['hub_challenge']) && isset($_REQUEST['hub_verify_token']) && $this->getValidationToken()==$_REQUEST['hub_verify_token'])
{
echo $_REQUEST['hub_challenge'];
exit;
}
}
hub_verify_token就是你自己设定的token,需要验证每次get的token,然后echo出hub_challenge
三.获取主页访问口令并订阅主页
建议把所有配置信息放在单独的文件里面,方便调用和修改。生成的口令不会在此界面保存。每次选择此主页都会生成一个新的口令。但之前生成的任何口令仍然有效。
四.接收消息
完成订阅后,系统需要在 webhook 中侦听 POST 调用。所有回调都将向此 webhook 发出。
Messenger Platform 的所有回调都使用相同的结构。
{
"object":"page",
"entry":[
{
"id":"PAGE_ID",
"time":1458692752478,
"messaging":[
{
"sender":{
"id":"USER_ID"
},
"recipient":{
"id":"PAGE_ID"
},
...
}
]
}
]
}
纯文字信息的详细结构
{
"object":"page",
"entry":[
{
"id":"PAGE_ID",
"time":1458692752478,
"messaging":[
{
"sender":{
"id":"USER_ID"
},
"recipient":{
"id":"PAGE_ID"
},
"timestamp":1458692752478,
"message":{
"mid":"mid.1457764197618:41d102a3e1ae206a38",
"seq":73,
"text":"hello, world!",
"quick_reply": {
"payload": "DEVELOPER_DEFINED_PAYLOAD"
}
}
}
]
}
]
}
附上webhook的参考文档的地址
https://developers.facebook.com/docs/messenger-platform/webhook-reference
- 1
关于具体处理消息的过程,我贴上我的代码
入口文件
require_once 'config.php';
require_once 'FacebookBot.php';
$bot = new FacebookBot(FACEBOOK_VALIDATION_TOKEN, FACEBOOK_PAGE_ACCESS_TOKEN);
$bot->run();
$messages = $bot->getReceivedMessages();
foreach ($messages as $message)
{
$recipientId = $message->senderId;
$text=$message->text;
if($text)
{
$bot->sendTextMessage($recipientId, $text);
}
elseif($message->attachments)
{
$bot->sendTextMessage($recipientId, "Attachment received");
}
}
定义类的文件
<?php
require_once 'config.php';
class FacebookBot
{
private $_validationToken;
private $_pageAccessToken;
private $_receivedMessages;
public function __construct($validationToken, $pageAccessToken)
{
$this->_validationToken = $validationToken;
$this->_pageAccessToken = $pageAccessToken;
$this->setupWebhook();
}
public function getReceivedMessages()
{
$this->run();
return $this->_receivedMessages;
}
public function getPageAccessToken()
{
return $this->_pageAccessToken;
}
public function getValidationToken()
{
return $this->_validationToken;
}
private function setupWebhook()
{
if(isset($_REQUEST['hub_challenge']) && isset($_REQUEST['hub_verify_token']) && $this->getValidationToken()==$_REQUEST['hub_verify_token'])
{
echo $_REQUEST['hub_challenge'];
exit;
}
}
public function sendTextMessage($recipientId, $text)
{
$url = "https://graph.facebook.com/v2.6/me/messages?access_token=%s";
$url = sprintf($url, FACEBOOK_PAGE_ACCESS_TOKEN);
$recipient = new stdClass();
$recipient->id = $recipientId;
$message = new stdClass();
$message->text = $text;
$parameters = ['recipient' => $recipient, 'message' => $message];
$response = self::executePost($url, $parameters, true);
if($response)
{
$responseObject = json_decode($response);
return is_object($responseObject) && isset($responseObject->recipient_id) && isset($responseObject->message_id);
}
return false;
}
public function run()
{
$request = self::getJsonRequest();
//var_dump($request);
if(!$request) return;
$entries = isset($request->entry) ? $request->entry : null;
if(!$entries) return;
$messages = [];
foreach ($entries as $entry)
{
$messagingList = isset($entry->messaging) ? $entry->messaging : null;
if(!$messagingList) continue;
foreach ($messagingList as $messaging)
{
$message = new stdClass();
$message->entryId = isset($entry->id) ? $entry->id : null;
$message->senderId = isset($messaging->sender->id) ? $messaging->sender->id : null;
$message->recipientId = isset($messaging->recipient->id) ? $messaging->recipient->id : null;
$message->timestamp = isset($messaging->timestamp) ? $messaging->timestamp : null;
$message->messageId = isset($messaging->message->mid) ? $messaging->message->mid : null;
$message->sequenceNumber = isset($messaging->message->seq) ? $messaging->message->seq : null;
$message->text = isset($messaging->message->text) ? $messaging->message->text : null;
$message->attachments = isset($messaging->message->attachments) ? $messaging->message->attachments : null;
$messages[] = $message;
}
}
$this->_receivedMessages = $messages;
}
private static function getJsonRequest()
{
$content = file_get_contents("php://input",true);
$return=json_decode($content, false, 512, JSON_BIGINT_AS_STRING);
return $return;
}
private static function executePost($url, $parameters, $json = false)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if($json)
{
$data = json_encode($parameters);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: ' . strlen($data)));
}
else
{
curl_setopt($ch, CURLOPT_POST, count($parameters));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parameters));
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
我这里做测试,返回的就是复述发送者的信息
六.测试
接入第三方平台和自己开发的差别还是很大的,起码报错消息你是看不见的,所以光从messenger那里发消息给主页是不方便调试的。
我这次用了shell下的curl来进行测试,用主页访问口令向 https://graph.facebook.com/v2.6/me/messages?access_token= 发出 POST 请求。负载必须以如下所述的 JSON 格式提供:
curl -X POST -H "Content-Type: application/json" -d '{
"recipient":{
"id":"USER_ID"
},
"message":{
"text":"hello, world!"
}
}' "https://graph.facebook.com/v2.6/me/messages?access_token=PAGE_ACCESS_TOKEN"
windows和linux略有区别。windows下建议用git bash等基于linux的环境而不要用cmd,例如上面的post请求,在cmd下其引号会失效,必须手动进行转义
七.关于一些坑
首先是facebook会偶尔向你的绑定的回调地址get消息,如果8个小时之内没有正确的返回的话,它就会自动解绑,我前一天晚上绑定的url第二天早上自动失效了,发现没有消息返回之后调了半天,才发现了这个问题。
其次是post回messenger的时候用了curl,需要开启php的curl,linux下的安装和windows不太一样,装的时候不要装错了php的版本,否则是不能生效的。
最后是messenger的应用没有提交审核之前是只能开发者发消息才有作用~
messenger的开发文档不算友好,全文算是译文吧,有的地方感觉比较生硬,比如它说的接受消息和发送消息是以用户做主体的,和一般人的理解还有一点出入。
php中引入facebook的messenger消息接口的更多相关文章
- 如何在项目中引入MetaQ消息收发机制
当需要异步发送和接收大量消息时,需要在Crystal项目中引入MetaQ消息收发机制. 关于MetaQ使用的官方例子可参考:https://github.com/killme2008/Metamorp ...
- JDK8在接口中引入的default
default关键字介绍 default是在java8中引入的关键字,也可称为Virtual extension methods——虚拟扩展方法.是指,在接口内部包含了一些默认的方法实现(也就是接口中 ...
- facebook充值实时更新接口文档翻译 希望对做facebook充值的小伙伴有帮助
Realtime Updates for Payments are an essential method by which you are informed of changes to orders ...
- 微信服务号模板消息接口新增"设置行业"和"添加模板"及细节优化
微信服务号模板消息可以向用户发送重要的服务通知,如信用卡刷卡通知,商品购买成功通知等.昨日,微信团队发布公告称模板消息新增“设置行业”和“添加模板”接口及细节优化,详细变动如下 模板消息[业务通知]自 ...
- 微信公众平台消息接口API指南
简介 微信公众平台消息接口为开发者提供了一种新的消息处理方式.微信公众平台消息接口为开发者提供与用户进行消息交互的能力.对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使 ...
- 通用权限管理系统接口文档V4.2 版本之消息接口介绍
通用权限管理系统提供的消息接口可实现消息获取,消息发送,底层使用Redis对消息进行缓存,解决消息的并发请求对数据库的压力. 前端可以通过客户端轮询来获取最新消息,前端效果截图如下:
- 微信公众平台消息接口开发-封装weixin.class.php
原文:微信公众平台消息接口开发-封装weixin.class.php 一.封装weixin.class.php 由于微信公众平台的通信使用的是特定格式的XML数据,每次接受和回复都要去做一大堆的数据处 ...
- 微信公众平台消息接口PHP版开发教程
原文:微信公众平台消息接口PHP版开发教程 一.写好接口程序 在你的服务器上上传好一个接口程序文件,如http://www.yourdomain.com/weixin.php 内容如下: &l ...
- vue中Axios的封装和API接口的管理
前端小白的声明: 这篇文章为转载:主要是为了方便自己查阅学习.如果对原博主造成侵犯,我会立即删除. 转载地址:点击查看 如图,面对一团糟代码的你~~~真的想说,What F~U~C~K!!! 回归正题 ...
随机推荐
- PCL智能指针疑云 <一>
背景: 最近写了一个包,使用ndt算法拼接点云,构建三维壁面环境的点云地图. 设计一个lidar类,表征激光雷达.可以获取点云数据并存储到容器 std::vector<PointCloudPtr ...
- mysql增删改查相关操作
mysql增删改查相关操作 以前用mysql用的少,对于数据库相关的操作不熟悉,现在开始要接触数据库了,记录一下相关的基础操作吧. 1.数据库的授权操作 # mysql -u root -p Ente ...
- Egret Tween
最近开始接触Egret,其实也就是为了写一些小的特效 1.egret.Tween.get() ,激活一个对象,对其添加 Tween 动画 2.to() ,将指定对象的属性修改为指定值 egret.Tw ...
- [BZOJ1902]:[NOIP2004]虫食算(搜索)
题目传送门 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母. 来看一个简单的例子: 43#98650#45+8468#6633=444455069 ...
- 几种常见的CSS布局
本文概要 本文将介绍如下几种常见的布局: 其中实现三栏布局有多种方式,本文着重介绍圣杯布局和双飞翼布局.另外几种可以猛戳实现三栏布局的几种方法 一.单列布局 常见的单列布局有两种: header,co ...
- java中的过滤器 --Filter
package filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.Filter ...
- 微信小程序 API 路由
路由:由于页面的跳转: wx.switchTab() 跳转到 tabBar 页面,并关闭掉其他所有非 tabBar 页面: 参数:为对象, 对象的属性: url:需要跳转的 tabBar 的页面路径( ...
- 方法一破解:Excel工作表保护密码
在excel2016中实测验证过有效 在Excel中,为了保护自已的工作表不被修改,我们可以添加保护密码. 操作步骤: 1.把Excel文件的扩展名xlsx修改为Rar.瞬间Excel文件变成了压缩包 ...
- oracle ogg--ogg搭建过程中遇到的错误及处理
1 PRVF-0002 : Could not retrieve local nodename---# Begin Stacktrace #---------------------------ID: ...
- tomcat 404 The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
1.原因 tomcat没有找到项目,因为是用eclipse启动的,不是在tomcat的目录下启动,所以我们需要在eclipse下配置启动目录,好让tomcat找到项目. 2.解决 用本地安装的tomc ...