您现在的位置是:网站首页 > 心得笔记

微信公众号开发——自定义菜单

盛悦2019-02-19526人围观
简介自定义菜单,它也是微信公众平台开发中使用最多的,就是在微信交互页面上显示的底部有三个菜单,就目前情况而言,一级菜单可以有3个、 二级菜单不能超过5个。 内容可以根据自己的情况自定义。比如说二级菜单可以定义成url的跳转、关键字回复

1、自定义菜单注意点:

  •   自定义菜单最多包含3个一级菜单,每个一级菜单最多包含5个二级菜单。

  •  一级菜单最多展示4个汉字,二级菜单最多展示7个汉字,多出来的部分将会以...代替。

  • 修改自定义菜单后由于缓存原因(24小时),可能不能立刻显示出来。测试时可以尝试取消关注公众号再次关注,则可以看到修改后的效果。
       

2、自定义菜单——按钮类型click和view

  •  click:点击推事件 用户点击click类型按钮后,key会随着事件推传递到第三方开发的url上。微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;

  •  view :跳转url用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的网页URL,可与网页授权获取用户基本信息接口结合,获得用户基本信息。


3、创建自定义菜单
    官方链接https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013
    
    3.1、申请微信提供的测试账号
    创建接口基于我们认证后的服务号(非订阅号,订阅号满足不了我们这里的需求)。我这里并不是使用真正的服务号,而是基于微信自己提供的测试账号,测试账号功能跟微信认证的服务号相比较,大部分能满足。
    开发者工具->公众平台测试账号 申请测试账号(注意:这里申请的是一个新的账号,不同于之前订阅号,所以appid appsecret都不一样了),配置测试账号信息,我还是按照之前订阅号配置的   

   

    3.2、代码实现自定义菜单

<?php
namespace App\Http\Controllers\Front;
use App\Http\Controllers\Controller;
use App\Model\Admin\Test;
use Illuminate\Http\Request;


class TestController extends Controller {
    
    public function api()
    {
        $echoStr = isset($_GET["echostr"]) ? $_GET["echostr"] : '';
        if (!empty($echoStr) && $this->checkSignature()) {
            echo $echoStr;
            exit;
        } else {
            $postStr = file_get_contents("php://input", 'r');
            //写入日志  在同级目录下建立php_log.txt
            error_log(var_export($postStr,1),3,'php_log.txt');

            if (!empty($postStr)){
                libxml_disable_entity_loader(true);
                $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                

                //自定义菜单的事件推送
                if (strtolower($postObj->Event) == 'click') {
                    if (strtolower($postObj->EventKey) == 'item1') {
                        $content = '这是item1菜单的事件推送';
                    }
                    if (strtolower($postObj->EventKey) == 'songs') {
                        $content = '这是歌曲菜单的事件推送';
                    }
                    $test->responseText($postObj,$content);
                }

                //如果自定义菜单中的event->view
                if (strtolower($postObj->Event) == 'view') {
                    $content = '跳转链接是'.$postObj->EventKey;
                    $test->responseText($postObj, $content);

                }
            } else {
                echo "";
                exit;
            }
        }

    }



