PHP接入微信公众号(二)- 如何实现“价值一个亿的AI”代码
PHP接入微信公众号
前言:对公众号进行基本的连接后,我们就可以开始对公众号进行开发了。这其中,就有很多的事可以做了
-
还没有了解如何接入微信公众号的同学们
,请查看上一遍博客PHP接入微信公众号(一) - 微信公众号文档地址 微信公众号文档
- 源码仓库地址(仅做学习开源)微信接口源码
获取access_token
- 说明:access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token
- 请求方式:HTTP GET
- 请求域名:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
-
参数说明:
|:–|:–|:–|
|参数|是否必须|说明|
|grant_type|是|获取access_token填写client_credential(固定即可
)|
|appid|是|第三方用户唯一凭证,公众号后台有|
|secret|是|第三方用户唯一凭证**,即appsecret| - 正常返回数据:{“access_token”:“ACCESS_TOKEN”,“expires_in”:7200}
- 错误返回数据:{“errcode”:40013,“errmsg”:“invalid appid”}
- 请求代码实现
/**
* 获取微信access_token
* 正确返回 {"access_token":"ACCESS_TOKEN","expires_in":7200}
* 错误返回 {"errcode":40013,"errmsg":"invalid appid"}
* @param $appID
* @param $secret
* @return mixed
* @throws Exception
*/
public function getAccessToken($appID, $secret)
{
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appID}&secret={$secret}";
Yii::warning("call wei_xin access_token", CATEGORIES_INFO);
try {
$response = (new Client())->get($url);
} catch (RequestException $e) {
Yii::error("cannot request to api.weixin.qq.com!", CATEGORIES_ERROR);
return false;
}
$content = $response->getBody()->getContents();
Yii::warning('request content:'.$content, CATEGORIES_WARN);
$jsonContent = \GuzzleHttp\json_decode($content, true);
if (isset($jsonContent['errcode'])) {
Yii::error("get access token error;msg:".$content, CATEGORIES_ERROR);
return false;
}
return $jsonContent;
}
- 业务逻辑:微信文档建议
统一获取access_token
,所以建议在请求完成后存于session或者其他缓存中,失效后再重新获取。
接收消息
- 说明:用户在公众号下留言后并已启用了服务器配置,那么微信公众平台就会将消息发送到所配置的服务器地址。如果不能正确处理并回复消息,用户将会收到公众号服务异常的消息。
-
消息类型:消息分加密和非加密,对于重要的消息可以采用加密模式。(但微信文档中的
加解密已经过时
,无法支持PHP7以上的版本,目前我还在调试中。。),非加密消息直接处理XML消息即可。由于加密模式示例代码已过时,这里暂时就只提非加密模式了 - 消息发送方式:HTTP POST 传送XML数据包
- 数据包格式:
<xml>
<ToUserName>< ![CDATA[toUser] ]></ToUserName>
<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType>< ![CDATA[text] ]></MsgType>
<Content>< ![CDATA[this is a test] ]></Content>
<MsgId>1234567890123456</MsgId>
</xml>
- 代码处理数据包:
//处理xml结构,转换为数组
libxml_disable_entity_loader(true);
$content = json_decode(json_encode(simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
- 消息返回:在接收到消息后,
你可以立刻回复消息
(需要在5秒内应答)。回复消息时请使用消息模板一样返回。若不想返回,或者无法立刻返回,可以先返回空字符串,然后再调用消息发送接口。
“价值一个亿的AI代码”
- 说明:大家应该有在朋友圈或其他论坛看到有一张玩笑的图,说是价值一个亿的AI代码,所以我在这里,也接着微信公众号的项目,试验了一下,仅供娱乐,哈哈_
-
主体:通过逻辑代码,做字符串切割,完成
伪智能
客服。 -
截图:
- 备注:详情请看源码
核心代码
public function actionIndex()
{
$params = (new Request())->get();
Yii::warning('wei_xin get_params:'.json_encode($params), CATEGORIES_WARN);
if (isset($params['echostr'])) {//公众号接入时的验证
Yii::warning('update config', CATEGORIES_WARN);
echo $this->valid($params);
exit();
}
/*
* 接收消息并处理
* 处理失败后直接回复空字符串或者content为success
*/
$data = file_get_contents("php://input");
Yii::warning('wei_xin post_data:'.$data, CATEGORIES_WARN);
if (empty($data)) {
echo '';
exit();
}
//处理xml结构
libxml_disable_entity_loader(true);
$content = json_decode(json_encode(simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
//样本记录数据库
$recordModel = new WxRecordModel();
$keys = getArrayKey($recordModel->typeMap, $this->getRealValue($content['MsgType']));//查找类型对应键值
$data = [
'msg_id' => $this->getRealValue($content['MsgId']),
'msg_type' => $keys[0],
'to_user_name' => $this->getRealValue($content['ToUserName']),
'from_user_name' => $this->getRealValue($content['FromUserName']),
'content' => $this->getRealValue($content['Content']),
];
if (!$recordModel->insert($data)) {
Yii::error('wx insert record failed;data:'.json_encode($data),CATEGORIES_ERROR);
}
//消息解密 - 采用明文模式则不需要解密
/*
$msg = '';
$pc = new WxBizMsgCrypt(WX_TOKEN, WX_AES_KEY, WX_APP_ID);
$rs = $pc->decryptMsg($params['msg_signature'], $params['timestamp'], $params['nonce'], $data, $msg);
Yii::warning('接收消息解密内容:'.$msg, CATEGORIES_WARN);
if ($rs != 0) {
echo '';
exit();
} else {
$replyMsg = $this->dealMsg($msg);
}
*/
//消息类型处理
switch ($keys[0]) {
case $recordModel::MSG_TYPE_TEXT :
$content['Content'] = $this->dealTextMsg($content['Content']);
break;
default :
$content['Content'] = '小主对不起,暂时无法支持该类消息哦';
break;
}
$resMsg = $this->transferMsg($content, $content['Content']);//组合xml消息体
Yii::warning('回复消息xml:'.$resMsg, CATEGORIES_WARN);
//消息加密
/*
$time = time();
$nonce = '123456';
$pc->encryptMsg($replyMsg, $time, $nonce, $resMsg);
$encryptResMsg = "<xml><Encrypt><![CDATA[{$resMsg}]></Encrypt><TimeStamp>{$time}</TimeStamp><Nonce>{$nonce}</Nonce></xml>";
Yii::warning('加密后的回复消息xml:'.$encryptResMsg, CATEGORIES_WARN);
*/
echo $resMsg;
}
/**
* 接入验证
* signature 微信加密签名
* timestamp 时间戳
* nonce 随机数
* echostr 随机字符串
* @param array $params
* @return string
*/
public function valid(array $params)
{
if (
empty($params)
|| empty($params['timestamp'])
|| empty($params['nonce'])
|| empty($params['signature'])
|| empty(['echostr'])
) {
return '';
}
$tmpArray = array(WX_TOKEN, $params['timestamp'], $params['nonce']);
sort($tmpArray, SORT_STRING);
$tmpStr = implode($tmpArray);
$tmpStr = sha1($tmpStr);
if ($params['signature'] == $tmpStr) {
return $params['echostr'];//输出随机字符串
}
return '';
}
/**
* 生成回复消息的xml格式
* @param array $data
* @param string $msg
* @return bool
*/
public function transferMsg($data = array(), $msg = '')
{
$format = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$result = sprintf($format, $data['FromUserName'], $data['ToUserName'], time(), $msg);
return $result;
}
/**
* 去除微信的外包层
* @param $str
* @return mixed
*/
public function getRealValue($str)
{
if (strpos($str, '<![CDATA[') !== false) {
$str = substr($str, 9);
}
if (strpos($str, ']]>') !== false) {
$str = substr($str, 0, -3);
}
return $str;
}
/**
* 价值一个亿的AI核心代码
* @param string $msg
* @return mixed|string
*/
public function dealTextMsg($msg = '')
{
$msg = $this->getRealValue($msg);
/*
* 规则替换
*/
$keyWords = (new WxRulesModel())->getRuleKeys(['status' => WxRulesModel::STATUS_OPEN, 'type' => WxRulesModel::TYPE_KEY_WORD]);
$illegalWord = (new WxRulesModel())->getRuleKeys(['status' => WxRulesModel::STATUS_OPEN, 'type' => WxRulesModel::TYPE_ILLEGAL_WORD]);
if (!empty($keyWords)) {//关键字回复
if (isset($ruleKeys[$msg])) {
return $ruleKeys[$msg];
}
}
if (!empty($illegalWord)) {//敏感词替换
}
$key = [',','.','?',',','。','?', '吗','嘛','吧','的','呀','啊'];
if (!empty($msg) && strlen($msg) > 1) {
if (in_array(mb_substr($msg, -1),$key)) {
$msg = mb_substr($msg, 0, -1);
}
if (strpos($msg, '我') !== false && strpos($msg, '你') !== false) {
$content = '';
$len = mb_strlen($msg);
for ($i = 0; $i < $len; $i++) {
$tmp = mb_substr($msg, $i, 1);
if ($tmp == '我') {
$tmp = '你';
} elseif ($tmp == '你') {
$tmp = '我';
}
$content = $content . $tmp;
}
return $content;
} elseif (strpos($msg, '我') !== false) {
$msg = str_replace('我', '你', $msg);
} elseif (strpos($msg, '你') !== false) {
$msg = str_replace('你', '我', $msg);
}
}
return $msg;
}
其他
- 真的要实现人工智能的话需要接入真正的机器学习模型,这个待之后实现,目前仅收集样本数据
可以实现关键字自动回复功能
- 可以处理多种消息类型
备注
大家有兴趣也可以关注下我的公众号,我会不定期技术文章和代码滴~~~
也欢迎大家一起交流学习_
扫码测试“AI”代码~