需求:实时更新外部联系人信息
环境:php+mysql
一、引言:
1.思路
- 建立存储外部联系人相关字段的数据表,两个字段需要注意,一个是userid,一个是external_userid。前者是所添加的外部联系人上级,后者是该外部联系人的id,想要根据这个id来查找其详细信息。简单来说就是:如果我是客服,我要去添加客户,那么我使用的账号的这个id就是userid,我所添加的客户(们)的id就是external_userid。
- 配置回调地址
- 根据回调地址触发事件来及时更新数据表(增删改)
2.参考文档
- https://developer.work.weixin.qq.com/document/path/92129
- https://developer.work.weixin.qq.com/document/path/92114
- https://blog.csdn.net/weixin_39658900/article/details/113475089
3.所遇到的棘手问题(所谓的坑)
所谓的坑,还是老样子,思路不清楚,所以觉得很坑(腾讯官方文档)。
1.验证回调地址不通过。从以下几点找一下问题所在:首先在浏览器另起一个窗口访问一下填的地址,看看能不能访问的通先。然后检查一下验证的接口结束的地方有没有一个返回值,需要将入参中的$sEchoStr
返回。还是不行的话可以试一下更换一下token
和EncodingAESKey
。
具体错误码对应的原因如下:
'0'=> 'success',
'-40001'=> '签名验证错误',
'-40002'=> 'xml解析失败',
'-40003'=> 'sha加密生成签名失败',
'-40004'=> 'encodingAesKey 非法',
'-40005'=> 'corpid 校验错误',
'-40006'=> 'aes 加密失败',
'-40007'=> 'aes 解密失败',
'-40008'=> '解密后得到的buffer非法',
'-40009'=> 'base64加密失败',
'-40010'=> 'base64解密失败',
'-40011'=> '生成xml失败',
2.验证完了回调地址后,回调事情里获取不到相关的xml数据,只返回了msg_signature
、 timestamp
、nonce
。如果文档读的不仔细的话很容易出现这个问题(读这个文档就像破案一样,一个一个去找相关的线索,....此处省略粗口一万字)。
所谓的消息体不是从地址栏中传来的,是从body里传来的。这里完是使用的php脚本语言,采用的获取方法为:file_get_contents("php://input");
3.如何打印这个回调里的数据?最好的办法是在回调的接口方法里,把需要的数据写入到文件中:file_put_contents
。使用如var_dump
,print
这种不行,因为打印的内容长度过长。
4.回调事件不触发。这里需要检查一下入参中的企业应用corpId
是否正确。然后再检查一下外部联系人的一些权限问题,根据文档给的一个一个去点开检查一下就行了。
5.根据打印写入的文件中的数据进行测试解密,返回 -40002 错误码。我遇到这个的原因是在打印中复制过来的xml格式有问题,经过了
json_encode
后,斜杠前面会多一个反斜杠,把其中的反斜杠删掉就行了。
二、代码
验证回调地址
public function text1(){
$sVerifyMsgSig = $_GET['msg_signature'];
$sVerifyTimeStamp = $_GET['timestamp'];
$sVerifyNonce = $_GET['nonce'];
$sVerifyEchoStr = $_GET['echostr'];
// 需要返回的明文
$sEchoStr = "321";
$wxcpt = new \WXBizMsgCrypt('eHtnCm7SVxxx', 'igM5h5jsCZbcTTI5ixomyPNDt33Pn9N2xxxxxx', 'ww15abe89fedxxxxx');
$errCode = $wxcpt->VerifyURL($sVerifyMsgSig, $sVerifyTimeStamp, $sVerifyNonce, $sVerifyEchoStr, $sEchoStr);
if ($errCode == 0) {
// 验证URL成功,将sEchoStr返回
return $sEchoStr;
} else {
print("ERR: " . $errCode . "\n\n");
}
}
处理回调数据
//接收回调
public function text(){
date_default_timezone_set('PRC');
$sReqMsgSig = isset($_GET['msg_signature'])?$_GET['msg_signature']:'';
$sReqTimeStamp = isset($_GET['timestamp'])?$_GET['timestamp']:'';
$sReqNonce = isset($_GET['nonce'])?$_GET['nonce']:'';
$sReqData = file_get_contents("php://input");
$params = $_GET; //get参数
$params['xmlContent'] = $sReqData; //post的xml数据
$sMsg = '';
$wxcpt = new \WXBizMsgCrypt('eHtnCm7Sxxx', 'igM5h5jsCZbcTTI5ixomyPNDt33Pn9N2JcXwxxxx', 'ww15abe89fed8xxxx');
$errCode = $wxcpt->DecryptMsg($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData, $sMsg);
if ($errCode == 0) {
//存缓存记录
$params['errorCode'] = $errCode;
$params['errorMsg'] = $this->_callbackErrorMsgArr[$errCode];
$params['sMsg'] = json_decode(json_encode(simplexml_load_string($sMsg,"SimpleXMLElement", LIBXML_NOCDATA),JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT),true);
$this->putMark($params);
$msg_arr = json_decode(json_encode(simplexml_load_string($sMsg,"SimpleXMLElement", LIBXML_NOCDATA)),true);
//外部联系人的userid
$external_userid = isset($msg_arr['ExternalUserID'])?$msg_arr['ExternalUserID']:'';
//客服userid
$userid = isset($msg_arr['UserID'])?$msg_arr['UserID']:'';
//应用id
$to_user_name = isset($msg_arr['ToUserName'])?$msg_arr['ToUserName']:'';
//改变类型
$type = isset($msg_arr['ChangeType'])?$msg_arr['ChangeType']:'';
if(!empty($external_userid) && !empty($userid)){
//数据库操作
if($type == 'add_external_contact'){ //增加
$is_ex = $this->db_text->table('qy_wx_back')->where('userid',$userid)->where('external_userid',$external_userid)->find();
if($is_ex){ //已存在
$update = [
'is_del' => 0,
'update_time' => date('Y-m-d H:i:s',time())
];
$this->db_text->table('qy_wx_back')
->where('userid',$userid)
->where('external_userid',$external_userid)
->update($update);
//外部联系人详情处理
$rr = $this->updateCustomerInfo(1,$userid,$external_userid);
}else{
$insert = [
'error_code' => $errCode,
'error_msg' => $params['errorMsg'],
'to_user_name' => $to_user_name,
'add_time' => date('Y-m-d H:i:s',time()),
'update_time' => date('Y-m-d H:i:s',time()),
'type' => $type,
'userid' => $userid,
'external_userid' => $external_userid,
'is_del' => 0
];
$this->db_text->table('qy_wx_back')->insert($insert);
//外部联系人详情处理
$rr = $this->updateCustomerInfo(2,$userid,$external_userid);
}
}elseif($type == 'del_external_contact'){ //删除
$is_ex1 = $this->db_text->table('qy_wx_back')->where('userid',$userid)->where('external_userid',$external_userid)->find();
if($is_ex1){
$update = [
'is_del' => 1,
'update_time' => date('Y-m-d H:i:s',time())
];
$this->db_text->table('qy_wx_back')
->where('userid',$userid)
->where('external_userid',$external_userid)
->update($update);
}else{
$insert = [
'error_code' => $errCode,
'error_msg' => $params['errorMsg'],
'to_user_name' => $to_user_name,
'add_time' => date('Y-m-d H:i:s',time()),
'update_time' => date('Y-m-d H:i:s',time()),
'type' => $type,
'userid' => $userid,
'external_userid' => $external_userid,
'is_del' => 1
];
$this->db_text->table('qy_wx_back')->insert($insert);
}
//外部联系人详情处理
$rr = $this->updateCustomerInfo(1,$userid,$external_userid);
}elseif($type == 'edit_external_contact'){
$is_ex1 = $this->db_text->table('qy_wx_back')->where('userid',$userid)->where('external_userid',$external_userid)->find();
if($is_ex1){
$update = [
'is_del' => 2,
'update_time' => date('Y-m-d H:i:s',time())
];
$this->db_text->table('qy_wx_back')
->where('userid',$userid)
->where('external_userid',$external_userid)
->update($update);
}else{
$insert = [
'error_code' => $errCode,
'error_msg' => $params['errorMsg'],
'to_user_name' => $to_user_name,
'add_time' => date('Y-m-d H:i:s',time()),
'update_time' => date('Y-m-d H:i:s',time()),
'type' => $type,
'userid' => $userid,
'external_userid' => $external_userid,
'is_del' => 1
];
$this->db_text->table('qy_wx_back')->insert($insert);
}
//外部联系人详情处理
$rr = $this->updateCustomerInfo(3,$userid,$external_userid);
}
//标签处理
var_dump($msg_arr);die;
}
} else {
$params['errorCode'] = $errCode;
$params['errorMsg'] = $this->_callbackErrorMsgArr[$errCode];
$this->putMark($params);
$insert = [
'error_code' => $errCode,
'error_msg' => $params['errorMsg'],
'to_user_name' => '',
'add_time' => date('Y-m-d H:i:s',time()),
'update_time' => date('Y-m-d H:i:s',time()),
'type' => 'error',
'userid' => '',
'external_userid' => '',
'is_del' => 0
];
$this->db_text->table('qy_wx_back')->insert($insert);
print("ERR: " . $errCode . "\n\n");
//exit(-1);
}
}
public function putMark($params){
# 记录入参
$time = date('Y-m-d h:i:s',time());
$params['date'] = date('Y-m-d H:i:s');
$paramsStr = json_encode($params,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
$data = $time.$paramsStr;
$address = Extend_PATH.'externalCallbackEvent_params.log';
file_put_contents($address,$data."\r\n",FILE_APPEND);
}
后续还要进行标签更新的处理,到时候看看需不需要更新上来吧,估计坑少就不写了。