    //检查签名
    private function checkSignature()
    {
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
        $token = "weixin";
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);
        if($tmpStr == $signature){
            return true;

        }else{
            return false;
        }
    }

    
     
     /**
     * $url  接口url     string
     * $type 请求类型     string
     * $res  返回数据类型  string
     * $arr  post请求参数 string
     */
      public function http_curl ($url, $type='get', $res='json', $arr='') {
        //1、curl初始化
        $ch = curl_init();

        //2、设置参数
        curl_setopt($ch, CURLOPT_URL, $url);//设置url
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//将抓取的数据返回
        if ($type == 'post') {
            curl_setopt($ch, CURLOPT_POST, 1);//定义是post请求
            curl_setopt($ch, CURLOPT_POSTFIELDS, $arr);//$arr是从第三方传过来的json 也可能是 数组
        }

        //3、调用接口
        $output = curl_exec( $ch );

        //4、关闭curl
        if ($res == 'json') {
          if (curl_errno( $ch )) {//请求失败,返回错误信息
            return curl_error( $ch );
          } else {//请求成功,json结果转为数组
            return json_decode($output, true);
          }
        }
        curl_close($ch);
      }

      //获取access_token 存储在session中 并返回
      public function getWxAccessToken () {
          if (!empty(session('access_token')) && session('expire_time') > time()) {//如果session中存在access_token并且过期时间大于当前时间
              return session('access_token');
          } else {
              $appid     = 'wx9886cbdb96107XXX';
              $appsecret = 'cf51fd33152723d3408420fea54faXXX';
              $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appid . '&secret=' . $appsecret;
              $res = $this->http_curl($url, 'get', 'json', '');
              $access_token = $res['access_token'];
              //将重新获取到的access_token存到session中
              session(['access_token'=> $access_token]);
              session(['expire_time'=> time() + 7200]);
              return $access_token;
          }
      }


    //创建微信菜单
      public function definedItem () {
          //设置header头 可使乱码消失
          header('content-type:text/html;charset=utf-8');
          //目前微信接口的调用方式都是curl post/get
          $access_token = $this->getWxAccessToken();
          $url = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token=' . $access_token;
          $postArr = array(//菜单格式严格按照官方文档来
              'button' => array(
                  array(
                      'name' => urlencode('菜单一'),
                      'type' => 'click',
                      'key'  => 'item1',
                  ),//第一个一级菜单
                  array(
                      'name' => urlencode('菜单二'),
                      'sub_button' => array(
                          array(
                             'name'  => urlencode('歌曲'),
                             'type'  => 'click',
                              'key'  => 'songs',
                          ),//第一个二级菜单
                          array(
                              'name' => urlencode('电影'),
                              'type' => 'view',
                              'url'  => 'http://www.baidu.com',
                          ),//第二个二级菜单
                      ),
                  ),//第二个一级菜单
                  array(
                      'name' => urlencode('菜单三'),
                      'type' => 'view',
                      'url' => 'http://www.qq.com',
                  ),//第三个一级菜单
              ),
          );
          $postJson = urldecode(json_encode($postArr));//中文在json中展示变成其他字符
          $res = $this->http_curl($url, 'post', 'json', $postJson);     
      }
    }


Test.php模型

<?php
namespace App\Model\Admin;
use Illuminate\Database\Eloquent\Model;

class Test extends Model
{
    //回复单文本的微信消息
    public function responseText ($postObj, $content) {
        $fromUsername = $postObj->FromUserName;
        $toUsername = $postObj->ToUserName;
        $time = time();
        $template = "<xml>
                               <ToUserName><![CDATA[%s]]></ToUserName>
                               <FromUserName><![CDATA[%s]]></FromUserName>
                               <CreateTime>%s</CreateTime>
                               <MsgType><![CDATA[%s]]></MsgType>
                               <Content><![CDATA[%s]]></Content>
                               </xml>";
        $msgType = "text";
        $resultStr = sprintf($template, $fromUsername, $toUsername, $time, $msgType, $content);
        echo $resultStr;
    }
}


演示效果图:

w2(2).png


4、自定义菜单中的事件推送
    自定义菜单时间推送有两种形式:

  • click:单击时 发送事件推送到我们第三方开发者填写的url地址上

  • view:当我们菜单是url地址跳转时,它也会推送事件到我们填写的第三方开发者的url地址上
           

具体代码已经写在上面了!参考之~~~   


此例有坑:
        问题1:你在编写时可能会遇到问题Protocol https not supported or disabled in libcurl
        解决方法:网址url前面有一个空格,去掉就正常了
        
        问题2:中文乱码问题
        解决方法:在中文处,使用urlencode(),将字符串以URL编码,用于编码处理;再设置header头 可使乱码消失 header('content-type:text/html;charset=utf-8');