一、首先启用 服务号中服务器配置。
注意:启用后 之前在服务号后台页面创建的菜单就没了,服务号下面所有菜单都只能通过api去创建。
二、 服务器地址URL 其实就相当于一个回调地址,类似支付回调地址URL一样,这个接口要做两个事情,一个就是效验token签名,另一个就是事件处理。
原理:用户每在服务号做任何操作 微信都会异步请求我们配置的回调地址(就是上面的服务器地址URL),我们可以if判断用户在做某些操作后回复种种消息之类的事情。比如(用户关注、取消关注事件等)
回调接口代码:
public function index()
{
ownLogs('test.log', 123456);
$timestamp = $_GET['timestamp'];//timestamp其实就是一个时间戳
$nonce = $_GET['nonce'];//nonce是一个随机参数
$token = "第一步配置的token";//这个token填写你在微信公众平台上写的那个值
$signature = $_GET['signature'];//这个signature其实就是在微信公众平台已经加密好的字符串
$echostr = $_GET['echostr'] ?? '';
$array = array($timestamp, $nonce, $token);
sort($array);
$tmpstr = implode('', $array);
$tmpstr = sha1($tmpstr);
if ($tmpstr == $signature && $echostr) {
//验签
ob_clean();
echo $echostr;
exit;
} else {
//回调处理
$this->responseMsg();
}
}
public function responseMsg()
{
//get post data, May be due to the different environments
$postStr = file_get_contents("php://input"); //php 7 以上版本
//$postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; //php 7以下版本,php.ini开启;always_populate_raw_post_data = On
//extract post data 请求数据
if (!empty($postStr)) {
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$keyword = trim($postObj->Content);
$time = time();
$toUser = $postObj->FromUserName;
$fromUser = $postObj->ToUserName;
$eventKey = $postObj->EventKey ?? '';
$ticket = $postObj->Ticket ?? '';
if (strtolower($postObj->MsgType) == 'event') {
//如果是关注事件(subscribe)
if (strtolower($postObj->Event == 'subscribe')) {
//回复用户消息
$data = [
'open_id' => $toUser,
'event_key' => $eventKey,
'ticket' => $ticket,
];
//关注数据写入数据库
list($status,$res) = GzhFollow::updateGzhFollowInfo($data);
if(!$status){
ownLogs('test.log', $res);
}
// ownLogs('test.log', 'fromUser=' . $fromUser . '|toUser=' . $toUser . '|keyword=' . $keyword);
}
//取消关注事件(subscribe)
if (strtolower($postObj->Event == 'unsubscribe')) {
//更新GzhFollow表status为取消关注
$open_id = $toUser;
$info = GzhFollow::getFollowInfoByOpenId($open_id);
if($info){
$info->status = GzhFollow::STATUS['off'];
$info->save();
}
}
//扫描带参数二维码事件
if($eventKey && $ticket){
$msgType = 'text';
$store_name = '李伟';//测试数据先写死
$description = '【' . $store_name . "】的店铺!";
//文字消息处理成超链接(因为我现在需求要跳转到小程序)
$content = '点击进入' . '<a data-miniprogram-appid="你的服务号openid" data-miniprogram-path="/pages/index/index">' . $description . '</a>';
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$info = sprintf($template, $toUser, $fromUser, $time, $msgType, $content);
echo $info;
}
}
} else {
echo "";
exit;
}
}
下面主要思路是三步:(自己可以封装成方法,我为了看着方便故意从封装的方法中提取到一个方法了)
1.需要先获取服务号对应的access_token
2.根据上面的access_token 和 open_id 去请求微信接口拿用户数据(主要想拿union_id 和小程序用户做关联)
请求成功可以拿到用户微信头像、昵称、open_id,union_id(需要先在开放平台绑定多项目(小程序/服务号),才会返回)
3.写入数据库。
/*
* $params 里面必包含参数open_id,
* 剩余两个参数event_key 和ticket 是识别带参数二维码进服务号的时候才会有的参数(根据自己需要是否存数据库)
*/
public static function updateGzhFollowInfo($params){
$app_id = config('wechat.official_account.yff_gzh.app_id');
$app_secret = config('wechat.official_account.yff_gzh.secret');
if (!$app_id || !$app_secret) {
return [false, '获取小程序配置失败!'];
}
$redisConfig = config('database.redis.default');
$redis = new Client($redisConfig);
//1.需要先获取服务号对应的access_token
$access_token = $redis->get('access_token_' . $app_id);
if (!$access_token) {
$third_api = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $app_id . "&secret=" . $app_secret;
$result = getHttpContent($third_api, 'GET');
$json = json_decode($result, true);
if (!isset($json['access_token']) || !$json['access_token']) {
return [false, '获取access_token失败'];
}
$access_token = $json['access_token'];
$redis->set('access_token_' . $app_id, $access_token);
$redis->expire('access_token_' . $app_id, 3600);
}
//2.根据上面的access_token 和 open_id 去请求微信接口拿用户数据(主要想拿union_id 和小程序用户做关联)
$open_id = $params['open_id'];
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" . $access_token . '&openid=' . $open_id . '&lang=' . 'zh_CN';
$result = WechatService::httpRequest($url);
$result_arr = json_decode($result, true);
if(!isset($result_arr['unionid']) || !$result_arr['unionid']){
return [false,'获取微信信息失败!'];
}
//3.组合需要的数据,写入数据库
$data = [
'status' => GzhFollow::STATUS['on'],
'union_id' => $result_arr['union_id'],
'sex' => $result_arr['sex'],
'addInfo' => json_encode($result_arr),
'open_id' => $open_id,
'event_key' => $params['event_key'],//根据自己需要(这个是识别带参数二维码进服务号的时候才会有的参数)
'ticket' => $params['ticket'],//根据自己需要(这个是识别带参数二维码进服务号的时候才会有的参数)
];
$res = GzhFollow::create($data);
if(!$res){
return [false,'创建记录失败!'];
}
return [true,'成功!'];
}