基于PHP实现微信客服欢迎语发送

背景:用户通过某客服链接进入客服会话页面,客服进行欢迎语的发送

技术栈:larvel+redis

本文章仅提供思路参考,详情查看官方文档

实现思路如下:

验证url:

实现微信客服正常使用首先需要在企微后台进行配置,如果要实现Api进行欢迎语发送时,就需要回调接口,该接口仅用一次配置成功后 该代码可注释 先将使用的方法进行封装一遍调用

该类为回调信息加解密 方便使用时调用 不理解的话可以参照官方文档一一对应即可
class WXBizMsgCrypt
{
    private $m_sToken;
    private $m_sEncodingAesKey;
    private $m_sReceiveId;

    /**
     * 构造函数
     * @param $token string 开发者设置的token
     * @param $encodingAesKey string 开发者设置的EncodingAESKey
     * @param $receiveId string, 不同应用场景传不同的id
     */
    public function __construct($token, $encodingAesKey, $receiveId)
    {
        $this->m_sToken = $token;
        $this->m_sEncodingAesKey = $encodingAesKey;
        $this->m_sReceiveId = $receiveId;
    }

    /*
   *验证URL
   *@param sMsgSignature: 签名串,对应URL参数的msg_signature
   *@param sTimeStamp: 时间戳,对应URL参数的timestamp
   *@param sNonce: 随机串,对应URL参数的nonce
   *@param sEchoStr: 随机串,对应URL参数的echostr
   *@param sReplyEchoStr: 解密之后的echostr,当return返回0时有效
   *@return:成功0,失败返回对应的错误码
   */
    public function VerifyURL($sMsgSignature, $sTimeStamp, $sNonce, $sEchoStr, &$sReplyEchoStr)
    {
        if (strlen($this->m_sEncodingAesKey) != 43) {
            return errorCode::$IllegalAesKey;
        }

        $pc = new Prpcrypt($this->m_sEncodingAesKey);
        //verify msg_signature
        $sha1 = new SHA1;
        $array = $sha1->getSHA1($this->m_sToken, $sTimeStamp, $sNonce, $sEchoStr);
        $ret = $array[0];

        if ($ret != 0) {
            return $ret;
        }

        $signature = $array[1];
        if ($signature != $sMsgSignature) {
            return errorCode::$ValidateSignatureError;
        }

        $result = $pc->decrypt($sEchoStr, $this->m_sReceiveId);
        if ($result[0] != 0) {
            return $result[0];
        }
        $sReplyEchoStr = $result[1];

        return errorCode::$OK;
    }

    /**
     * 检验消息的真实性,并且获取解密后的明文.
     * <ol>
     *    <li>利用收到的密文生成安全签名,进行签名验证</li>
     *    <li>若验证通过,则提取xml中的加密消息</li>
     *    <li>对消息进行解密</li>
     * </ol>
     *
     * @param $msgSignature string 签名串,对应URL参数的msg_signature
     * @param $timestamp string 时间戳 对应URL参数的timestamp
     * @param $nonce string 随机串,对应URL参数的nonce
     * @param $postData string 密文,对应POST请求的数据
     * @param &$msg string 解密后的原文,当return返回0时有效
     *
     * @return int 成功0,失败返回对应的错误码
     */
    public function DecryptMsg($sMsgSignature, $sTimeStamp = null, $sNonce, $sPostData, &$sMsg)
    {
        if (strlen($this->m_sEncodingAesKey) != 43) {
            return ErrorCode::$IllegalAesKey;
        }

        $pc = new Prpcrypt($this->m_sEncodingAesKey);

        //提取密文
        $xmlparse = new XMLParse;
        $array = $xmlparse->extract($sPostData);
        $ret = $array[0];

        if ($ret != 0) {
            return $ret;
        }

        if ($sTimeStamp == null) {
            $sTimeStamp = time();
        }

        $encrypt = $array[1];

        //验证安全签名
        $sha1 = new SHA1;
        $array = $sha1->getSHA1($this->m_sToken, $sTimeStamp, $sNonce, $encrypt);
        $ret = $array[0];

        if ($ret != 0) {
            return $ret;
        }

        $signature = $array[1];
        if ($signature != $sMsgSignature) {
            return errorCode::$ValidateSignatureError;
        }

        $result = $pc->decrypt($encrypt, $this->m_sReceiveId);
        if ($result[0] != 0) {
            return $result[0];
        }
        $sMsg = $result[1];

        return errorCode::$OK;
    }

}
用SHA1算法生成安全签名
  /**
     * 用SHA1算法生成安全签名
     * @param string $token token
     * @param string $timestamp 时间戳
     * @param string $nonce 随机字符串
     * @param string $encrypt 密文消息
     */
    public function getSHA1($token, $timestamp, $nonce, $encrypt_msg)
    {
        //排序
        try {
            $array = array($encrypt_msg, $token, $timestamp, $nonce);
            sort($array, SORT_STRING);
            $str = implode($array);
            return array(errorCode::$OK, sha1($str));
        } catch (\Exception $e) {
            print $e . "\n";
            return array(errorCode::$ComputeSignatureError, null);
        }
    }
