php微信開發(fā)之帶參數(shù)二維碼的使用
最近做微信PC端網頁微信相關功能的開發(fā),從一個新手的角度來說,微信公眾號的文檔還是不好理解的,網上找的帖子大都也都基本上是復制微信公眾平臺上給的文檔,開發(fā)微信帶參數(shù)二維碼過程中還是遇到不少坑的,在此把我的開發(fā)過程比較詳細的記錄下,希望對大家有所幫助。
我本次開發(fā)使用的是認證服務號。
1 接入
首先進入微信公眾號 -> 基本配置
下面是基本配置的頁面,在URL中填寫服務器地址,這個地址就是接受微信推送事件的一個接口,我是使用thinkPHP框架開發(fā)的程序,在其中一個Module(Decoration)的Action目錄下新建一個類,比如叫: WechatAction.class.php ,在該Action中新建一個public方法,比如叫: URLRedirect() ,那么在這個URL中填寫的就是 http://[IP]:[port]/index.php/Decoration/Wechat/UrlRedirect ,然后填寫Token,Token隨意填,EncodingAESKey要不要都行,然后點擊確認,微信會往這個URL上發(fā)送一個get請求,里面包含很多參數(shù),其中大部分都是讓我們自己核對這次訪問是不是微信服務器請求的,我自己沒有驗證,他的要求是如果我們核對成功,即原樣返回get請求中的一個參數(shù)echostr,這里的返回不是return,也不是ajaxReturn,而使用echo,如果用thinkPHP開發(fā)的話,直接使用 echo I('echostr'); 即可。然后接口即驗證成功了。

