php微信开发实现自定义菜单功能

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php微信开发实现自定义菜单功能相关的知识,希望对你有一定的参考价值。

首先说一下遇到的坑吧!

01我用的测试公众号,说好的有接口权限,结果呢,微信留了个坑,返回错误代码 48001 

 一查错误码 微信文档这样写:api功能未授权,请确认公众号已获得该接口,可以在公众平台官网-开发者中心页中查看接口权限

懵逼了吧!

半信半疑中,我果断换了认证过的服务号,一测试OK了

02代码的开头有空格也会报错,跟tp的机制有关,我的代码在tp下面。

03 调用接口的链接为https,结果我的服务器可能验证证书出错,最后找了半天才找到一种解决办法,就是在使用curl的部分使用如下代码:

可以通过添加一下代码解决
 curl_setopt_array(
         $ch,
         array(
            CURLOPT_URL => $url,
            CURLOPT_REFERER => $url,
            CURLOPT_AUTOREFERER => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_CONNECTTIMEOUT => 1,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_USERAGENT => ‘Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/34.0.1847.116 Safari/537.36‘,)
         );

接下来就直接上代码吧!我的代码是在tp5下的代码,单独编写不方便运行,就用的tp5

我的访问路径为:http://wexin.bsgrj.com/wexin/public/index.php/index/index/definedItem

