php 企业微信指令回调借款_企业微信外部联系人回调事件
企业微信外部联系人回调事件
说明:
1) 下列"外部联系人" 和 "客户联系" 其实都是一个意思,都是指顾客,但是由于企业微信开发文档中叫"外部联系人",管理后台叫"客户联系", 为方便操作,故本文名称跟企业微信保持一致
2) 下列两段代码实例,默认使用者已经有PHP-SDK, 原生代码案例可以自行前往git下载PHP-SDK(地址见官方文档),ThinkPHP5.*版本案例,可以参考本人下载资源中的PHP-SDK,或者根据官方提供的sdk自行修改命名空间; 由于时间问题,原生代码部分由TP5版本代码修改而成,仅供参考代码,暂未实测; ThinkPHP5.*版本代码亲测有效,有异议欢迎提出讨论
1.作用
企业成员 添加/删除外部联系人 时,可在企业后台接收添加/删除的外部人数据,及时更新企业后台数据
2.运行原理
1) 开发者验证回调事件url有效性,验证通过后,可在企业微信管理员后台,配置回调所需的3个参数: 回调事件url, Token , EncodingAESKey
2) 企业微信管理后台给相关企业成员配置"客户联系"权限
3) 当企业成员(需要配置客户联系操作权限) 添加/删除外部联系人时,企业微信服务器会向外部联系人回调事件url 推送一段加密字符串(xml格式) ,具体事件格式可参照开发文档, 而且务必保证正确处理数据,
3.开发者操作步骤
1) 管理后台配置外部联系人回调事件url地址,并验证该url有效性
A) 先调用调试工具,验证回调事件url有效性,具体参见:
![验证回调事件url的详情图片](https://img-blog.csdnimg.cn/20190221220329870.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2R1cmluZ25vbmU=,size_16,color_FFFFFF,t_70)
B) 除了A)操作,还需要在该url中,返回解密后的加密消息内容,首先两点;
a) 调用PHP-SDK中的XMLparse类中的VerifyUrl方法(Verify方法可验证回调事件url); PHP-SDK可下载本人下载资源中的SDK(此SDK根据ThinkPHP5.0进行了命名空间的封装),或者参考企业微信开发文档自行编写
b) **坑一**: 在回调事件中必须 return 企业微信调试工具发送的Get请求结果(ps:企业微信文档中说的是正确响应,经和其技术沟通,并亲测为使用return关键字即可,示例代码如下:
$params = $_GET;
$obj = new XMLparse();
$callbackRes = $obj->VerifyUrl($params);//调用SDK中的VerifyUrl方法,返回值为解密后的消息,即步骤A)图中的 "测试消息123"
return $callbackRes;// 相当于直接返回明文消息: return"测试消息123";
)
c) **坑二**: 验证回调事件url有效性时,即调用verifyUrl方法时,必须先urldecode('echoStr参数'),否则会抛出异常; 若使用原生代码示例,务必自行添加urldecode,若使用框架可自行输出参数查看;(本人使用ThinkPHP5.*框架,ThinkPHp5.*框架中做了urldecode的处理,可以不必开发者手动urldecode;)
2) url通过验证后,添加/删除外部联系人时,会想该url推送指定格式的xml数据(加密字符)
A) **坑三**: 接收xml数据时,确保接收的数据事原生的,最好使用 $params = file_get_contents('php://input');(ps: 本人就是因为在框架配置了htmlspecialchars(html标签过滤函数)这个函数将<>转义了,导致SDK中的DOMDocument类的loadXML方法, 无法读取正确的xml数据,抛出异常,记得将数据恢复成xml格式数据,若使用了htmlspecialchars,记得htmlspecialchars_decode一次)
B) **坑四**: 因为涉及的字符串长度过长(400~750个字节),使用var_dump,echo,print_r均无法正常输出字符内容,建议使用将字符写入文件中(使用函数fopen(),fwrite(),或者file_put_content())
C) 具体代码过程参见下列两个版本,以ThinkPHP5.*版本为准,如有异议,欢迎提出讨论
3) 详情参见企业微信api开发文档,
A)文档地址:
https://work.weixin.qq.com/api/doc#90000/90135/90664
B) 接口调试工具地址:
https://work.weixin.qq.com/api/devtools/devtool.php
3.注意:
1) 上述有提及四个坑点,请各位开发者多留意 (可结合下列示例代码理解)
2) 必须先登录企业管理后台(管理员身份),配置回调事件的url相关的参数,并给相关企业成员配置"客户联系"权限
4.PHP原生代码示例 (使用前提,需要先获取SDK)
class External {
protected $_weworkConfig = [
'corpId' => '',//企业ID
];
protected $_externalCallbackEvent = [//回调事件参数
'url'=> 'http://www.test.com/External/callbackEvent',
'token' => '',
'encodingAESKey' => ''
];
protected $_callbackObj; // 回调事件对象(外部联系人添加/删除)
protected $_callbackErrorMsgArr = [//企业微信(添加/删除外部联系人)回调事件错误码+错误信息
'0'=> 'success',
'-40001'=> '签名验证错误',
'-40002'=> 'xml解析失败',
'-40003'=> 'sha加密生成签名失败',
'-40004'=> 'encodingAesKey 非法',
'-40005'=> 'corpid 校验错误',
'-40006'=> 'aes 加密失败',
'-40007'=> 'aes 解密失败',
'-40008'=> '解密后得到的buffer非法',
'-40009'=> 'base64加密失败',
'-40010'=> 'base64解密失败',
'-40011'=> '生成xml失败',
];
public function __construct() {
# 回调事件对象
$this->_callbackObj = new \weworkapi\callback\WXBizMsgCrypt($this->_externalCallbackEvent['token'], $this->_externalCallbackEvent['encodingAESKey'], $this->_weworkConfig['corpId']); //企业应用回调, 消息加密/解密类WXBizMsgCrypt
}
/**
* 验证(添加/删除外部联系人)回调事件url有效性
*/
public function verifyUrl($data) {
$params = $_GET;
$params2 = $_POST;
$params = array_merge($params,$params2); // get数据+post数据
try {
if (empty($params['msg_signature'])) {
throw new \Exception('msg_signature不得为空');
}
if (empty($params['timestamp'])) {
throw new \Exception('timestamp不得为空');
}
if (empty($params['nonce'])) {
throw new \Exception('nonce不得为空');
}
if (empty($params['echostr'])) {
throw new \Exception('echostr不得为空');
}
$sReplyEchoStr = "";
$verifyRes = $this->_callbackObj->VerifyURL($data['msg_signature'], $data['timestamp'], $data['nonce'], urldecode($data['echostr']),$sReplyEchoStr); // 此处需要urldecode($data['echoStr'])
0 !== $verifyRes && exception('errCode: '.$verifyRes .', errMsg: '.$this->_callbackErrorMsgArr[$verifyRes]);
return $sReplyEchoStr;
} catch (\Exception $ex) {
return ['errCode'=>'0084','errMsg'=>$ex->getMessage()];
}
return ['errCode'=>'0','errMsg'=>'success','data'=>$verifyRes];
}
/**
* 测试企业微信的外部联系人事件回调
*/
public function callbackEvent() {
$params = $_GET; //get参数
$params['xmlContent'] = file_get_contents('php://input'); //post的xml数据
# 记录入参
$params['date'] = date('Y-m-d H:i:s');
$paramsStr = json_encode($params);
$fp = fopen('./externalCallbackEvent_params.log', 'w');
fwrite($fp, $paramsStr);
try {
//若回调url验证通过,处理回调的xml消息
if (!empty($params['xmlContent']) && empty($params['echostr'])) {
$dealRes = $this->dealCallbackEvent($params);
if ('success' !== $dealRes['desc']) {
throw new \Exception($dealRes['desc']);
}
# 记录调用结果
$callbakcRes = json_encode(['date'=>date('Y-m-d H:i:s'),'result'=>$dealRes['data']]);
$fp2 = fopen('./externalCallbackEvent_result.log', 'w');
fwrite($fp2, $callbakcRes);
return $dealRes['data'];
} else { //验证url有效性
$verifyRes = $this->verifyUrl($params);
if ('success' !== $verifyRes['desc']) {
throw new \Exception($verifyRes['desc']);
}
return $verifyRes['data']; // 解密后的消息内容(务必原文输出),否则报错
}
} catch (\Exception $ex) {
return ['errCode'=>'0083','errMsg'=>$ex->getMessage()];
}
}
/**
* 验证(添加/删除外部联系人)回调事件消息加密
*/
public function dealCallbackEvent($data) {
try {
# 解密
$decryptMsg = $this->decryptMsg($data);
$decryptMsgArr = $this->XMLString2Array($decryptMsg);
switch ($decryptMsgArr['ChangeType']) {
case 'add_external_contact': // 添加外部联系人回调事件
$dealRes = $this->addExternalCallbackEvent($decryptMsgArr);
break;
case 'del_external_contact': // 删除外部联系人回调事件
$dealRes = $this->delExternalCallbackEvent($decryptMsgArr);
break;
default:
throw new \Exception($type . '回调事件类型不合法');
break;
}
return $dealRes;
}catch (\Exception $ex) {
throw new \Exception($ex->getMessage());
}
}
/**
* 消息加密
*/
public function encryptMsg($data) {
try {
// $sReqTimeStamp = "1409659813";
// $sReqNonce = "1372623149";
// $sRespData = "13488318601234567890123456128";
$sReqTimeStamp = $data['timestamp']; //时间戳
$sReqNonce = $data['nonce']; //随机字符串
$content = $data['content']; //被加密的消息内容
// 需要发送的明文
$sRespData = "".$sReqNonce."1234567890123456".Config::get('WEWORK_AGENT_ID')."";
$sEncryptMsg = ""; //xml格式的密文
$errCode = $this->_callbackObj->EncryptMsg($sRespData, $sReqTimeStamp, $sReqNonce, $sEncryptMsg);
if (0 !== $errCode) {
throw new \Exceptionexception('errCode: '.$errCode .', errMsg: '.$this->_callbackErrorMsgArr[$errCode]);
}
return $sEncryptMsg;
} catch (\Exception $ex) {
throw new \Exception($ex->getMessage());
}
}
/**
* 消息解密
*/
public function decryptMsg($data) {
try {
// $sReqMsgSig = "477715d11cdb4164915debcba66cb864d751f3e6";
// $sReqTimeStamp = "1409659813";
// $sReqNonce = "1372623149";
// $sReqData = "";
$sReqMsgSig = $data['msg_signature'];
$sReqTimeStamp = $data['timestamp'];
$sReqNonce = $data['nonce'];
$sReqData = $data['xmlContent']; // post请求的密文数据
$decryptMsg = ""; // 解析之后的明文
$errCode = $this->_callbackObj->DecryptMsg($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData, $decryptMsg);
if (0 !== $errCode) {
throw new \Exception('errCode: '.$errCode .', errMsg: '.$_callbackErrorMsgArr[$errCode]);
}
return $decryptMsg;
} catch (\Exception $ex) {
throw new \Exception($ex->getMessage());
}
}
/**
* 提取xml数据中的指定参数
* (转换原理:xml字符串->xml对象->json对象->数组)
* @param string xml格式数据
* @return array array格式数据
*/
public function XMLString2Array($xmlStr) {
try {
//xml字符转换为xml对象
$xmlObj = simplexml_load_string($xmlStr,'SimpleXMLElement', LIBXML_NOCDATA);
$jsonObj = json_encode($xmlObj);
return json_decode($jsonObj,true);
} catch (\Exception $ex) {
throw new Exception($ex->getMessage());
}
}
/**
* 添加外部联系人回调处理
* 原理:
* 1) 获取外部联系人userid(异步处理时,userid从队列中获取)
* 2) 获取外部联系人详情
* 3) 将外部联系人插入数据库
* @param array
*/
public function addExternalCallbackEvent($data) {
}
/**
* 删除外部联系人回调处理
* 原理:
* 1) 获取外部联系人userid(异步处理时,userid从队列中获取)
* 2) 删除本地数据库中外部联系人记录
*/
public function delExternalCallbackEvent($data) {
}
}
5. ThinkPHP5.*实例(先获取PHP-SDK)
use \think\Validate;//ThinkPHP5.*的验证类
class External {
protected $_weworkConfig = [
'corpId' => '',//企业ID
];
protected $_externalCallbackEvent = [//回调事件参数
'url'=> 'http://www.test.com/External/callbackEvent',
'token' => '',
'encodingAESKey' => ''
];
protected $_callbackObj; // 回调事件对象(外部联系人添加/删除)
protected $_callbackErrorMsgArr = [//企业微信(添加/删除外部联系人)回调事件错误码+错误信息
'0'=> 'success',
'-40001'=> '签名验证错误',
'-40002'=> 'xml解析失败',
'-40003'=> 'sha加密生成签名失败',
'-40004'=> 'encodingAesKey 非法',
'-40005'=> 'corpid 校验错误',
'-40006'=> 'aes 加密失败',
'-40007'=> 'aes 解密失败',
'-40008'=> '解密后得到的buffer非法',
'-40009'=> 'base64加密失败',
'-40010'=> 'base64解密失败',
'-40011'=> '生成xml失败',
];
public function __construct() {
# 回调事件对象
$this->_callbackObj = new \weworkapi\callback\WXBizMsgCrypt($this->_externalCallbackEvent['token'], $this->_externalCallbackEvent['encodingAESKey'], $this->_weworkConfig['corpId']); //企业应用回调,消息加密/解密类WXBizMsgCrypt
}
/**
* 测试企业微信的外部联系人事件回调
*/
public function callbackEvent() {
$params = Request::instance()->param(); //get参数
$params['xmlContent'] = file_get_contents('php://input'); //post的xml数据
# 记录入参
$params['date'] = date('Y-m-d H:i:s');
$paramsStr = json_encode($params);
$fp = fopen('./externalCallbackEvent_params.log', 'w');
fwrite($fp, $paramsStr);
try {
//若回调url验证通过,处理回调的xml消息
if (!empty($params['xmlContent']) && empty($params['echostr'])) {
$dealRes = $this->dealCallbackEvent($params);
'success' !== $dealRes['desc'] && exception($dealRes['desc']);
# 记录调用结果
$callbakcRes = json_encode(['date'=>date('Y-m-d H:i:s'),'result'=>$dealRes['data']]);
$fp2 = fopen('./externalCallbackEvent_result.log', 'w');
fwrite($fp2, $callbakcRes);
return $dealRes['data'];
} else { //验证url有效性
$verifyRes = $this->verifyUrl($params);
'success' !== $verifyRes['desc'] && exception($verifyRes['desc']);
return $verifyRes['data']; // 解密后的消息内容(务必原文输出),否则报错
}
} catch (\Exception $ex) {
$this->result([],'0083',$ex->getMessage(),'json');
}
}
/**
* 验证(添加/删除外部联系人)回调事件消息加密
*/
public function dealCallbackEvent($data) {
try {
$rules = [
'msg_signature' => 'require',
'timestamp' => 'require',
'nonce' => 'require',
'xmlContent' => 'require', //接企业微信服务器发送的回调的xml消息内容
];
$validate = new Validate($rules);
!$validate->check($params) && exception($validate->getError());
// $params['xmlContent'] = htmlspecialchars_decode($params['xmlContent']); //若配置中使用了htmlspecialchars函数,转义了等符号
# 解密
$decryptMsg = $this->decryptMsg($data);
$decryptMsgArr = $this->XMLString2Array($decryptMsg);
switch ($decryptMsgArr['ChangeType']) {
case 'add_external_contact': // 添加外部联系人回调事件
$dealRes = $this->addExternalCallbackEvent($decryptMsgArr);
break;
case 'del_external_contact': // 删除外部联系人回调事件
$dealRes = $this->delExternalCallbackEvent($decryptMsgArr);
break;
default:
throw new \Exception($type . '回调事件类型不合法');
break;
}
return $dealRes;
}catch (\Exception $ex) {
throw new \Exception($ex->getMessage());
}
}
/**
* 验证URL有效性
* @param array 参数
* @return int 错误码,0-正常,否则出错
*/
public function verifyUrl($data) {
try {
$rules = [
'msg_signature' => 'require',
'timestamp' => 'require',
'nonce' => 'require',
'echostr' => 'require',
];
$validate = new Validate($rules);
!$validate->check($params) && exception($validate->getError());
$sReplyEchoStr = "";
$verifyRes = $this->_callbackObj->VerifyURL($data['msg_signature'], $data['timestamp'], $data['nonce'], $data['echostr'],$sReplyEchoStr); // 此处不需要urldecode($data['echoStr']),初步猜测是TP5的Request类已经做过了urldecode处理
0 !== $verifyRes && exception('errCode: '.$verifyRes .', errMsg: '.$this->_callbackErrorMsgArr[$verifyRes]);
return $sReplyEchoStr;
} catch (\Exception $ex) {
throw new \Exception($ex->getMessage());
}
}
/**
* 消息加密
*/
public function encryptMsg($data) {
try {
// $sReqTimeStamp = "1409659813";
// $sReqNonce = "1372623149";
// $sRespData = "13488318601234567890123456128";
$sReqTimeStamp = $data['timestamp']; //时间戳
$sReqNonce = $data['nonce']; //随机字符串
$content = $data['content']; //被加密的消息内容
// 需要发送的明文
$sRespData = "".$sReqNonce."1234567890123456".Config::get('WEWORK_AGENT_ID')."";
$sEncryptMsg = ""; //xml格式的密文
$errCode = $this->_callbackObj->EncryptMsg($sRespData, $sReqTimeStamp, $sReqNonce, $sEncryptMsg);
0 !== $errCode && exception('errCode: '.$errCode .', errMsg: '.$this->_callbackErrorMsgArr[$errCode]);
return $sEncryptMsg;
} catch (\Exception $ex) {
throw new \Exception($ex->getMessage());
}
}
/**
* 消息解密
*/
public function decryptMsg($data) {
try {
// $sReqMsgSig = "477715d11cdb4164915debcba66cb864d751f3e6";
// $sReqTimeStamp = "1409659813";
// $sReqNonce = "1372623149";
// $sReqData = "";
$sReqMsgSig = $data['msg_signature'];
$sReqTimeStamp = $data['timestamp'];
$sReqNonce = $data['nonce'];
$sReqData = $data['xmlContent']; // post请求的密文数据
$decryptMsg = ""; // 解析之后的明文
$errCode = $this->_callbackObj->DecryptMsg($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData, $decryptMsg);
0 !== $errCode && exception('errCode: '.$errCode .', errMsg: '.$this->_callbackErrorMsgArr[$errCode]);
return $decryptMsg;
} catch (\Exception $ex) {
throw new \Exception($ex->getMessage());
}
}
/**
* 提取xml数据中的指定参数
* (转换原理:xml字符串->xml对象->json对象->数组)
* @param string xml格式数据
* @return array array格式数据
*/
public function XMLString2Array($xmlStr) {
try {
//xml字符转换为xml对象
$xmlObj = simplexml_load_string($xmlStr,'SimpleXMLElement', LIBXML_NOCDATA);
$jsonObj = json_encode($xmlObj);
return json_decode($jsonObj,true);
} catch (\Exception $ex) {
throw new Exception($ex->getMessage());
}
}
/**
* 添加外部联系人回调处理
* 原理:
* 1) 获取外部联系人userid(异步处理时,userid从队列中获取)
* 2) 获取外部联系人详情
* 3) 将外部联系人插入数据库
* @param array
*/
public function addExternalCallbackEvent($data) {
}
/**
* 删除外部联系人回调处理
* 原理:
* 1) 获取外部联系人userid(异步处理时,userid从队列中获取)
* 2) 删除本地数据库中外部联系人记录
*/
public function delExternalCallbackEvent($data) {
}
}
php 企业微信指令回调借款_企业微信外部联系人回调事件相关推荐
- 企业微信SCRM系统部署_企业微信SCRM二次开发_企业微信SCRM系统独立版源码价格
企业微信SCRM系统部署_企业微信SCRM二次开发_企业微信SCRM系统独立版源码价格 点趣互动是企业微信系统的第三方应用提供厂商,用于管理员工企业微信的内一款系统软件.点趣互动企业微信scrm软件主 ...
- 企业微信加密消息体_企业微信机器人怎么发消息?企业微信机器人可以定时发消息吗?...
企业微信外部群自带群机器人功能,可以协助员工高效管理社群,帮助我们运营客户,那么企业微信机器人怎么用呢? 使用企业微信机器人,需要管理员先进入企业微信管理后台,在[客户联系]-[效率工具]-[自动回复 ...
- 企业微信的外部联系人回调处理技巧
一.关于设置接收事件服务器的信息 在企业微信管理后台的"客户联系-客户"页面,点开"API"小按钮,再点击"接收事件服务器"配置,进入配置页 ...
- PC企业微信hook接口,通过查询添加外部联系人教程
通过查询添加为联系人(外部联系人) 操作码 102008 请求说明 参数名 必选 类型 说明 type 是 int 类型 addType 是 string 类型14微信用户 1企业用户 user_id ...
- 企业信息化投入中咨询服务_企业信息化咨询中的问题与对策研究
龙源期刊网 http://www.qikan.com.cn 企业信息化咨询中的问题与对策研究 作者:宋 倩 张 燕 周 镭 来源:<商场现代化> 2008 年第 22 期 [ 摘要 ] 我 ...
- 企业信息化投入中咨询服务_企业信息化咨询问题研究
龙源期刊网 http://www.qikan.com.cn 企业信息化咨询问题研究 作者:姜妍 来源:<中国管理信息化> 2018 年第 17 期 [ 摘 要 ] 随着互联网络技术的发展和 ...
- 企业信息化投入中咨询服务_企业信息化咨询业务分析报告.doc
企业信息化咨询业务分析 目录 引言 企业信息化与管理咨询,是当前学术界.企业界谈论的一个焦点话题,也是被IT公司和管理咨询公司认为当前最富有商机的"交叉.边缘"领域之一.几年前,I ...
- Exchange企业实战技巧(15)启用向外部联系人发送邮件时的提醒
Exchange在系统默认的设置下,对于外部联系人的邮件传递是不出现任何提示信息.为避免将企业内部的重要邮件误发给外部的收件人.可以通过EMS控制台修改系统设置,来开启提醒功能,实现当用户使用OWA或 ...
- 斐波纳契回调线_斐波那契回调线(黄金分割线)神级操作-经典
斐波那契回调线(黄金分割线)神级操作-经典 斐波那契回调线,又称黄金分割线.在交易市场上,大多数的技术指标都具有滞后性,导致交易者在使用时不太好掌握.但是,斐波那契回调线具有提前性,能很好的帮助交易者 ...
最新文章
- MVP架构设计 初探
- 白话Elasticsearch67-不随意调节jvm和thread pool的原因jvm和服务器内存分配的最佳实践
- Android 程序适应多种多分辨率
- java线程知识梳理_Java多线程——多线程相关知识的逻辑关系梳理
- leetcode103. 二叉树的锯齿形层次遍历(bfs)
- python列表生成式内必须定义匿名函数_Python基础-----基础概念总结
- 用python numpy实现幻方
- 开发大型高负载类网站应用的几个要点
- H5_0020:判断安卓苹果平台
- POJ2513Colored Sticks
- xposed框架_把安卓手机开发到极致的框架xposed
- FMS3.5的安装使用
- 有效id和密码_ID和密码恢复
- androi的AT指令
- android xposed miui9,vxposed在小米-安卓9上闪退
- 使用evo工具评估ORB_SLAM2在TUM数据集上的运行轨迹
- 线性系统大作业——2.二阶倒立摆建模与控制系统设计(上)
- 企业级架构之LNMP
- 论文阅读:高炉炼铁工序入炉焦比预测的研究
- arm解锁 j-flash_J-Link固件烧录以及使用J-Flash向arm硬件板下载固件程序(示例代码)...
热门文章
- 网络工程师_记录的一些真题_2005上半年上午
- C语言,统计0~9出现次数。_只愿与一人十指紧扣_新浪博客
- 技术12期:如何设计rowkey使hbase更快更好用【大数据-全解析】
- OpenCV中BLOB特征提取与几何形状分类
- 深度学习最近发现详细分析报告
- 浙大版《C语言程序设计(第3版)》题目集 练习2-17 生成3的乘方表 (15 分)
- Android Studio第三十四期 - git企业级应用命令
- 修改tomcat6.0.25日志默认路径
- reactor与proactor模式
- atitit.mp4 视频文件多媒体格式结构详解