思路
1.点击应用的菜单-在线客服-触发事件
$result1 = $this->receiveEvent($postObj);
2.分配客服 - 使用缓存memcache进行存储分配客服的信息(项目部署在sae,所以在sae上面开启memcache即可)
$mmc = memcache_init(); //初始化缓存
memcache_set($mmc, "service", '{"from":"'.$from.'","to":"'.$to.'"}'); //分配的信息
3.发送信息接入客服和用户
$this->send_custom_msg($from, "text", "正在为您接入客服,请稍候..");
4.断开连接,结束在线客服模式
memcache_delete($mmc, "service");
回调模式
对企业号进行开发的必要条件,就是开启回调模式。
开启回调
index.php
/*
------------验证回调URL---------------
*企业开启回调模式时,企业号会向验证url发送一个get请求
假设点击验证时,企业收到类似请求:
* GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3×tamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D
* HTTP/1.1 Host: qy.weixin.qq.com
接收到该请求时,企业应
1.解析出Get请求的参数,包括消息体签名(msg_signature),时间戳(timestamp),随机数字串(nonce)以及公众平台推送过来的随机加密字符串(echostr),
这一步注意作URL解码。
2.验证消息体签名的正确性
3. 解密出echostr原文,将原文当作Get请求的response,返回给公众平台
第2,3步可以用公众平台提供的库函数VerifyURL来实现。
*/
<?php
include_once "inc/WXBizMsgCrypt.php"; //企业微信接口可下载此文件 ①
include_once "information.php"; //此为在线客服功能方法类文件
include_once "constant.php"; //静态参数类
//如下参数静态定义在constant.php,其值与企业微信相应值对应
$encodingAesKey= Constant::$EncodingAesKey;
$token = Constant::$Token;
$corpId = Constant::$CorpId;
$sVMsgSig = $_GET['msg_signature']; //消息体签名
$sVTimeStamp = $_GET['timestamp']; //时间戳
$sVNonce = $_GET['nonce']; //随机字符串
$sVEchoStr = $_GET['echostr']; //随机加密字符串
$wxcpt = new WXBizMsgCrypt($token, $encodingAesKey, $corpId);
if($sVEchoStr){
$sEchoStr = "";
$errCode = $wxcpt->VerifyURL($sVMsgSig, $sVTimeStamp, $sVNonce, $sVEchoStr, $sEchoStr);
if ($errCode == 0) {
echo $sEchoStr;
} else {
print($errCode . "\n\n");
}
exit;
}else{
$wechatObj = new information(); //在线客服类
$wechatObj->responseMsg();
}
①代码地址:WXBizMsgCrypt.php
菜单
$menu = '{
"button":[{
"name":"点我其他",
"sub_button":[
{
"type":"clik",
"name":"其他",
"key":"qt"
},
{
"type":"click",
"name":"在线客服",
"key":"qt_kf"
}]
}]
}';
$corpsecret = Constant::$Corpsecret;
$corpId = Constant::$CorpId;
//获取token的url
$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$corpId&corpsecret=$corpsecret";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
$jsoninfo = json_decode($output, true);
$access_token = $jsoninfo["access_token"];
$agentid = Constant::$Agentid;
//创建菜单的url
$url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token=$access_token&agentid=$agentid";
$result = https_request($url, $jsonmenu);
function https_request($url,$data = null){
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
在线客服
information.php
<?php
include_once "inc/WXBizMsgCrypt.php";
include_once "constant.php";
/**
------------在线客服---------------
1、用户点击菜单在线客服,判断memcache状态
2、若存在,则发送等待信息至用户
3、若不存在,则初始化memcache,并发送相应连接客服信息至用户以及客服
4、客服发信息,则至用户;用户发信息,则至客服
5、直至客服点击菜单在线客服,则结束连接
注:此memcache需在sae上开启的memcache,否则无效
*/
class information
{
public function responseMsg()
{
$encodingAesKey = Constant::$EncodingAesKey;
$token = Constant::$Token;
$corpId = Constant::$CorpId;
$agentId = Constant::$Agentid;
$wxcpt = new WXBizMsgCrypt($token, $encodingAesKey, $corpId);
$sReqMsgSig = $_GET["msg_signature"];
$sReqTimeStamp = $_GET["timestamp"];
$sReqNonce =$_GET["nonce"];
$sReqData = file_get_contents('php://input');
$sMsg = ""; // 解析之后的明文
$errCode = $wxcpt->DecryptMsg($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData, $sMsg);
if ($errCode == 0) {
$postStr=$sMsg;
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$result1= "";
$RX_TYPE = trim($postObj->MsgType);
switch($RX_TYPE)
{
case "text": //文本消息
$result1 = $this->receiveText($postObj);
break;
case "image": //图文消息
$result1 = $this->receiveImage($postObj);
break;
case "event": //事件 触发在线客服连接,以及断开在线客服连接
$result1 = $this->receiveEvent($postObj);
break;
default:
$result1 = "unknow msg type:".$RX_TYPE;
break;
}
//加密输出
$sEncryptMsg = "";
//xml格式的密文
$errCode = $wxcpt->EncryptMsg($result1, $sReqTimeStamp, $sReqNonce, $sEncryptMsg);
if ($errCode == 0) {
echo $sEncryptMsg;
} else {
print("ERR: " . $errCode . "\n\n");
}
} else {
print("ERR: " . $errCode . "\n\n");
}
}
}
客服用户对话连接
private function receiveEvent($object)
{
$content = "";
switch($object->Event){
case "click":
switch($object->EventKey)
{
case "qt_kf":
$mmc = memcache_init();
//客服单击,结束对话
if($object->FromUserName== Constant::$Staff1 ){
$service = memcache_get($mmc,"service");
$relation = json_decode($service, true);
$from = $relation['to'];
$to = $relation['from'];
$this->send_custom_msg($from, "text", "你已结束本次对话!");
$this->send_custom_msg($to, "text", "感谢您的咨询。期待下次再会!");
memcache_delete($mmc, "service"); //删除memcache
}
else{ //用户单机,开始对话
$service = memcache_get($mmc,"service");
$relation = json_decode($service, true);
if($relation['from'] == null)
{
$from =strval($object->FromUserName);
$to = Constant::$Staff1;
memcache_set($mmc, "service", '{"from":"'.$from.'","to":"'.$to.'"}');
$this->send_custom_msg($from, "text", "正在为您接入客服,请稍候..");
$this->send_custom_msg($to, "text", "有用户请求接入,请响应!");
}else { //如有memcache,则提示占线
$from =strval($object->FromUserName);
if($from != $relation['from']){
$this->send_custom_msg($from, "text", "在线客服占线,请稍后再试。");
}
}
}
return;
default:
$content = "菜单默认回复";
break;
}
break;
}
if(is_array($content)){
$result = $this->transmitNews($object,$content);
}else{
$result = $this->transmitText($object,$content);
}
return $result;
}
接收文本信息
/**
用户和客服之间的文本交互,若是在线客服功能已连接,则通过此方法,进行信息传递
*/
private function receiveText($object) //文本消息
{
$keyword = trim($object->Content);
$mmc = memcache_init(); //初始化memcache
$service = memcache_get($mmc, "service");
if($service){ //当前有人工客服对话
$relation = json_decode($service, true);
//用户处在人工客服交互中
if(in_array($object->FromUserName, $relation))
{
$to = ($relation['from'] == strval($object->FromUserName))?$relation['to']:$relation['from'];
$this->send_custom_msg($to, "text", $keyword);
return;
}
$content = "";
if(is_array($content)){
$result = $this->transmitNews($object, $content);
}else{
$result = $this->transmitText($object, $content);
}
}
return $result;
}
发送文本信息
public function send_custom_msg($from, $type, $content)
{
$access_token = $this->getAccessToken(); //获取access_token
//发送信息的url
$sendmsg_url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$access_token";
//信息格式
$data ='{ "touser": "'.$from.'",
"toparty": "",
"totag": "",
"msgtype": "text",
"agentid": 0,
"text": { "content": "'.$content.'" },
"safe": "0" }';
return $this->mn_post($sendmsg_url,$data);
}
//获取access_token
private function getAccessToken(){
$corpid = Constant::$CorpId;
$corpsecret = Constant::$Corpsecret;
$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$corpid&corpsecret=$corpsecret";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
$jsoninfo = json_decode($output, true);
$access_token = $jsoninfo["access_token"];
return $access_token;
}
function mn_post($url,$data){ // 模拟提交数据函数
$curl = curl_init(); // 启动一个CURL会话
curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检测
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Expect:')); //解决数据包大不能提交
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
curl_setopt($curl, CURLOPT_COOKIEFILE, $GLOBALS['cookie_file']); // 读取上面所储存的Cookie信息
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循
curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
$tmpInfo = curl_exec($curl); // 执行操作
if (curl_errno($curl)) {
echo 'Errno'.curl_error($curl);
}
curl_close($curl); // 关键CURL会话
return $tmpInfo; // 返回数据
}
多客服
如需开发多客服功能,则参考微信企业号多客服功能开发