直接在浏览器运行就可以。

  1 <?php
  2 
  3 namespace app\index\controller;
  4  
  5 use think\Controller;
  6   
  7 //define your token
  8 define("TOKEN", "weixin");
  9 
 10 Class Index extends Controller
 11 {
 12     public function index()//接收微信客户端发送的信息并回应! 
 13     {
 14         //get post data, May be due to the different environments
 15       $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];     
 16      //extract post data
 17       if (!empty($postStr)){
 18          /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
 19           the best way is to check the validity of xml by yourself */
 20           libxml_disable_entity_loader(true);
 21           $postObj = simplexml_load_string($postStr, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
 22           $fromUsername = $postObj->FromUserName;
 23           $toUsername = $postObj->ToUserName;
 24           $keyword = trim($postObj->Content);
 25           $time = time();
 26           $msgType = $postObj->MsgType;//消息类型
 27           $event = $postObj->Event;//时间类型,subscribe(订阅)、unsubscribe(取消订阅)
 28           $textTpl = "<xml>
 29           <ToUserName><![CDATA[%s]]></ToUserName>
 30           <FromUserName><![CDATA[%s]]></FromUserName>
 31           <CreateTime>%s</CreateTime>
 32           <MsgType><![CDATA[%s]]></MsgType>
 33           <Content><![CDATA[%s]]></Content>
 34           <FuncFlag>0</FuncFlag>
 35           </xml>";    
 36           switch($msgType){
 37           case "event":
 38           if($event=="subscribe"){
 39           $contentStr = "Hi,欢迎关注168php微信开发"."\n"."回复数字‘1‘,了解相关基础教程."."\n"."回复数字‘2‘,添加技术交流群.";
 40           } 
 41           break;
 42           case "text":
 43           switch($keyword){
 44           case "1":
 45           $contentStr = "相关教程:"."\n"."<a href=‘http://www.imooc.com/‘>慕课网</a>."; 
 46           break;
 47           case "2":
 48           $contentStr = "技术交流群:"."\n"." QQ群:184037581.";
 49           break;
 50           case "3":
 51           $this->singleGraphic($postObj);
 52           exit;
 53           default:
 54           $contentStr = "对不起,你的内容我会稍后回复";
 55           }
 56           break;
 57           }
 58           $msgType = "text";
 59           $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
 60           echo $resultStr;
 61       }else {
 62           echo "";
 63           exit;
 64       }
 65     }
 66     private  function singleGraphic($postObj) /**多图文回复*/
 67     {
 68       $toUser = $postObj->FromUserName;
 69       $fromUser = $postObj->ToUserName;
 70       $arr = array(
 71           array(
 72             ‘title‘=>‘imooc‘,
 73             ‘description‘=>"imooc is very cool",
 74             ‘picUrl‘=>‘http://www.imooc.com/static/img/common/logo.png‘,
 75             ‘url‘=>‘http://www.imooc.com‘,
 76           ),
 77           array(
 78             ‘title‘=>‘hao123‘,
 79             ‘description‘=>"hao123 is very cool",
 80             ‘picUrl‘=>‘https://www.baidu.com/img/bdlogo.png‘,
 81             ‘url‘=>‘http://www.hao123.com‘,
 82           ),
 83           array(
 84             ‘title‘=>‘qq‘,
 85             ‘description‘=>"qq is very cool",
 86             ‘picUrl‘=>‘http://www.imooc.com/static/img/common/logo.png‘,
 87             ‘url‘=>‘http://www.qq.com‘,
 88            ),
 89       );
 90       $template = "<xml>
 91               <ToUserName><![CDATA[%s]]></ToUserName>
 92               <FromUserName><![CDATA[%s]]></FromUserName>
 93               <CreateTime>%s</CreateTime>
 94               <MsgType><![CDATA[%s]]></MsgType>
 95               <ArticleCount>".count($arr)."</ArticleCount>
 96               <Articles>";
 97       foreach($arr as $k=>$v){
 98           $template .="<item>
 99                 <Title><![CDATA[".$v[‘title‘]."]]></Title> 
100                 <Description><![CDATA[".$v[‘description‘]."]]></Description>
101                 <PicUrl><![CDATA[".$v[‘picUrl‘]."]]></PicUrl>
102                 <Url><![CDATA[".$v[‘url‘]."]]></Url>
103                 </item>";
104        }
105        $template .="</Articles>
106           </xml> ";
107        echo sprintf($template, $toUser, $fromUser, time(), ‘news‘);
108     }
109     private function checkSignature()//验证服务器
110     {
111          // you must define TOKEN by yourself
112         if (!defined("TOKEN")) {
113           throw new Exception(‘TOKEN is not defined!‘);
114         }  
115         $signature = $_GET["signature"];
116         $timestamp = $_GET["timestamp"];
117         $nonce = $_GET["nonce"]; 
118         $token = TOKEN;
119         $tmpArr = array($token, $timestamp, $nonce);
120          // use SORT_STRING rule
121         sort($tmpArr, SORT_STRING);
122         $tmpStr = implode( $tmpArr );
123         $tmpStr = sha1( $tmpStr );  
124         if( $tmpStr == $signature ){
125          return true;
126         }else{
127          return false;
128         }
129     }
130     public function http_curl($url,$type=‘get‘,$res=‘json‘,$arr=‘‘)//接口调用函数
131     {
132         /*
133         *$cur 接口url string
134         *$type 请求类型 string
135         $res   返回数据类型 string
136         $arr  post请求参数 string
137         */
138        //1.初始化curl
139        $ch=curl_init();
140        //2.设置curl的参数
141       // curl_setopt($ch, CURLOPT_URL, $url);
142       // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
143        
144         curl_setopt_array(
145          $ch,
146          array(
147             CURLOPT_URL => $url,
148             CURLOPT_REFERER => $url,
149             CURLOPT_AUTOREFERER => true,
150             CURLOPT_RETURNTRANSFER => true,
151             CURLOPT_SSL_VERIFYPEER => false,
152             CURLOPT_SSL_VERIFYHOST => false,
153             CURLOPT_CONNECTTIMEOUT => 1,
154             CURLOPT_TIMEOUT => 30,
155             )
156          );
157        
158        if($type==‘post‘){
159             curl_setopt($ch, CURLOPT_POST, 1);
160             curl_setopt($ch, CURLOPT_POSTFIELDS, $arr);
161         //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//测试
162        // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//测试
163       
164        }
165        //3.采集
166        $output=curl_exec($ch);
167        //4.关闭
168        if($res==‘json‘){
169            if(curl_error($ch)){
170                return curl_error($ch);
171              curl_close($ch);
172            }else{
173                return json_decode($output,true);    
174            }
175        } 
176     }
177     public function getWxAccessToken()//返回access_token *session解决办法 ,存mysql或memcache都可以
178     {
179         //将access_token 存在session/cookie中
180         if(isset($_SESSION[‘access_token‘])&&isset($_SESSION[‘expire_time‘])){
181             if($_SESSION[‘access_token‘]&&$_SESSION[‘expire_time‘]>time()){
182             //如果access_token在session中并没有过期
183             return $_SESSION[‘access_token‘];
184             }
185         }
186         else{
187             //如果access_token不存在或者已经过期,重新取access_token
188             $appid=‘wx4e91a0e959b399a5‘;
189             $appsecret=‘46cf302c8ff3585026682f6ae603da94‘;
190             $url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$appsecret;
191             $res=$this->http_curl($url,‘get‘,‘json‘);
192             $access_token=$res[‘access_token‘];
193             $_SESSION[‘access_token‘]=$access_token;
194             $_SESSION[‘expire_time‘]=time()+7000;
195             return $access_token;
196         }
197     }
198     public function definedItem()//创建微信菜单
199     {
200        //目前微信接口的调用方式都是通过curl post/get
201         header(‘content-type:text/html;charset=utf-8‘);
202         echo $access_token=$this->getWxAccessToken();
203         echo $url="https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$access_token;
204         $postArr=array(
205          ‘button‘=>array(
206              array( 
207                      ‘name‘=>urlencode(‘科技力量‘),
208                      ‘type‘=>‘view‘,
209                       ‘url‘=>‘https://m.eqxiu.com/s/4Z7xqPHv‘,
210              ),//第一个一级菜单
211              array(
212                    ‘name‘=>urlencode(‘公司官网‘),
213                 ‘type‘=>‘view‘,
214                 ‘url‘=>‘http://m.yztsaas.com‘,
215              ),//第二个一级菜单
216              array(
217                   ‘name‘=>urlencode(‘下载APP‘),
218                 ‘type‘=>‘view‘,
219                 ‘url‘=>‘http://qrt.huilinchina.com/Home/Index/download‘,
220              ),//第三个一级菜单
221 
222         ));
223         $postJson=urldecode(json_encode($postArr));//数组转换为json
224         //var_dump($postJson);
225         $res=$this->http_curl($url,‘post‘,‘json‘,$postJson);
226         var_dump($res);
227     }
228    
229 
230 }

接下来,开发微信卡包电子会员!加油!耽误10天左右了,入了好多坑,真心累!

以上是关于php微信开发实现自定义菜单功能的主要内容,如果未能解决你的问题,请参考以下文章

最全面 think php 实现微信公众号回复编号进行投票,自定义菜单功能

微信公众平台开发教程自定义菜单

微信公众平台开发教程自定义菜单

夺命雷公狗---微信开发17----自定义菜单的事件推送,响应菜单的CLICK

玩玩微信公众号Java版之四:自定义公众号菜单

夺命雷公狗---微信开发15----编写进行创建自定义菜单