最近学习了关于微信公众号开发的相关知识,为了帮助自己更好的理解,在此重新再梳理一遍
更多关于微信公众号开发的功能可以参考微信公众平台的开发技术文档
完成开发者配置
第一步,需要在微信公众平台配置我们的服务器
在接口的文件需要写入以下代码以完成验证:
class Wxapi
{
public function __construct()
{
$this->index();
}
public function index()
{
$echostr = isset($_GET[‘echostr‘]) ? $_GET[‘echostr‘] : ‘‘;
if($$this->checkSignature && $echostr){
echo $echostr; //输出微信服务器传过来的验证通过的字符串
} else {
$this->responseMsg(); //后面部分再提这个方法
}
}
public function checkSignature()
{
//获取微信服务器传过来的signature、token、nonce和timestamp
$token = "weixin"; //这是我自己设置的token值
$timestamp() = $_GET[‘timestamp‘];
$nonce = $_GET[‘nonce‘];
$signature = $_GET[‘signature‘];
//对token、nonce和timestamp按字典序排序
$tmpArr = array($token, $nonce, $timestamp);
sort($tmpArr);
//与singnature进行对比校验
if($tmpArr == $signature){
return true;
} else {
return false;
}
}
}
curl方法
在微信公众号开发过程中,我们的第三方服务器(公众号中配置的接口服务器)与微信之间的通信都是用curl的方式来完成的,下面写一下我开发过程中用到的curl实例方法
class Wxapi
{
public function httpCurl($url, $type=‘get‘, $postData=‘‘)
{
//1.初始化
$ch = curl_init();
//2.设置curl参数
curl_setopt($ch, CURLOPT_URL, $url); //要链接的url
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //将curl_exec()获取的信息以字符串返回,而不是直接输出。
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//部分链接url要以https协议进行,设定以跳过证书验证
if($type == ‘post‘){
curl_setopt($ch, CURLOPT_POST, true); //true时发送post请求;
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
}
//3.执行curl请求
$res = curl_exec($ch); //将返回一个json格式的字符串
//4.返回结果并关闭curl连接
if(curl_errno($ch)){
return curl_error($ch);
}
curl_close($ch);
return $res;
}
}
获取access_token
这里的access_token是指的全局access_token 在调用很多微信后台的接口时都需要用access_token验证,通过后才可以调用相关接口实现相应的功能,我们可以通过appid和appsecret获取到我们的access_token
class Wxapi
{
public function getWxAccessToken()
{
if($_SESSION[‘access_token‘] && $_SESSION[‘expire_time‘] > time()){
return $_SESSION[‘access_token‘];
} else {
$appid = ‘‘; //填入自己的appid
$appsecret = ‘‘;
$url = ‘https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=‘.$appid.‘&secret=‘.$appsecret;
$res = $this->httpCurl($url); //调用上面提到的curl方法
$res = json_decode($res, true);
$access_token = $res[‘access_token‘];
$_SESSION[‘access_token‘] = $access_token; //将access_token存入缓存,也可用redis、memcache等方式
$_SESSION[‘expire_time‘] = time()+7000; //获取的access_token的有效期为7200秒,因此缓存的时间应小于7200秒;
return $access_token();
}
}
获取微信服务器的IP地址
很多时候我们会收到微信传过来的信息,但是我们并不清楚这些信息是不是真的是由微信服务器传过来的,因此微信也提供了一个接口,返回微信服务器的地址以便我们验证信息来源;
class Wxapi
{
public function getWxServerIp()
{
$access_token = $this->getWxAccessToken();
$url = ‘https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=‘.$access_token;
$res = $this->httpCurl($url);
$arr = json_decode($res,true);
return $arr;
}
}
自定义菜单
自定义菜单是公众号常用的一个功能,每个公众号有自己的定位,菜单的内容当然也不同,自定义菜单也需要使用全局access_token来完成。下面用实例写两种常用的菜单类型,更多内容请参考开发文档
public function defineMenu()
{
$access_token = $this->getWxAccessToken();
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$access_token;
//菜单内容
$postArr = array(
‘button‘ => array(
//第一个一级菜单
array(
‘name‘ => ‘菜单名‘,
‘type‘ => ‘click‘, //分为click和view两种,click为点击事件,view为跳转到指定url
‘key‘ => ‘EventKey‘ // type为click时为key,可针对传入的eventkey设定回复内容,见下面的事件回复
),
//第二个一级菜单
array(
‘name‘ => ‘‘,
‘sub_button‘ => array(
//二级菜单
array(
‘name‘ => ‘‘,
‘type‘ => ‘view‘,
‘url‘ => ‘‘ //type为view时key值为url
)
)
)
)
);
$postJson = json_encode($postArr); //post数据的格式为json
$res = $this->httpCurl($url, ‘post‘, $postJson);
}
事件回复及关键字回复
验证通过后,可以开始配置我们公众号常用的一些功能,这部分主要是事件回复以及关键回复
事件回复我这里主要指的用户关注的事件,具体消息的模版参考微信公众平台开发模版的消息管理
class Wxapi
{
public function responseMsg()
{
//1.获取微信推过来的post数据(xml格式)
$postArr = $GLOBALS[‘HTTP_RAW_POST_DATA‘];
//2.根据消息类型进行回复
if(!empty($postArr)){
$postObj = simplexml_load_string($postArr); //将xml数据转换为对象
//2.1.判断消息类型
if(strtolower($postObj->MsgType) == ‘event‘){
//关注事件,新用户关注后自动回复
if(strtolower($postObj->Event) == ‘subcribe‘){
$content = ‘‘; //自定义回复内容
$info = $this->responseText($postObj, $content);
echo $info;
} elseif(strtolower($postObj->Event) == ‘click‘){
//点击菜单事件
switch($postObj->EventKey){
case ‘‘: //自定义菜单关键字
$content = ‘‘; //自定义回复内容
$info = $this->responseText($postObj, $content);
echo $info;
break;
case ‘‘: //
//也可回复图文消息
$arr = array(
array(
‘title‘ => ‘潮图|你的姆爷Slim Shady‘,
‘description‘ => ‘高能预警‘,
‘picUrl‘ => ‘‘,
‘url‘ => ‘‘,
)
);
$info = $this->responseNews($postObj, $arr);
echo $info;
break;
}
} elseif(strtolower($postObj->Event) == ‘scan‘) {
//扫码事件,用户扫码后会跳转至公众号,可自动回复相关内容
switch ($postObj->EventKey){
case 2000:
$content = "";
$info = $this->responseText($postObj, $content);
echo $info;
break;
}
}
}
//用户输入关键字回复
if(strtolower($postObj->MsgType) == ‘text‘){
$keyword = trim($postObj->Content);
if(!empty($keyword)) {
//返回图文信息
if($keyword == ‘slimshady‘){
$arr = array(
array(
‘title‘ => ‘‘,
‘description‘ => ‘‘,
‘picUrl‘ => ‘‘,
‘url‘ => ‘‘,
),
);
$info = $this->responseNews($postObj, $arr);
echo $info;
}
//返回文本消息
switch ($keyword) {
case ‘shadypop‘:
//返回的文本消息也可以是链接形式
$content = "<a href=‘http://jason9351.get.vip‘>欢迎访问我的主页</a>";
break;
default:
$content = "表示看不懂你说的";
break;
}
$info = $indexModel->responseText($postObj, $content);
echo $info;
}
}
}
}
//回复文字消息
public function responseText($postObj, $content)
{
$toUser = $postObj->FromUserName;
$fromUser = $postObj->ToUserName;
$time = time();
//返回文字消息的模板
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$info = sprintf($textTpl, $toUser, $fromUser, $time, $content);
return $info;
}
//回复图文消息
public function responseNews($postObj, $arr)
{
$toUser = $postObj->FromUserName;
$fromUser = $postObj->ToUserName;
$time = time();
$newsTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>".count($arr)."</ArticleCount>
<Articles>";
foreach ($arr as $k => $v) {
$newsTpl .= "<item>
<Title><![CDATA[".$v[‘title‘]."]]></Title>
<Description><![CDATA[".$v[‘description‘]."]]></Description>
<PicUrl><![CDATA[".$v[‘picUrl‘]."]]></PicUrl>
<Url><![CDATA[".$v[‘url‘]."]]></Url>
</item>";
}
$newsTpl .= "</Articles>
</xml>";
$info = sprintf($newsTpl, $toUser, $fromUser, $time);
return $info;
}
}
生成带参数的二维码
目前微信支持生成临时二维码和永久二维码两种。临时二维码有效期为30天,主要用于帐号绑定等不要求二维码永久保存的业务场景。永久二维码没有过期时间,但是数量有限,为10万个,主要用于适用于帐号绑定、用户来源统计等场景。
用户扫描带场景值二维码时,可能推送以下两种事件:
如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。
如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。
生成二维码分为两步:首先创建二维码ticket,然后凭借ticket到指定URL换取二维码。
创建二维码ticket
每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id);
临时二维码:
public function getTmpQRCode()
{
//1.获取ticket票据
$access_token = $this->getWxAccessToken();
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$access_token;
$postArr = array(
‘expire_seconds‘ => 604800, //24*60*60*7
‘action_name‘ => ‘QR_SCENE‘,
‘action_info‘ => array(
‘scene‘ => array(‘scene_id‘ => ‘自行设定‘)//扫码事件中的EventKey
)
);
$postJson = json_encode($postArr);
$res = $this->httpCurl($url, ‘post‘, $postJson);
$res = json_decode($res, true);
$ticket = urlencode($res[‘ticket‘]);
//2.使用ticket获取二维码图片
$url = ‘https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=‘.$ticket;
echo "<img src=‘{$url}‘ />";
}
永久二维码:
永久二维码与临时二维码不同就在于action_name不同,并且没有expire_time:
public function getInsQRCode()
{
//1.获取ticket票据
$access_token = $this->getWxAccessToken();
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$access_token;
$postArr = array(
‘action_name‘ => ‘QR_LIMIT_SCENE‘,
‘action_info‘ => array(
‘scene‘ => array(‘scene_id‘ => ‘‘)//扫码事件中的EventKey
)
);
$postJson = json_encode($postArr);
$res = $this->httpCurl($url, ‘post‘, $postJson);
$res = json_decode($res, true);
$ticket = urlencode($res[‘ticket‘]);
//2.使用ticket获取二维码图片
$url = ‘https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=‘.$ticket;
echo "<img src=‘{$url}‘ />";
}
获取网页授权以及用户的基本信息
在用户同意授权的情况下,我们可以获取到用户的一些基本信息,来实现我们的业务逻辑
关于授权回调域名的两点说明:
1.在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;
2.授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权
另外, 网页授权也分为两种类型,分别是scope_base和scope_userinfo,两者有以下区别:
1、以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)//即无需用户点击同意
2、以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
3、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。
具体而言,网页授权流程分为四步:
1、引导用户进入授权页面同意授权,获取code
2、通过code换取网页授权access_token(与基础支持中的access_token不同)
3、如果需要,开发者可以刷新网页授权access_token,避免过期
4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)
以下为实例:
只获取用户openid,scope_base类型
public function getBaseInfo()
{
$appid = ‘‘; //上文提及的公众号自己的appid
$redirectUri = urlencode(‘调用getUserOpenId的uri‘);
$url = ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appId.‘&redirect_uri=‘.$redirectUri.‘&response_type=code&scope=snsapi_base&state=123#wechat_redirect‘;
header(‘location:‘.$url); //此步仅做演示,实际业务中引导用户访问调用此方法的链接来跳转至redirectUrl
}
public function getUserOpenId()
{
$appId = ‘wx693062b792d58274‘;
$appSecret = ‘885cab15b3d47e0ccddfb065da734eff‘;
$code = $_GET[‘code‘]; //getBaseInfo 方法传来的code
$url = ‘https://api.weixin.qq.com/sns/oauth2/access_token?appid=‘.$appId.‘&secret=‘.$appSecret.‘&code=‘.$code.‘&grant_type=authorization_code‘;
$res = $this->httpCurl($url);
//返回值的格式:{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
}
至此,我们就获取到了我们需要的openid值。
获取用户的详细信息
public function getBaseInfo()
{
$appid = ‘‘; //上文提及的公众号自己的appid
$redirectUri = urlencode(‘调用getUserInfo的uri‘);
$url = ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appId.‘&redirect_uri=‘.$redirectUri.‘&response_type=code&scope=snsapi_base&state=123#wechat_redirect‘;
header(‘location:‘.$url); //此步仅做演示,实际业务中引导用户访问调用此方法的链接来跳转至redirectUrl
}
public function getUserInfo()
{
//获取openid和网页授权access_token
$appId = ‘wx693062b792d58274‘;
$appSecret = ‘885cab15b3d47e0ccddfb065da734eff‘;
$code = $_GET[‘code‘]; //getBaseInfo 方法传来的code
$url = ‘https://api.weixin.qq.com/sns/oauth2/access_token?appid=‘.$appId.‘&secret=‘.$appSecret.‘&code=‘.$code.‘&grant_type=authorization_code‘;
$res = $this->httpCurl($url);
//返回值的格式:{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
$res = json_decode($res, true);
$access_token = $res[‘access_token‘];
$openid = $res[‘openid‘];
//获取用户的详细信息
$url = ‘ https://api.weixin.qq.com/sns/userinfo?access_token=‘.$access_token.‘&openid=‘.$openid.‘&lang=zh_CN‘;
$arr = $this->httpCurl($url);
}
此处返回以下格式的内容:
正确时返回的JSON数据包如下:
{"openid":" OPENID",
"nickname": NICKNAME,
"sex":"1",
"province":"PROVINCE"
"city":"CITY",
"country":"COUNTRY",
"headimgurl":
"http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}