企业微信外部联系人回调事件

本文详细介绍了企业微信外部联系人回调事件的用途、运行机制和开发者实施步骤,提供PHP原生代码示例及ThinkPHP5.*框架下的应用实例,帮助开发者理解和利用企业微信的客户联系功能。

企业微信外部联系人回调事件

说明:

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)

<?php

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 = "<xml><ToUserName><![CDATA[mycreate]]></ToUserName><FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId><AgentID>128</AgentID></xml>";
            $sReqTimeStamp = $data['timestamp'];    //时间戳
            $sReqNonce = $data['nonce'];    //随机字符串
            $content = $data['content'];    //被加密的消息内容
            // 需要发送的明文
            $sRespData = "<xml><ToUserName><![CDATA[mycreate]]></ToUserName><FromUserName><![CDATA[".Config::get('wework.CORP_ID')."]]></FromUserName><CreateTime>".$sReqNonce."</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[".$content."]]></Content><MsgId>1234567890123456</MsgId><AgentID>".Config::get('WEWORK_AGENT_ID')."</AgentID></xml>";
            $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 = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";
            $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)

<?php
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 = "<xml><ToUserName><![CDATA[mycreate]]></ToUserName><FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId><AgentID>128</AgentID></xml>";
            $sReqTimeStamp = $data['timestamp'];    //时间戳
            $sReqNonce = $data['nonce'];    //随机字符串
            $content = $data['content'];    //被加密的消息内容
            // 需要发送的明文
            $sRespData = "<xml><ToUserName><![CDATA[mycreate]]></ToUserName><FromUserName><![CDATA[".Config::get('wework.CORP_ID')."]]></FromUserName><CreateTime>".$sReqNonce."</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[".$content."]]></Content><MsgId>1234567890123456</MsgId><AgentID>".Config::get('WEWORK_AGENT_ID')."</AgentID></xml>";
            $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 = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";
            $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) {
           
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值