在CI框架下面實現了自定義菜單功能.寫了一個model,一個類庫.順便附帶access_token的實現方式
<?php
class Makemenu{
public $menustr;
public function __construct(){
}
public function init(){
$this->dolist();
return $this->setmenu();
}
private function dolist(){
$CI =& get_instance();
$CI -> load ->model("Menu_model","menu");
$plist = $CI->menu ->isplist();
foreach($plist as $pid){
$pidarr[] = $pid['pid'];
}
$list = $CI->menu ->maketree($CI->menu->getlist());
foreach($list as $btn){
if(in_array($btn['id'],$pidarr)){
//生成不帶key和url的鏈接作為父級菜單
$btn_arr[$btn['id']] = array("type"=>$btn['menutype'],
"name"=>$btn['content']);
}elseif($btn['pid'] == 0){
//生成有操作的一級菜單
$btn_arr[$btn['id']] = array("type"=>$btn['menutype'],
"name"=>$btn['content'],
"key"=>$btn['clickkey'],
"url"=>$btn['url']);
}else{
//生成子菜單
$btn_arr[$btn['pid']]['sub_button'][] = array("type"=>$btn['menutype'],
"name"=>$btn['content'],
"key"=>$btn['clickkey'],
"url"=>$btn['url']);
}
}
$btnarr['button'] = array_values($btn_arr);
$r = $this->menustr = json_encode($btnarr,JSON_UNESCAPED_UNICODE);
return $r;
}
private function setmenu(){
$accesstoken = get_access_token();
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={$accesstoken}";
$ch = curl_init();
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_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, $this->menustr);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$info = curl_exec($ch);
if (curl_errno($ch)) {
return curl_error($ch);
}
curl_close($ch);
return $info;
}
}
上面是library裡面的內容,主要是根據數據表生成菜單的json串
<?php
class Menu_model extends CI_Model {
public $table_name;
public function __construct(){
parent::__construct();
$this->load->database();
$this->table_name = "data_menu";
}
public function query($sql){
return $this->db->query($sql);
}
public function getone($id){
$get_sql = "select * from {$this->table_name} where id = {$id}";
return $this->query($get_sql)->row();
}
public function addone($data){
if(($data['pid'] == 0)&&($this->checksum()>=3)){
//一級菜單不超過3個
return "toomany1";
}elseif(($data['pid']!=0)&&($this->checksum($data['pid']))>=7){
//二級菜單不超過7個
return "toomany2";
}
if(is_array($data)&&!empty($data)){
$keys = "`".implode("`,`",array_keys($data))."`";
$vals = "'".implode("','",array_values($data))."'";
$insert_sql = "insert into {$this->table_name} ($keys) values ($vals)";
return $this->query($insert_sql);
}else{
return false;
}
}
public function del($id){
$infos = $this->getone($id);
$del_sql = "delete from {$this->table_name} where id = {$id} and pid = {$id}";
return $this->query($del_sql);
}
private function checksum($id = ''){
if($id == ''){
$get_sql = "select count(1) as total from {$this->table_name} where pid =0";
}else{
$id = intval($id);
$get_sql = "select count(1) as total from {$this->table_name} where pid ={$id}";
}
$r = $this->db->query($get_sql)->row();
return $r->total;
}
public function getplist(){
//獲取一級菜單
$get_sql = "select * from {$this->table_name} where pid=0 order by menuorder asc";
return $this->db->query($get_sql)->result_array();
}
public function isplist(){
$get_sql = "select pid from {$this->table_name} where pid <> 0 group by pid";
return $this->db->query($get_sql)->result_array();
}
public function getlist(){
$get_sql = "select * from {$this->table_name} where 1 order by pid asc, menuorder asc";
return $this->db->query($get_sql)->result_array();
}
public function maketree($data){
$pids = array();
foreach($data as $k=>$v){
if($v['pid'] == 0){
$pids[$v['id']][] = $v;
}else{
$pids[$v['pid']][] = $v;
}
}
list($t1,$t2,$t3) = array_values($pids);
$r = array_merge_recursive(is_array($t1)?$t1:array(),is_array($t2)?$t2:array(),is_array($t3)?$t3:array());
return $r;
}
public function update($data){
if(is_array($data)&&!empty($data)){
$id = $data['id'];
unset($data['id']);
foreach($data as $k=>$v){
$update_arr[] = "`".$k."` = '".$v."'";
}
$update_fs = implode(",",$update_arr);
$update_sql = "update {$this->table_name} set {$update_fs} where id = {$id}";
return $this->query($update_sql);
}else{
return false;
}
}
}
上面是model裡面的各種方法.
數據庫的表結構如下,附創建表的語句.
CREATE TABLE `menu` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` varchar(20) DEFAULT NULL,
`pid` int(11) DEFAULT '0',
`menutype` enum('click','view','scancode_push','scancode_waitmsg','pic_sysphoto','pic_photo_or_album','pic_weixin','location_select') DEFAULT 'view' COMMENT '消息類型',
`url` varchar(200) DEFAULT NULL COMMENT '鏈接地址',
`clickkey` varchar(20) DEFAULT NULL COMMENT '事件KEY',
`menuorder` int(11) DEFAULT NULL COMMENT '排序',
`submenu` tinyint(2) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8
Field Type Comment 主鍵 id int(11) NOT NULL <ID> content varchar(20) NULL <內容> pid int(11) NULL <父類ID> menutype enum('click','view','scancode_push','scancode_waitmsg','pic_sysphoto','pic_photo_or_album','pic_weixin','location_select') NULL 消息類型 url varchar(200) NULL 鏈接地址 clickkey varchar(20) NULL 事件KEY menuorder int(11) NULL 排序 submenu tinyint(2) NULL <是否是子菜單>
下面是寫在system/core/common.php下面的獲取token的方法,其實要做一個加鹽處理,要麼會有惡心的人做惡心的事情.
function get_access_token(){
//從微信服務器獲取access_token 並保留一個小時
$old_filename = APPPATH."cache/".md5(date("YmdH",time()-3600)).".php";
@unlink($old_filename);
$filename = APPPATH."cache/".md5(date("YmdH",time())).".php";
if(is_file($filename)){
$r = include($filename);
}else{
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".APPID."&secret=".APPSECRET;
$access_token = file_get_contents($url);
$res = "<?php return ".var_export(json_decode($access_token,1),1).";";
file_put_contents($filename,$res);
$r = include($filename);
}
return ($r['access_token']);
}
前面的菜單管理就不寫了,就是管理那個表的數據,保證數據表裡面的數據沒問題即可.
在控制器裡面只需要
$this->load->library("Makemenu");
然後調用 $this->makemenu->dolist();
就會推送到微信的服務器. 還需要注意在入口文件定義兩個常量 APPID和APPSECRET .
放出來給大家,希望有用,也給我自己備份個.