XML解密
/**
     * 解密
     *
     * @param $encrypted
     * @param $receiveId
     * @return array
     */
    public function decrypt($encrypted, $receiveId)
    {
        try {
            //解密
            if (function_exists('openssl_decrypt')) {
                $decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $this->iv);
            } else {
                $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, base64_decode($encrypted), MCRYPT_MODE_CBC, $this->iv);
            }
        } catch (\Exception $e) {
            return array(errorCode::$DecryptAESError, null);
        }
        try {
            //删除PKCS#7填充
            $pkc_encoder = new PKCS7Encoder;
            $result = $pkc_encoder->decode($decrypted);
            if (strlen($result) < 16) {
                return array();
            }
            //拆分
            $content = substr($result, 16, strlen($result));
            $len_list = unpack('N', substr($content, 0, 4));
            $xml_len = $len_list[1];
            $xml_content = substr($content, 4, $xml_len);
            $from_receiveId = substr($content, $xml_len + 4);
        } catch (\Exception $e) {
            print $e;
            return array(errorCode::$IllegalBuffer, null);
        }
        if ($from_receiveId != $receiveId) {
            return array(errorCode::$ValidateCorpidError, null);
        }
        return array(0, $xml_content);
    }
}
书写验证接口 参数需要unclode需要使用$_Get 
 //获取会话信息参数
        $msg_signature = $_GET['msg_signature'];
        $timestamp = $_GET['timestamp'];
        $nonce = $_GET['nonce'];
        $echostr = $_GET['echostr'];
//        if(empty($msg_signature) || empty($timestamp) || empty($nonce) ||empty($echostr)){
//            return json_encode([
//                'code'=>"0001",
//                'msg'=>'回调参数为空!'
//            ]);
//        }
        //配置文件
        $corpid = \App\Extend\Qy\Pay\WechatApplet\Config::corp_id;
        $token = \App\Extend\Qy\Pay\WechatApplet\Config::corp_token;
        $EncodingAESKey = \App\Extend\Qy\Pay\WechatApplet\Config::EncodingAESKey;
        $wxcpt = new WXBizMsgCrypt($token, $EncodingAESKey, $corpid);
     // 验证url 有效性
        $sEchoStr = "";  // 需要返回的明文
        $errCode = $wxcpt->VerifyURL($msg_signature, $timestamp, $nonce, $echostr, $sEchoStr);
        Log::info("明文日志==>".$sEchoStr);
        if ($errCode != 0) {
            return json_encode([
                'code'=>$errCode,  // 返回错误码到errorCode 查看错误信息
                'msg'=>'明文返回失败!!'
            ]);
        }
当获取到xml回调信息后 解析密文在上边封装过调用即可  xml转数组
//xml 格式转换 数组
        $xml = simplexml_load_string($sMsg, 'SimpleXMLElement', LIBXML_NOCDATA);
仔细阅读文档会发现获取到回调后 需要对接读取接口 接收用户事件 对此事件不理解的可以 去了解下swoole  参数自行理解
  /**
     * @param $open_kfid
     * @param $token
     * @return false|string
     * 读取信息
     */
    public function sync_msg($cursor,$open_kfid,$token){
        //获取access_token
        $access_token = $this->getaccess_token($open_kfid);
        $url="https://qyapi.weixin.qq.com/cgi-bin/kf/sync_msg?access_token=".$access_token."&debug=1";
        $param = [
            "cursor"=>$cursor,
            "token" =>$token,
            "limit" =>1000,
            "voice_format"=>0,
            "open_kfid"=>$open_kfid
        ];
        $headers = [
            'Content-Length: '.strlen(json_encode($param)),
            'Content-Type: application/json;charset=UTF-8',
        ];
        $res = $this->POST($url,$headers,json_encode($param));
        Log::info("读取消息日志==>",[$res]);
        return $res;
    }
根据读取到的信息 可以进行发送欢迎语  具体看文档

这里简述一下思路 :

首次用户操作读取next_cursor  该值可为空,获取到后可以存入redis 方便下次调用;

首次用户触发读取接口时可以获取到welcome_code,可以根据该值进行欢迎语发送,但是该值会在微信存放48小时,再次期间还想发送信息的话需要注意 msgtype 事件类型

用户每次触发都会更改事件类型 48小时内再次触发不会出现code值所以我们需要获取用户userid进行信息发送

到此微信客服发送欢迎语的思路全部结束,如有问题看官方手册或私聊我进行讨论,该功能需要了解swoole的运行机制方便深入了解该功能
 
 

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值