微信公衆號開發(四)自定義菜單
一、說明
微信的自定義菜單分爲普通菜單和個性化菜單,個性化菜單能夠根據地區、性別、語言等爲不一樣的用戶展現不一樣的菜單,定義個性化菜單以前必須定義普通菜單,刪除普通菜單則個性化菜單也會刪除,自定義菜單有如下須要注意的地方:
- 自定義菜單最多包括三個一級菜單,每一個一級菜單最多包括5個二級菜單。
- 一級菜單最多4個漢字,二級菜單最多7個漢字,多出來的部分將會以「...」顯示。
- 建立自定義菜單後,菜單的刷新策略是,在用戶進入公衆號會話頁或公衆號profile頁時,若是發現上一次拉取菜單的請求在5分鐘之前,就會拉取一下菜單,若是菜單有更新,就會刷新客戶端的菜單。測試時能夠嘗試取消關注公衆帳號後再次關注,則能夠看到建立後的效果。
本項目的目錄結構以下:
create_menu.php:建立菜單
delete_menu.php:刪除菜單
get_menu.php:查詢菜單
index.php:接收和處理微信服務器的消息
output_log.php、output_query.php、Utils.php能夠參見
微信公衆號開發(一),主要用於日誌的打印,另外Utils.php增長了兩函數,分別用於發送請求和獲取access_token
Utils.php
<?php
class Utils
{
/**
* 捕獲RUL查詢字符串到query.xml
*/
public static function traceHttp()
{
$content = date('Y-m-d H:i:s')."\n\rremote_ip:".$_SERVER["REMOTE_ADDR"].
"\n\r".$_SERVER["QUERY_STRING"]."\n\r\n\r";
$max_size = 1000;
$log_filename = "./query.xml";
if (file_exists($log_filename) and (abs(filesize($log_filename))) > $max_size){
unlink($log_filename);
}else {
}
file_put_contents($log_filename, $content, FILE_APPEND);
}
/**
* 打印日誌到log.xml
* @param $log_content:日誌內容
* @param string $type:日誌來源,默認‘用戶’
*/
public static function logger($log_content, $type = '用戶')
{
$max_size = 3000;
$log_filename = "./log.xml";
if (file_exists($log_filename) and (abs(filesize($log_filename)) >
$max_size)) {
unlink($log_filename);
}
file_put_contents($log_filename, "$type ".date('Y-m-d H:i:s')."\n\r".$log_content."\n\r",
FILE_APPEND);
}
/**
* 獲取access_token
* @return mixed
*/
public static function get_access_token()
{
$appid = "wx07fff9c79a410b69"; //需替換成你的appID
$appsecret = "092c0c0c5bd62f66b76ad241612915fb"; //需替換成你的appsecret
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&".
"appid=$appid&secret=$appsecret";
$output = Utils::https_request($url);
$jsoninfo = json_decode($output, true);
return $jsoninfo["access_token"];
}
/**
* 發送請求
* @param $url:地址
* @param null $data:post的數據
* @return mixed:請求返回的結果
*/
public static function https_request($url, $data = null)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
}
二、自定義菜單的類型
自定義菜單有8種類型:
- click:點擊推事件,點擊後彈出「獲取中...」,微信服務器會經過消息接口推送消息類型爲event的結構給開發者,並帶上按鈕中開發者填寫的key值,開發者可用此key值與用戶進行交互。
- view:跳轉URL,用戶點擊後直接打開微信瀏覽器跳轉到該URL的地址。
- scancode_push:掃碼推事件,點擊按鈕後,微信客戶端將調用「掃一掃」功能,完成掃碼後在微信瀏覽器顯示掃碼結果(若是是URL,則直接進入該URL),且會將掃碼結果傳送給開發者,此時能夠下發消息給用戶,可是用戶收不到該消息。
- scancode_waitmsg:掃碼推事件且彈出「獲取中...」提示框,用戶點擊按鈕後客戶端將調用「掃一掃」功能,將掃碼結果傳給開發者,同時收起「掃一掃」功能,而後彈出「獲取中...」提示框,隨後可能收到開發者下發的消息。
- pic_sysphoto:彈出系統拍照發圖用戶點擊按鈕後,微信客戶端將調起系統相機,完成拍照操做後,會將拍攝的相片發送給開發者,並推送事件給開發者,同時收起系統相機,隨後可能會收到開發者下發的消息。
- pic_photo_or_album:彈出拍照或者相冊發圖用戶點擊按鈕後,微信客戶端將彈出選擇器供用戶選擇「拍照」或者「從手機相冊選擇」。用戶選擇後即走其餘兩種流程。
- pic_weixin:彈出相冊發圖器用戶點擊按鈕後,微信客戶端將調起相冊,完成選擇操做後,將選擇的相片發送給開發者的服務器,並推送事件給開發者,同時收起相冊,隨後可能會收到開發者下發的消息。
- location_select:彈出地理位置選擇器用戶點擊按鈕後,微信客戶端將調起地理位置選擇工具,完成選擇操做後,將選擇的地理位置發送給開發者的服務器,同時收起位置選擇工具,隨後可能會收到開發者下發的消息。
三、建立普通自定義菜單
create_menu.php
<?php
require_once('./Utils.php');
//菜單字符串
$menujson = '{
"button": [
{
"name": "掃碼",
"sub_button": [
{
"type": "scancode_waitmsg",
"name": "掃碼帶提示",
"key": "button_0_0"
},
{
"type": "scancode_push",
"name": "掃碼推事件",
"key": "button_0_1"
}
]
},
{
"name": "發圖",
"sub_button": [
{
"type": "pic_sysphoto",
"name": "系統拍照發圖",
"key": "button_1_0"
},
{
"type": "pic_photo_or_album",
"name": "拍照或者相冊發圖",
"key": "button_1_1"
},
{
"type": "pic_weixin",
"name": "微信相冊發圖",
"key": "button_1_2"
}
]
},
{
"name": "其餘",
"sub_button": [
{
"type": "location_select",
"name": "發送位置",
"key": "button_2_0"
},
{
"type": "click",
"name": "單擊",
"key": "button_2_1"
},
{
"type": "view",
"name": "百度",
"url": "http://www.baidu.com"
}
]
}
]
}';
$url = $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="
.Utils::get_access_token();
//建立菜單
$result = Utils::https_request($url, $menujson);
//返回{"errcode":0,"errmsg":"ok"}表示成功
echo $result;
返回結果爲{"errcode":0,"errmsg":"ok"}表示成功。注意從新關注公衆號才能立刻看到效果。截圖以下:
再寫一個index.php文件來接收服務器推送的消息:
<?php
//設置時區
date_default_timezone_set("Asia/Shanghai");
//定義TOKEN常量,這裏的"weixin"就是在公衆號裏配置的TOKEN
require_once("Utils.php");
//打印請求的URL查詢字符串到query.xml
Utils::traceHttp();
$wechatObj = new wechatCallBackapiTest();
$wechatObj->responseMsg();
class wechatCallBackapiTest
{
public function responseMsg()
{
//獲取post過來的數據,它一個XML格式的數據
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
//將數據打印到log.xml
Utils::logger($postStr);
if (!empty($postStr)) {
//將XML數據解析爲一個對象
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$RX_TYPE = trim($postObj->MsgType);
//消息類型分離
switch($RX_TYPE)
{
case "event":
$result = $this->receiveEvent($postObj);
break;
case "image":
$result = $this->receiveImage($postObj);
break;
case "location":
$result = $this->receiveLocation($postObj);
break;
default:
$result = "";
break;
}
Utils::logger($result, '公衆號');
echo $result;
}else {
echo "";
exit;
}
}
/*
* 接收事件消息
*/
private function receiveEvent($object)
{
switch ($object->Event)
{
case "subscribe": //關注公衆號事件
$content = "歡迎關注微微一笑很傾城";
break;
case "unsubscribe":
$content = "";
break;
case "CLICK": //注意這裏是大寫的CLICK
$content = $object->EventKey;
break;
case "scancode_waitmsg":
sleep(2); //方便測試觀看效果
$content = $object->EventKey." ".$object->ScanCodeInfo->ScanResult;
break;
case "scancode_push":
sleep(2); //方便測試觀看效果
$content = $object->EventKey." ".$object->ScanCodeInfo->ScanResult;
break;
case "pic_weixin":
//回覆無效
//$content = $object->Event." ".$object->EventKey;
exit;
break;
case "pic_photo_or_album":
//回覆無效
//$content = $object->Event." ".$object->EventKey;
exit;
break;
case "pic_sysphoto":
//回覆無效
exit;
break;
case "location_select":
//回覆無效
//$content = "location";
exit;
break;
default:
$content = "";
break;
}
$result = $this->transmitText($object, $content);
return $result;
}
/**
* 接收圖片消息,經過MediaId回覆相同的圖片給用戶
*/
private function receiveImage($object)
{
$content = array("MediaId"=>$object->MediaId);
$result = $this->transmitImage($object, $content);
return $result;
}
/**
* 接收位置消息
*/
private function receiveLocation($object)
{
$content = "你發送的是位置,緯度爲:".$object->Location_X.";經度爲:".
$object->Location_Y.";縮放級別爲:".$object->Scale.";位置爲:".$object->Label;
$result = $this->transmitText($object, $content);
return $result;
}
/**
* 回覆文本消息
*/
private function transmitText($object, $content)
{
$xmlTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime><![CDATA[%s]]></CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), $content);
return $result;
}
/**
* 回覆圖片消息
*/
private function transmitImage($object, $imageArray)
{
$itemTpl = "<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>";
$item_str = sprintf($itemTpl, $imageArray['MediaId']);
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
$item_str
</xml>";
$result = sprintf($textTpl, $object->FromUserName, $object->ToUserName,
time());
return $result;
}
}
點擊「單擊」菜單後,直接推送了一個CLICK事件過來。
點擊「發送位置」,除開推送location_select事件過來以外,還推送一個loaction消息過來。
點擊view「百度」菜單,什麼也沒推送過來,在微信瀏覽器打開了百度網頁。
點擊「系統拍照發圖」菜單,直接彈出了相機功能,拍完照後直接發送一個圖片消息過來,沒有事件消息。
點擊「」微信相冊發圖「菜單後,直接彈出相冊,選擇2張圖片發送和,顯示發送了一個pic_weixin的事件,而後分別有發送了2個圖片消息,可分別對2個圖片消息作回覆,對事件消息回覆無效。
單擊」拍照或相冊發圖「,會彈出選擇框供用戶選擇,除了推送的事件是pic_photo_or_album外,其餘選擇以後的消息和以上兩個同樣。
單擊」掃碼帶提示「,則彈出掃碼框掃描得到結果以後,會彈出」獲取中...「,推送一個事件給開發者,稍候可能會得到開發者回覆的消息,如圖是我掃描一個百度URL的二維碼的結果,直接把掃碼結果回覆給用戶。
點擊」掃碼推事件「菜單,掃描到結果後,會推送一個事件給開發者,開發者回覆消息用戶不會接收到,若是是URL,則直接跳轉到該URL,不然顯示掃碼結果。
四、查詢自定義菜單
查詢自定義菜單接口是https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN,代碼實現以下
get_menu.php
<?php
@header('Content-type: text/plain;charset=UTF-8');
require_once('./Utils.php');
$url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=".Utils::get_access_token();
//查詢菜單
$result = Utils::https_request($url);
echo $result;
結果返回以下:
五、刪除自定義菜單
刪除自定義菜單的接口是:https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
delete_menu.php
<?php
@header('Content-type: text/plain;charset=UTF-8');
require_once('./Utils.php');
$url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=".Utils::get_access_token();
//刪除菜單
$result = Utils::https_request($url);
echo $result;
返回結果是以下表示成功:
從新關注微信號後能夠看見菜單被刪除了