最近做微信PC端網頁微信相關功能的開發,從一個新手的角度來說,微信公眾號的文檔還是不好理解的,網上找的帖子大都也都基本上是複製微信公眾平台上給的文檔,開發微信帶參數二維碼過程中還是遇到不少坑的,在此把我的開發過程比較詳細的記錄下,希望對大家有所幫助。
我本次開發使用的是認證服務號碼。
1 存取
# 先進入微信公眾號碼->基本設定
下面是基本配置的頁面,在URL中填寫伺服器位址,這個位址就是接受微信推送事件的一個接口,我是使用thinkPHP框架開發的程序,在其中一個Module(Decoration)的Action目錄下新建一個類,例如叫:
WechatAction.class.php ,在該Action中新建一個public方法,例如叫: URLRedirect()
,那麼在這個URL中填寫的就是http://[IP]:[port]/index.php/Decoration/Wechat/UrlRedirect ,然後填寫Token,Token隨意填,EncodingAESKey要不要都行,然後點選確認,微信會往這個URL上發送一個get請求,裡麵包含很多參數,其中大部分都是讓我們自己核對這次訪問是不是微信伺服器請求的,我自己沒有驗證,他的要求是如果我們核對成功,即原樣返回get請求中的一個參數echostr,這裡的回傳不是return,也不是ajaxReturn,而使用echo,如果用thinkPHP開發的話,直接使用 echo I('echostr'); 即可。然後接口即驗證成功了。
2 帶有參數二維碼的作用
微信的帶參數二維碼有兩種,一種是臨時二維碼,一種是永久二維碼,但是永久二維碼的生成是有個數限制的,我這次要實現的功能是用戶未登錄的情況下在網站上使用產品,比如獲得某商品的詳細報價,但是又不想註冊,然而又想保存這個報價單,這個時候網頁可以產生一張二維碼,用戶只要用微信掃一掃這個二維碼,官方公眾號就會給這個用戶發送一天圖文訊息,圖文訊息點開後就是用戶剛剛獲得的報價單,而且可以隨時點擊查看並且分享給朋友進行比價。所以臨時二維碼即可正常使用。 上面是我是怎麼使用的,下面介紹一下整個互動的流程:
當用戶掃描這個二維碼,如果用戶追蹤了公眾號,用戶會直接進入與公眾號的會話頁面,微信伺服器會給我們在上一步設定的伺服器URL中推送一條訊息,其中可以攜帶一個我們自訂的參數。如果使用者未追蹤公眾號,使用者首先會跳到公眾號追蹤頁面,使用者點擊追蹤後,會直接進入公眾號的會話頁面,微信伺服器這時也會為我們設定的URL推送一個事件訊息,攜帶我們自訂參數,我們可以根據這個參數和事件類型做控制下一步動作。
######3 特定開發流程##################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
其中的參數APPID和APPSECRET是我們公眾號的APPID和APPSECRET,在微信公眾號-> 基本配置中可以查到,呼叫成功會回傳如下JSON資料:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
其中access_token就是呼叫介面憑證,expire_in是token有效時間。
我自己是把access_token存在資料庫中,同時儲存過期時間,然後封裝公用函數 getWechatAccessToken() ,每次先檢查access_token是否過期,如果過期則重新獲取,否則直接使用資料庫保存的access_token即可,我忘了在哪裡看加過,這個access_token每天的獲取次數應該是有限制的。下面是 getWechatAccessToken() 的具體實作:
1 //获取access_token 2 function getWechatAccessToken(){ 3 $wechatInfo = M('wechat_info')->select(); 4 $wechatInfo = array_reduce($wechatInfo, create_function('$result, $v', '$result[$v["conf_name"]] = $v;return $result;')); 5 $expireTime = $wechatInfo['PUBLIC_WECHAT_ACCESSTOKEN_EXPIRES']['conf_value']; //前面不用管,是我数据库相应设置 6 7 if (time() < $expireTime){ //access_token未过期 8 return $wechatInfo['PUBLIC_WECHAT_ACCESSTOKEN']['conf_value']; 9 }else{ //access_token过期,重新获取10 $baseUrl = C('WECHAT_PUBLIC_GET_ACCESS_TOKEN');11 $url = str_replace("##APPSECRET##", $wechatInfo['PUBLIC_WECHAT_APPSECRET']['conf_value'], str_replace("##APPID##", $wechatInfo['PUBLIC_WECHAT_APPID']['conf_value'], $baseUrl));12 $result = file_get_contents($url);13 $result = json_decode($result, true);14 15 if (array_key_exists('errorcode', $result)){ //失败重试一次16 return false;17 }else{18 M('wechat_info')->where(array('conf_name' => 'PUBLIC_WECHAT_ACCESSTOKEN'))->save(array('conf_value' => $result['access_token']));19 M('wechat_info')->where(array('conf_name' => 'PUBLIC_WECHAT_ACCESSTOKEN_EXPIRES'))->save(array('conf_value' => time()+$result['expires_in']-200));20 return $result['access_token'];21 }22 }23 }
C('WECHAT_PUBLIC_GET_ACCESS_TOKEN') = https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
封裝這個之後,我們每次就可以安心的使用了。
3.2 建立臨時二維碼
#3.2.1 取得ticket
#请求方式: POST 接口:https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN POST数据: {"expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
介面URL中的TOKEN即我們在3.1中取得的access_token,post資料中expire_seconds是二維碼的有效時間,最多為30天,action_name臨時二維碼的話固定就是QR_SCENE ,scene_id即我們自訂參數,是個32位元非0整數,我在應用程式中把它設為訂單的ID,微信伺服器推送事件的時候會把這個值傳回給我們設定的介面中,然後我會根據這個值去拿對應的訂單資料展示在網頁上,這是後話。
下面是封裝的產生暫存二維碼的方法:
//创建临时二维码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() 是其中的方法 api_notice_increment()
是我封裝的一個POST方法函數,我試過很多POST的方法,可能由於微信介面對POST方法和參數的限制比較嚴格,這個浪費了好久時間,最後在網上找到了一個可以使用的封裝好的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;
}
}
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"}
3.2.2 取得二維碼位址
请求方式: GET
接口:https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
3.3 使用者掃描在二維碼之後發生的事情
3.3.1 掃描後發生了什麼
######上面提到了,用户扫描我们生成的临时二维码,如果用户未关注公众号,则首先会跳转到公众号的关注页面,点击关注后,会进入公众号的会话页面,同时会给我们设置的接口推送一个事件。如果用户已经关注了,用户微信会直接跳转到公众号会话页面,然后微信服务器会给我们设置的接口推送一个事件。
用户关注与否微信服务器给我们推送的事件是差不多的,只是新关注用户推送的事件中scene_id前面会加一个前缀。下面是微信公众平台文档的说明:
用户未关注时,进行关注后的事件推送
<xml><ToUserName><![CDATA[toUser]]></ToUserName> //开发者微信号<FromUserName><![CDATA[FromUser]]></FromUserName> //发送者账号(openid)<CreateTime>123456789</CreateTime> //消息创建时间(整型)<MsgType><![CDATA[event]]></MsgType> //消息类型 event<Event><![CDATA[subscribe]]></Event> //事件类型(subscribe)<EventKey><![CDATA[qrscene_123123]]></EventKey> //事件KEY值,qrscene_为前缀,后面为二维码参数值<Ticket><![CDATA[TICKET]]></Ticket> //二维码ticke值,可以用来换取二维码图片</xml>
用户已关注时的事件推送
<xml><ToUserName><![CDATA[toUser]]></ToUserName> //开发者微信号<FromUserName><![CDATA[FromUser]]></FromUserName> //发送者账号(openid)<CreateTime>123456789</CreateTime> //消息创建时间<MsgType><![CDATA[event]]></MsgType> //消息类型event<Event><![CDATA[SCAN]]></Event> //事件类型 event<EventKey><![CDATA[SCENE_VALUE]]></EventKey> //事件key值,是一个32位无符号整数,即创建二维码时的二维码scene_id<Ticket><![CDATA[TICKET]]></Ticket> //二维码的ticke,可以用来换取二维码图片</xml>
3.3.2 我们要做些什么
我们需要在自己填写的URL接口中接收这个事件,然后拿到我们需要的东西做我们想干的事儿。因为我要实现的功能比较简单,只需要拿到scene_id即可,因为这是我要展示给用户看的订单数据。下面是我写的接收和处理部分,比较简单,主要看一下应该怎么接收微信推送的事件:
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]); } }
我没有使用其他参数,只是根据不同的推送事件拿到我想要的订单ID,然后这时候其实相当于你在这里用公众号的客服在跟扫码的这个用户对话,上段代码中调用的sendMessage()是使用客户账号给扫码用户发送一个图文消息,因为我在拿scen_id的同时也拿到了用户的openid,可以利用这个给用户发送消息。
下面是 sendMessage() 方法:
//给用户发送图文消息,点击跳转到报价页面 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,就是在组给用户发送的文字而已,需要注意$dataStr的格式,这里面要求JSON字符串比较严格,必须所有的字符串都用双引号括起来。微信接口对POST参数的限制真心严格。
下面是微信公众平台开发者文档中要求发送图文消息的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请求地址,里面携带参数是用户的openid和订单id,这样用户点击开图文消息就可以看到自己刚才下单的内容了,因为需要在网页上展示用户的微信头像和昵称,所以我把openid也放到参数里,在页面加载前先拿到用户的个人信息和订单数据,再展示网页。这样流程:用户未登录下单 -> 生成微信二维码 -> 用户扫码关注公众号 -> 查看订单详细信息 就完成了。而且因为这个图文消息打开后的链接携带的参数是这个用户的额openid和其下单的订单ID,不管分享到哪儿,用什么浏览器打开都是可以访问的,且展示的也是这个用户的头像和昵称信息,这也是我要实现的一个效果。
以上是微信開發帶參數二維碼的實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!