2 帶參數(shù)二維碼的作用
微信的帶參數(shù)二維碼有兩種,一種是臨時二維碼,一種是永久二維碼,但是永久二維碼的生成是有個數(shù)限制的,我這次要實現(xiàn)的功能是用戶未登錄的情況下在網站上使用產品,比如獲得某商品的詳細報價,但是又不想注冊,然而又想保存這個報價單,這個時候網頁可以生成一張二維碼,用戶只要用微信掃一掃這個二維碼,官方公眾號就會給這個用戶發(fā)送一天圖文消息,圖文消息點開后就是用戶剛剛獲得的報價單,而且可以隨時點擊查看并且分享給朋友進行比價。所以臨時二維碼即可正常使用。
上面是我是怎么使用的,下面介紹一下整個交互的流程:
當用戶掃描這個二維碼,如果用戶關注了公眾號,用戶會直接進入與公眾號的會話頁面,微信服務器會給我們在上一步設置的服務器URL中推送一條消息,其中可以攜帶一個我們自定義的參數(shù)。如果用戶未關注公眾號,則用戶首先會跳轉到公眾號關注頁面,用戶點擊關注后,會直接進入公眾號的會話頁面,微信服務器這時也會給我們設置的URL推送一個事件消息,攜帶我們自定義參數(shù),我們可以根據這個參數(shù)和事件類型做控制下一步動作。
3 具體開發(fā)過程
3.1 獲取access_token
這個access_token是我們程序調用微信接口的憑證,目前的有效期是7200秒,所以我們需要定時更新access_token。
獲得方法:
方法 : GET
url :https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
其中的參數(shù)APPID和APPSECRET是我們公眾號的APPID和APPSECRET,在微信公眾號 -> 基本配置中可以查到,調用成功會返回如下JSON數(shù)據:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
其中access_token就是調用接口憑證,expire_in是token有效時間。
我本人是把access_token存在數(shù)據庫中,同時保存過期時間,然后封裝公用函數(shù) getWechatAccessToken() ,每次先檢查access_token是否過期,如果過期則重新獲取,否則直接使用數(shù)據庫保存的access_token即可,我忘了在哪兒看加過,這個access_token每天的獲取次數(shù)應該是有限制的。下面是 getWechatAccessToken() 的具體實現(xiàn):
//獲取access_token
function getWechatAccessToken(){
$wechatInfo = M('wechat_info')->select();
$wechatInfo = array_reduce($wechatInfo, create_function('$result, $v', '$result[$v["conf_name"]] = $v;return $result;'));
$expireTime = $wechatInfo['PUBLIC_WECHAT_ACCESSTOKEN_EXPIRES']['conf_value']; //前面不用管,是我數(shù)據庫相應設置
if (time() < $expireTime){ //access_token未過期
return $wechatInfo['PUBLIC_WECHAT_ACCESSTOKEN']['conf_value'];
}else{ //access_token過期,重新獲取
$baseUrl = C('WECHAT_PUBLIC_GET_ACCESS_TOKEN');
$url = str_replace("##APPSECRET##", $wechatInfo['PUBLIC_WECHAT_APPSECRET']['conf_value'], str_replace("##APPID##", $wechatInfo['PUBLIC_WECHAT_APPID']['conf_value'], $baseUrl));
$result = file_get_contents($url);
$result = json_decode($result, true);
if (array_key_exists('errorcode', $result)){ //失敗重試一次
return false;
}else{
M('wechat_info')->where(array('conf_name' => 'PUBLIC_WECHAT_ACCESSTOKEN'))->save(array('conf_value' => $result['access_token']));
M('wechat_info')->where(array('conf_name' => 'PUBLIC_WECHAT_ACCESSTOKEN_EXPIRES'))->save(array('conf_value' => time()+$result['expires_in']-200));
return $result['access_token'];
}
}
}
C('WECHAT_PUBLIC_GET_ACCESS_TOKEN') = https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
封裝好這個之后,我們每次就可以安心的使用了。
.2 創(chuàng)建臨時二維碼
3.2.1 獲取ticket3
請求方式: POST
接口:https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
POST數(shù)據: {"expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
接口URL中的TOKEN即我們在3.1中獲取的access_token,post數(shù)據中expire_seconds是二維碼的有效時間,最多為30天,action_name臨時二維碼的話固定就是QR_SCENE,scene_id即我們自定義參數(shù),是個32位非0整數(shù),我在應用中把它設為訂單的ID,微信服務器推送事件的時候會把這個值返回給我們設置的接口中,然后我會根據這個值去拿相應的訂單數(shù)據展示在網頁上,這是后話。
下面是封裝的生成臨時二維碼的方法:
//創(chuàng)建臨時二維碼
function getTemporaryQrcode($orderId){
$accessToken = getWechatAccessToken();
$url = str_replace("##TOKEN##", $accessToken, C('WECHAT_PUBLIC_GET_TEMPORARY_TICKET'));
$qrcode = '{"expire_seconds": 1800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": '.$orderId.'}}}';
$result = api_notice_increment($url, $qrcode);
$result = json_decode($result, true);
return urldecode($result['url']);
}
其中的方法 api_notice_increment() 是我封裝的一個POST方法函數(shù),我試過很多POST的方法,可能由于微信接口對POST方法和參數(shù)的限制比較嚴格,這個浪費了好久時間,最后在網上找到了一個可以使用的封裝好的POST方法,建議大家先自己試試,如果微信返回錯誤嗎,就用這個吧,起碼我測試微信這個接口的時候用postman測試返回的都是錯誤,而且一定要用JSON字符串,一定要是非常嚴格的JSON字符串。下面是這個方法:
function api_notice_increment($url, $data){
$ch = curl_init();
$header = "Accept-Charset: utf-8";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$tmpInfo = curl_exec($ch);
if (curl_errno($ch)) {
curl_close( $ch );
return $ch;
}else{
curl_close( $ch );
return $tmpInfo;
}
}
getTemporaryQrcode() 中有一個在配置文件中的參數(shù)給大家看下,其實就是微信接口鏈接:
C('WECHAT_PUBLIC_GET_TEMPORARY_TICKET') = https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=##TOKEN##
這個接口的返回值是:
{"ticket":"gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm3sUw==","expire_seconds":60,"url":"http:\/\/weixin.qq.com\/q\/kZgfwMTm72WWPkovabbI"}
其中ticket是讓我們用來進行下一步調用的憑證,expire_seconds是二維碼的有效期,url是我們生成的二維碼掃描后打開的鏈接。所以如果我們自己實現(xiàn)了生成二維碼的方法,就不用再進行下一步調用,我本人即在這一步就停止了,直接返回url的值,然后利用這個url的值生成二維碼存在本地即可。PHP生成二維碼可以使用phpqrcode,挺好用的。下一步也大致提一下:
3.2.2 獲取二維碼地址
請求方式: GET
接口:https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
這個接口的返回值是一張圖片,可以直接展示或者下載,我們有具體使用過,所以也不知道應該怎么展示。
3.3 用戶掃描二維碼之后發(fā)生的事情
3.3.1 掃描后發(fā)生了什么
上面提到了,用戶掃描我們生成的臨時二維碼,如果用戶未關注公眾號,則首先會跳轉到公眾號的關注頁面,點擊關注后,會進入公眾號的會話頁面,同時會給我們設置的接口推送一個事件。如果用戶已經關注了,用戶微信會直接跳轉到公眾號會話頁面,然后微信服務器會給我們設置的接口推送一個事件。
用戶關注與否微信服務器給我們推送的事件是差不多的,只是新關注用戶推送的事件中scene_id前面會加一個前綴。下面是微信公眾平臺文檔的說明:
用戶未關注時,進行關注后的事件推送
<xml><ToUserName><![CDATA[toUser]]></ToUserName> //開發(fā)者微信號 <FromUserName><![CDATA[FromUser]]></FromUserName> //發(fā)送者賬號(openid) <CreateTime>123456789</CreateTime> //消息創(chuàng)建時間(整型) <MsgType><![CDATA[event]]></MsgType> //消息類型 event <Event><![CDATA[subscribe]]></Event> //事件類型(subscribe) <EventKey><![CDATA[qrscene_123123]]></EventKey> //事件KEY值,qrscene_為前綴,后面為二維碼參數(shù)值 <Ticket><![CDATA[TICKET]]></Ticket> //二維碼ticke值,可以用來換取二維碼圖片 </xml>
用戶已關注時的事件推送
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> //開發(fā)者微信號 <FromUserName><![CDATA[FromUser]]></FromUserName> //發(fā)送者賬號(openid) <CreateTime>123456789</CreateTime> //消息創(chuàng)建時間 <MsgType><![CDATA[event]]></MsgType> //消息類型event <Event><![CDATA[SCAN]]></Event> //事件類型 event <EventKey><![CDATA[SCENE_VALUE]]></EventKey> //事件key值,是一個32位無符號整數(shù),即創(chuàng)建二維碼時的二維碼scene_id <Ticket><![CDATA[TICKET]]></Ticket> //二維碼的ticke,可以用來換取二維碼圖片 </xml>
3.3.2 我們要做些什么
我們需要在自己填寫的URL接口中接收這個事件,然后拿到我們需要的東西做我們想干的事兒。因為我要實現(xiàn)的功能比較簡單,只需要拿到scene_id即可,因為這是我要展示給用戶看的訂單數(shù)據。下面是我寫的接收和處理部分,比較簡單,主要看一下應該怎么接收微信推送的事件:
public function urlRedirect(){
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = (string)$postObj->FromUserName;
$EventKey = trim((string)$postObj->EventKey);
$keyArray = explode("_", $EventKey);
if (count($keyArray) == 1){ //已關注者掃描
$this->sendMessage($fromUsername, $EventKey);
}else{ //未關注者關注后推送事件
$this->sendMessage($fromUsername, $keyArray[1]);
}
}
我沒有使用其他參數(shù),只是根據不同的推送事件拿到我想要的訂單ID,然后這時候其實相當于你在這里用公眾號的客服在跟掃碼的這個用戶對話,上段代碼中調用的sendMessage()是使用客戶賬號給掃碼用戶發(fā)送一個圖文消息,因為我在拿scen_id的同時也拿到了用戶的openid,可以利用這個給用戶發(fā)送消息。
下面是sendMessage()方法:
//給用戶發(fā)送圖文消息,點擊跳轉到報價頁面
public function sendMessage($openid,$orderId){
$url = str_replace('##TOKEN##', getWechatAccessToken(), C('WECHAT_SEND_MESSAGE'));
$redirectUrl = str_replace("##ORDERID##", $orderId, str_replace("##OPENID##", $openid, C('WECHAT_REDIRECT_URL_PRE')));
$orderInfo = M('order')->where(array('orderid' => $orderId))->field(array('totalMoney', 'savedMoney', 'roomarea'))->find();
$description = str_replace("##ROOMAREA##", intval($orderInfo['roomarea'] * 1.25), C('WECHAT_MESSAGE_BRIEF'));
$description = str_replace("##TOTALBUDGET##", $orderInfo['totalMoney'], $description);
$description = str_replace("##MARKETBUDGET##", $orderInfo['totalMoney']+$orderInfo['savedMoney'], $description);
$description = str_replace("##SAVEMONEY##", $orderInfo['savedMoney'], $description);
$dataStr = '{"touser":"' . $openid . '","msgtype":"news","news":{"articles":[{"title":"' . C('WECHAT_MESSAGE_TITLE') .
'","description":"' . $description . '","url":"' . $redirectUrl . '","picurl":"' . C('WECHAT_MESSAGE_PICURL') . '""}]}}';
api_notice_increment($url, $dataStr);
}
其中 C('WECHAT_SEND_MESSAGE') = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=##TOKEN##' 至于下面的一大段str_replace,就是在組給用戶發(fā)送的文字而已,需要注意$dataStr的格式,這里面要求JSON字符串比較嚴格,必須所有的字符串都用雙引號括起來。微信接口對POST參數(shù)的限制真心嚴格。
下面是微信公眾平臺開發(fā)者文檔中要求發(fā)送圖文消息的POST data格式:
{
"touser":"OPENID",
"msgtype":"news",
"news":{
"articles": [
{
"title":"Happy Day",
"description":"Is Really A Happy Day",
"url":"URL",
"picurl":"PIC_URL"
},
{
"title":"Happy Day",
"description":"Is Really A Happy Day",
"url":"URL",
"picurl":"PIC_URL"
}
]
}
}
其中url是用戶點擊這個消息之后打開的地址,這個時候我就組了一個自己網站的地址,是一個get請求地址,里面攜帶參數(shù)是用戶的openid和訂單id,這樣用戶點擊開圖文消息就可以看到自己剛才下單的內容了,因為需要在網頁上展示用戶的微信頭像和昵稱,所以我把openid也放到參數(shù)里,在頁面加載前先拿到用戶的個人信息和訂單數(shù)據,再展示網頁。這樣流程:用戶未登錄下單 -> 生成微信二維碼 -> 用戶掃碼關注公眾號 -> 查看訂單詳細信息 就完成了。而且因為這個圖文消息打開后的鏈接攜帶的參數(shù)是這個用戶的額openid和其下單的訂單ID,不管分享到哪兒,用什么瀏覽器打開都是可以訪問的,且展示的也是這個用戶的頭像和昵稱信息,這也是我要實現(xiàn)的一個效果。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
thinkPHP5.0框架整體架構總覽【應用,模塊,MVC,驅動,行為,命名空間等】
這篇文章主要介紹了thinkPHP5.0框架整體架構,簡單介紹了thinkPHP5.0的應用,模塊,MVC,驅動,行為,命名空間等概念與基本用法,需要的朋友可以參考下2017-03-03
thinkphp5.1 框架導入/導出excel文件操作示例
這篇文章主要介紹了thinkphp5.1 框架導入/導出excel文件操作,結合實例形式分析了thinkphp5.1 框架導入/導出excel文件具體操作實現(xiàn)技巧與相關注意事項,需要的朋友可以參考下2020-05-05
Yii2中OAuth擴展及QQ互聯(lián)登錄實現(xiàn)方法
這篇文章主要介紹了Yii2中OAuth擴展及QQ互聯(lián)登錄的方法,實例分析了OAuth擴展的相關配置與QQ互聯(lián)登陸的實現(xiàn)技巧,需要的朋友可以參考下2016-05-05
laravel5.4利用163郵箱發(fā)送郵件的步驟詳解
發(fā)送郵件是我們日常在開發(fā)中必不可少會遇到的一個需求,下面這篇文章主要給大家介紹了關于laravel5.4利用163郵箱發(fā)送郵件的步驟,文中通過示例代碼和圖片介紹的非常詳細,需要的朋友可以參考下。2017-09-09
PHP unlink與rmdir刪除目錄及目錄下所有文件實例代碼
這篇文章主要介紹了PHP unlink與rmdir刪除目錄及目錄下所有文件的實例代碼,需要的朋友可以參考下2018-02-02

