那么微信公众平台订阅号和服务号有什么区别呢?看看官方的解释:http://www.5icool.org/a/201308/a2086.html
因此,在使用自定义菜单之前,必须先申请获得服务号的权限,这个审核经过实践需要一周的时间,而且最近好像这方面的审核管理的比较松,只要合理的申请都能通过。
进入正题,我们先来看看创建自定义菜单的步骤和原理:
1.注册公众号、开通开发者模式时,平台将提供两个参数APPID、APPSECRET(订阅号不提供这两项参数)
2.自定义菜单前,必须先向平台申请一个使用凭证(AccessToken),方法如下:
用GET方式读取URL https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
其中:APPID,APPSECRET 用实际参数值代入
返回结果是一个JSON格式的文本,其中有AccessToken. (JSON是一种数据交换格式,不了解的同学要从头学一下才能明白)
AccessToken不是永久有效的,返回结果中有一个失效时间,即过了XX秒后(一般是两个小时),AccessToken就会失效。
3.获得有效的AccessToken后,就可以进行自定义菜单的创建、删除操作了
3.1 创建菜单
用POST方式向这个URL提交菜单定义数据, URL:https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
其中:ACCESS_TOKEN 用实际参数值代入
菜单定义数据是一个JSON格式的文本 (开发文档讲得不是那么清晰,让我理解了好一会),做为POST方式的提交数据
返回结果是一个JSON格式的文本,其中有操作成功码和出错信息
3.2 删除菜单
用GET方式读取URL https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
其中:ACCESS_TOKEN 用实际参数值代入
返回结果是一个JSON格式的文本,其中有AccessToken. (JSON是一种数据交换格式,不了解的同学要从头学一下才能明白)
AccessToken不是永久有效的,返回结果中还有一个失效时间,即过了XX秒后(一般是两个小时),AccessToken就会失效。
上述过程需要开发者非常了解HTTP协议细节和JSON数据格式,这里,我将编码、测试没问题的核心代码贴在这里,供自己以后翻看,也希望对大家有用:
<?php
header('Content-Type: text/html; charset=UTF-8');
include_once("config.inc"); //包含系统配置文件
require_once 'dbop.inc'; //包含数据库操作
$mydb=new dbUtil; //数据库操作类
class Weixin
{
public $token;//token
public $debug;//是否debug的状态标示,方便我们在调试的时候记录一些中间数据
public $setFlag;
public $msgtype; //('text','image','location')
public $msgevent;
public $EventKey;
public $msg;
function __construct(){
$this->debug = true;//是否debug的状态标示,方便我们在调试的时候记录一些中间数据
$this->setFlag = false;
$this->msgtype = 'text'; //('text','image','location')
$this->msg = array();
$this->token = "******"; //token ,共六位
$this->__getMsg();
$this->__createMenu();
}
function __destruct(){
}
public function __getMsg(){
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if (!empty($postStr)) {
$this->msg = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$this->msgtype = strtolower($this->msg['MsgType']);
if($this->msgtype=='event'){
$this->msgevent=$this->msg['Event'];
$this->EventKey=$this->msg['EventKey'];
}
}
}
//回复文本消息
public function __makeText($text=''){
$CreateTime = time();
$FuncFlag = $this->setFlag ? 1 : 0;
$textTpl = "<xml>
<ToUserName><![CDATA[{$this->msg['FromUserName']}]]></ToUserName>
<FromUserName><![CDATA[{$this->msg['ToUserName']}]]></FromUserName>
<CreateTime>{$CreateTime}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>%s</FuncFlag>
</xml>";
return sprintf($textTpl,$text,$FuncFlag);
}
//根据数组参数回复图文消息
public function __makeNews($item=array(),$flag){
$CreateTime = time();//其他数据貌似不好使 如$item['dateAndTime']
$FuncFlag = $this->setFlag ? 1 : 0;
$newTplHeader = "<xml>
<ToUserName><![CDATA[{$this->msg['FromUserName']}]]></ToUserName>
<FromUserName><![CDATA[{$this->msg['ToUserName']}]]></FromUserName>
<CreateTime>{$CreateTime}</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>%s</ArticleCount><Articles>";
$newTplItem = "<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>";
$newTplFoot = "</Articles>
<FuncFlag>%s</FuncFlag></xml>";
$Content = '';
$Content.= sprintf($newTplItem,$item['title'],$item['content'],'http://www.goldcjc.com/upload_file/'.$item['picurl'],$item['url']);
$itemsCount=1;
$header = sprintf($newTplHeader,$itemsCount);
$footer = sprintf($newTplFoot,$FuncFlag);
return $header.$Content.$footer;
}
public function __reply($data){
if ($this->debug) {
$this->__write_log($data);
}
echo $data;
}
public function __valid(){
if ($this->__checkSignature()) {
if( $_SERVER['REQUEST_METHOD']=='GET' )
{
echo $_GET['echostr'];
exit;
}
}else{
exit;
}
}
private function __checkSignature(){
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$tmpArr = array($this->token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
public function __write_log($log){
$oldmask = @umask(0);
$fp = @fopen("weixinlog.log","w");
@flock($fp, 3);
if(!$fp) {
return false;
}
else {
@fwrite($fp,$log);
@fclose($fp);
@umask($oldmask);
return true;
}
}
public function __getNewsFromDb($condition='',$mydb){
$result = $mydb->execute($condition);
if(mysql_num_rows($result)) {
if($post = mysql_fetch_array($result,MYSQL_ASSOC)) {
return $post;
} else {
return '';
}
}else {
return '';
}
}
public function __createMenu(){
$APPID="******************";
$APPSECRET="********************************";
$TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$APPID."&secret=".$APPSECRET;
$json=file_get_contents($TOKEN_URL);
$result=json_decode($json,true);
$ACC_TOKEN=$result['access_token'];//跟token不是一个概念,位数都不同
$data='{
"button":[
{
"name":"菜单一",
"sub_button":[
{
"type":"click",
"name":"项一",
"key":"CJSJGB"
},
{
"type":"click",
"name":"项二",
"key":"MRSJJD"
},
{
"type":"click",
"name":"项三",
"key":"CJPL"
}]
},
{
"name":"菜单二",
"sub_button":[
{
"type":"click",
"name":"项一",
"key":"KHYL"
},
{
"type":"click",
"name":"项二",
"key":"KHHK"
},
{
"type":"click",
"name":"项三",
"key":"ZTHD"
}]
},
{
"name":"菜单三",
"sub_button":[
{
"type":"click",
"name":"项一",
"key":"KHCX"
},
{
"type":"click",
"name":"项二",
"key":"HQBJ"
},
{
"type":"click",
"name":"项三",
"key":"YNJD"
}]
}]
}';
$MENU_URL="https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$ACC_TOKEN;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $MENU_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_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)) {
return curl_error($ch);
}
curl_close($ch);
return $tmpInfo;
}
}
?>
<?php
$weixin=new Weixin;
$reply="";
$selectFlag=0;
$type = $weixin->msgtype;//消息类型
$msgevent = $weixin->msgevent;//消息事件
$eventkey = $weixin->EventKey;//事件键值
$username = $weixin->msg['FromUserName'];//哪个用户给你发的消息,这个$username是微信加密之后的,但是每个用户都是一一对应的
if ($type==='text') {
$reply = $weixin->__makeText("未搜索到相应资源\n谢谢您的宝贵提醒!\n我们会尽快弥补不足!");
}elseif ($type==='location') {
$reply = $weixin->__makeText("未搜索到相应资源\n谢谢您的宝贵提醒!\n我们会尽快弥补不足!");
}elseif ($type==='image') {
$reply = $weixin->__makeText("未搜索到相应资源\n谢谢您的宝贵提醒!\n我们会尽快弥补不足!");
}elseif ($type==='voice') {
$reply = $weixin->__makeText("未搜索到相应资源\n谢谢您的宝贵提醒!\n我们会尽快弥补不足!");
}elseif ($type==='event') {
if ($msgevent=='subscribe'){//订阅
$reply = $weixin->__makeText("谢谢您的关注!");
}elseif ($msgevent=='unsubscribe'){//取消订阅,用户收不到任何信息
}elseif ($msgevent=='CLICK'){
if($eventkey=="CJSJGB"){
$query="SELECT * FROM calendar ORDER BY 'dateAndTime' DESC LIMIT 0 , 10";
$selectFlag=0;
}elseif($eventkey=="MRSJJD"){
$query="SELECT * FROM datainterpretation ORDER BY 'dateAndTime' DESC LIMIT 0 , 1";
$selectFlag=1;
}elseif($eventkey=="CJPL"){
$query="select * from comment order by 'dateAndTime' desc LIMIT 0 , 1";
$selectFlag=2;
}elseif($eventkey=="KHYL"){
$query="select * from present order by 'dateAndTime' desc LIMIT 0 , 1";
$selectFlag=3;
}elseif($eventkey=="KHHK"){
$query="select * from feedback order by 'dateAndTime' desc LIMIT 0 , 1";
$selectFlag=4;
}elseif($eventkey=="ZTHD"){
$query="select * from activity order by 'dateAndTime' desc LIMIT 0 , 1";
$selectFlag=5;
}elseif($eventkey=="KHCX"){
$query="select * from query LIMIT 0 , 1";
$selectFlag=6;
}elseif($eventkey=="HQBJ"){
$query="select * from background LIMIT 0 , 1";
$selectFlag=7;
}elseif($eventkey=="YNJD"){
$query="select * from problem LIMIT 0 , 1";
$selectFlag=8;
}
$postStr=$weixin->__getNewsFromDb($query,$mydb);
$reply = $weixin->__makeNews($postStr,$selectFlag);
}
}
$weixin->__reply($reply);
?>