在做微信接口调用的时候,需求是这样的 用户回复“666”-----》给用户发送一段文字,再给用户发送一张图片,,,,因为微信模板消息发送只能给用户发送一条消息,所以只用模板消息发送不行了,看大家用的是 客服消息发送,,所以果断用起,把过程记录一下,中间不少坑
1、用 客服消息发送 接口 第一步要先启用 客服消息 接口 ,不启用的话调不通,位置看图片
2、里面的具体接口调用就不说了,我是用 php ,curl 走起一般没啥问题 ,坑在后面
当用户 回复 666 的时候,当时想 先用模板消息发送,再调用微信客服接口发图片,结果发现不行,只发图片不发文字,而且微信那边没收到回复,会一直请求三次,结果给用户发了三次图片,这个不行,那只用客服消息,先发文字,再发图片,结果还是因为微信那边没收到消息,给用户发了三次文字,三次图片,这条路也不行,,,,,,,,,然后在网上找,看大家都用 ob 函数,我们也用起,结果发现不行,不起作用(怀疑微信那边改版了),期间也试了给微信那边回复 echo " " , echo “null” , echo “success”,等,都不行,,这可难为死我了
最后实在没办法就给数据库加了个字段,用来记录微信请求了几次,当用户第一次请求后,改变字段状态(0改为1),微信再次请求时判断转态,为1,直接exit(); 即使微信那边请求了三次,但就只给用户发一次,不说了,上代码![这里写图片描述]
补充,为什么微信那边一直收不到信息,因为上传图片这里太耗时了,加上这句话就可以解决了,红色箭头出,我上源码吧在这里插入代码片
<?php
date_default_timezone_set(“Asia/Shanghai”);
header(‘content-type:text/html;charset=utf-8’);
define(“xxx”, “xxxx”); //define your token
$wx = new wechatCallbackapiTest();
//增加自定义菜单
w x − > c r e a t e m e n u ( ) ; / / 第 一 步 是 接 收 微 信 后 台 发 送 的 验 证 消 息 , 微 信 后 台 会 发 送 一 个 G E T 请 求 到 上 面 的 U R L , 并 附 带 以 下 参 数 : / / s i g n a t u r e , t i m e s t a m p , n o n c e , e c h o s t r / / 我 们 的 服 务 器 在 接 收 到 上 述 参 数 后 , 需 要 验 证 s i g n a t u r e 是 否 正 确 , 验 证 方 法 是 先 对 t i m e s t a m p 、 n o n c e 和 t o k e n 先 排 序 , 再 拼 接 成 一 个 字 符 串 , 计 算 出 s h a 1 , 并 和 s i g n a t u r e 对 比 : i f ( wx->createmenu(); // 第一步是接收微信后台发送的验证消息,微信后台会发送一个GET请求到上面的URL,并附带以下参数: // signature,timestamp,nonce,echostr // 我们的服务器在接收到上述参数后,需要验证signature是否正确,验证方法是先对timestamp、nonce和token先排序,再拼接成一个字符串,计算出sha1,并和signature对比: if( wx−>createmenu();//第一步是接收微信后台发送的验证消息,微信后台会发送一个GET请求到上面的URL,并附带以下参数://signature,timestamp,nonce,echostr//我们的服务器在接收到上述参数后,需要验证signature是否正确,验证方法是先对timestamp、nonce和token先排序,再拼接成一个字符串,计算出sha1,并和signature对比:if(_GET[‘echostr’]){
$wx->valid(); //如果发来了echostr则进行验证
}else{
$wx->responseMsg(); //如果没有echostr,则返回消息
}
class wechatCallbackapiTest{
private $_cache=array(‘uid’ => 0);
public function valid(){ //valid signature , option
$echoStr = $_GET["echostr"];
if($this->checkSignature()){ //调用验证字段
echo $echoStr;
exit;
}
}
public function responseMsg(){
//get post data, May be due to the different environments
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; //接收微信发来的XML数据
//extract post data
if(!empty($postStr)){
//解析post来的XML为一个对象$postObj
//把 XML 字符串载入对象中,返回类 SimpleXMLElement 的一个对象,该对象的属性包含 XML 文档中的数据
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = $postObj->FromUserName; //请求消息的用户
$toUsername = $postObj->ToUserName; //"我"的公众号id
$keyword = trim($postObj->Content); //消息内容
$eventKey = trim($postObj->EventKey);//获取微信返回信息的类型
$time = time(); //时间戳
$msgtype = 'text'; //消息类型:文本
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$textImgTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
<FuncFlag>0</FuncFlag>
</xml>";
//在新用户关注你的公众号时,自动返回信息:(把这段代码加在判断$keyword之前)。
if($postObj->MsgType == 'event'){ //如果XML信息里消息类型为event
if($postObj->Event == 'subscribe'){ //如果是订阅事件
$contentStr = "欢迎进入5xxx";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
echo $resultStr;
if (empty($eventKey)) {
$userPic = $this->getUserInfos($fromUsername);
$pdo= new PDO('mysql:host=localhost;dbname=weixin','root','*oscent#51testing');
$sql1 = 'select openId from `sharerecord` where openId="'.$fromUsername.'"';
$stmt=$pdo->prepare($sql1);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($data[0])) {
$sql = 'insert into `sharerecord` (openId,nickname,picture,city,country,attenTime) values ("'.$fromUsername.'","'.$userPic['nickname'].'","'.$userPic['headimgurl'].'","'.$userPic['city'].'","'.$userPic['country'].'","'.time().'")';
$stmt=$pdo->prepare($sql);
$stmt->execute();
}
}
$keyArray = explode('_',$eventKey);//截取判断是否是已关注还是未关注用户
if (!empty($keyArray['1']) && is_numeric($keyArray['1'])) {
//判断该用户之前是否已关注过本公众号,还是取消后再关注过的
$pdo= new PDO('mysql:host=localhost;dbname=weixin','root','*oscent#51testing');
$sql = 'select openId from `sharerecord` where openId="'.$fromUsername.'"';
$stmt=$pdo->prepare($sql);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($data['0']['openId'])) {
//同时处理数据库,拿到scene_id 将分享者分享次数加一,并发送消息给分享者
// $pdo= new PDO('mysql:host=localhost;dbname=weixin','root','*oscent#51testing');
$sql1 = 'update `sharerecord` set `shareNum`= shareNum+1 where num="'.$keyArray['1'].'"';
//获取数据,执行语句
$stmt=$pdo->prepare($sql1);
$stmt->execute();
//给分享者发送模板消息
$this->sendTplToShare($keyArray['1']);
file_put_contents('num3.txt', $keyArray['1']);
//将用户保存在数据库
$userPic = $this->getUserInfos($fromUsername);
$sql = 'insert into `sharerecord` (openId,nickname,picture,city,country,attenTime) values ("'.$fromUsername.'","'.$userPic['nickname'].'","'.$userPic['headimgurl'].'","'.$userPic['city'].'","'.$userPic['city'].'","'.time().'")';
$stmt=$pdo->prepare($sql);
$stmt->execute();
}
}
}
exit();
}
if($keyword == '666'){
$pdo= new PDO('mysql:host=localhost;dbname=weixin','root','*oscent#51testing');
$sql = 'select isAdd,imageId from `sharerecord` where openId="'.$fromUsername.'"';
$stmt=$pdo->prepare($sql);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!$data) {
$userPic = $this->getUserInfos($fromUsername);
$sql2 = 'insert into `sharerecord` (openId,nickname,picture,city,country,attenTime) values ("'.$fromUsername.'","'.$userPic['nickname'].'","'.$userPic['headimgurl'].'","'.$userPic['city'].'","'.$userPic['city'].'","'.time().'")';
$stmt=$pdo->prepare($sql2);
$stmt->execute();
}
if ( $data[0]['isAdd']) {
if (!empty($data[0]['imageId'])) {
$msgtype = 'image';
$contentStr = $data[0]['imageId'];
$resultStr = sprintf($textImgTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
echo $resultStr;
}
exit();
}
//将isAdd 字段加1
$sql1 = 'update `sharerecord` set `isAdd`=1 where openId="'.$fromUsername.'"';
//获取数据,执行语句
$stmt1=$pdo->prepare($sql1);
$stmt1->execute();
ignore_user_abort(true);
ob_start();
header('Connection: close');
header('Content-Length: ' . ob_get_length());
ob_end_flush();
ob_flush();
flush();
echo '';
$accessToken = $this->getAccessToken();
//发送文本
$this->getSeverice($fromUsername,$accessToken);
//发送图片前先检查用户之前是否生成过,生成过则直接发送
// if ($data[0]['imageId']) {
// $msgtype = 'image';
// $contentStr = $data[0]['imageId'];
// $resultStr = sprintf($textImgTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
// echo $resultStr;
// exit();
// }
//发送图片
$this->backImg($fromUsername,$accessToken);
}else{
$contentStr = '输入666试试';
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
echo $resultStr;
exit();
}
}else {
echo "";
exit;
}
}
//验证字段
private function checkSignature()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
//排序
sort($tmpArr);
//字符串
$tmpStr = implode( $tmpArr );
//SHA-1 散列
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
//获取access_token
public function getAccessToken()
{
//先从缓存中拿token,过期再更新token
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=xxxx";
$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);
$outp