前一段时间需要开发一个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消息接口的更多相关文章

  1. 如何在项目中引入MetaQ消息收发机制

    当需要异步发送和接收大量消息时,需要在Crystal项目中引入MetaQ消息收发机制. 关于MetaQ使用的官方例子可参考:https://github.com/killme2008/Metamorp ...

  2. JDK8在接口中引入的default

    default关键字介绍 default是在java8中引入的关键字,也可称为Virtual extension methods——虚拟扩展方法.是指,在接口内部包含了一些默认的方法实现(也就是接口中 ...

  3. facebook充值实时更新接口文档翻译 希望对做facebook充值的小伙伴有帮助

    Realtime Updates for Payments are an essential method by which you are informed of changes to orders ...

  4. 微信服务号模板消息接口新增"设置行业"和"添加模板"及细节优化

    微信服务号模板消息可以向用户发送重要的服务通知,如信用卡刷卡通知,商品购买成功通知等.昨日,微信团队发布公告称模板消息新增“设置行业”和“添加模板”接口及细节优化,详细变动如下 模板消息[业务通知]自 ...

  5. 微信公众平台消息接口API指南

    简介 微信公众平台消息接口为开发者提供了一种新的消息处理方式.微信公众平台消息接口为开发者提供与用户进行消息交互的能力.对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使 ...

  6. 通用权限管理系统接口文档V4.2 版本之消息接口介绍

    通用权限管理系统提供的消息接口可实现消息获取,消息发送,底层使用Redis对消息进行缓存,解决消息的并发请求对数据库的压力. 前端可以通过客户端轮询来获取最新消息,前端效果截图如下:

  7. 微信公众平台消息接口开发-封装weixin.class.php

    原文:微信公众平台消息接口开发-封装weixin.class.php 一.封装weixin.class.php 由于微信公众平台的通信使用的是特定格式的XML数据,每次接受和回复都要去做一大堆的数据处 ...

  8. 微信公众平台消息接口PHP版开发教程

    原文:微信公众平台消息接口PHP版开发教程  一.写好接口程序 在你的服务器上上传好一个接口程序文件,如http://www.yourdomain.com/weixin.php  内容如下: &l ...

  9. vue中Axios的封装和API接口的管理

    前端小白的声明: 这篇文章为转载:主要是为了方便自己查阅学习.如果对原博主造成侵犯,我会立即删除. 转载地址:点击查看 如图,面对一团糟代码的你~~~真的想说,What F~U~C~K!!! 回归正题 ...

随机推荐

  1. java+struts上传文件夹文件

    这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了: 上传文件实体类: 看得 ...

  2. 浅谈 Catalan number——卡特兰数

    一.定义: 卡特兰数是一组满足下面递推关系的数列: 二.变形: 首先,设h(n)为Catalan数的第n+1项,令h(0)=1,h(1)=1,Catalan数满足递推式: h(n)= h(0)*h(n ...

  3. (62)通信协议之一protobuf

     Protobuf协议特点分析 KingKa.吴永聪 1.protobuf是什么? protobuf(Google Protocol Buffers)是Google提供的一个具有高效的协议数据交换格式 ...

  4. 买SD卡和TF卡要买U3和A2协议的

    A3 最低平稳写入30M/s

  5. NOIP2018复赛游记

    Day -oo (这里是负无穷啦qwq) 为了NOIP2018,我已经准备了好久 暑假的封闭式训练,国庆后停掉了晚自习,距NOIP一周时更是停掉了全天的课...... 我像是一个圆,在近乎无限的空间里 ...

  6. vue 在移动端实现红包雨 (兼容性好)

    下面是代码:<template>    <div class="ser_home">        <ul class="red_packe ...

  7. SettingBar的点击事件拦截

    接下来我们再来看另外一个案例,正如上面界面上显示的两个条目,车辆选择和始发地点选择,他们都有一个共同的特点就是都有共同的标题,内容和右剪头按钮,这种情况下我们都会把它封装成一个组合的自定义View来显 ...

  8. material of DeepLearning

    下面这个链接是深度学习相关的资料,内含很多dl的链接资料: http://blog.csdn.net/augusdi/article/details/20238157 MIT Deep Learnin ...

  9. html上传文件

    不太懂Html 做备用 html的文件上传分两个 第一个是Html文件 浏览器加载用的 另一个是PHP文件 处理上传文件的 下面是Html文件 叫index.html <html> < ...

  10. 一、基础篇--1.1Java基础-自定义注解的场景及实现

    自定义注解使用场景: 类属性自动赋值,例如对上下文.传入参数等赋值 验证对象属性完整性,例如,对参数的校验 代替配置文件功能,像spring基于注解的配置 可以生成文档,例如java 最早提供的注解. ...