精华内容
参与话题
问答
  • 本文实例讲述了微信公众平台开发之微信开发集成的使用。分享给大家供大家参考,具体如下: 背景  这几天又在接触微信PHP方面的开发,认为之前写的文章确实有些乱,刚好发现了一个不错的集成(看原始代码,出自...
  • 一款完整的php微信开发类,一款完整的php微信开发类,一款完整的php微信开发类
  • 主要介绍了PHP微信开发之二维码生成,本文使用微信接口实现二维码的生成,并直接给出示例代码,需要的朋友可以参考下
  • 背景:这几天又在接触微信PHP方面的开发,认为之前写的文章确实有些乱,刚好发现了一个不错的集成(看原始代码,出自“云知梦军哥”,不算打广告,只是尊重别人的开发成果,谢谢),里面涉及了非常全面的函数,在...

    背景

      这几天又在接触微信PHP方面的开发,认为之前写的文章确实有些乱,刚好发现了一个不错的集成类(看原始代码,出自“云知梦军哥”,不算打广告,只是尊重别人的开发成果,谢谢)里面涉及了非常全面的函数,在此针对我自己的实际使用过程简单的描述一下希望能给同道小白们一个诚恳的引导 ...

      框架:ThinkPHP 3.2.3

    前期准备:

    ①.微信公众平台的配置

    这里不赘述,具体的可以参考我前面所写的1、2章,个人认为还是比较全面的

    ②. 将文件 Weixin.class.php 放在对应的 library 目录中

    不过本人人开发是基于 ThinkPHP 框架,如果使用了其它的方式,注意更改引用路径,相信还是较为容易的,参考截图如下:

    ③. 对应的数据库中需要新建一个表

    当然,后期优化可以考虑去掉或自行设计,在这里个人觉得比较合理,也方便自己测试(公众号在线接口调试工具)

    ④. 此表是用来微信授权时自动存储公众号信息及其token 获取时间

    而对应操作此表的代码位于 Weixin.class 中的 getaccesstoken()方法,

    如果不是采用的 ThinkPHP 框架,可针对此方法中的 sql 语句进行替换截取部分代码可供参考

    一.开发者模式配置

    ①. 参考配置截图

    ②. 注意匹配对应目录以及令牌

    /**
     * 微信开发配置控制器
     * Class WeixinController
     * @package M\Controller
     */
    class WeixinController extends Controller
    {
        public function index()
        {
            import('Org.Wechat.Weixin');
            //参数传值 token、AppID、AppSecert
            $wechat = new \Weixin('zxxxi', 'wxxxxxxxxx89', 'efxxxxxxxxxxxxxxxxxxxxxxxb7');
            if (!isset($_GET['echostr'])) {
                //TODO 调用响应消息函数 自动回复
                $wechat->responseMsg();
            } else {
                //实现网址接入,调用验证消息函数
                $wechat->valid();
            }
        }
    }

    ③. 必要文件上传

        微信公众平台近期发现规定需要在相应域名的根目录下上传文件,具体可从公众号下载。

     

    二. 请求授权登录,获取微信用户信息

    ①. 代码参考

        下面是本人摘抄并精简的部分代码,具体的业务逻辑需要自己相应进行补充或删减

    import('Org.Wechat.Weixin');
    //参数传值 token、AppID、AppSecert
    $wechat=new \Weixin('zxxxxi','wxxxxxxxxxxxxx9','efxxxxxxxxxxxxxxxxxxxxxxxxxxxx7');
    //可理解为这是当下的链接地址
    $url = "http://www.xxxxx.com".$_SERVER['REQUEST_URI'];
    //TODO 判断 memcache是否有值,是否过期 (此处只是一个判断举例)
    if(!S(session('XXXNAME').'_NAMEID')){
       if(!$_GET['code']){
          $redirect_uri = $url;
          $urls=$wechat->getOauthRedirect($redirect_uri);
          header("Location:".$urls);
          die;
       }
    }
    $reT=$wechat->getOauthAccessToken();
    //TODO 如果获得 token值
    if($reT){
       $openid = $reT['openid'];
       $user_info = $wechat->getOauthUserinfo($reT['access_token'],$openid);
       //查询数据库是否存在
       $userData = M('users')
          ->where("openid = '$openid'")
          ->Field('user_id,user_name,abnormal')
          ->find();
       if ($userData['user_id']) {
          //执行操作 或者跳转页面
          header("Location:???????");
       }else{
          //没有帐号需要转到用户名填写页面来完成授权
          $maxuid = M('users')->max('user_id');
          $user['openid'] = $openid;
          $user['nickname'] = $user_info['nickname'];
          $user['sex'] = $user_info['sex'];
          $user['reg_time'] = time();
          $user['user_img'] = $user_info['headimgurl'];
          //TODO 进行新用户的添加
          $addTag = add('users',$user);
       }
    }else{
    //重新跳转,或其他操作...
    }

    ②. 手机微信端登录对应链接的结果

     

    ③. 补充说明

    $user_info = $wechat->getOauthUserinfo($reT['access_token'],$openid);

       此处返回的$user_info 为授权用户的详细信息,可追踪方法查看源代码中 OAUTH_USERINFO_URL 的定义开发者文档有介绍其意义,之前的两篇文章里也做了简单介绍

    三、微信端分享功能

    ①. 配置微信分享相应数据

    下面的方法个人设计面向对象时是在继承的 Controller 构造函数中初始化调用的,大家可以按自己需求放置

    /**
     * 配置微信分享功能
     */
    public function getWxShare(){
        import('Org.Wechat.Weixin');
        $wechat=new \Weixin('zxxxxi','wxxxxxxxxxxxx9','efxxxxxxxxxxxxxxxxxxb7');
        $url = "http://www.xxxxxmi.com".$_SERVER['REQUEST_URI'];
        $res = $wechat->getJsSign($url);
        $res['wxurl'] = $url;
        $this->assign('wx',$res);
    }

    ②. 前台页面的配置信息

    多数就是 html 前台文件,补充如下的 js 代码,具体的数据可自己修改

    <script src="http://res.wx.qq.com/open/js/jweixin-1.1.0.js" type="text/javascript"></script>

    <script>
        /**
         * Created by 百鬼夜行 on 2017/4/27.
         */
        //通过config接口注入权限验证配置
        wx.config({
            debug : false,
            appId : "{$wx.appid}",
            timestamp : "{$wx.timestamp}",
            nonceStr : "{$wx.noncestr}",
            url : "{$wx.url}",
            signature : "{$wx.signature}",
            jsApiList : ['onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo']
        });
        wx.ready(function(){
            //朋友圈
            wx.onMenuShareTimeline({
                title : "真米如初:美好的东西 如期相遇 值得期待",  // 分享标题
                link : "{$wx.wxurl}",  // 分享链接
                desc : "关注饮食,品质生活。您的健康,是我们最好的坚持,有真米,生活才够美!",  //分享描述
                imgUrl : "http://img.52zhenmi.com/Public/upload/20170426/149321008494428.jpg", // 分享图标
            });
            //发送给好友
            wx.onMenuShareAppMessage({
                title : "真米如初:美好的东西 如期相遇 值得期待",  // 分享标题
                link : "{$wx.wxurl}",  // 分享链接
                desc : "关注饮食,品质生活。您的健康,是我们最好的坚持,有真米,生活才够美!",  //分享描述
                imgUrl : "http://img.52zhenmi.com/Public/upload/20170426/149321008494428.jpg", // 分享图标
            });
            //QQ好友
            wx.onMenuShareQQ({
                title : "真米如初:美好的东西 如期相遇 值得期待",  // 分享标题
                link : "{$wx.wxurl}",  // 分享链接
                desc : "关注饮食,品质生活。您的健康,是我们最好的坚持,有真米,生活才够美!",  //分享描述
                imgUrl : "http://img.52zhenmi.com/Public/upload/20170426/149321008494428.jpg", // 分享图标
            });
            //腾讯微博
            wx.onMenuShareWeibo({
                title : "真米如初:美好的东西 如期相遇 值得期待",  // 分享标题
                link : "{$wx.wxurl}",  // 分享链接
                desc : "关注饮食,品质生活。您的健康,是我们最好的坚持,有真米,生活才够美!",  //分享描述
                imgUrl : "http://img.52zhenmi.com/Public/upload/20170426/149321008494428.jpg", // 分享图标
            });
        });
    </script>

    ③. 最终实现的效果如下

    补充提醒:

    (1).首先要保证开发配置信息的准确性

    (2).有时会出现token令牌失效的情况,注意本地测试时很可能会影响线上,应该就是获取新的令牌使得线上的数据库中不对应,注意一下。

    (3).分享页面的操作,为了方便处理可能出现的失败情况,可以先用调试模式将wx.config中的 debug值更改为true,待正确无误后再改回来。针对具体的报错信息需要查询微信开发者文档,相信每一个想走程序猿道路的人,都会强制习惯补坑填坑 ...

    debug : true,

    四、公众号发送消息

    可用于简单消息的发送,比如用户购物完成后对公众号管理员的消息提醒等.

    ①. 前提

    所要发送信息的用户关注了当前的公众号

    ②. 代码举例

    /**
     * 此方法不支持 图片发送 注意文字的换行显示
     */
    public function postMsg(){
        import('Org.Wechat.Weixin');
        $wechat=new \Weixin('zxxxxi','wxxxxxxxxxx9','efxxxxxxxxxxxxxxxxxxxxxxxxxb7');
        $content = "微信公众号发送:\n";
        $content .= "人生如戏,我们以为可以改变自己的命运,却没想到我们的结局早已注定。\n无论怎么做都摆脱不了戏里既定的安排,可谓殊途同归。";
        $content .= "如此看来,我们的拼搏和挣扎就像小丑在跳舞,徒惹人发笑罢了。";
        //TODO 微信用户唯一标记-openID 前提是对方已经关注公众号
        $wxOpenID = "oIaCOxxxxxxxxxxxxxxxxxxxxFe0";
        $wechat->postMaggerToUser($wxOpenID,$content);
    }

    ③. 实现效果


    五、公众号自动回复

    功能主要用于用户操作公众号时的触发事件处理,比如关注时的消息发送、按钮点击的监听等

    ①. 主要的配置

    其实来源于上面第一节对开发者模式的配置,而举例代码中 WeixinController 的 index()重要的就是那不到十行的代码

    ②. 监听响应消息的函数

    监听响应消息的函数为 Weixin.class 中的 responseMsg(),对于其中详细的数据处理可根据不同的触发事件路径进行代码的修改

        

    ③. 举例:关注公众号后的消息发送

    ④. 举例:

    根据用户的输入进行消息的自动回复,代码实际开发中可根据获得的文字进行项目数据库中的文字匹配,此处简单演示即可。


    ⑤. 效果实现截图

      

    附录

    因为集成的微信类代码偏多,不在此粘贴,可从下面的链接进行下载参考    

    ①. 前期文章参考

    获取用户Openid及个人信息

    参考文章二:微信端分享功能

    ②. 源代码

    源代码下载 >>>

    展开全文
  • 为大家介绍比较完整的微信开发php代码,封装成一个微信接口,验证服务器地址有效性,接收微信服务器发送POST请求到开发者服务器,携带的XML数据包,获取接收消息中的参数内容,聚合数据-获取最新趣图。
  • 微信公众号开发 PHP类

    2018-08-22 11:33:33
    1、AccesstokenService.class.php 微信token(生成微信access_token、微信js ticket 并保存到数据库,过期将重新生成) 2、Wechat.class.php 微信公众平台PHP-SDK 封装了公众号的全部功能,几行代码调用完成复杂...
  • php微信开发之二维码生成
  • 很简单的方法获取微信openid 可用于微信登陆网页等操作。php 微信开发获取 Openid 封装
  • PHP微信API接口

    2020-10-21 16:29:15
    很全面详细的PHP微信API接口,帮助大家更好的进行php微信开发,感兴趣的小伙伴们可以参考一下
  • 本文实例为大家分享了微信开发php代码,供大家参考,具体内容如下 <?php //封装成一个微信接口 class WeixinApi { private $appid; private $appsecret; //构造方法 初始化赋值 public function __...
  • 自己开发一套微信支付接口(SDK)是子恒老师《子恒说微信开发》视频教程的第15部。详细讲解了用php开发一套自己的微信支付接口。内容包含微信支付开发思路,基础开发,微信支付接口应用,公众号发红包,企业付款等等...
  •   ... 2、用户回复wz9,1,腾讯 则能返回科技文章中,关键词为“腾讯”的...下面的代码是responseMsg方法里的一部分,觉得看得不明白的或者第一次接触微信开发的,可以参考我的文章:https://www.jb51.net/article/872
  • 主要介绍了php微信公众平台开发类,实例分析了针对微信消息的响应、回复、编码等相关技巧,非常具有实用价值,需要的朋友可以参考下
  • PHP微信API接口.zip

    2019-07-11 09:58:43
    很全面详细的PHP微信API接口,帮助大家更好的进行php微信开发,感兴趣的小伙伴们可以参考一下 实现valid验证方法:实现对接微信公众平台。
  • 微信卡券PHP开发API

    2019-09-12 06:01:44
    <?php /** *微信卡券 *@authorHatchSolution *@linkhttp://www.hatchsolution.com *@version1.0.0 *@uses$hongbaoHelper=new...
    <?php
    /**
    * 微信卡券类
    *      @author HatchSolution
    *      @link http://www.hatchsolution.com
    *      @version 1.0.0
    *      @uses $hongbaoHelper = new WxCardHelper();
    *      @package POI门店管理接口 陆续会继续进行更新
    *
    * 卡券通过审核、卡券被用户领取、卡券被用户删除均会触发事件推送,该事件将发送至开发者填写的URL(登录公众平台进入开发者中心设置)
    * 特殊卡券:会员卡,电影票,会议门票
    */
    namespace Lib\Org\Util;
    class WxCardHelper
    {
    	function __construct()
    	{
    		
    	}
         
        /****************************************************
         *  微信获取ApiTicket 返回指定微信公众号的at信息
         ****************************************************/
     
        public function wxJsApiTicket($accessToken){
            $url            = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=".$accessToken."&type=wx_card";
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url);
            $jsoninfo       = json_decode($result, true);
            $ticket         = $jsoninfo['ticket'];
            //echo $ticket . "<br />";
            return $ticket;
        }
     
        /*******************************************************
         *      微信卡券:获取颜色
         *******************************************************/
        public function wxCardColor($wxAccessToken){
            $url            = "https://api.weixin.qq.com/card/getcolors?access_token=".$wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok","colors":[{"name":"Color010","value":"#55bd47"},{"name":"Color020","value":"#10ad61"},{"name":"Color030","value":"#35a4de"}]}
        }
         
        /*******************************************************
         *      微信卡券:创建卡券
    	 *
    	 *{ "card": {
    	 *	"card_type": "GROUPON",
    	 *		"groupon": {
    	 *			"base_info": {
    	 *				"logo_url":
    	 *				"http:\/\/www.supadmin.cn\/uploads\/allimg\/120216\/1_120216214725_1.jpg",
    	 *				"brand_name":"海底捞",
    	 *				"code_type":"CODE_TYPE_TEXT",
    	 *				"title": "132 元双人火锅套餐",
    	 *				"sub_title": "",
    	 *				"color": "Color010",
    	 *				"notice": "使用时向服务员出示此券",
    	 *				"service_phone": "020-88888888",
    	 *				"description": "不可与其他优惠同享\n 如需团购券发票, 请在消费时向商户提出\n 店内均可
    	 *				使用,仅限堂食\n 餐前不可打包,餐后未吃完,可打包\n 本团购券不限人数,建议 2 人使用,超过建议人
    	 *				数须另收酱料费 5 元/位\n 本单谢绝自带酒水饮料",
    	 *				"date_info": {
    	 *					"type": 1,
    	 *					"begin_timestamp": 1397577600 ,
    	 *					"end_timestamp": 1422724261
    	 *				},
    	 *				"sku": {
    	 *					"quantity": 50000000
    	 *				},
    	 *				"get_limit": 3,
    	 *				"use_custom_code": false,
    	 *				"bind_openid": false,
    	 *				"can_share": true,
    	 *				"can_give_friend": true,
    	 *				"location_id_list" : [123, 12321, 345345],
    	 *				"custom_url_name": "立即使用",
    	 *				"custom_url": "http://www.qq.com",
    	 *				"custom_url_sub_title": "6 个汉字 tips",
    	 *				"promotion_url_name": "更多优惠",
    	 *				"promotion_url": "http://www.qq.com",
    	 *				"source": "大众点评"
    	 *			},
    	 *			"deal_detail": "以下锅底 2 选 1(有菌王锅、麻辣锅、大骨锅、番茄锅、清补凉锅、酸菜鱼锅可
    	 *			选):\n 大锅 1 份 12 元\n 小锅 2 份 16 元\n 以下菜品 2 选 1\n 特级肥牛 1 份 30 元\n 洞庭鮰鱼卷 1 份
    	 *			20 元\n 其他\n 鲜菇猪肉滑 1 份 18 元\n 金针菇 1 份 16 元\n 黑木耳 1 份 9 元\n 娃娃菜 1 份 8 元\n 冬
    	 *			瓜 1 份 6 元\n 火锅面 2 个 6 元\n 欢乐畅饮 2 位 12 元\n 自助酱料 2 位 10 元"
    			}
    	 *	}
    	 *}
    	 *{
    	 *	"errcode":0,
    	 *	"errmsg":"ok",
    	 *	"card_id":"p1Pj9jr90_SQRaVqYI239Ka1erkI"
    	 *}
         *******************************************************/
        public function wxCardCreated($jsonData, $wxAccessToken) {
            $url            = "https://api.weixin.qq.com/card/create?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok","card_id":"p1Pj9jr90_SQRaVqYI239Ka1erkI"}
        }
        
    	/****************************************************
         *  微信生成二维码Card
    	 *{
    	 *	"action_name": "QR_CARD",
    	 *	"action_info": {
    	 *		"card": {
    	 *			"card_id": "pFS7Fjg8kV1IdDz01r4SQwMkuCKc",
    	 *			"code": "198374613512",
    	 *			"openid": "oFS7Fjl0WsZ9AMZqrI80nbIq8xrA",
    	 *			"expire_seconds": "1800",
    	 *			"is_unique_code": false ,
    	 *			"outer_id" : 1
    	 *		}
    	 *	}
    	 *}
         ****************************************************/
     
        public function wxQrCodeCard($jsonData, $wxAccessToken){
            $url        = "https://api.weixin.qq.com/card/qrcode/create?access_token=".$wxAccessToken;
            $result     = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            return $result;
    		//{"errcode":0,"errmsg":"ok","ticket":"gQG28DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0FuWC1DNmZuVEhvMVp4NDNMRnNRAAIEesLvUQMECAcAAA=="}
        }
     
        /*******************************************************
         *      微信卡券:消耗卡券
    	 *{
    	 *	"code":"110201201245",
    	 *	"card_id":"pFS7Fjg8kV1IdDz01r4SQwMkuCKc"
    	 *}
         *******************************************************/
        public function wxCardConsume($code, $card_id = '', $wxAccessToken){
    		$jsonData = json_encode(array("code" => $code , 'card_id' => $cardId ));
            $url            = "https://api.weixin.qq.com/card/code/consume?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;  
    		//{"errcode":0,"errmsg":"ok","card":{"card_id":"pFS7Fjg8kV1IdDz01r4SQwMkuCKc"},"openid":"oFS7Fjl0WsZ9AMZqrI80nbIq8xrA"}
        }
         
        /*******************************************************
         *      微信卡券:选择卡券 - 解析CODE
    	 *{
    	 *	"encrypt_code":
    	 *	"XXIzTtMqCxwOaawoE91+VJdsFmv7b8g0VZIZkqf4GWA60Fzpc8ksZ/5ZZ0DVkXdE"
    	 *}
         *******************************************************/       
        public function wxCardDecryptCode($encrypt_code, $wxAccessToken){
    		$jsonData = json_encode(array("encrypt_code" => $encrypt_code));
            $url            = "https://api.weixin.qq.com/card/code/decrypt?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok","code":"751234212312"}
        }
     
        /*******************************************************
         *      微信卡券:删除卡券
    	 *{
    	 *	"card_id": "p1Pj9jr90_SQRaVqYI239Ka1erkI"
    	 *}
         *******************************************************/
        public function wxCardDelete($card_id, $wxAccessToken){
    		$jsonData = json_encode(array("card_id" => $card_id));
            $url            = "https://api.weixin.qq.com/card/delete?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok"}
        }
    	
        /*******************************************************
         *      微信卡券:查询用户CODE
    	 *{
    	 *	"code":"110201201245"
    	 *}
         *******************************************************/       
        public function wxCardQueryCode($code , $card_id = '', $wxAccessToken){         
            $jsonData = json_encode(array("code" => $code , 'card_id' => $card_id ));
            $url            = "https://api.weixin.qq.com/card/code/get?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok","openid":"oFS7Fjl0WsZ9AMZqrI80nbIq8xrA"," card":{"card_id":"pFS7Fjg8kV1IdDz01r4SQwMkuCKc","begin_time": 1404205036,"end_time": 1404205036,}}
        }
    	
    	/*******************************************************
         *      微信卡券:查询用户CODE
    	 *{
    	 *	"code":"110201201245"
    	 *}
         *******************************************************/       
        public function wxCardBatchGet($offset, $count, $wxAccessToken){
    		$jsonData = json_encode(array("offset" => $offset , 'count' => $count ));
            $url            = "https://api.weixin.qq.com/card/batchget?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok","card_id_list":["ph_gmt7cUVrlRk8swPwx7aDyF-pg"],"total_num":1}
        }
    	
        /*******************************************************
         *      微信卡券:查询卡券详情
    	 *{
    	 *	"card_id":"pFS7Fjg8kV1IdDz01r4SQwMkuCKc"
    	 *}
         *******************************************************/
        public function wxCardGetInfo($card_id, $wxAccessToken) {
    		$jsonData = json_encode(array("card_id" => $card_id));
            $url            = "https://api.weixin.qq.com/card/get?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
        }
    	
    	/*******************************************************
         *      微信卡券:更改卡券code
    	 *{
    	 *	"code": "12345678",
    	 *	"card_id": "p1Pj9jr90_SQRaxxxxxxxx",
    	 *	"new_code": "3495739475"
    	 *}
         *******************************************************/
        public function wxCardUpdateCode($code, $card_id, $new_code, $wxAccessToken) {
    		$jsonData = json_encode(array("code" => $code , 'card_id' => $card_id , 'new_code' => $new_code));
            $url            = "https://api.weixin.qq.com/card/code/update?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok"}
        }
    	
    	/*******************************************************
         *      微信卡券:设置卡券失效接口
    	 *{
    	 *	"code": "12312313"
    	 *}
         *******************************************************/
        public function wxCardUnavailableCode($code, $card_id, $wxAccessToken) {
    		$data['code'] = $code;
    		if (!empty($card_id)) {
    			$data['card_id'] = $card_id;
    		}
    		$jsonData = json_encode($data);
            $url            = "https://api.weixin.qq.com/card/code/unavailable?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok"}
        }
    	
    	/*******************************************************
         *      微信卡券:更改卡券信息接口
    	 {
    	 *"card_id": "xxxxxxxxxxxxx",
    	 *"member_card": {
    	 *	"base_info": {
    	 *		"logo_url":
    	 *		"http:\/\/www.supadmin.cn\/uploads\/allimg\/120216\/1_120216214725_1.jpg",
    	 *		"color": "Color010",
    	 *		"notice": "使用时向服务员出示此券",
    	 *		"service_phone": "020-88888888",
    	 *		"description": "不可与其他优惠同享\n 如需团购券发票,请在消费时向商户提出\n
    	 *		店内均可使用,仅限堂食\n 餐前不可打包,餐后未吃完,可打包\n 本团购券不限人数,建议 2 人使用,超
    	 *		过建议人数须另收酱料费 5 元/位\n 本单谢绝自带酒水饮料"
    	 *		"location_id_list" : [123, 12321, 345345]
    	 *	},
    	 *	"bonus_cleared": "aaaaaaaaaaaaaa",
    	 *	"bonus_rules": "aaaaaaaaaaaaaa",
    	 *	"prerogative": ""
    	 *	}
    	 *}
         *******************************************************/
        public function wxCardUpdate($jsonData, $wxAccessToken) {
            $url            = "https://api.weixin.qq.com/card/update?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok"}
        }	
         
        /*******************************************************
         *      微信卡券:更改库存
    	 *{
    	 *	"card_id": "xxxx_card_id",
    	 *	"increase_stock_value": 1231231,
    	 *	"reduce_stock_value": 1231231
    	 *}
         *******************************************************/
        public function wxCardModifyStock($cardId , $wxAccessToken, $increase_stock_value = 0 , $reduce_stock_value = 0){
            if(intval($increase_stock_value) == 0 && intval($reduce_stock_value) == 0){
                return false;
            }
             
            $jsonData = json_encode(array("card_id" => $cardId , 'increase_stock_value' => intval($increase_stock_value) , 'reduce_stock_value' => intval($reduce_stock_value)));
             
            $url            = "https://api.weixin.qq.com/card/modifystock?access_token=" . $wxAccessToken;
            $result         = \Lib\Org\Util\WxApi::wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
    		//{"errcode":0,"errmsg":"ok"}
        }
      
        /*******************************************************
         *      微信卡券:设置白名单
    	 * {
    	 *	"openid": [
    	 *		"o1Pj9jmZvwSyyyyyyBa4aULW2mA",
    	 *		"o1Pj9jmZvxxxxxxxxxULW2mA"
    	 *	],
    	 *	"username": [
    	 *		"afdvvf",
    	 *		"abcd"
    	 *	]
    	 *}
         *******************************************************/
        public function wxCardWhiteList($jsonData, $wxAccessToken){
            $url            = "https://api.weixin.qq.com/card/testwhitelist/set?access_token=" . $wxAccessToken;
            $result         = $this->wxHttpsRequest($url,$jsonData);
            $jsoninfo       = json_decode($result, true);
            return $jsoninfo;
        }
     
    }
    
    ?>


    转载于:https://my.oschina.net/jarvisliu/blog/404051

    展开全文
  • 主要介绍了php微信公众平台开发类,实例分析了针对微信消息的响应、回复、编码等相关技巧,非常具有实用价值,微信推送过来的数据或响应数据,构造方法,用于实例化微信SDK,获取微信推送的数据,响应微信发送的信息。
  • 微信网页开发 素材管理 图文消息留言管理 用户管理 帐号管理 数据统计 微信卡券 微信门店 微信小店 智能接口 微信设备功能 新版客服功能 微信摇一摇周边 微信连Wi-Fi 微信扫一扫 微信发票 &lt;...

     

    微信网页开发

    素材管理

    图文消息留言管理

    用户管理

    帐号管理

    数据统计

    微信卡券

    微信门店

    微信小店

    智能接口

    微信设备功能

    新版客服功能

    微信摇一摇周边

    微信连Wi-Fi

    微信扫一扫

    微信发票

    <?php
    /**
     *	微信公众平台PHP-SDK, 官方API部分
     *  @author  dodge <dodgepudding@gmail.com>
     *  @link https://github.com/dodgepudding/wechat-php-sdk
     *  @version 1.2
     *  usage:
     *   $options = array(
     *			'token'=>'tokenaccesskey', //填写你设定的key
     *			'encodingaeskey'=>'encodingaeskey', //填写加密用的EncodingAESKey
     *			'appid'=>'wxdk1234567890', //填写高级调用功能的app id
     *			'appsecret'=>'xxxxxxxxxxxxxxxxxxx' //填写高级调用功能的密钥
     *		);
     *	 $weObj = new Wechat($options);
     *   $weObj->valid();
     *   $type = $weObj->getRev()->getRevType();
     *   switch($type) {
     *   		case Wechat::MSGTYPE_TEXT:
     *   			$weObj->text("hello, I'm wechat")->reply();
     *   			exit;
     *   			break;
     *   		case Wechat::MSGTYPE_EVENT:
     *   			....
     *   			break;
     *   		case Wechat::MSGTYPE_IMAGE:
     *   			...
     *   			break;
     *   		default:
     *   			$weObj->text("help info")->reply();
     *   }
     *
     *   //获取菜单操作:
     *   $menu = $weObj->getMenu();
     *   //设置菜单
     *   $newmenu =  array(
     *   		"button"=>
     *   			array(
     *   				array('type'=>'click','name'=>'最新消息','key'=>'MENU_KEY_NEWS'),
     *   				array('type'=>'view','name'=>'我要搜索','url'=>'http://www.baidu.com'),
     *   				)
     *  		);
     *   $result = $weObj->createMenu($newmenu);
     */
    class WechatAbstract
    {
    	const MSGTYPE_TEXT = 'text';
    	const MSGTYPE_IMAGE = 'image';
    	const MSGTYPE_LOCATION = 'location';
    	const MSGTYPE_LINK = 'link';
    	const MSGTYPE_EVENT = 'event';
    	const MSGTYPE_MUSIC = 'music';
    	const MSGTYPE_NEWS = 'news';
    	const MSGTYPE_VOICE = 'voice';
    	const MSGTYPE_VIDEO = 'video';
    	const EVENT_SUBSCRIBE = 'subscribe';       //订阅
    	const EVENT_UNSUBSCRIBE = 'unsubscribe';   //取消订阅
    	const EVENT_SCAN = 'SCAN';                 //扫描带参数二维码
    	const EVENT_LOCATION = 'LOCATION';         //上报地理位置
    	const EVENT_MENU_VIEW = 'VIEW';                     //菜单 - 点击菜单跳转链接
    	const EVENT_MENU_CLICK = 'CLICK';                   //菜单 - 点击菜单拉取消息
    	const EVENT_MENU_SCAN_PUSH = 'scancode_push';       //菜单 - 扫码推事件(客户端跳URL)
    	const EVENT_MENU_SCAN_WAITMSG = 'scancode_waitmsg'; //菜单 - 扫码推事件(客户端不跳URL)
    	const EVENT_MENU_PIC_SYS = 'pic_sysphoto';          //菜单 - 弹出系统拍照发图
    	const EVENT_MENU_PIC_PHOTO = 'pic_photo_or_album';  //菜单 - 弹出拍照或者相册发图
    	const EVENT_MENU_PIC_WEIXIN = 'pic_weixin';         //菜单 - 弹出微信相册发图器
    	const EVENT_MENU_LOCATION = 'location_select';      //菜单 - 弹出地理位置选择器
    	const EVENT_SEND_MASS = 'MASSSENDJOBFINISH';        //发送结果 - 高级群发完成
    	const EVENT_SEND_TEMPLATE = 'TEMPLATESENDJOBFINISH';//发送结果 - 模板消息发送结果
    	const EVENT_KF_SEESION_CREATE = 'kfcreatesession';  //多客服 - 接入会话
    	const EVENT_KF_SEESION_CLOSE = 'kfclosesession';    //多客服 - 关闭会话
    	const EVENT_KF_SEESION_SWITCH = 'kfswitchsession';  //多客服 - 转接会话
    	const EVENT_CARD_PASS = 'card_pass_check';          //卡券 - 审核通过
    	const EVENT_CARD_NOTPASS = 'card_not_pass_check';   //卡券 - 审核未通过
    	const EVENT_CARD_USER_GET = 'user_get_card';        //卡券 - 用户领取卡券
    	const EVENT_CARD_USER_DEL = 'user_del_card';        //卡券 - 用户删除卡券
    	const EVENT_MERCHANT_ORDER = 'merchant_order';        //微信小店 - 订单付款通知
    	const API_URL_PREFIX = 'https://api.weixin.qq.com/cgi-bin';
    	const AUTH_URL = '/token?grant_type=client_credential&';
    	const MENU_CREATE_URL = '/menu/create?';
    	const MENU_GET_URL = '/menu/get?';
    	const MENU_DELETE_URL = '/menu/delete?';
    	const GET_TICKET_URL = '/ticket/getticket?';
    	const CALLBACKSERVER_GET_URL = '/getcallbackip?';
    	const QRCODE_CREATE_URL='/qrcode/create?';
    	const QR_SCENE = 0;
    	const QR_LIMIT_SCENE = 1;
    	const QRCODE_IMG_URL='https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=';
    	const SHORT_URL='/shorturl?';
    	const USER_GET_URL='/user/get?';
    	const USER_INFO_URL='/user/info?';
    	const USER_UPDATEREMARK_URL='/user/info/updateremark?';
    	const GROUP_GET_URL='/groups/get?';
    	const USER_GROUP_URL='/groups/getid?';
    	const GROUP_CREATE_URL='/groups/create?';
    	const GROUP_UPDATE_URL='/groups/update?';
    	const GROUP_MEMBER_UPDATE_URL='/groups/members/update?';
    	const GROUP_MEMBER_BATCHUPDATE_URL='/groups/members/batchupdate?';
    	const CUSTOM_SEND_URL='/message/custom/send?';
    	const MEDIA_UPLOADNEWS_URL = '/media/uploadnews?';
    	const MASS_SEND_URL = '/message/mass/send?';
    	const TEMPLATE_SET_INDUSTRY_URL = '/message/template/api_set_industry?';
    	const TEMPLATE_ADD_TPL_URL = '/template/api_add_template?';
    	const TEMPLATE_SEND_URL = '/message/template/send?';
    	const MASS_SEND_GROUP_URL = '/message/mass/sendall?';
    	const MASS_DELETE_URL = '/message/mass/delete?';
    	const MASS_PREVIEW_URL = '/message/mass/preview?';
    	const MASS_QUERY_URL = '/message/mass/get?';
    	const UPLOAD_MEDIA_URL = 'http://file.api.weixin.qq.com/cgi-bin';
    	const MEDIA_UPLOAD_URL = '/media/upload?';
    	const MEDIA_UPLOADIMG_URL = '/media/uploadimg?';//图片上传接口
    	const MEDIA_GET_URL = '/media/get?';
    	const MEDIA_VIDEO_UPLOAD = '/media/uploadvideo?';
        const MEDIA_FOREVER_UPLOAD_URL = '/material/add_material?';
        const MEDIA_FOREVER_NEWS_UPLOAD_URL = '/material/add_news?';
        const MEDIA_FOREVER_NEWS_UPDATE_URL = '/material/update_news?';
        const MEDIA_FOREVER_GET_URL = '/material/get_material?';
        const MEDIA_FOREVER_DEL_URL = '/material/del_material?';
        const MEDIA_FOREVER_COUNT_URL = '/material/get_materialcount?';
        const MEDIA_FOREVER_BATCHGET_URL = '/material/batchget_material?';
    	const OAUTH_PREFIX = 'https://open.weixin.qq.com/connect/oauth2';
    	const OAUTH_AUTHORIZE_URL = '/authorize?';
    	///多客服相关地址
    	const CUSTOM_SERVICE_GET_RECORD = '/customservice/getrecord?';
    	const CUSTOM_SERVICE_GET_KFLIST = '/customservice/getkflist?';
    	const CUSTOM_SERVICE_GET_ONLINEKFLIST = '/customservice/getonlinekflist?';
    	const API_BASE_URL_PREFIX = 'https://api.weixin.qq.com'; //以下API接口URL需要使用此前缀
    	const OAUTH_TOKEN_URL = '/sns/oauth2/access_token?';
    	const OAUTH_REFRESH_URL = '/sns/oauth2/refresh_token?';
    	const OAUTH_USERINFO_URL = '/sns/userinfo?';
    	const OAUTH_AUTH_URL = '/sns/auth?';
    	///多客服相关地址
    	const CUSTOM_SESSION_CREATE = '/customservice/kfsession/create?';
    	const CUSTOM_SESSION_CLOSE = '/customservice/kfsession/close?';
    	const CUSTOM_SESSION_SWITCH = '/customservice/kfsession/switch?';
    	const CUSTOM_SESSION_GET = '/customservice/kfsession/getsession?';
    	const CUSTOM_SESSION_GET_LIST = '/customservice/kfsession/getsessionlist?';
    	const CUSTOM_SESSION_GET_WAIT = '/customservice/kfsession/getwaitcase?';
    	const CS_KF_ACCOUNT_ADD_URL = '/customservice/kfaccount/add?';
    	const CS_KF_ACCOUNT_UPDATE_URL = '/customservice/kfaccount/update?';
    	const CS_KF_ACCOUNT_DEL_URL = '/customservice/kfaccount/del?';
    	const CS_KF_ACCOUNT_UPLOAD_HEADIMG_URL = '/customservice/kfaccount/uploadheadimg?';
    	///卡券相关地址
    	const CARD_CREATE                     = '/card/create?';
    	const CARD_DELETE                     = '/card/delete?';
    	const CARD_UPDATE                     = '/card/update?';
    	const CARD_GET                        = '/card/get?';
    	const CARD_BATCHGET                   = '/card/batchget?';
    	const CARD_MODIFY_STOCK               = '/card/modifystock?';
    	const CARD_LOCATION_BATCHADD          = '/card/location/batchadd?';
    	const CARD_LOCATION_BATCHGET          = '/card/location/batchget?';
    	const CARD_GETCOLORS                  = '/card/getcolors?';
    	const CARD_QRCODE_CREATE              = '/card/qrcode/create?';
    	const CARD_CODE_CONSUME               = '/card/code/consume?';
    	const CARD_CODE_DECRYPT               = '/card/code/decrypt?';
    	const CARD_CODE_GET                   = '/card/code/get?';
    	const CARD_CODE_UPDATE                = '/card/code/update?';
    	const CARD_CODE_UNAVAILABLE           = '/card/code/unavailable?';
    	const CARD_TESTWHILELIST_SET          = '/card/testwhitelist/set?';
    	const CARD_MEETINGCARD_UPDATEUSER      = '/card/meetingticket/updateuser?';    //更新会议门票
    	const CARD_MEMBERCARD_ACTIVATE        = '/card/membercard/activate?';      //激活会员卡
    	const CARD_MEMBERCARD_UPDATEUSER      = '/card/membercard/updateuser?';    //更新会员卡
    	const CARD_MOVIETICKET_UPDATEUSER     = '/card/movieticket/updateuser?';   //更新电影票(未加方法)
    	const CARD_BOARDINGPASS_CHECKIN       = '/card/boardingpass/checkin?';     //飞机票-在线选座(未加方法)
    	const CARD_LUCKYMONEY_UPDATE          = '/card/luckymoney/updateuserbalance?';     //更新红包金额
    	const SEMANTIC_API_URL = '/semantic/semproxy/search?'; //语义理解
    	///数据分析接口
    	static $DATACUBE_URL_ARR = array(        //用户分析
    	        'user' => array(
    	                'summary' => '/datacube/getusersummary?',		//获取用户增减数据(getusersummary)
    	                'cumulate' => '/datacube/getusercumulate?',		//获取累计用户数据(getusercumulate)
    	        ),
    	        'article' => array(            //图文分析
    	                'summary' => '/datacube/getarticlesummary?',		//获取图文群发每日数据(getarticlesummary)
    	                'total' => '/datacube/getarticletotal?',		//获取图文群发总数据(getarticletotal)
    	                'read' => '/datacube/getuserread?',			//获取图文统计数据(getuserread)
    	                'readhour' => '/datacube/getuserreadhour?',		//获取图文统计分时数据(getuserreadhour)
    	                'share' => '/datacube/getusershare?',			//获取图文分享转发数据(getusershare)
    	                'sharehour' => '/datacube/getusersharehour?',		//获取图文分享转发分时数据(getusersharehour)
    	        ),
    	        'upstreammsg' => array(        //消息分析
    	                'summary' => '/datacube/getupstreammsg?',		//获取消息发送概况数据(getupstreammsg)
    					'hour' => '/datacube/getupstreammsghour?',	//获取消息分送分时数据(getupstreammsghour)
    	                'week' => '/datacube/getupstreammsgweek?',	//获取消息发送周数据(getupstreammsgweek)
    	                'month' => '/datacube/getupstreammsgmonth?',	//获取消息发送月数据(getupstreammsgmonth)
    	                'dist' => '/datacube/getupstreammsgdist?',	//获取消息发送分布数据(getupstreammsgdist)
    	                'distweek' => '/datacube/getupstreammsgdistweek?',	//获取消息发送分布周数据(getupstreammsgdistweek)
    	               	'distmonth' => '/datacube/getupstreammsgdistmonth?',	//获取消息发送分布月数据(getupstreammsgdistmonth)
    	        ),
    	        'interface' => array(        //接口分析
    	                'summary' => '/datacube/getinterfacesummary?',	//获取接口分析数据(getinterfacesummary)
    	                'summaryhour' => '/datacube/getinterfacesummaryhour?',	//获取接口分析分时数据(getinterfacesummaryhour)
    	        )
    	);
    	///微信摇一摇周边
    	const SHAKEAROUND_DEVICE_APPLYID = '/shakearound/device/applyid?';//申请设备ID
        const SHAKEAROUND_DEVICE_UPDATE = '/shakearound/device/update?';//编辑设备信息
    	const SHAKEAROUND_DEVICE_SEARCH = '/shakearound/device/search?';//查询设备列表
    	const SHAKEAROUND_DEVICE_BINDLOCATION = '/shakearound/device/bindlocation?';//配置设备与门店ID的关系
    	const SHAKEAROUND_DEVICE_BINDPAGE = '/shakearound/device/bindpage?';//配置设备与页面的绑定关系
        const SHAKEAROUND_MATERIAL_ADD = '/shakearound/material/add?';//上传摇一摇图片素材
    	const SHAKEAROUND_PAGE_ADD = '/shakearound/page/add?';//增加页面
    	const SHAKEAROUND_PAGE_UPDATE = '/shakearound/page/update?';//编辑页面
    	const SHAKEAROUND_PAGE_SEARCH = '/shakearound/page/search?';//查询页面列表
    	const SHAKEAROUND_PAGE_DELETE = '/shakearound/page/delete?';//删除页面
    	const SHAKEAROUND_USER_GETSHAKEINFO = '/shakearound/user/getshakeinfo?';//获取摇周边的设备及用户信息
    	const SHAKEAROUND_STATISTICS_DEVICE = '/shakearound/statistics/device?';//以设备为维度的数据统计接口
        const SHAKEAROUND_STATISTICS_PAGE = '/shakearound/statistics/page?';//以页面为维度的数据统计接口
    	///微信小店相关接口
    	const MERCHANT_ORDER_GETBYID = '/merchant/order/getbyid?';//根据订单ID获取订单详情
    	const MERCHANT_ORDER_GETBYFILTER = '/merchant/order/getbyfilter?';//根据订单状态/创建时间获取订单详情
    	const MERCHANT_ORDER_SETDELIVERY = '/merchant/order/setdelivery?';//设置订单发货信息
    	const MERCHANT_ORDER_CLOSE = '/merchant/order/close?';//关闭订单
    
    	private $token;
    	private $encodingAesKey;
    	private $encrypt_type;
    	private $appid;
    	private $appsecret;
    	private $access_token;
    	private $jsapi_ticket;
    	private $api_ticket;
    	private $user_token;
    	private $partnerid;
    	private $partnerkey;
    	private $paysignkey;
    	private $postxml;
    	private $_msg;
    	private $_funcflag = false;
    	private $_receive;
    	private $_text_filter = true;
    	public $debug =  false;
    	public $errCode = 40001;
    	public $errMsg = "no access";
    	public $logcallback;
    
    	public function __construct($options)
    	{
    		$this->token = isset($options['token'])?$options['token']:'';
    		$this->encodingAesKey = isset($options['encodingaeskey'])?$options['encodingaeskey']:'';
    		$this->appid = isset($options['appid'])?$options['appid']:'';
    		$this->appsecret = isset($options['appsecret'])?$options['appsecret']:'';
    		$this->debug = isset($options['debug'])?$options['debug']:false;
    		$this->logcallback = isset($options['logcallback'])?$options['logcallback']:false;
    	}
    
    	/**
    	 * For weixin server validation
    	 */
    	private function checkSignature($str='')
    	{
            $signature = isset($_GET["signature"])?$_GET["signature"]:'';
    	    $signature = isset($_GET["msg_signature"])?$_GET["msg_signature"]:$signature; //如果存在加密验证则用加密验证段
            $timestamp = isset($_GET["timestamp"])?$_GET["timestamp"]:'';
            $nonce = isset($_GET["nonce"])?$_GET["nonce"]:'';
    
    		$token = $this->token;
    		$tmpArr = array($token, $timestamp, $nonce,$str);
    		sort($tmpArr, SORT_STRING);
    		$tmpStr = implode( $tmpArr );
    		$tmpStr = sha1( $tmpStr );
    
    		if( $tmpStr == $signature ){
    			return true;
    		}else{
    			return false;
    		}
    	}
    
    	/**
    	 * For weixin server validation
    	 * @param bool $return 是否返回
    	 */
    	public function valid($return=false)
        {
            $encryptStr="";
            if ($_SERVER['REQUEST_METHOD'] == "POST") {
                $postStr = file_get_contents("php://input");
                $array = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $this->encrypt_type = isset($_GET["encrypt_type"]) ? $_GET["encrypt_type"]: '';
                if ($this->encrypt_type == 'aes') { //aes加密
                    $this->log($postStr);
                	$encryptStr = $array['Encrypt'];
                	$pc = new Prpcrypt($this->encodingAesKey);
                	$array = $pc->decrypt($encryptStr,$this->appid);
                	if (!isset($array[0]) || ($array[0] != 0)) {
                	    if (!$return) {
                	        die('decrypt error!');
                	    } else {
                	        return false;
                	    }
                	}
                	$this->postxml = $array[1];
                	if (!$this->appid)
                	    $this->appid = $array[2];//为了没有appid的订阅号。
                } else {
                    $this->postxml = $postStr;
                }
            } elseif (isset($_GET["echostr"])) {
            	$echoStr = $_GET["echostr"];
            	if ($return) {
            		if ($this->checkSignature())
            			return $echoStr;
            		else
            			return false;
            	} else {
            		if ($this->checkSignature())
            			die($echoStr);
            		else
            			die('no access');
            	}
            }
    
            if (!$this->checkSignature($encryptStr)) {
            	if ($return)
            		return false;
            	else
            		die('no access');
            }
            return true;
        }
    
    	/**
    	 * 设置发送消息
    	 * @param array $msg 消息数组
    	 * @param bool $append 是否在原消息数组追加
    	 */
        public function Message($msg = '',$append = false){
        		if (is_null($msg)) {
        			$this->_msg =array();
        		}elseif (is_array($msg)) {
        			if ($append)
        				$this->_msg = array_merge($this->_msg,$msg);
        			else
        				$this->_msg = $msg;
        			return $this->_msg;
        		} else {
        			return $this->_msg;
        		}
        }
    
        /**
         * 设置消息的星标标志,官方已取消对此功能的支持
         */
        public function setFuncFlag($flag) {
        		$this->_funcflag = $flag;
        		return $this;
        }
    
        /**
         * 日志记录,可被重载。
         * @param mixed $log 输入日志
         * @return mixed
         */
        protected function log($log){
        		if ($this->debug && function_exists($this->logcallback)) {
        			if (is_array($log)) $log = print_r($log,true);
        			return call_user_func($this->logcallback,$log);
        		}
        }
    
        /**
         * 获取微信服务器发来的信息
         */
    	public function getRev()
    	{
    		if ($this->_receive) return $this;
    		$postStr = !empty($this->postxml)?$this->postxml:file_get_contents("php://input");
    		//兼顾使用明文又不想调用valid()方法的情况
    		$this->log($postStr);
    		if (!empty($postStr)) {
    			$this->_receive = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
    		}
    		return $this;
    	}
    
    	/**
    	 * 获取微信服务器发来的信息
    	 */
    	public function getRevData()
    	{
    		return $this->_receive;
    	}
    
    	/**
    	 * 获取消息发送者
    	 */
    	public function getRevFrom() {
    		if (isset($this->_receive['FromUserName']))
    			return $this->_receive['FromUserName'];
    		else
    			return false;
    	}
    
    	/**
    	 * 获取消息接受者
    	 */
    	public function getRevTo() {
    		if (isset($this->_receive['ToUserName']))
    			return $this->_receive['ToUserName'];
    		else
    			return false;
    	}
    
    	/**
    	 * 获取接收消息的类型
    	 */
    	public function getRevType() {
    		if (isset($this->_receive['MsgType']))
    			return $this->_receive['MsgType'];
    		else
    			return false;
    	}
    
    	/**
    	 * 获取消息ID
    	 */
    	public function getRevID() {
    		if (isset($this->_receive['MsgId']))
    			return $this->_receive['MsgId'];
    		else
    			return false;
    	}
    
    	/**
    	 * 获取消息发送时间
    	 */
    	public function getRevCtime() {
    		if (isset($this->_receive['CreateTime']))
    			return $this->_receive['CreateTime'];
    		else
    			return false;
    	}
    
    	/**
    	 * 获取接收消息内容正文
    	 */
    	public function getRevContent(){
    		if (isset($this->_receive['Content']))
    			return $this->_receive['Content'];
    		else if (isset($this->_receive['Recognition'])) //获取语音识别文字内容,需申请开通
    			return $this->_receive['Recognition'];
    		else
    			return false;
    	}
    
    	/**
    	 * 获取接收消息图片
    	 */
    	public function getRevPic(){
    		if (isset($this->_receive['PicUrl']))
    			return array(
    				'mediaid'=>$this->_receive['MediaId'],
    				'picurl'=>(string)$this->_receive['PicUrl'],    //防止picurl为空导致解析出错
    			);
    		else
    			return false;
    	}
    
    	/**
    	 * 获取接收消息链接
    	 */
    	public function getRevLink(){
    		if (isset($this->_receive['Url'])){
    			return array(
    				'url'=>$this->_receive['Url'],
    				'title'=>$this->_receive['Title'],
    				'description'=>$this->_receive['Description']
    			);
    		} else
    			return false;
    	}
    
    	/**
    	 * 获取接收地理位置
    	 */
    	public function getRevGeo(){
    		if (isset($this->_receive['Location_X'])){
    			return array(
    				'x'=>$this->_receive['Location_X'],
    				'y'=>$this->_receive['Location_Y'],
    				'scale'=>$this->_receive['Scale'],
    				'label'=>$this->_receive['Label']
    			);
    		} else
    			return false;
    	}
    
    	/**
    	 * 获取上报地理位置事件
    	 */
    	public function getRevEventGeo(){
            	if (isset($this->_receive['Latitude'])){
            		 return array(
    				'x'=>$this->_receive['Latitude'],
    				'y'=>$this->_receive['Longitude'],
    				'precision'=>$this->_receive['Precision'],
    			);
    		} else
    			return false;
    	}
    
    	/**
    	 * 获取接收事件推送
    	 */
    	public function getRevEvent(){
    		if (isset($this->_receive['Event'])){
    			$array['event'] = $this->_receive['Event'];
    		}
    		if (isset($this->_receive['EventKey'])){
    			$array['key'] = $this->_receive['EventKey'];
    		}
    		if (isset($array) && count($array) > 0) {
    			return $array;
    		} else {
    			return false;
    		}
    	}
    
    	/**
    	 * 获取自定义菜单的扫码推事件信息
    	 *
    	 * 事件类型为以下两种时则调用此方法有效
    	 * Event	 事件类型,scancode_push
    	 * Event	 事件类型,scancode_waitmsg
    	 *
    	 * @return: array | false
    	 * array (
    	 *     'ScanType'=>'qrcode',
    	 *     'ScanResult'=>'123123'
    	 * )
    	 */
    	public function getRevScanInfo(){
    		if (isset($this->_receive['ScanCodeInfo'])){
    		    if (!is_array($this->_receive['ScanCodeInfo'])) {
    		        $array=(array)$this->_receive['ScanCodeInfo'];
    		        $this->_receive['ScanCodeInfo']=$array;
    		    }else {
    		        $array=$this->_receive['ScanCodeInfo'];
    		    }
    		}
    		if (isset($array) && count($array) > 0) {
    			return $array;
    		} else {
    			return false;
    		}
    	}
    
    	/**
    	 * 获取自定义菜单的图片发送事件信息
    	 *
    	 * 事件类型为以下三种时则调用此方法有效
    	 * Event	 事件类型,pic_sysphoto        弹出系统拍照发图的事件推送
    	 * Event	 事件类型,pic_photo_or_album  弹出拍照或者相册发图的事件推送
    	 * Event	 事件类型,pic_weixin          弹出微信相册发图器的事件推送
    	 *
    	 * @return: array | false
    	 * array (
    	 *   'Count' => '2',
    	 *   'PicList' =>array (
    	 *         'item' =>array (
    	 *             0 =>array ('PicMd5Sum' => 'aaae42617cf2a14342d96005af53624c'),
    	 *             1 =>array ('PicMd5Sum' => '149bd39e296860a2adc2f1bb81616ff8'),
    	 *         ),
    	 *   ),
    	 * )
    	 *
    	 */
    	public function getRevSendPicsInfo(){
    		if (isset($this->_receive['SendPicsInfo'])){
    		    if (!is_array($this->_receive['SendPicsInfo'])) {
    		        $array=(array)$this->_receive['SendPicsInfo'];
    		        if (isset($array['PicList'])){
    		            $array['PicList']=(array)$array['PicList'];
    		            $item=$array['PicList']['item'];
    		            $array['PicList']['item']=array();
    		            foreach ( $item as $key => $value ){
    		                $array['PicList']['item'][$key]=(array)$value;
    		            }
    		        }
    		        $this->_receive['SendPicsInfo']=$array;
    		    } else {
    		        $array=$this->_receive['SendPicsInfo'];
    		    }
    		}
    		if (isset($array) && count($array) > 0) {
    			return $array;
    		} else {
    			return false;
    		}
    	}
    
    	/**
    	 * 获取自定义菜单的地理位置选择器事件推送
    	 *
    	 * 事件类型为以下时则可以调用此方法有效
    	 * Event	 事件类型,location_select        弹出地理位置选择器的事件推送
    	 *
    	 * @return: array | false
    	 * array (
    	 *   'Location_X' => '33.731655000061',
    	 *   'Location_Y' => '113.29955200008047',
    	 *   'Scale' => '16',
    	 *   'Label' => '某某市某某区某某路',
    	 *   'Poiname' => '',
    	 * )
    	 *
    	 */
    	public function getRevSendGeoInfo(){
    	    if (isset($this->_receive['SendLocationInfo'])){
    	        if (!is_array($this->_receive['SendLocationInfo'])) {
    	            $array=(array)$this->_receive['SendLocationInfo'];
    	            if (empty($array['Poiname'])) {
    	                $array['Poiname']="";
    	            }
    	            if (empty($array['Label'])) {
    	                $array['Label']="";
    	            }
    	            $this->_receive['SendLocationInfo']=$array;
    	        } else {
    	            $array=$this->_receive['SendLocationInfo'];
    	        }
    	    }
    	    if (isset($array) && count($array) > 0) {
    	        return $array;
    	    } else {
    	        return false;
    	    }
    	}
    
    	/**
    	 * 获取接收语音推送
    	 */
    	public function getRevVoice(){
    		if (isset($this->_receive['MediaId'])){
    			return array(
    				'mediaid'=>$this->_receive['MediaId'],
    				'format'=>$this->_receive['Format'],
    			);
    		} else
    			return false;
    	}
    
    	/**
    	 * 获取接收视频推送
    	 */
    	public function getRevVideo(){
    		if (isset($this->_receive['MediaId'])){
    			return array(
    					'mediaid'=>$this->_receive['MediaId'],
    					'thumbmediaid'=>$this->_receive['ThumbMediaId']
    			);
    		} else
    			return false;
    	}
    
    	/**
    	 * 获取接收TICKET
    	 */
    	public function getRevTicket(){
    		if (isset($this->_receive['Ticket'])){
    			return $this->_receive['Ticket'];
    		} else
    			return false;
    	}
    
    	/**
    	* 获取二维码的场景值
    	*/
    	public function getRevSceneId (){
    		if (isset($this->_receive['EventKey'])){
    			return str_replace('qrscene_','',$this->_receive['EventKey']);
    		} else{
    			return false;
    		}
    	}
    
    	/**
    	* 获取主动推送的消息ID
    	* 经过验证,这个和普通的消息MsgId不一样
    	* 当Event为 MASSSENDJOBFINISH 或 TEMPLATESENDJOBFINISH
    	*/
    	public function getRevTplMsgID(){
    		if (isset($this->_receive['MsgID'])){
    			return $this->_receive['MsgID'];
    		} else
    			return false;
    	}
    
    	/**
    	* 获取模板消息发送状态
    	*/
    	public function getRevStatus(){
    		if (isset($this->_receive['Status'])){
    			return $this->_receive['Status'];
    		} else
    			return false;
    	}
    
    	/**
    	* 获取群发或模板消息发送结果
    	* 当Event为 MASSSENDJOBFINISH 或 TEMPLATESENDJOBFINISH,即高级群发/模板消息
    	*/
    	public function getRevResult(){
    		if (isset($this->_receive['Status'])) //发送是否成功,具体的返回值请参考 高级群发/模板消息 的事件推送说明
    			$array['Status'] = $this->_receive['Status'];
    		if (isset($this->_receive['MsgID'])) //发送的消息id
    			$array['MsgID'] = $this->_receive['MsgID'];
    
    		//以下仅当群发消息时才会有的事件内容
    		if (isset($this->_receive['TotalCount']))     //分组或openid列表内粉丝数量
    			$array['TotalCount'] = $this->_receive['TotalCount'];
    		if (isset($this->_receive['FilterCount']))    //过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数
    			$array['FilterCount'] = $this->_receive['FilterCount'];
    		if (isset($this->_receive['SentCount']))     //发送成功的粉丝数
    			$array['SentCount'] = $this->_receive['SentCount'];
    		if (isset($this->_receive['ErrorCount']))    //发送失败的粉丝数
    			$array['ErrorCount'] = $this->_receive['ErrorCount'];
    		if (isset($array) && count($array) > 0) {
    		    return $array;
    		} else {
    		    return false;
    		}
    	}
    
    	/**
    	 * 获取多客服会话状态推送事件 - 接入会话
    	 * 当Event为 kfcreatesession 即接入会话
    	 * @return string | boolean  返回分配到的客服
    	 */
    	public function getRevKFCreate(){
    		if (isset($this->_receive['KfAccount'])){
    			return $this->_receive['KfAccount'];
    		} else
    			return false;
    	}
    
    	/**
    	 * 获取多客服会话状态推送事件 - 关闭会话
    	 * 当Event为 kfclosesession 即关闭会话
    	 * @return string | boolean  返回分配到的客服
    	 */
    	public function getRevKFClose(){
    	    if (isset($this->_receive['KfAccount'])){
    	        return $this->_receive['KfAccount'];
    	    } else
    	        return false;
    	}
    
    	/**
    	 * 获取多客服会话状态推送事件 - 转接会话
    	 * 当Event为 kfswitchsession 即转接会话
    	 * @return array | boolean  返回分配到的客服
    	 * {
    	 *     'FromKfAccount' => '',      //原接入客服
    	 *     'ToKfAccount' => ''            //转接到客服
    	 * }
    	 */
    	public function getRevKFSwitch(){
    	    if (isset($this->_receive['FromKfAccount']))     //原接入客服
    	        $array['FromKfAccount'] = $this->_receive['FromKfAccount'];
    	    if (isset($this->_receive['ToKfAccount']))    //转接到客服
    	        $array['ToKfAccount'] = $this->_receive['ToKfAccount'];
    	    if (isset($array) && count($array) > 0) {
    	        return $array;
    	    } else {
    	        return false;
    	    }
    	}
    
    	/**
    	 * 获取卡券事件推送 - 卡卷审核是否通过
    	 * 当Event为 card_pass_check(审核通过) 或 card_not_pass_check(未通过)
    	 * @return string|boolean  返回卡券ID
    	 */
    	public function getRevCardPass(){
    	    if (isset($this->_receive['CardId']))
    	        return $this->_receive['CardId'];
    	    else
    	        return false;
    	}
    
    	/**
    	 * 获取卡券事件推送 - 领取卡券
    	 * 当Event为 user_get_card(用户领取卡券)
    	 * @return array|boolean
    	 */
    	public function getRevCardGet(){
    	    if (isset($this->_receive['CardId']))     //卡券 ID
    	        $array['CardId'] = $this->_receive['CardId'];
    	    if (isset($this->_receive['IsGiveByFriend']))    //是否为转赠,1 代表是,0 代表否。
    	        $array['IsGiveByFriend'] = $this->_receive['IsGiveByFriend'];
    	        $array['OldUserCardCode'] = $this->_receive['OldUserCardCode'];
    	    if (isset($this->_receive['UserCardCode']) && !empty($this->_receive['UserCardCode'])) //code 序列号。自定义 code 及非自定义 code的卡券被领取后都支持事件推送。
    	        $array['UserCardCode'] = $this->_receive['UserCardCode'];
    	    if (isset($array) && count($array) > 0) {
    	        return $array;
    	    } else {
    	        return false;
    	    }
    	}
    
    	/**
    	 * 获取卡券事件推送 - 删除卡券
    	 * 当Event为 user_del_card(用户删除卡券)
    	 * @return array|boolean
    	 */
    	public function getRevCardDel(){
    	    if (isset($this->_receive['CardId']))     //卡券 ID
    	        $array['CardId'] = $this->_receive['CardId'];
    	    if (isset($this->_receive['UserCardCode']) && !empty($this->_receive['UserCardCode'])) //code 序列号。自定义 code 及非自定义 code的卡券被领取后都支持事件推送。
    	        $array['UserCardCode'] = $this->_receive['UserCardCode'];
    	    if (isset($array) && count($array) > 0) {
    	        return $array;
    	    } else {
    	        return false;
    	    }
    	}
    
    	/**
    	 * 获取订单ID - 订单付款通知
    	 * 当Event为 merchant_order(订单付款通知)
    	 * @return orderId|boolean
    	 */
    	public function getRevOrderId(){
    		if (isset($this->_receive['OrderId']))     //订单 ID
    			return $this->_receive['OrderId'];
    		else
    			return false;
    	}
    
    	public static function xmlSafeStr($str)
    	{
    		return '<![CDATA['.preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/",'',$str).']]>';
    	}
    
    	/**
    	 * 数据XML编码
    	 * @param mixed $data 数据
    	 * @return string
    	 */
    	public static function data_to_xml($data) {
    	    $xml = '';
    	    foreach ($data as $key => $val) {
    	        is_numeric($key) && $key = "item id=\"$key\"";
    	        $xml    .=  "<$key>";
    	        $xml    .=  ( is_array($val) || is_object($val)) ? self::data_to_xml($val)  : self::xmlSafeStr($val);
    	        list($key, ) = explode(' ', $key);
    	        $xml    .=  "</$key>";
    	    }
    	    return $xml;
    	}
    
    	/**
    	 * XML编码
    	 * @param mixed $data 数据
    	 * @param string $root 根节点名
    	 * @param string $item 数字索引的子节点名
    	 * @param string $attr 根节点属性
    	 * @param string $id   数字索引子节点key转换的属性名
    	 * @param string $encoding 数据编码
    	 * @return string
    	*/
    	public function xml_encode($data, $root='xml', $item='item', $attr='', $id='id', $encoding='utf-8') {
    	    if(is_array($attr)){
    	        $_attr = array();
    	        foreach ($attr as $key => $value) {
    	            $_attr[] = "{$key}=\"{$value}\"";
    	        }
    	        $attr = implode(' ', $_attr);
    	    }
    	    $attr   = trim($attr);
    	    $attr   = empty($attr) ? '' : " {$attr}";
    	    $xml   = "<{$root}{$attr}>";
    	    $xml   .= self::data_to_xml($data, $item, $id);
    	    $xml   .= "</{$root}>";
    	    return $xml;
    	}
    
    	/**
    	 * 过滤文字回复\r\n换行符
    	 * @param string $text
    	 * @return string|mixed
    	 */
    	private function _auto_text_filter($text) {
    		if (!$this->_text_filter) return $text;
    		return str_replace("\r\n", "\n", $text);
    	}
    
    	/**
    	 * 设置回复消息
    	 * Example: $obj->text('hello')->reply();
    	 * @param string $text
    	 */
    	public function text($text='')
    	{
    		$FuncFlag = $this->_funcflag ? 1 : 0;
    		$msg = array(
    			'ToUserName' => $this->getRevFrom(),
    			'FromUserName'=>$this->getRevTo(),
    			'MsgType'=>self::MSGTYPE_TEXT,
    			'Content'=>$this->_auto_text_filter($text),
    			'CreateTime'=>time(),
    			'FuncFlag'=>$FuncFlag
    		);
    		$this->Message($msg);
    		return $this;
    	}
    	/**
    	 * 设置回复消息
    	 * Example: $obj->image('media_id')->reply();
    	 * @param string $mediaid
    	 */
    	public function image($mediaid='')
    	{
    		$FuncFlag = $this->_funcflag ? 1 : 0;
    		$msg = array(
    			'ToUserName' => $this->getRevFrom(),
    			'FromUserName'=>$this->getRevTo(),
    			'MsgType'=>self::MSGTYPE_IMAGE,
    			'Image'=>array('MediaId'=>$mediaid),
    			'CreateTime'=>time(),
    			'FuncFlag'=>$FuncFlag
    		);
    		$this->Message($msg);
    		return $this;
    	}
    
    	/**
    	 * 设置回复消息
    	 * Example: $obj->voice('media_id')->reply();
    	 * @param string $mediaid
    	 */
    	public function voice($mediaid='')
    	{
    		$FuncFlag = $this->_funcflag ? 1 : 0;
    		$msg = array(
    			'ToUserName' => $this->getRevFrom(),
    			'FromUserName'=>$this->getRevTo(),
    			'MsgType'=>self::MSGTYPE_VOICE,
    			'Voice'=>array('MediaId'=>$mediaid),
    			'CreateTime'=>time(),
    			'FuncFlag'=>$FuncFlag
    		);
    		$this->Message($msg);
    		return $this;
    	}
    
    	/**
    	 * 设置回复消息
    	 * Example: $obj->video('media_id','title','description')->reply();
    	 * @param string $mediaid
    	 */
    	public function video($mediaid='',$title='',$description='')
    	{
    		$FuncFlag = $this->_funcflag ? 1 : 0;
    		$msg = array(
    			'ToUserName' => $this->getRevFrom(),
    			'FromUserName'=>$this->getRevTo(),
    			'MsgType'=>self::MSGTYPE_VIDEO,
    			'Video'=>array(
    			        'MediaId'=>$mediaid,
    			        'Title'=>$title,
    			        'Description'=>$description
    			),
    			'CreateTime'=>time(),
    			'FuncFlag'=>$FuncFlag
    		);
    		$this->Message($msg);
    		return $this;
    	}
    
    	/**
    	 * 设置回复音乐
    	 * @param string $title
    	 * @param string $desc
    	 * @param string $musicurl
    	 * @param string $hgmusicurl
    	 * @param string $thumbmediaid 音乐图片缩略图的媒体id,非必须
    	 */
    	public function music($title,$desc,$musicurl,$hgmusicurl='',$thumbmediaid='') {
    		$FuncFlag = $this->_funcflag ? 1 : 0;
    		$msg = array(
    			'ToUserName' => $this->getRevFrom(),
    			'FromUserName'=>$this->getRevTo(),
    			'CreateTime'=>time(),
    			'MsgType'=>self::MSGTYPE_MUSIC,
    			'Music'=>array(
    				'Title'=>$title,
    				'Description'=>$desc,
    				'MusicUrl'=>$musicurl,
    				'HQMusicUrl'=>$hgmusicurl
    			),
    			'FuncFlag'=>$FuncFlag
    		);
    		if ($thumbmediaid) {
    			$msg['Music']['ThumbMediaId'] = $thumbmediaid;
    		}
    		$this->Message($msg);
    		return $this;
    	}
    
    	/**
    	 * 设置回复图文
    	 * @param array $newsData
    	 * 数组结构:
    	 *  array(
    	 *  	"0"=>array(
    	 *  		'Title'=>'msg title',
    	 *  		'Description'=>'summary text',
    	 *  		'PicUrl'=>'http://www.domain.com/1.jpg',
    	 *  		'Url'=>'http://www.domain.com/1.html'
    	 *  	),
    	 *  	"1"=>....
    	 *  )
    	 */
    	public function news($newsData=array())
    	{
    		$FuncFlag = $this->_funcflag ? 1 : 0;
    		$count = count($newsData);
    
    		$msg = array(
    			'ToUserName' => $this->getRevFrom(),
    			'FromUserName'=>$this->getRevTo(),
    			'MsgType'=>self::MSGTYPE_NEWS,
    			'CreateTime'=>time(),
    			'ArticleCount'=>$count,
    			'Articles'=>$newsData,
    			'FuncFlag'=>$FuncFlag
    		);
    		$this->Message($msg);
    		return $this;
    	}
    
    	/**
    	 *
    	 * 回复微信服务器, 此函数支持链式操作
    	 * Example: $this->text('msg tips')->reply();
    	 * @param string $msg 要发送的信息, 默认取$this->_msg
    	 * @param bool $return 是否返回信息而不抛出到浏览器 默认:否
    	 */
    	public function reply($msg=array(),$return = false)
    	{
    		if (empty($msg)) {
    		    if (empty($this->_msg))   //防止不先设置回复内容,直接调用reply方法导致异常
    		        return false;
    			$msg = $this->_msg;
    		}
    		$xmldata=  $this->xml_encode($msg);
    		$this->log($xmldata);
    		if ($this->encrypt_type == 'aes') { //如果来源消息为加密方式
    		    $pc = new Prpcrypt($this->encodingAesKey);
    		    $array = $pc->encrypt($xmldata, $this->appid);
    		    $ret = $array[0];
    		    if ($ret != 0) {
    		        $this->log('encrypt err!');
    		        return false;
    		    }
    		    $timestamp = time();
    		    $nonce = rand(77,999)*rand(605,888)*rand(11,99);
    		    $encrypt = $array[1];
    		    $tmpArr = array($this->token, $timestamp, $nonce,$encrypt);//比普通公众平台多了一个加密的密文
    		    sort($tmpArr, SORT_STRING);
    		    $signature = implode($tmpArr);
    		    $signature = sha1($signature);
    		    $xmldata = $this->generate($encrypt, $signature, $timestamp, $nonce);
    		    $this->log($xmldata);
    		}
    		if ($return)
    			return $xmldata;
    		else
    			echo $xmldata;
    	}
    
        /**
         * xml格式加密,仅请求为加密方式时再用
         */
    	private function generate($encrypt, $signature, $timestamp, $nonce)
    	{
    	    //格式化加密信息
    	    $format = "<xml>
    <Encrypt><![CDATA[%s]]></Encrypt>
    <MsgSignature><![CDATA[%s]]></MsgSignature>
    <TimeStamp>%s</TimeStamp>
    <Nonce><![CDATA[%s]]></Nonce>
    </xml>";
    	    return sprintf($format, $encrypt, $signature, $timestamp, $nonce);
    	}
    
    	/**
    	 * GET 请求
    	 * @param string $url
    	 */
    	private function http_get($url){
    		$oCurl = curl_init();
    		if(stripos($url,"https://")!==FALSE){
    			curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
    			curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
    			curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
    		}
    		curl_setopt($oCurl, CURLOPT_URL, $url);
    		curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
    		$sContent = curl_exec($oCurl);
    		$aStatus = curl_getinfo($oCurl);
    		curl_close($oCurl);
    		if(intval($aStatus["http_code"])==200){
    			return $sContent;
    		}else{
    			return false;
    		}
    	}
    
    	/**
    	 * POST 请求
    	 * @param string $url
    	 * @param array $param
    	 * @param boolean $post_file 是否文件上传
    	 * @return string content
    	 */
    	private function http_post($url,$param,$post_file=false){
    		$oCurl = curl_init();
    		if(stripos($url,"https://")!==FALSE){
    			curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
    			curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
    			curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
    		}
    		if (is_string($param) || $post_file) {
    			$strPOST = $param;
    		} else {
    			$aPOST = array();
    			foreach($param as $key=>$val){
    				$aPOST[] = $key."=".urlencode($val);
    			}
    			$strPOST =  join("&", $aPOST);
    		}
    		curl_setopt($oCurl, CURLOPT_URL, $url);
    		curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
    		curl_setopt($oCurl, CURLOPT_POST,true);
    		curl_setopt($oCurl, CURLOPT_POSTFIELDS,$strPOST);
    		$sContent = curl_exec($oCurl);
    		$aStatus = curl_getinfo($oCurl);
    		curl_close($oCurl);
    		if(intval($aStatus["http_code"])==200){
    			return $sContent;
    		}else{
    			return false;
    		}
    	}
    
    	/**
    	 * 设置缓存,按需重载
    	 * @param string $cachename
    	 * @param mixed $value
    	 * @param int $expired
    	 * @return boolean
    	 */
    	protected function setCache($cachename,$value,$expired){
    		//TODO: set cache implementation
    		return false;
    	}
    
    	/**
    	 * 获取缓存,按需重载
    	 * @param string $cachename
    	 * @return mixed
    	 */
    	protected function getCache($cachename){
    		//TODO: get cache implementation
    		return false;
    	}
    
    	/**
    	 * 清除缓存,按需重载
    	 * @param string $cachename
    	 * @return boolean
    	 */
    	protected function removeCache($cachename){
    		//TODO: remove cache implementation
    		return false;
    	}
    
    	/**
    	 * 获取access_token
    	 * @param string $appid 如在类初始化时已提供,则可为空
    	 * @param string $appsecret 如在类初始化时已提供,则可为空
    	 * @param string $token 手动指定access_token,非必要情况不建议用
    	 */
    	public function checkAuth($appid='',$appsecret='',$token=''){
    		if (!$appid || !$appsecret) {
    			$appid = $this->appid;
    			$appsecret = $this->appsecret;
    		}
    		if ($token) { //手动指定token,优先使用
    		    $this->access_token=$token;
    		    return $this->access_token;
    		}
    
    		$authname = 'wechat_access_token'.$appid;
    		if ($rs = $this->getCache($authname))  {
    			$this->access_token = $rs;
    			return $rs;
    		}
    
    		$result = $this->http_get(self::API_URL_PREFIX.self::AUTH_URL.'appid='.$appid.'&secret='.$appsecret);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || isset($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			$this->access_token = $json['access_token'];
    			$expire = $json['expires_in'] ? intval($json['expires_in'])-100 : 3600;
    			$this->setCache($authname,$this->access_token,$expire);
    			return $this->access_token;
    		}
    		return false;
    	}
    
    	/**
    	 * 删除验证数据
    	 * @param string $appid
    	 */
    	public function resetAuth($appid=''){
    		if (!$appid) $appid = $this->appid;
    		$this->access_token = '';
    		$authname = 'wechat_access_token'.$appid;
    		$this->removeCache($authname);
    		return true;
    	}
    
    	/**
    	 * 删除JSAPI授权TICKET
    	 * @param string $appid 用于多个appid时使用
    	 */
    	public function resetJsTicket($appid=''){
    		if (!$appid) $appid = $this->appid;
    		$this->jsapi_ticket = '';
    		$authname = 'wechat_jsapi_ticket'.$appid;
    		$this->removeCache($authname);
    		return true;
    	}
    
    	/**
    	 * 获取JSAPI授权TICKET
    	 * @param string $appid 用于多个appid时使用,可空
    	 * @param string $jsapi_ticket 手动指定jsapi_ticket,非必要情况不建议用
    	 */
    	public function getJsTicket($appid='',$jsapi_ticket=''){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		if (!$appid) $appid = $this->appid;
    		if ($jsapi_ticket) { //手动指定token,优先使用
    		    $this->jsapi_ticket = $jsapi_ticket;
    		    return $this->jsapi_ticket;
    		}
    		$authname = 'wechat_jsapi_ticket'.$appid;
    		if ($rs = $this->getCache($authname))  {
    			$this->jsapi_ticket = $rs;
    			return $rs;
    		}
    		$result = $this->http_get(self::API_URL_PREFIX.self::GET_TICKET_URL.'access_token='.$this->access_token.'&type=jsapi');
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			$this->jsapi_ticket = $json['ticket'];
    			$expire = $json['expires_in'] ? intval($json['expires_in'])-100 : 3600;
    			$this->setCache($authname,$this->jsapi_ticket,$expire);
    			return $this->jsapi_ticket;
    		}
    		return false;
    	}
    
    
    	/**
    	 * 获取JsApi使用签名
    	 * @param string $url 网页的URL,自动处理#及其后面部分
    	 * @param string $timestamp 当前时间戳 (为空则自动生成)
    	 * @param string $noncestr 随机串 (为空则自动生成)
    	 * @param string $appid 用于多个appid时使用,可空
    	 * @return array|bool 返回签名字串
    	 */
    	public function getJsSign($url, $timestamp=0, $noncestr='', $appid=''){
    	    if (!$this->jsapi_ticket && !$this->getJsTicket($appid) || !$url) return false;
    	    if (!$timestamp)
    	        $timestamp = time();
    	    if (!$noncestr)
    	        $noncestr = $this->generateNonceStr();
    	    $ret = strpos($url,'#');
    	    if ($ret)
    	        $url = substr($url,0,$ret);
    	    $url = trim($url);
    	    if (empty($url))
    	        return false;
    	    $arrdata = array("timestamp" => $timestamp, "noncestr" => $noncestr, "url" => $url, "jsapi_ticket" => $this->jsapi_ticket);
    	    $sign = $this->getSignature($arrdata);
    	    if (!$sign)
    	        return false;
    	    $signPackage = array(
    	            "appId"     => $this->appid,
    	            "nonceStr"  => $noncestr,
    	            "timestamp" => $timestamp,
    	            "url"       => $url,
    	            "signature" => $sign
    	    );
    	    return $signPackage;
    	}
    
    	/**
    	 * 微信api不支持中文转义的json结构
    	 * @param array $arr
    	 */
    	static function json_encode($arr) {
    		if (count($arr) == 0) return "[]";
    		$parts = array ();
    		$is_list = false;
    		//Find out if the given array is a numerical array
    		$keys = array_keys ( $arr );
    		$max_length = count ( $arr ) - 1;
    		if (($keys [0] === 0) && ($keys [$max_length] === $max_length )) { //See if the first key is 0 and last key is length - 1
    			$is_list = true;
    			for($i = 0; $i < count ( $keys ); $i ++) { //See if each key correspondes to its position
    				if ($i != $keys [$i]) { //A key fails at position check.
    					$is_list = false; //It is an associative array.
    					break;
    				}
    			}
    		}
    		foreach ( $arr as $key => $value ) {
    			if (is_array ( $value )) { //Custom handling for arrays
    				if ($is_list)
    					$parts [] = self::json_encode ( $value ); /* :RECURSION: */
    				else
    					$parts [] = '"' . $key . '":' . self::json_encode ( $value ); /* :RECURSION: */
    			} else {
    				$str = '';
    				if (! $is_list)
    					$str = '"' . $key . '":';
    				//Custom handling for multiple data types
    				if (!is_string ( $value ) && is_numeric ( $value ) && $value<2000000000)
    					$str .= $value; //Numbers
    				elseif ($value === false)
    				$str .= 'false'; //The booleans
    				elseif ($value === true)
    				$str .= 'true';
    				else
    					$str .= '"' . addslashes ( $value ) . '"'; //All other things
    				// :TODO: Is there any more datatype we should be in the lookout for? (Object?)
    				$parts [] = $str;
    			}
    		}
    		$json = implode ( ',', $parts );
    		if ($is_list)
    			return '[' . $json . ']'; //Return numerical JSON
    		return '{' . $json . '}'; //Return associative JSON
    	}
    
    	/**
    	 * 获取签名
    	 * @param array $arrdata 签名数组
    	 * @param string $method 签名方法
    	 * @return boolean|string 签名值
    	 */
    	public function getSignature($arrdata,$method="sha1") {
    		if (!function_exists($method)) return false;
    		ksort($arrdata);
    		$paramstring = "";
    		foreach($arrdata as $key => $value)
    		{
    			if(strlen($paramstring) == 0)
    				$paramstring .= $key . "=" . $value;
    			else
    				$paramstring .= "&" . $key . "=" . $value;
    		}
    		$Sign = $method($paramstring);
    		return $Sign;
    	}
    
    	/**
    	 * 获取微信卡券api_ticket
    	 * @param string $appid 用于多个appid时使用,可空
    	 * @param string $api_ticket 手动指定api_ticket,非必要情况不建议用
    	 */
    	public function getJsCardTicket($appid='',$api_ticket=''){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		if (!$appid) $appid = $this->appid;
    		if ($api_ticket) { //手动指定token,优先使用
    		    $this->api_ticket = $api_ticket;
    		    return $this->api_ticket;
    		}
    		$authname = 'wechat_api_ticket_wxcard'.$appid;
    		if ($rs = $this->getCache($authname))  {
    			$this->api_ticket = $rs;
    			return $rs;
    		}
    		$result = $this->http_get(self::API_URL_PREFIX.self::GET_TICKET_URL.'access_token='.$this->access_token.'&type=wx_card');
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			$this->api_ticket = $json['ticket'];
    			$expire = $json['expires_in'] ? intval($json['expires_in'])-100 : 3600;
    			$this->setCache($authname,$this->api_ticket,$expire);
    			return $this->api_ticket;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取微信卡券签名
    	 * @param array $arrdata 签名数组
    	 * @param string $method 签名方法
    	 * @return boolean|string 签名值
    	 */
    	public function getTicketSignature($arrdata,$method="sha1") {
    		if (!function_exists($method)) return false;
    		$newArray = array();
    		foreach($arrdata as $key => $value)
    		{
    			array_push($newArray,(string)$value);
    		}
    		sort($newArray,SORT_STRING);
    		return $method(implode($newArray));
    	}
    
    	/**
    	 * 生成随机字串
    	 * @param number $length 长度,默认为16,最长为32字节
    	 * @return string
    	 */
    	public function generateNonceStr($length=16){
    		// 密码字符集,可任意添加你需要的字符
    		$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    		$str = "";
    		for($i = 0; $i < $length; $i++)
    		{
    			$str .= $chars[mt_rand(0, strlen($chars) - 1)];
    		}
    		return $str;
    	}
    
    	/**
    	 * 获取微信服务器IP地址列表
    	 * @return array('127.0.0.1','127.0.0.1')
    	 */
    	public function getServerIp(){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_get(self::API_URL_PREFIX.self::CALLBACKSERVER_GET_URL.'access_token='.$this->access_token);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || isset($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json['ip_list'];
    		}
    		return false;
    	}
    
    	/**
    	 * 创建菜单(认证后的订阅号可用)
    	 * @param array $data 菜单数组数据
    	 * example:
         * 	array (
         * 	    'button' => array (
         * 	      0 => array (
         * 	        'name' => '扫码',
         * 	        'sub_button' => array (
         * 	            0 => array (
         * 	              'type' => 'scancode_waitmsg',
         * 	              'name' => '扫码带提示',
         * 	              'key' => 'rselfmenu_0_0',
         * 	            ),
         * 	            1 => array (
         * 	              'type' => 'scancode_push',
         * 	              'name' => '扫码推事件',
         * 	              'key' => 'rselfmenu_0_1',
         * 	            ),
         * 	        ),
         * 	      ),
         * 	      1 => array (
         * 	        'name' => '发图',
         * 	        'sub_button' => array (
         * 	            0 => array (
         * 	              'type' => 'pic_sysphoto',
         * 	              'name' => '系统拍照发图',
         * 	              'key' => 'rselfmenu_1_0',
         * 	            ),
         * 	            1 => array (
         * 	              'type' => 'pic_photo_or_album',
         * 	              'name' => '拍照或者相册发图',
         * 	              'key' => 'rselfmenu_1_1',
         * 	            )
         * 	        ),
         * 	      ),
         * 	      2 => array (
         * 	        'type' => 'location_select',
         * 	        'name' => '发送位置',
         * 	        'key' => 'rselfmenu_2_0'
         * 	      ),
         * 	    ),
         * 	)
         * type可以选择为以下几种,其中5-8除了收到菜单事件以外,还会单独收到对应类型的信息。
         * 1、click:点击推事件
         * 2、view:跳转URL
         * 3、scancode_push:扫码推事件
         * 4、scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框
         * 5、pic_sysphoto:弹出系统拍照发图
         * 6、pic_photo_or_album:弹出拍照或者相册发图
         * 7、pic_weixin:弹出微信相册发图器
         * 8、location_select:弹出地理位置选择器
    	 */
    	public function createMenu($data){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::MENU_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return true;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取菜单(认证后的订阅号可用)
    	 * @return array('menu'=>array(....s))
    	 */
    	public function getMenu(){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_get(self::API_URL_PREFIX.self::MENU_GET_URL.'access_token='.$this->access_token);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || isset($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 删除菜单(认证后的订阅号可用)
    	 * @return boolean
    	 */
    	public function deleteMenu(){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_get(self::API_URL_PREFIX.self::MENU_DELETE_URL.'access_token='.$this->access_token);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return true;
    		}
    		return false;
    	}
    
    	/**
    	 * 上传临时素材,有效期为3天(认证后的订阅号可用)
    	 * 注意:上传大文件时可能需要先调用 set_time_limit(0) 避免超时
    	 * 注意:数组的键值任意,但文件名前必须加@,使用单引号以避免本地路径斜杠被转义
         * 注意:临时素材的media_id是可复用的!
    	 * @param array $data {"media":'@Path\filename.jpg'}
    	 * @param type 类型:图片:image 语音:voice 视频:video 缩略图:thumb
    	 * @return boolean|array
    	 */
    	public function uploadMedia($data, $type){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		//原先的上传多媒体文件接口使用 self::UPLOAD_MEDIA_URL 前缀
    		$result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_UPLOAD_URL.'access_token='.$this->access_token.'&type='.$type,$data,true);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取临时素材(认证后的订阅号可用)
    	 * @param string $media_id 媒体文件id
    	 * @param boolean $is_video 是否为视频文件,默认为否
    	 * @return raw data
    	 */
    	public function getMedia($media_id,$is_video=false){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		//原先的上传多媒体文件接口使用 self::UPLOAD_MEDIA_URL 前缀
    		//如果要获取的素材是视频文件时,不能使用https协议,必须更换成http协议
    		$url_prefix = $is_video?str_replace('https','http',self::API_URL_PREFIX):self::API_URL_PREFIX;
    		$result = $this->http_get($url_prefix.self::MEDIA_GET_URL.'access_token='.$this->access_token.'&media_id='.$media_id);
    		if ($result)
    		{
                if (is_string($result)) {
                    $json = json_decode($result,true);
                    if (isset($json['errcode'])) {
                        $this->errCode = $json['errcode'];
                        $this->errMsg = $json['errmsg'];
                        return false;
                    }
                }
    			return $result;
    		}
    		return false;
    	}
    
    	/**
    	 * 上传图片,本接口所上传的图片不占用公众号的素材库中图片数量的5000个的限制。图片仅支持jpg/png格式,大小必须在1MB以下。 (认证后的订阅号可用)
    	 * 注意:上传大文件时可能需要先调用 set_time_limit(0) 避免超时
    	 * 注意:数组的键值任意,但文件名前必须加@,使用单引号以避免本地路径斜杠被转义      
    	 * @param array $data {"media":'@Path\filename.jpg'}
    	 * 
    	 * @return boolean|array
    	 */
    	public function uploadImg($data){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		//原先的上传多媒体文件接口使用 self::UPLOAD_MEDIA_URL 前缀
    		$result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_UPLOADIMG_URL.'access_token='.$this->access_token,$data,true);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    
        /**
         * 上传永久素材(认证后的订阅号可用)
         * 新增的永久素材也可以在公众平台官网素材管理模块中看到
         * 注意:上传大文件时可能需要先调用 set_time_limit(0) 避免超时
         * 注意:数组的键值任意,但文件名前必须加@,使用单引号以避免本地路径斜杠被转义
         * @param array $data {"media":'@Path\filename.jpg'}
         * @param type 类型:图片:image 语音:voice 视频:video 缩略图:thumb
         * @param boolean $is_video 是否为视频文件,默认为否
         * @param array $video_info 视频信息数组,非视频素材不需要提供 array('title'=>'视频标题','introduction'=>'描述')
         * @return boolean|array
         */
        public function uploadForeverMedia($data, $type,$is_video=false,$video_info=array()){
            if (!$this->access_token && !$this->checkAuth()) return false;
            //#TODO 暂不确定此接口是否需要让视频文件走http协议
            //如果要获取的素材是视频文件时,不能使用https协议,必须更换成http协议
            //$url_prefix = $is_video?str_replace('https','http',self::API_URL_PREFIX):self::API_URL_PREFIX;
            //当上传视频文件时,附加视频文件信息
            if ($is_video) $data['description'] = self::json_encode($video_info);
            $result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_FOREVER_UPLOAD_URL.'access_token='.$this->access_token.'&type='.$type,$data,true);
            if ($result)
            {
                $json = json_decode($result,true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 上传永久图文素材(认证后的订阅号可用)
         * 新增的永久素材也可以在公众平台官网素材管理模块中看到
         * @param array $data 消息结构{"articles":[{...}]}
         * @return boolean|array
         */
        public function uploadForeverArticles($data){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_FOREVER_NEWS_UPLOAD_URL.'access_token='.$this->access_token,self::json_encode($data));
            if ($result)
            {
                $json = json_decode($result,true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 修改永久图文素材(认证后的订阅号可用)
         * 永久素材也可以在公众平台官网素材管理模块中看到
         * @param string $media_id 图文素材id
         * @param array $data 消息结构{"articles":[{...}]}
         * @param int $index 更新的文章在图文素材的位置,第一篇为0,仅多图文使用
         * @return boolean|array
         */
        public function updateForeverArticles($media_id,$data,$index=0){
            if (!$this->access_token && !$this->checkAuth()) return false;
            if (!isset($data['media_id'])) $data['media_id'] = $media_id;
            if (!isset($data['index'])) $data['index'] = $index;
            $result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_FOREVER_NEWS_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));
            if ($result)
            {
                $json = json_decode($result,true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 获取永久素材(认证后的订阅号可用)
         * 返回图文消息数组或二进制数据,失败返回false
         * @param string $media_id 媒体文件id
         * @param boolean $is_video 是否为视频文件,默认为否
         * @return boolean|array|raw data
         */
        public function getForeverMedia($media_id,$is_video=false){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $data = array('media_id' => $media_id);
            //#TODO 暂不确定此接口是否需要让视频文件走http协议
            //如果要获取的素材是视频文件时,不能使用https协议,必须更换成http协议
            //$url_prefix = $is_video?str_replace('https','http',self::API_URL_PREFIX):self::API_URL_PREFIX;
            $result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_FOREVER_GET_URL.'access_token='.$this->access_token,self::json_encode($data));
            if ($result)
            {
                if (is_string($result)) {
                    $json = json_decode($result,true);
                    if ($json) {
                        if (isset($json['errcode'])) {
                            $this->errCode = $json['errcode'];
                            $this->errMsg = $json['errmsg'];
                            return false;
                        }
                        return $json;
                    } else {
                        return $result;
                    }
                }
                return $result;
            }
            return false;
        }
    
        /**
         * 删除永久素材(认证后的订阅号可用)
         * @param string $media_id 媒体文件id
         * @return boolean
         */
        public function delForeverMedia($media_id){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $data = array('media_id' => $media_id);
            $result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_FOREVER_DEL_URL.'access_token='.$this->access_token,self::json_encode($data));
            if ($result)
            {
                $json = json_decode($result,true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 获取永久素材列表(认证后的订阅号可用)
         * @param string $type 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news)
         * @param int $offset 全部素材的偏移位置,0表示从第一个素材
         * @param int $count 返回素材的数量,取值在1到20之间
         * @return boolean|array
         * 返回数组格式:
         * array(
         *  'total_count'=>0, //该类型的素材的总数
         *  'item_count'=>0,  //本次调用获取的素材的数量
         *  'item'=>array()   //素材列表数组,内容定义请参考官方文档
         * )
         */
        public function getForeverList($type,$offset,$count){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $data = array(
                'type' => $type,
                'offset' => $offset,
                'count' => $count,
            );
            $result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_FOREVER_BATCHGET_URL.'access_token='.$this->access_token,self::json_encode($data));
            if ($result)
            {
                $json = json_decode($result,true);
                if (isset($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 获取永久素材总数(认证后的订阅号可用)
         * @return boolean|array
         * 返回数组格式:
         * array(
         *  'voice_count'=>0, //语音总数量
         *  'video_count'=>0, //视频总数量
         *  'image_count'=>0, //图片总数量
         *  'news_count'=>0   //图文总数量
         * )
         */
        public function getForeverCount(){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_get(self::API_URL_PREFIX.self::MEDIA_FOREVER_COUNT_URL.'access_token='.$this->access_token);
            if ($result)
            {
                $json = json_decode($result,true);
                if (isset($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
    	/**
    	 * 上传图文消息素材,用于群发(认证后的订阅号可用)
    	 * @param array $data 消息结构{"articles":[{...}]}
    	 * @return boolean|array
    	 */
    	public function uploadArticles($data){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_UPLOADNEWS_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 上传视频素材(认证后的订阅号可用)
    	 * @param array $data 消息结构
    	 * {
    	 *     "media_id"=>"",     //通过上传媒体接口得到的MediaId
    	 *     "title"=>"TITLE",    //视频标题
    	 *     "description"=>"Description"        //视频描述
    	 * }
    	 * @return boolean|array
    	 * {
    	 *     "type":"video",
    	 *     "media_id":"mediaid",
    	 *     "created_at":1398848981
    	 *  }
    	 */
    	public function uploadMpVideo($data){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_post(self::UPLOAD_MEDIA_URL.self::MEDIA_VIDEO_UPLOAD.'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 高级群发消息, 根据OpenID列表群发图文消息(订阅号不可用)
    	 * 	注意:视频需要在调用uploadMedia()方法后,再使用 uploadMpVideo() 方法生成,
    	 *             然后获得的 mediaid 才能用于群发,且消息类型为 mpvideo 类型。
    	 * @param array $data 消息结构
    	 * {
    	 *     "touser"=>array(
    	 *         "OPENID1",
    	 *         "OPENID2"
    	 *     ),
    	 *      "msgtype"=>"mpvideo",
    	 *      // 在下面5种类型中选择对应的参数内容
    	 *      // mpnews | voice | image | mpvideo => array( "media_id"=>"MediaId")
    	 *      // text => array ( "content" => "hello")
    	 * }
    	 * @return boolean|array
    	 */
    	public function sendMassMessage($data){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::MASS_SEND_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 高级群发消息, 根据群组id群发图文消息(认证后的订阅号可用)
    	 * 	注意:视频需要在调用uploadMedia()方法后,再使用 uploadMpVideo() 方法生成,
    	 *             然后获得的 mediaid 才能用于群发,且消息类型为 mpvideo 类型。
    	 * @param array $data 消息结构
    	 * {
    	 *     "filter"=>array(
    	 *         "is_to_all"=>False,     //是否群发给所有用户.True不用分组id,False需填写分组id
    	 *         "group_id"=>"2"     //群发的分组id
    	 *     ),
    	 *      "msgtype"=>"mpvideo",
    	 *      // 在下面5种类型中选择对应的参数内容
    	 *      // mpnews | voice | image | mpvideo => array( "media_id"=>"MediaId")
    	 *      // text => array ( "content" => "hello")
    	 * }
    	 * @return boolean|array
    	 */
    	public function sendGroupMassMessage($data){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::MASS_SEND_GROUP_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 高级群发消息, 删除群发图文消息(认证后的订阅号可用)
    	 * @param int $msg_id 消息id
    	 * @return boolean|array
    	 */
    	public function deleteMassMessage($msg_id){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::MASS_DELETE_URL.'access_token='.$this->access_token,self::json_encode(array('msg_id'=>$msg_id)));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return true;
    		}
    		return false;
    	}
    
    	/**
    	 * 高级群发消息, 预览群发消息(认证后的订阅号可用)
    	 * 	注意:视频需要在调用uploadMedia()方法后,再使用 uploadMpVideo() 方法生成,
    	 *             然后获得的 mediaid 才能用于群发,且消息类型为 mpvideo 类型。
    	 * @param array $data 消息结构
    	 * {
    	 *     "touser"=>"OPENID",
    	 *      "msgtype"=>"mpvideo",
    	 *      // 在下面5种类型中选择对应的参数内容
    	 *      // mpnews | voice | image | mpvideo => array( "media_id"=>"MediaId")
    	 *      // text => array ( "content" => "hello")
    	 * }
    	 * @return boolean|array
    	 */
    	public function previewMassMessage($data){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_post(self::API_URL_PREFIX.self::MASS_PREVIEW_URL.'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 高级群发消息, 查询群发消息发送状态(认证后的订阅号可用)
    	 * @param int $msg_id 消息id
    	 * @return boolean|array
    	 * {
    	 *     "msg_id":201053012,     //群发消息后返回的消息id
    	 *     "msg_status":"SEND_SUCCESS" //消息发送后的状态,SENDING表示正在发送 SEND_SUCCESS表示发送成功
    	 * }
    	 */
    	public function queryMassMessage($msg_id){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::MASS_QUERY_URL.'access_token='.$this->access_token,self::json_encode(array('msg_id'=>$msg_id)));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 创建二维码ticket
    	 * @param int|string $scene_id 自定义追踪id,临时二维码只能用数值型
    	 * @param int $type 0:临时二维码;1:数值型永久二维码(此时expire参数无效);2:字符串型永久二维码(此时expire参数无效)
    	 * @param int $expire 临时二维码有效期,最大为604800秒
    	 * @return array('ticket'=>'qrcode字串','expire_seconds'=>604800,'url'=>'二维码图片解析后的地址')
    	 */
    	public function getQRCode($scene_id,$type=0,$expire=604800){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		if (!isset($scene_id)) return false;
    		switch ($type) {
    			case '0':
    				if (!is_numeric($scene_id))
    					return false;
    				$action_name = 'QR_SCENE';
    				$action_info = array('scene'=>(array('scene_id'=>$scene_id)));
    				break;
    
    			case '1':
    				if (!is_numeric($scene_id))
    					return false;
    				$action_name = 'QR_LIMIT_SCENE';
    				$action_info = array('scene'=>(array('scene_id'=>$scene_id)));
    				break;
    
    			case '2':
    				if (!is_string($scene_id))
    					return false;
    				$action_name = 'QR_LIMIT_STR_SCENE';
    				$action_info = array('scene'=>(array('scene_str'=>$scene_id)));
    				break;
    
    			default:
    				return false;
    		}
    
    		$data = array(
    			'action_name'    => $action_name,
    			'expire_seconds' => $expire,
    			'action_info'    => $action_info
    		);
    		if ($type) {
    			unset($data['expire_seconds']);
    		}
    
    		$result = $this->http_post(self::API_URL_PREFIX.self::QRCODE_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result) {
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取二维码图片
    	 * @param string $ticket 传入由getQRCode方法生成的ticket参数
    	 * @return string url 返回http地址
    	 */
    	public function getQRUrl($ticket) {
    		return self::QRCODE_IMG_URL.urlencode($ticket);
    	}
    
    	/**
    	 * 长链接转短链接接口
    	 * @param string $long_url 传入要转换的长url
    	 * @return boolean|string url 成功则返回转换后的短url
    	 */
    	public function getShortUrl($long_url){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $data = array(
                'action'=>'long2short',
                'long_url'=>$long_url
    	    );
    	    $result = $this->http_post(self::API_URL_PREFIX.self::SHORT_URL.'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json['short_url'];
    	    }
    	    return false;
    	}
    
    	/**
    	 * 获取统计数据
    	 * @param string $type  数据分类(user|article|upstreammsg|interface)分别为(用户分析|图文分析|消息分析|接口分析)
    	 * @param string $subtype   数据子分类,参考 DATACUBE_URL_ARR 常量定义部分 或者README.md说明文档
    	 * @param string $begin_date 开始时间
    	 * @param string $end_date   结束时间
    	 * @return boolean|array 成功返回查询结果数组,其定义请看官方文档
    	 */
    	public function getDatacube($type,$subtype,$begin_date,$end_date=''){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    		if (!isset(self::$DATACUBE_URL_ARR[$type]) || !isset(self::$DATACUBE_URL_ARR[$type][$subtype]))
    			return false;
    	    $data = array(
                'begin_date'=>$begin_date,
                'end_date'=>$end_date?$end_date:$begin_date
    	    );
    	    $result = $this->http_post(self::API_BASE_URL_PREFIX.self::$DATACUBE_URL_ARR[$type][$subtype].'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return isset($json['list'])?$json['list']:$json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 批量获取关注用户列表
    	 * @param unknown $next_openid
    	 */
    	public function getUserList($next_openid=''){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_get(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$this->access_token.'&next_openid='.$next_openid);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (isset($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取关注者详细信息
    	 * @param string $openid
    	 * @return array {subscribe,openid,nickname,sex,city,province,country,language,headimgurl,subscribe_time,[unionid]}
    	 * 注意:unionid字段 只有在用户将公众号绑定到微信开放平台账号后,才会出现。建议调用前用isset()检测一下
    	 */
    	public function getUserInfo($openid){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_get(self::API_URL_PREFIX.self::USER_INFO_URL.'access_token='.$this->access_token.'&openid='.$openid);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (isset($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 设置用户备注名
    	 * @param string $openid
    	 * @param string $remark 备注名
    	 * @return boolean|array
    	 */
    	public function updateUserRemark($openid,$remark){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $data = array(
    			'openid'=>$openid,
    			'remark'=>$remark
    	    );
    	    $result = $this->http_post(self::API_URL_PREFIX.self::USER_UPDATEREMARK_URL.'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 获取用户分组列表
    	 * @return boolean|array
    	 */
    	public function getGroup(){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_get(self::API_URL_PREFIX.self::GROUP_GET_URL.'access_token='.$this->access_token);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (isset($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取用户所在分组
    	 * @param string $openid
    	 * @return boolean|int 成功则返回用户分组id
    	 */
    	public function getUserGroup($openid){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $data = array(
    	            'openid'=>$openid
    	    );
    	    $result = $this->http_post(self::API_URL_PREFIX.self::USER_GROUP_URL.'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        } else
                    if (isset($json['groupid'])) return $json['groupid'];
    	    }
    	    return false;
    	}
    
    	/**
    	 * 新增自定分组
    	 * @param string $name 分组名称
    	 * @return boolean|array
    	 */
    	public function createGroup($name){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$data = array(
    				'group'=>array('name'=>$name)
    		);
    		$result = $this->http_post(self::API_URL_PREFIX.self::GROUP_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 更改分组名称
    	 * @param int $groupid 分组id
    	 * @param string $name 分组名称
    	 * @return boolean|array
    	 */
    	public function updateGroup($groupid,$name){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$data = array(
    				'group'=>array('id'=>$groupid,'name'=>$name)
    		);
    		$result = $this->http_post(self::API_URL_PREFIX.self::GROUP_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 移动用户分组
    	 * @param int $groupid 分组id
    	 * @param string $openid 用户openid
    	 * @return boolean|array
    	 */
    	public function updateGroupMembers($groupid,$openid){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$data = array(
    				'openid'=>$openid,
    				'to_groupid'=>$groupid
    		);
    		$result = $this->http_post(self::API_URL_PREFIX.self::GROUP_MEMBER_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 批量移动用户分组
    	 * @param int $groupid 分组id
    	 * @param string $openid_list 用户openid数组,一次不能超过50个
    	 * @return boolean|array
    	 */
    	public function batchUpdateGroupMembers($groupid,$openid_list){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$data = array(
    				'openid_list'=>$openid_list,
    				'to_groupid'=>$groupid
    		);
    		$result = $this->http_post(self::API_URL_PREFIX.self::GROUP_MEMBER_BATCHUPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 发送客服消息
    	 * @param array $data 消息结构{"touser":"OPENID","msgtype":"news","news":{...}}
    	 * @return boolean|array
    	 */
    	public function sendCustomMessage($data){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::CUSTOM_SEND_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * oauth 授权跳转接口
    	 * @param string $callback 回调URI
    	 * @return string
    	 */
    	public function getOauthRedirect($callback,$state='',$scope='snsapi_userinfo'){
    		return self::OAUTH_PREFIX.self::OAUTH_AUTHORIZE_URL.'appid='.$this->appid.'&redirect_uri='.urlencode($callback).'&response_type=code&scope='.$scope.'&state='.$state.'#wechat_redirect';
    	}
    
    	/**
    	 * 通过code获取Access Token
    	 * @return array {access_token,expires_in,refresh_token,openid,scope}
    	 */
    	public function getOauthAccessToken(){
    		$code = isset($_GET['code'])?$_GET['code']:'';
    		if (!$code) return false;
    		$result = $this->http_get(self::API_BASE_URL_PREFIX.self::OAUTH_TOKEN_URL.'appid='.$this->appid.'&secret='.$this->appsecret.'&code='.$code.'&grant_type=authorization_code');
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			$this->user_token = $json['access_token'];
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 刷新access token并续期
    	 * @param string $refresh_token
    	 * @return boolean|mixed
    	 */
    	public function getOauthRefreshToken($refresh_token){
    		$result = $this->http_get(self::API_BASE_URL_PREFIX.self::OAUTH_REFRESH_URL.'appid='.$this->appid.'&grant_type=refresh_token&refresh_token='.$refresh_token);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			$this->user_token = $json['access_token'];
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取授权后的用户资料
    	 * @param string $access_token
    	 * @param string $openid
    	 * @return array {openid,nickname,sex,province,city,country,headimgurl,privilege,[unionid]}
    	 * 注意:unionid字段 只有在用户将公众号绑定到微信开放平台账号后,才会出现。建议调用前用isset()检测一下
    	 */
    	public function getOauthUserinfo($access_token,$openid){
    		$result = $this->http_get(self::API_BASE_URL_PREFIX.self::OAUTH_USERINFO_URL.'access_token='.$access_token.'&openid='.$openid);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 检验授权凭证是否有效
    	 * @param string $access_token
    	 * @param string $openid
    	 * @return boolean 是否有效
    	 */
    	public function getOauthAuth($access_token,$openid){
    	    $result = $this->http_get(self::API_BASE_URL_PREFIX.self::OAUTH_AUTH_URL.'access_token='.$access_token.'&openid='.$openid);
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        } else
    	          if ($json['errcode']==0) return true;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 模板消息 设置所属行业
    	 * @param int $id1  公众号模板消息所属行业编号,参看官方开发文档 行业代码
    	 * @param int $id2  同$id1。但如果只有一个行业,此参数可省略
    	 * @return boolean|array
    	 */
    	public function setTMIndustry($id1,$id2=''){
    	    if ($id1) $data['industry_id1'] = $id1;
    	    if ($id2) $data['industry_id2'] = $id2;
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_post(self::API_URL_PREFIX.self::TEMPLATE_SET_INDUSTRY_URL.'access_token='.$this->access_token,self::json_encode($data));
    	    if($result){
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 模板消息 添加消息模板
    	 * 成功返回消息模板的调用id
    	 * @param string $tpl_id 模板库中模板的编号,有“TM**”和“OPENTMTM**”等形式
    	 * @return boolean|string
    	 */
    	public function addTemplateMessage($tpl_id){
    	    $data = array ('template_id_short' =>$tpl_id);
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_post(self::API_URL_PREFIX.self::TEMPLATE_ADD_TPL_URL.'access_token='.$this->access_token,self::json_encode($data));
    	    if($result){
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json['template_id'];
    	    }
    	    return false;
    	}
    
    	/**
    	 * 发送模板消息
    	 * @param array $data 消息结构
    	 * {
    			"touser":"OPENID",
    			"template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
    			"url":"http://weixin.qq.com/download",
    			"topcolor":"#FF0000",
    			"data":{
    				"参数名1": {
    					"value":"参数",
    					"color":"#173177"	 //参数颜色
    					},
    				"Date":{
    					"value":"06月07日 19时24分",
    					"color":"#173177"
    					},
    				"CardNumber":{
    					"value":"0426",
    					"color":"#173177"
    					},
    				"Type":{
    					"value":"消费",
    					"color":"#173177"
    					}
    			}
    		}
    	 * @return boolean|array
    	 */
    	public function sendTemplateMessage($data){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::TEMPLATE_SEND_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if($result){
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取多客服会话记录
    	 * @param array $data 数据结构{"starttime":123456789,"endtime":987654321,"openid":"OPENID","pagesize":10,"pageindex":1,}
    	 * @return boolean|array
    	 */
    	public function getCustomServiceMessage($data){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_URL_PREFIX.self::CUSTOM_SERVICE_GET_RECORD.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 转发多客服消息
    	 * Example: $obj->transfer_customer_service($customer_account)->reply();
    	 * @param string $customer_account 转发到指定客服帐号:test1@test
    	 */
    	public function transfer_customer_service($customer_account = '')
    	{
    		$msg = array(
    			'ToUserName' => $this->getRevFrom(),
    			'FromUserName'=>$this->getRevTo(),
    			'CreateTime'=>time(),
    			'MsgType'=>'transfer_customer_service',
    		);
    		if ($customer_account) {
    			$msg['TransInfo'] = array('KfAccount'=>$customer_account);
    		}
    		$this->Message($msg);
    		return $this;
    	}
    
    	/**
    	 * 获取多客服客服基本信息
    	 *
    	 * @return boolean|array
    	 */
    	public function getCustomServiceKFlist(){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_get(self::API_URL_PREFIX.self::CUSTOM_SERVICE_GET_KFLIST.'access_token='.$this->access_token);
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 获取多客服在线客服接待信息
    	 *
    	 * @return boolean|array {
    	 "kf_online_list": [
    	 {
    	 "kf_account": "test1@test",	//客服账号@微信别名
    	 "status": 1,			//客服在线状态 1:pc在线,2:手机在线,若pc和手机同时在线则为 1+2=3
    	 "kf_id": "1001",		//客服工号
    	 "auto_accept": 0,		//客服设置的最大自动接入数
    	 "accepted_case": 1		//客服当前正在接待的会话数
    	 }
    	 ]
    	 }
    	 */
    	public function getCustomServiceOnlineKFlist(){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_get(self::API_URL_PREFIX.self::CUSTOM_SERVICE_GET_ONLINEKFLIST.'access_token='.$this->access_token);
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 创建指定多客服会话
    	 * @tutorial 当用户已被其他客服接待或指定客服不在线则会失败
    	 * @param string $openid           //用户openid
    	 * @param string $kf_account     //客服账号
    	 * @param string $text                 //附加信息,文本会展示在客服人员的多客服客户端,可为空
    	 * @return boolean | array            //成功返回json数组
    	 * {
    	 *   "errcode": 0,
    	 *   "errmsg": "ok",
    	 * }
    	 */
    	public function createKFSession($openid,$kf_account,$text=''){
    	    $data=array(
    	    	"openid" =>$openid,
    	        "kf_account" => $kf_account
    	    );
    	    if ($text) $data["text"] = $text;
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_post(self::API_BASE_URL_PREFIX.self::CUSTOM_SESSION_CREATE.'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 关闭指定多客服会话
    	 * @tutorial 当用户被其他客服接待时则会失败
    	 * @param string $openid           //用户openid
    	 * @param string $kf_account     //客服账号
    	 * @param string $text                 //附加信息,文本会展示在客服人员的多客服客户端,可为空
    	 * @return boolean | array            //成功返回json数组
    	 * {
    	 *   "errcode": 0,
    	 *   "errmsg": "ok",
    	 * }
    	 */
    	public function closeKFSession($openid,$kf_account,$text=''){
    	    $data=array(
    	    	"openid" =>$openid,
    	        "kf_account" => $kf_account
    	    );
    	    if ($text) $data["text"] = $text;
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_post(self::API_BASE_URL_PREFIX.self::CUSTOM_SESSION_CLOSE .'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 获取用户会话状态
    	 * @param string $openid           //用户openid
    	 * @return boolean | array            //成功返回json数组
    	 * {
    	 *     "errcode" : 0,
    	 *     "errmsg" : "ok",
    	 *     "kf_account" : "test1@test",    //正在接待的客服
    	 *     "createtime": 123456789,        //会话接入时间
    	 *  }
    	 */
    	public function getKFSession($openid){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_get(self::API_BASE_URL_PREFIX.self::CUSTOM_SESSION_GET .'access_token='.$this->access_token.'&openid='.$openid);
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 获取指定客服的会话列表
    	 * @param string $openid           //用户openid
    	 * @return boolean | array            //成功返回json数组
    	 *  array(
    	 *     'sessionlist' => array (
    	 *         array (
    	 *             'openid'=>'OPENID',             //客户 openid
    	 *             'createtime'=>123456789,  //会话创建时间,UNIX 时间戳
    	 *         ),
    	 *         array (
    	 *             'openid'=>'OPENID',             //客户 openid
    	 *             'createtime'=>123456789,  //会话创建时间,UNIX 时间戳
    	 *         ),
    	 *     )
    	 *  )
    	 */
    	public function getKFSessionlist($kf_account){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_get(self::API_BASE_URL_PREFIX.self::CUSTOM_SESSION_GET_LIST .'access_token='.$this->access_token.'&kf_account='.$kf_account);
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 获取未接入会话列表
    	 * @param string $openid           //用户openid
    	 * @return boolean | array            //成功返回json数组
    	 *  array (
    	 *     'count' => 150 ,                            //未接入会话数量
    	 *     'waitcaselist' => array (
    	 *         array (
    	 *             'openid'=>'OPENID',             //客户 openid
    	 *             'kf_account ' =>'',                   //指定接待的客服,为空则未指定
    	 *             'createtime'=>123456789,  //会话创建时间,UNIX 时间戳
    	 *         ),
    	 *         array (
    	 *             'openid'=>'OPENID',             //客户 openid
    	 *             'kf_account ' =>'',                   //指定接待的客服,为空则未指定
    	 *             'createtime'=>123456789,  //会话创建时间,UNIX 时间戳
    	 *         )
    	 *     )
    	 *  )
    	 */
    	public function getKFSessionWait(){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_get(self::API_BASE_URL_PREFIX.self::CUSTOM_SESSION_GET_WAIT .'access_token='.$this->access_token);
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 添加客服账号
    	 *
    	 * @param string $account      //完整客服账号,格式为:账号前缀@公众号微信号,账号前缀最多10个字符,必须是英文或者数字字符
    	 * @param string $nickname     //客服昵称,最长6个汉字或12个英文字符
    	 * @param string $password     //客服账号明文登录密码,会自动加密
    	 * @return boolean|array
    	 * 成功返回结果
    	 * {
    	 *   "errcode": 0,
    	 *   "errmsg": "ok",
    	 * }
    	 */
    	public function addKFAccount($account,$nickname,$password){
    	    $data=array(
    	    	"kf_account" =>$account,
    	        "nickname" => $nickname,
    	        "password" => md5($password)
    	    );
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::CS_KF_ACCOUNT_ADD_URL.'access_token='.$this->access_token,self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (!$json || !empty($json['errcode'])) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json;
    		}
    		return false;
    	}
    
    	/**
    	 * 修改客服账号信息
    	 *
    	 * @param string $account      //完整客服账号,格式为:账号前缀@公众号微信号,账号前缀最多10个字符,必须是英文或者数字字符
    	 * @param string $nickname     //客服昵称,最长6个汉字或12个英文字符
    	 * @param string $password     //客服账号明文登录密码,会自动加密
    	 * @return boolean|array
    	 * 成功返回结果
    	 * {
    	 *   "errcode": 0,
    	 *   "errmsg": "ok",
    	 * }
    	 */
    	public function updateKFAccount($account,$nickname,$password){
    	    $data=array(
    	            "kf_account" =>$account,
    	            "nickname" => $nickname,
    	            "password" => md5($password)
    	    );
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_post(self::API_BASE_URL_PREFIX.self::CS_KF_ACCOUNT_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 删除客服账号
    	 *
    	 * @param string $account      //完整客服账号,格式为:账号前缀@公众号微信号,账号前缀最多10个字符,必须是英文或者数字字符
    	 * @return boolean|array
    	 * 成功返回结果
    	 * {
    	 *   "errcode": 0,
    	 *   "errmsg": "ok",
    	 * }
    	 */
    	public function deleteKFAccount($account){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_get(self::API_BASE_URL_PREFIX.self::CS_KF_ACCOUNT_DEL_URL.'access_token='.$this->access_token.'&kf_account='.$account);
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 上传客服头像
    	 *
    	 * @param string $account //完整客服账号,格式为:账号前缀@公众号微信号,账号前缀最多10个字符,必须是英文或者数字字符
    	 * @param string $imgfile //头像文件完整路径,如:'D:\user.jpg'。头像文件必须JPG格式,像素建议640*640
    	 * @return boolean|array
    	 * 成功返回结果
    	 * {
    	 *   "errcode": 0,
    	 *   "errmsg": "ok",
    	 * }
    	 */
    	public function setKFHeadImg($account,$imgfile){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $result = $this->http_post(self::API_BASE_URL_PREFIX.self::CS_KF_ACCOUNT_UPLOAD_HEADIMG_URL.'access_token='.$this->access_token.'&kf_account='.$account,array('media'=>'@'.$imgfile),true);
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
    	/**
    	 * 语义理解接口
    	 * @param String $uid      用户唯一id(非开发者id),用户区分公众号下的不同用户(建议填入用户openid)
    	 * @param String $query    输入文本串
    	 * @param String $category 需要使用的服务类型,多个用“,”隔开,不能为空
    	 * @param Float $latitude  纬度坐标,与经度同时传入;与城市二选一传入
    	 * @param Float $longitude 经度坐标,与纬度同时传入;与城市二选一传入
    	 * @param String $city     城市名称,与经纬度二选一传入
    	 * @param String $region   区域名称,在城市存在的情况下可省略;与经纬度二选一传入
    	 * @return boolean|array
    	 */
    	public function querySemantic($uid,$query,$category,$latitude=0,$longitude=0,$city="",$region=""){
    	    if (!$this->access_token && !$this->checkAuth()) return false;
    	    $data=array(
    	            'query' => $query,
    	            'category' => $category,
    	            'appid' => $this->appid,
    	            'uid' => ''
    	    );
    	    //地理坐标或城市名称二选一
    	    if ($latitude) {
    	        $data['latitude'] = $latitude;
    	        $data['longitude'] = $longitude;
    	    } elseif ($city) {
    	        $data['city'] = $city;
    	    } elseif ($region) {
    	        $data['region'] = $region;
    	    }
    	    $result = $this->http_post(self::API_BASE_URL_PREFIX.self::SEMANTIC_API_URL.'access_token='.$this->access_token,self::json_encode($data));
    	    if ($result)
    	    {
    	        $json = json_decode($result,true);
    	        if (!$json || !empty($json['errcode'])) {
    	            $this->errCode = $json['errcode'];
    	            $this->errMsg = $json['errmsg'];
    	            return false;
    	        }
    	        return $json;
    	    }
    	    return false;
    	}
    
        /**
         * 创建卡券
         * @param Array $data      卡券数据
         * @return array|boolean 返回数组中card_id为卡券ID
         */
        public function createCard($data) {
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_CREATE . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 更改卡券信息
         * 调用该接口更新信息后会重新送审,卡券状态变更为待审核。已被用户领取的卡券会实时更新票面信息。
         * @param string $data
         * @return boolean
         */
        public function updateCard($data) {
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_UPDATE . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 删除卡券
         * 允许商户删除任意一类卡券。删除卡券后,该卡券对应已生成的领取用二维码、添加到卡包 JS API 均会失效。
         * 注意:删除卡券不能删除已被用户领取,保存在微信客户端中的卡券,已领取的卡券依旧有效。
         * @param string $card_id 卡券ID
         * @return boolean
         */
        public function delCard($card_id) {
            $data = array(
                'card_id' => $card_id,
            );
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_DELETE . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 查询卡券详情
         * @param string $card_id
         * @return boolean|array    返回数组信息比较复杂,请参看卡券接口文档
         */
        public function getCardInfo($card_id) {
            $data = array(
                'card_id' => $card_id,
            );
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_GET . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 获取颜色列表
    	 * 获得卡券的最新颜色列表,用于创建卡券
    	 * @return boolean|array   返回数组请参看 微信卡券接口文档 的json格式
         */
        public function getCardColors() {
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_get(self::API_BASE_URL_PREFIX . self::CARD_GETCOLORS . 'access_token=' . $this->access_token);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 拉取门店列表
    	 * 获取在公众平台上申请创建的门店列表
    	 * @param int $offset  开始拉取的偏移,默认为0从头开始
    	 * @param int $count   拉取的数量,默认为0拉取全部
    	 * @return boolean|array   返回数组请参看 微信卡券接口文档 的json格式
         */
        public function getCardLocations($offset=0,$count=0) {
    	    $data=array(
    	    	'offset'=>$offset,
    	        'count'=>$count
    	    );
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_LOCATION_BATCHGET . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 批量导入门店信息
    	 * @tutorial 返回插入的门店id列表,以逗号分隔。如果有插入失败的,则为-1,请自行核查是哪个插入失败
    	 * @param array $data    数组形式的json数据,由于内容较多,具体内容格式请查看 微信卡券接口文档
    	 * @return boolean|string 成功返回插入的门店id列表
         */
        public function addCardLocations($data) {
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_LOCATION_BATCHADD . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 生成卡券二维码
    	 * 成功则直接返回ticket值,可以用 getQRUrl($ticket) 换取二维码url
    	 *
    	 * @param string $cardid 卡券ID 必须
    	 * @param string $code 指定卡券 code 码,只能被领一次。use_custom_code 字段为 true 的卡券必须填写,非自定义 code 不必填写。
    	 * @param string $openid 指定领取者的 openid,只有该用户能领取。bind_openid 字段为 true 的卡券必须填写,非自定义 openid 不必填写。
    	 * @param int $expire_seconds 指定二维码的有效时间,范围是 60 ~ 1800 秒。不填默认为永久有效。
    	 * @param boolean $is_unique_code 指定下发二维码,生成的二维码随机分配一个 code,领取后不可再次扫描。填写 true 或 false。默认 false。
    	 * @param string $balance 红包余额,以分为单位。红包类型必填(LUCKY_MONEY),其他卡券类型不填。
         * @return boolean|string
         */
        public function createCardQrcode($card_id,$code='',$openid='',$expire_seconds=0,$is_unique_code=false,$balance='') {
            $card = array(
                'card_id' => $card_id
            );
            $data = array(
                'action_name' => "QR_CARD"
            );
            if ($code)
                $card['code'] = $code;
            if ($openid)
                $card['openid'] = $openid;
            if ($is_unique_code)
                $card['is_unique_code'] = $is_unique_code;
            if ($balance)
                $card['balance'] = $balance;
            if ($expire_seconds)
                $data['expire_seconds'] = $expire_seconds;
            $data['action_info'] = array('card' => $card);
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_QRCODE_CREATE . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 消耗 code
         * 自定义 code(use_custom_code 为 true)的优惠券,在 code 被核销时,必须调用此接口。
         *
         * @param string $code 要消耗的序列号
         * @param string $card_id 要消耗序列号所述的 card_id,创建卡券时use_custom_code 填写 true 时必填。
         * @return boolean|array
         * {
         *  "errcode":0,
         *  "errmsg":"ok",
         *  "card":{"card_id":"pFS7Fjg8kV1IdDz01r4SQwMkuCKc"},
         *  "openid":"oFS7Fjl0WsZ9AMZqrI80nbIq8xrA"
         * }
         */
        public function consumeCardCode($code,$card_id='') {
            $data = array('code' => $code);
            if ($card_id)
                $data['card_id'] = $card_id;
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_CODE_CONSUME . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * code 解码
         * @param string $encrypt_code 通过 choose_card_info 获取的加密字符串
         * @return boolean|array
         * {
         *  "errcode":0,
         *  "errmsg":"ok",
         *  "code":"751234212312"
         *  }
         */
        public function decryptCardCode($encrypt_code) {
            $data = array(
                'encrypt_code' => $encrypt_code,
            );
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_CODE_DECRYPT . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 查询 code 的有效性(非自定义 code)
         * @param string $code
         * @return boolean|array
         * {
         *  "errcode":0,
         *  "errmsg":"ok",
         *  "openid":"oFS7Fjl0WsZ9AMZqrI80nbIq8xrA",    //用户 openid
         *  "card":{
         *      "card_id":"pFS7Fjg8kV1IdDz01r4SQwMkuCKc",
         *      "begin_time": 1404205036,               //起始使用时间
         *      "end_time": 1404205036,                 //结束时间
         *  }
         * }
         */
        public function checkCardCode($code) {
            $data = array(
                'code' => $code,
            );
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_CODE_GET . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 批量查询卡列表
    	 * @param $offset  开始拉取的偏移,默认为0从头开始
    	 * @param $count   需要查询的卡片的数量(数量最大50,默认50)
         * @return boolean|array
         * {
         *  "errcode":0,
         *  "errmsg":"ok",
         *  "card_id_list":["ph_gmt7cUVrlRk8swPwx7aDyF-pg"],    //卡 id 列表
         *  "total_num":1                                       //该商户名下 card_id 总数
         * }
         */
        public function getCardIdList($offset=0,$count=50) {
            if ($count>50)
                $count = 50;
            $data = array(
                'offset' => $offset,
                'count'  => $count,
            );
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_BATCHGET . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 更改 code
         * 为确保转赠后的安全性,微信允许自定义code的商户对已下发的code进行更改。
         * 注:为避免用户疑惑,建议仅在发生转赠行为后(发生转赠后,微信会通过事件推送的方式告知商户被转赠的卡券code)对用户的code进行更改。
         * @param string $code      卡券的 code 编码
         * @param string $card_id   卡券 ID
         * @param string $new_code  新的卡券 code 编码
         * @return boolean
         */
        public function updateCardCode($code,$card_id,$new_code) {
            $data = array(
                'code' => $code,
                'card_id' => $card_id,
                'new_code' => $new_code,
            );
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_CODE_UPDATE . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 设置卡券失效
         * 设置卡券失效的操作不可逆
         * @param string $code 需要设置为失效的 code
         * @param string $card_id 自定义 code 的卡券必填。非自定义 code 的卡券不填。
         * @return boolean
         */
        public function unavailableCardCode($code,$card_id='') {
            $data = array(
                'code' => $code,
            );
            if ($card_id)
                $data['card_id'] = $card_id;
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_CODE_UNAVAILABLE . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 库存修改
         * @param string $data
         * @return boolean
         */
        public function modifyCardStock($data) {
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_MODIFY_STOCK . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 更新门票
         * @param string $data
         * @return boolean
         */
        public function updateMeetingCard($data) {
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_MEETINGCARD_UPDATEUSER . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 激活/绑定会员卡
         * @param string $data 具体结构请参看卡券开发文档(6.1.1 激活/绑定会员卡)章节
         * @return boolean
         */
        public function activateMemberCard($data) {
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_MEMBERCARD_ACTIVATE . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 会员卡交易
         * 会员卡交易后每次积分及余额变更需通过接口通知微信,便于后续消息通知及其他扩展功能。
         * @param string $data 具体结构请参看卡券开发文档(6.1.2 会员卡交易)章节
         * @return boolean|array
         */
        public function updateMemberCard($data) {
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_MEMBERCARD_UPDATEUSER . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 更新红包金额
         * @param string $code      红包的序列号
         * @param $balance          红包余额
         * @param string $card_id   自定义 code 的卡券必填。非自定义 code 可不填。
         * @return boolean|array
         */
        public function updateLuckyMoney($code,$balance,$card_id='') {
            $data = array(
                    'code' => $code,
                    'balance' => $balance
            );
            if ($card_id)
                $data['card_id'] = $card_id;
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_LUCKYMONEY_UPDATE . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 设置卡券测试白名单
         * @param string $openid    测试的 openid 列表
         * @param string $user      测试的微信号列表
         * @return boolean
         */
        public function setCardTestWhiteList($openid=array(),$user=array()) {
            $data = array();
            if (count($openid) > 0)
                $data['openid'] = $openid;
            if (count($user) > 0)
                $data['username'] = $user;
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::CARD_TESTWHILELIST_SET . 'access_token=' . $this->access_token, self::json_encode($data));
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 申请设备ID
         * [applyShakeAroundDevice 申请配置设备所需的UUID、Major、Minor。
         * 若激活率小于50%,不能新增设备。单次新增设备超过500 个,需走人工审核流程。
         * 审核通过后,可用迒回的批次ID 用“查询设备列表”接口拉取本次申请的设备ID]
         * @param array $data
         * array(
         *      "quantity" => 3,         //申请的设备ID 的数量,单次新增设备超过500 个,需走人工审核流程(必填)
         *      "apply_reason" => "测试",//申请理由(必填)
         *      "comment" => "测试专用", //备注(非必填)
         *      "poi_id" => 1234         //设备关联的门店ID(非必填)
         * )
         * @return boolean|mixed
         * {
            "data": {
                "apply_id": 123,
                "device_identifiers":[
                {
                "device_id":10100,
                "uuid":"FDA50693-A4E2-4FB1-AFCF-C6EB07647825",
                "major":10001,
                "minor":10002
                }
                ]
            },
            "errcode": 0,
            "errmsg": "success."
            }
    
            apply_id:申请的批次ID,可用在“查询设备列表”接口按批次查询本次申请成功的设备ID
            device_identifiers:指定的设备ID 列表
            device_id:设备编号
            uuid、major、minor
            audit_status:审核状态。0:审核未通过、1:审核中、2:审核已通过;审核会在三个工作日内完成
            audit_comment:审核备注,包括审核不通过的原因
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-3-25 下午1:24:06
         * @copyright Show More
         */
        public function applyShakeAroundDevice($data){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_DEVICE_APPLYID . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 编辑设备信息
         * [updateShakeAroundDevice 编辑设备的备注信息。可用设备ID或完整的UUID、Major、Minor指定设备,二者选其一。]
         * @param array $data
         * array(
         *      "device_identifier" => array(
         *          		"device_id" => 10011,   //当提供了device_id则不需要使用uuid、major、minor,反之亦然
         *          		"uuid" => "FDA50693-A4E2-4FB1-AFCF-C6EB07647825",
         *          		"major" => 1002,
         *          		"minor" => 1223
         *      ),
         *      "comment" => "测试专用", //备注(非必填)
         * )
         * {
            "data": {
            },
            "errcode": 0,
            "errmsg": "success."
           }
         * @return boolean
         * @author binsee<binsee@163.com>
         * @version 2015-4-20 23:45:00
         */
        public function updateShakeAroundDevice($data){
        	if (!$this->access_token && !$this->checkAuth()) return false;
        	$result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_DEVICE_UPDATE . 'access_token=' . $this->access_token, self::json_encode($data));
        	$this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return true;
            }
            return false;
        }
    
        /**
         * 查询设备列表
         * [searchShakeAroundDevice 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息。
         * 可指定设备ID 或完整的UUID、Major、Minor 查询,也可批量拉取设备信息列表。]
         * @param array $data
         * $data 三种格式:
         * ①查询指定设备时:$data = array(
         *                              "device_identifiers" => array(
         *                                                          array(
         *                                                              "device_id" => 10100,
         *                                                              "uuid" => "FDA50693-A4E2-4FB1-AFCF-C6EB07647825",
         *                                                              "major" => 10001,
         *                                                              "minor" => 10002
         *                                                          )
         *                                                      )
         *                              );
         * device_identifiers:指定的设备
         * device_id:设备编号,若填了UUID、major、minor,则可不填设备编号,若二者都填,则以设备编号为优先
         * uuid、major、minor:三个信息需填写完整,若填了设备编号,则可不填此信息
         * +-------------------------------------------------------------------------------------------------------------
         * ②需要分页查询或者指定范围内的设备时: $data = array(
         *                                                  "begin" => 0,
         *                                                  "count" => 3
         *                                               );
         * begin:设备列表的起始索引值
         * count:待查询的设备个数
         * +-------------------------------------------------------------------------------------------------------------
         * ③当需要根据批次ID 查询时: $data = array(
         *                                      "apply_id" => 1231,
         *                                      "begin" => 0,
         *                                      "count" => 3
         *                                    );
         * apply_id:批次ID
         * +-------------------------------------------------------------------------------------------------------------
         * @return boolean|mixed
         *正确迒回JSON 数据示例:
         *字段说明
            {
                "data": {
                    "devices": [          //指定的设备信息列表
                        {
                            "comment": "", //设备的备注信息
                            "device_id": 10097, //设备编号
                            "major": 10001,
                            "minor": 12102,
                            "page_ids": "15369", //与此设备关联的页面ID 列表,用逗号隔开
                            "status": 1, //激活状态,0:未激活,1:已激活(但不活跃),2:活跃
                            "poi_id": 0, //门店ID
                            "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
                        },
                        {
                            "comment": "", //设备的备注信息
                            "device_id": 10098, //设备编号
                            "major": 10001,
                            "minor": 12103,
                            "page_ids": "15368", //与此设备关联的页面ID 列表,用逗号隔开
                            "status": 1, //激活状态,0:未激活,1:已激活(但不活跃),2:活跃
                            "poi_id": 0, //门店ID
                            "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
                        }
                    ],
                    "total_count": 151 //商户名下的设备总量
                },
                "errcode": 0,
                "errmsg": "success."
            }
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-3-25 下午1:45:42
         * @copyright Show More
         */
        public function searchShakeAroundDevice($data){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_DEVICE_SEARCH . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * [bindLocationShakeAroundDevice 配置设备与门店的关联关系]
         * @param string $device_id 设备编号,若填了UUID、major、minor,则可不填设备编号,若二者都填,则以设备编号为优先
         * @param int $poi_id 待关联的门店ID
         * @param string $uuid UUID、major、minor,三个信息需填写完整,若填了设备编号,则可不填此信息
         * @param int $major
         * @param int $minor
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
         * {
            "data": {
            },
            "errcode": 0,
            "errmsg": "success."
           }
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-4-21 00:14:00
         * @copyright Show More
         */
        public function bindLocationShakeAroundDevice($device_id,$poi_id,$uuid='',$major=0,$minor=0){
            if (!$this->access_token && !$this->checkAuth()) return false;
            if(!$device_id){
                if(!$uuid || !$major || !$minor){
                    return false;
                }
                $device_identifier = array(
                    'uuid' => $uuid,
                    'major' => $major,
                    'minor' => $minor
                );
            }else{
                $device_identifier = array(
                    'device_id' => $device_id
                );
            }
            $data = array(
                'device_identifier' => $device_identifier,
                'poi_id' => $poi_id
            );
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_DEVICE_BINDLOCATION . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json; //这个可以更改为返回true
            }
            return false;
        }
    
        /**
         * [bindPageShakeAroundDevice 配置设备与页面的关联关系。
         * 支持建立或解除关联关系,也支持新增页面或覆盖页面等操作。
         * 配置完成后,在此设备的信号范围内,即可摇出关联的页面信息。
         * 若设备配置多个页面,则随机出现页面信息]
         * @param string $device_id 设备编号,若填了UUID、major、minor,则可不填设备编号,若二者都填,则以设备编号为优先
         * @param array $page_ids 待关联的页面列表
         * @param number $bind 关联操作标志位, 0 为解除关联关系,1 为建立关联关系
         * @param number $append 新增操作标志位, 0 为覆盖,1 为新增
         * @param string $uuid UUID、major、minor,三个信息需填写完整,若填了设备编号,则可不填此信息
         * @param int $major
         * @param int $minor
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
         * {
            "data": {
            },
            "errcode": 0,
            "errmsg": "success."
           }
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-4-21 00:31:00
         * @copyright Show More
         */
        public function bindPageShakeAroundDevice($device_id,$page_ids=array(),$bind=1,$append=1,$uuid='',$major=0,$minor=0){
            if (!$this->access_token && !$this->checkAuth()) return false;
            if(!$device_id){
                if(!$uuid || !$major || !$minor){
                    return false;
                }
                $device_identifier = array(
                    'uuid' => $uuid,
                    'major' => $major,
                    'minor' => $minor
                );
            }else{
                $device_identifier = array(
                    'device_id' => $device_id
                );
            }
            $data = array(
                'device_identifier' => $device_identifier,
                'page_ids' => $page_ids,
                'bind' => $bind,
                'append' => $append
            );
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_DEVICE_BINDPAGE . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * 上传在摇一摇页面展示的图片素材
         * 注意:数组的键值任意,但文件名前必须加@,使用单引号以避免本地路径斜杠被转义
         * @param array $data {"media":'@Path\filename.jpg'} 格式限定为:jpg,jpeg,png,gif,图片大小建议120px*120 px,限制不超过200 px *200 px,图片需为正方形。
         * @return boolean|array
         * {
            "data": {
                "pic_url":"http://shp.qpic.cn/wechat_shakearound_pic/0/1428377032e9dd2797018cad79186e03e8c5aec8dc/120"
            },
                "errcode": 0,
                "errmsg": "success."
            }
           }
         * @author binsee<binsee@163.com>
         * @version 2015-4-21 00:51:00
         */
        public function uploadShakeAroundMedia($data){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $result = $this->http_post(self::API_URL_PREFIX.self::SHAKEAROUND_MATERIAL_ADD.'access_token='.$this->access_token,$data,true);
            if ($result)
            {
                $json = json_decode($result,true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * [addShakeAroundPage 增加摇一摇出来的页面信息,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。]
         * @param string $title 在摇一摇页面展示的主标题,不超过6 个字
         * @param string $description 在摇一摇页面展示的副标题,不超过7 个字
         * @param sting $icon_url 在摇一摇页面展示的图片, 格式限定为:jpg,jpeg,png,gif; 建议120*120 , 限制不超过200*200
         * @param string $page_url 跳转链接
         * @param string $comment 页面的备注信息,不超过15 个字,可不填
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
         * {
            "data": {
                "page_id": 28840 //新增页面的页面id
            }
            "errcode": 0,
            "errmsg": "success."
           }
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-3-25 下午2:57:09
         * @copyright Show More
         */
        public function addShakeAroundPage($title,$description,$icon_url,$page_url,$comment=''){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $data = array(
                "title" => $title,
                "description" => $description,
                "icon_url" => $icon_url,
                "page_url" => $page_url,
                "comment" => $comment
            );
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_PAGE_ADD . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * [updateShakeAroundPage 编辑摇一摇出来的页面信息,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。]
         * @param int $page_id
         * @param string $title 在摇一摇页面展示的主标题,不超过6 个字
         * @param string $description 在摇一摇页面展示的副标题,不超过7 个字
         * @param sting $icon_url 在摇一摇页面展示的图片, 格式限定为:jpg,jpeg,png,gif; 建议120*120 , 限制不超过200*200
         * @param string $page_url 跳转链接
         * @param string $comment 页面的备注信息,不超过15 个字,可不填
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
         * {
            "data": {
                "page_id": 28840 //编辑页面的页面ID
            }
            "errcode": 0,
            "errmsg": "success."
           }
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-3-25 下午3:02:51
         * @copyright Show More
         */
        public function updateShakeAroundPage($page_id,$title,$description,$icon_url,$page_url,$comment=''){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $data = array(
                "page_id" => $page_id,
                "title" => $title,
                "description" => $description,
                "icon_url" => $icon_url,
                "page_url" => $page_url,
                "comment" => $comment
            );
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_PAGE_UPDATE . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * [searchShakeAroundPage 查询已有的页面,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
         * 提供两种查询方式,①可指定页面ID 查询,②也可批量拉取页面列表。]
         * @param array $page_ids
         * @param int $begin
         * @param int $count
         * ①需要查询指定页面时:
         * {
            "page_ids":[12345, 23456, 34567]
           }
         * +-------------------------------------------------------------------------------------------------------------
         * ②需要分页查询或者指定范围内的页面时:
         * {
            "begin": 0,
            "count": 3
           }
         * +-------------------------------------------------------------------------------------------------------------
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
            {
                "data": {
                    "pages": [
                        {
                            "comment": "just for test",
                            "description": "test",
                            "icon_url": "https://www.baidu.com/img/bd_logo1.png",
                            "page_id": 28840,
                            "page_url": "http://xw.qq.com/testapi1",
                            "title": "测试1"
                        },
                        {
                            "comment": "just for test",
                            "description": "test",
                            "icon_url": "https://www.baidu.com/img/bd_logo1.png",
                            "page_id": 28842,
                            "page_url": "http://xw.qq.com/testapi2",
                            "title": "测试2"
                        }
                        ],
                    "total_count": 2
                },
                "errcode": 0,
                "errmsg": "success."
            }
         *字段说明:
         *total_count 商户名下的页面总数
         *page_id 摇周边页面唯一ID
         *title 在摇一摇页面展示的主标题
         *description 在摇一摇页面展示的副标题
         *icon_url 在摇一摇页面展示的图片
         *page_url 跳转链接
         *comment 页面的备注信息
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-3-25 下午3:12:17
         * @copyright Show More
         */
        public function searchShakeAroundPage($page_ids=array(),$begin=0,$count=1){
            if (!$this->access_token && !$this->checkAuth()) return false;
            if(!empty($page_ids)){
                $data = array(
                    'page_ids' => $page_ids
                );
            }else{
                $data = array(
                    'begin' => $begin,
                    'count' => $count
                );
            }
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_PAGE_SEARCH . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * [deleteShakeAroundPage 删除已有的页面,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
         * 只有页面与设备没有关联关系时,才可被删除。]
         * @param array $page_ids
         * {
            "page_ids":[12345,23456,34567]
           }
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
         * {
            "data": {
            },
            "errcode": 0,
            "errmsg": "success."
           }
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-3-25 下午3:23:00
         * @copyright Show More
         */
        public function deleteShakeAroundPage($page_ids=array()){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $data = array(
                'page_ids' => $page_ids
            );
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_PAGE_DELETE . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * [getShakeInfoShakeAroundUser 获取设备信息,包括UUID、major、minor,以及距离、openID 等信息。]
         * @param string $ticket 摇周边业务的ticket,可在摇到的URL 中得到,ticket生效时间为30 分钟
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
         * {
            "data": {
                "page_id ": 14211,
                "beacon_info": {
                    "distance": 55.00620700469034,
                    "major": 10001,
                    "minor": 19007,
                    "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
                },
                "openid": "oVDmXjp7y8aG2AlBuRpMZTb1-cmA"
            },
            "errcode": 0,
            "errmsg": "success."
           }
         * 字段说明:
         * beacon_info 设备信息,包括UUID、major、minor,以及距离
         * UUID、major、minor UUID、major、minor
         * distance Beacon 信号与手机的距离
         * page_id 摇周边页面唯一ID
         * openid 商户AppID 下用户的唯一标识
         * poi_id 门店ID,有的话则返回,没有的话不会在JSON 格式内
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-3-25 下午3:28:20
         * @copyright Show More
         */
        public function getShakeInfoShakeAroundUser($ticket){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $data = array('ticket' => $ticket);
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_USER_GETSHAKEINFO . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
        /**
         * [deviceShakeAroundStatistics 以设备为维度的数据统计接口。
         * 查询单个设备进行摇周边操作的人数、次数,点击摇周边消息的人数、次数;查询的最长时间跨度为30天。]
         * @param int $device_id 设备编号,若填了UUID、major、minor,即可不填设备编号,二者选其一
         * @param int $begin_date 起始日期时间戳,最长时间跨度为30 天
         * @param int $end_date 结束日期时间戳,最长时间跨度为30 天
         * @param string $uuid UUID、major、minor,三个信息需填写完成,若填了设备编辑,即可不填此信息,二者选其一
         * @param int $major
         * @param int $minor
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
         * {
            "data": [
                {
                    "click_pv": 0,
                    "click_uv": 0,
                    "ftime": 1425052800,
                    "shake_pv": 0,
                    "shake_uv": 0
                },
                {
                    "click_pv": 0,
                    "click_uv": 0,
                    "ftime": 1425139200,
                    "shake_pv": 0,
                    "shake_uv": 0
                }
            ],
            "errcode": 0,
            "errmsg": "success."
           }
         * 字段说明:
         * ftime 当天0 点对应的时间戳
         * click_pv 点击摇周边消息的次数
         * click_uv 点击摇周边消息的人数
         * shake_pv 摇周边的次数
         * shake_uv 摇周边的人数
         * @access public
         * @author polo<gao.bo168@gmail.com>
         * @version 2015-4-21 00:39:00
         * @copyright Show More
         */
        public function deviceShakeAroundStatistics($device_id,$begin_date,$end_date,$uuid='',$major=0,$minor=0){
            if (!$this->access_token && !$this->checkAuth()) return false;
            if(!$device_id){
                if(!$uuid || !$major || !$minor){
                    return false;
                }
                $device_identifier = array(
                    'uuid' => $uuid,
                    'major' => $major,
                    'minor' => $minor
                );
            }else{
                $device_identifier = array(
                    'device_id' => $device_id
                );
            }
            $data = array(
                'device_identifier' => $device_identifier,
                'begin_date' => $begin_date,
                'end_date' => $end_date
            );
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_STATISTICS_DEVICE . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
    
        /**
         * [pageShakeAroundStatistics 以页面为维度的数据统计接口。
         * 查询单个页面通过摇周边摇出来的人数、次数,点击摇周边页面的人数、次数;查询的最长时间跨度为30天。]
         * @param int $page_id 指定页面的ID
         * @param int $begin_date 起始日期时间戳,最长时间跨度为30 天
         * @param int $end_date 结束日期时间戳,最长时间跨度为30 天
         * @return boolean|mixed
         * 正确返回JSON 数据示例:
         * {
            "data": [
                {
                    "click_pv": 0,
                    "click_uv": 0,
                    "ftime": 1425052800,
                    "shake_pv": 0,
                    "shake_uv": 0
                },
                {
                    "click_pv": 0,
                    "click_uv": 0,
                    "ftime": 1425139200,
                    "shake_pv": 0,
                    "shake_uv": 0
                }
            ],
            "errcode": 0,
            "errmsg": "success."
           }
         * 字段说明:
         * ftime 当天0 点对应的时间戳
         * click_pv 点击摇周边消息的次数
         * click_uv 点击摇周边消息的人数
         * shake_pv 摇周边的次数
         * shake_uv 摇周边的人数
         * @author binsee<binsee@163.com>
         * @version 2015-4-21 00:43:00
         */
        public function pageShakeAroundStatistics($page_id,$begin_date,$end_date){
            if (!$this->access_token && !$this->checkAuth()) return false;
            $data = array(
                'page_id' => $page_id,
                'begin_date' => $begin_date,
                'end_date' => $end_date
            );
            $result = $this->http_post(self::API_BASE_URL_PREFIX . self::SHAKEAROUND_STATISTICS_DEVICE . 'access_token=' . $this->access_token, self::json_encode($data));
            $this->log($result);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || !empty($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg  = $json['errmsg'];
                    return false;
                }
                return $json;
            }
            return false;
        }
    
    	/**
    	 * 根据订单ID获取订单详情
    	 * @param string $order_id 订单ID
    	 * @return order array|bool
    	 */
    	public function getOrderByID($order_id){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		if (!$order_id) return false;
    
    		$data = array(
    			'order_id'=>$order_id
    		);
    		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::MERCHANT_ORDER_GETBYID.'access_token='.$this->access_token, self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (isset($json['errcode']) && $json['errcode']) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json['order'];
    		}
    		return false;
    	}
    
    	/**
    	 * 根据订单状态/创建时间获取订单详情
    	 * @param int $status 订单状态(不带该字段-全部状态, 2-待发货, 3-已发货, 5-已完成, 8-维权中, )
    	 * @param int $begintime 订单创建时间起始时间(不带该字段则不按照时间做筛选)
    	 * @param int $endtime 订单创建时间终止时间(不带该字段则不按照时间做筛选)
    	 * @return order list array|bool
    	 */
    	public function getOrderByFilter($status = null, $begintime = null, $endtime = null){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    
    		$data = array();
    
    		$valid_status = array(2, 3, 5, 8);
    		if (is_numeric($status) && in_array($status, $valid_status)) {
    			$data['status'] = $status;
    		}
    
    		if (is_numeric($begintime) && is_numeric($endtime)) {
    			$data['begintime'] = $begintime;
    			$data['endtime'] = $endtime;
    		}
    		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::MERCHANT_ORDER_GETBYFILTER.'access_token='.$this->access_token, self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (isset($json['errcode']) && $json['errcode']) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return $json['order_list'];
    		}
    		return false;
    	}
    
    	/**
    	 * 设置订单发货信息
    	 * @param string $order_id 订单 ID
    	 * @param int $need_delivery 商品是否需要物流(0-不需要,1-需要)
    	 * @param string $delivery_company 物流公司 ID
    	 * @param string $delivery_track_no 运单 ID
    	 * @param int $is_others 是否为 6.4.5 表之外的其它物流公司(0-否,1-是)
    	 * @return bool
    	 */
    	public function setOrderDelivery($order_id, $need_delivery = 0, $delivery_company = null, $delivery_track_no = null, $is_others = 0){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		if (!$order_id) return false;
    
    		$data = array();
    		$data['order_id'] = $order_id;
    		if ($need_delivery) {
    			$data['delivery_company'] = $delivery_company;
    			$data['delivery_track_no'] = $delivery_track_no;
    			$data['is_others'] = $is_others;
    		}
    		else {
    			$data['need_delivery'] = $need_delivery;
    		}
    
    		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::MERCHANT_ORDER_SETDELIVERY.'access_token='.$this->access_token, self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (isset($json['errcode']) && $json['errcode']) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return true;
    		}
    		return false;
    	}
    
    	/**
    	 * 关闭订单
    	 * @param string $order_id 订单 ID
    	 * @return bool
    	 */
    	public function closeOrder($order_id){
    		if (!$this->access_token && !$this->checkAuth()) return false;
    		if (!$order_id) return false;
    
    		$data = array(
    			'order_id'=>$order_id
    		);
    
    		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::MERCHANT_ORDER_CLOSE.'access_token='.$this->access_token, self::json_encode($data));
    		if ($result)
    		{
    			$json = json_decode($result,true);
    			if (isset($json['errcode']) && $json['errcode']) {
    				$this->errCode = $json['errcode'];
    				$this->errMsg = $json['errmsg'];
    				return false;
    			}
    			return true;
    		}
    		return false;
    	}
    
    	private function parseSkuInfo($skuInfo) {
    		$skuInfo = str_replace("\$", "", $skuInfo);
    		$matches = explode(";", $skuInfo);
    
    		$result = array();
    		foreach ($matches as $matche) {
    			$arrs = explode(":", $matche);
    			$result[$arrs[0]] = $arrs[1];
    		}
    
    		return $result;
    	}
    
    	/**
    	 * 获取订单SkuInfo - 订单付款通知
    	 * 当Event为 merchant_order(订单付款通知)
    	 * @return array|boolean
    	 */
    	public function getRevOrderSkuInfo(){
    		if (isset($this->_receive['SkuInfo']))     //订单 SkuInfo
    			return $this->parseSkuInfo($this->_receive['SkuInfo']);
    		else
    			return false;
    	}
    }
    /**
     * PKCS7Encoder class
     *
     * 提供基于PKCS7算法的加解密接口.
     */
    class PKCS7Encoder
    {
        public static $block_size = 32;
    
        /**
         * 对需要加密的明文进行填充补位
         * @param $text 需要进行填充补位操作的明文
         * @return 补齐明文字符串
         */
        function encode($text)
        {
            $block_size = PKCS7Encoder::$block_size;
            $text_length = strlen($text);
            //计算需要填充的位数
            $amount_to_pad = PKCS7Encoder::$block_size - ($text_length % PKCS7Encoder::$block_size);
            if ($amount_to_pad == 0) {
                $amount_to_pad = PKCS7Encoder::block_size;
            }
            //获得补位所用的字符
            $pad_chr = chr($amount_to_pad);
            $tmp = "";
            for ($index = 0; $index < $amount_to_pad; $index++) {
                $tmp .= $pad_chr;
            }
            return $text . $tmp;
        }
    
        /**
         * 对解密后的明文进行补位删除
         * @param decrypted 解密后的明文
         * @return 删除填充补位后的明文
         */
        function decode($text)
        {
    
            $pad = ord(substr($text, -1));
            if ($pad < 1 || $pad > PKCS7Encoder::$block_size) {
                $pad = 0;
            }
            return substr($text, 0, (strlen($text) - $pad));
        }
    
    }
    
    /**
     * Prpcrypt class
     *
     * 提供接收和推送给公众平台消息的加解密接口.
     */
    class Prpcrypt
    {
        public $key;
    
        function __construct($k) {
            $this->key = base64_decode($k . "=");
        }
    
        /**
         * 兼容老版本php构造函数,不能在 __construct() 方法前边,否则报错
         */
        function Prpcrypt($k)
        {
            $this->key = base64_decode($k . "=");
        }
    
        /**
         * 对明文进行加密
         * @param string $text 需要加密的明文
         * @return string 加密后的密文
         */
        public function encrypt($text, $appid)
        {
    
            try {
                //获得16位随机字符串,填充到明文之前
                $random = $this->getRandomStr();//"aaaabbbbccccdddd";
                $text = $random . pack("N", strlen($text)) . $text . $appid;
                // 网络字节序
                $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
                $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
                $iv = substr($this->key, 0, 16);
                //使用自定义的填充方式对明文进行补位填充
                $pkc_encoder = new PKCS7Encoder;
                $text = $pkc_encoder->encode($text);
                mcrypt_generic_init($module, $this->key, $iv);
                //加密
                $encrypted = mcrypt_generic($module, $text);
                mcrypt_generic_deinit($module);
                mcrypt_module_close($module);
    
                //			print(base64_encode($encrypted));
                //使用BASE64对加密后的字符串进行编码
                return array(ErrorCode::$OK, base64_encode($encrypted));
            } catch (Exception $e) {
                //print $e;
                return array(ErrorCode::$EncryptAESError, null);
            }
        }
    
        /**
         * 对密文进行解密
         * @param string $encrypted 需要解密的密文
         * @return string 解密得到的明文
         */
        public function decrypt($encrypted, $appid)
        {
    
            try {
                //使用BASE64对需要解密的字符串进行解码
                $ciphertext_dec = base64_decode($encrypted);
                $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
                $iv = substr($this->key, 0, 16);
                mcrypt_generic_init($module, $this->key, $iv);
                //解密
                $decrypted = mdecrypt_generic($module, $ciphertext_dec);
                mcrypt_generic_deinit($module);
                mcrypt_module_close($module);
            } catch (Exception $e) {
                return array(ErrorCode::$DecryptAESError, null);
            }
    
    
            try {
                //去除补位字符
                $pkc_encoder = new PKCS7Encoder;
                $result = $pkc_encoder->decode($decrypted);
                //去除16位随机字符串,网络字节序和AppId
                if (strlen($result) < 16)
                    return "";
                $content = substr($result, 16, strlen($result));
                $len_list = unpack("N", substr($content, 0, 4));
                $xml_len = $len_list[1];
                $xml_content = substr($content, 4, $xml_len);
                $from_appid = substr($content, $xml_len + 4);
                if (!$appid)
                    $appid = $from_appid;
                //如果传入的appid是空的,则认为是订阅号,使用数据中提取出来的appid
            } catch (Exception $e) {
                //print $e;
                return array(ErrorCode::$IllegalBuffer, null);
            }
            if ($from_appid != $appid)
                return array(ErrorCode::$ValidateAppidError, null);
            //不注释上边两行,避免传入appid是错误的情况
            return array(0, $xml_content, $from_appid); //增加appid,为了解决后面加密回复消息的时候没有appid的订阅号会无法回复
    
        }
    
    
        /**
         * 随机生成16位字符串
         * @return string 生成的字符串
         */
        function getRandomStr()
        {
    
            $str = "";
            $str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
            $max = strlen($str_pol) - 1;
            for ($i = 0; $i < 16; $i++) {
                $str .= $str_pol[mt_rand(0, $max)];
            }
            return $str;
        }
    
    }
    
    /**
     * error code
     * 仅用作类内部使用,不用于官方API接口的errCode码
     */
    class ErrorCode
    {
        public static $OK = 0;
        public static $ValidateSignatureError = 40001;
        public static $ParseXmlError = 40002;
        public static $ComputeSignatureError = 40003;
        public static $IllegalAesKey = 40004;
        public static $ValidateAppidError = 40005;
        public static $EncryptAESError = 40006;
        public static $DecryptAESError = 40007;
        public static $IllegalBuffer = 40008;
        public static $EncodeBase64Error = 40009;
        public static $DecodeBase64Error = 40010;
        public static $GenReturnXmlError = 40011;
        public static $errCode=array(
                '0' => '处理成功',
                '40001' => '校验签名失败',
                '40002' => '解析xml失败',
                '40003' => '计算签名失败',
                '40004' => '不合法的AESKey',
                '40005' => '校验AppID失败',
                '40006' => 'AES加密失败',
                '40007' => 'AES解密失败',
                '40008' => '公众平台发送的xml不合法',
                '40009' => 'Base64编码失败',
                '40010' => 'Base64解码失败',
                '40011' => '公众帐号生成回包xml失败'
        );
        public static function getErrText($err) {
            if (isset(self::$errCode[$err])) {
                return self::$errCode[$err];
            }else {
                return false;
            };
        }
    }
    

     

    展开全文
  • <?php // http://tstcwx.sinaapp.com/sea_server.php /* 微信帐号echo_server的实现 */ /*定义TOKEN为 token*/ ... // 登录教务系统的的文件 //函数功能:验证微信的来源的正确性。 function c...
    <?php
    // http://tstcwx.sinaapp.com/sea_server.php
    /*
    微信帐号echo_server的实现
    */
    /*定义TOKEN为 token*/
    define("TOKEN","token");
    include 'jwgl.class.php';   // 登录教务系统的类的文件
    
    //函数功能:验证微信的来源的正确性。
    function checkSignature()
    {
    		// 获取GET参数
    	$signature = $_GET['signature'];
    	$nonce = $_GET['nonce'];
    	$timestamp = $_GET['timestamp'];
    	
    	//把nonce timestamp和token组装到数列里并排序
    	$token = TOKEN;
    	$tmpArr = array($token, $timestamp, $nonce);
    	sort($tmpArr, SORT_STRING);
    	
    	//把数组中的元素合并成字符串
    	$tmpStr = implode($tmpArr);
    	//shal加密
    	$tmpStr = sha1($tmpStr);
    	
    	if($tmpStr == $signature)
    	{
    		//相等就返回echostr
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    //判断
    
    if(false == checkSignature())
    {
    	exit(0);
    }
    // 获取echostr
    $echostr = $_GET['echostr'];
    if($echostr)
    {
    	echo $echostr;
    	exit(0);
    }
    
    // 分析用户输入并输出
    //获取POST数据
    function getPostData()
    {
    	global $HTTP_RAW_POST_DATA;
    	$data = $HTTP_RAW_POST_DATA;
    // 判断post数据是否为空
    	if(!$data)
    	{
    		echo "wrong input!";
    		exit(0);
    	}
    	return $data;
    }
    $PostData = getPostData();
    // 解析XML字符串
    $xmlObj = simplexml_load_string($PostData,'SimpleXMLElement',LIBXML_NOCDATA);
    if(!$xmlObj)
    {
    	echo 'wring input!';
    	exit(0);
    }
    //获取FromUserName
    $fromUserName = $xmlObj->FromUserName;
    //获取ToUserName
    $toUserName = $xmlObj->ToUserName;
    //获取MsgType
    $msgType = $xmlObj->MsgType;
    
    
    //函数功能 检查数据库中是否有该用户数据,若存在则返回账户密码,若不存在则返回false
    function checkopenid()
    {
    	$db_host=SAE_MYSQL_HOST_M;                                           //连接的服务器地址
    	$db_user=SAE_MYSQL_USER;                                                  //连接数据库的用户名
    	$db_psw=SAE_MYSQL_PASS;                                                  //连接数据库的密码
    	$db_name=SAE_MYSQL_DB;                                                 //连接的数据库名称
        
    	global $fromUserName;
    	
    	$db = new MySQLi($db_host,$db_user,$db_psw,$db_name,SAE_MYSQL_PORT);
    
    	if (mysqli_connect_errno()) 
    	{
    		echo "Error: Could not connect to database.  Please try again later.";
    		exit;
    	}
    	
    	$query = "select * from user where openid = '".$fromUserName."'";
    	
    	$result = $db->query($query);
    	
    	$num_results = $result->num_rows;
    	
    	sae_debug($num_results);
    	
    	if($num_results != 0)
    	{
    		$row = $result->fetch_array();
    		//sae_debug(error_msg(str_split($row)));
    		//var_dump($row);
    		sae_debug(count($row));
    		$stu = array('stuID' => $row['SID'],'SIDpasswd' => $row['SIDpasswd']);
    		//echo '<br>';
    		//var_dump($stu);
    		//echo '<br>enter';
    		return $stu;
    	}
    	else
    	{
    		return NULL;
    	}
    	
    	//echo '<br>'.$num_results.'<br>';
    }
    
    if('text' != $msgType)
    {
    	$retMsg = '只支持文本消息';
    }
    else
    {
    	if(($stu = checkopenid()) != NULL)
    	{
    		// 若数据库中有数据
    		//sae_debug(count($stu));
    		$stuID = $stu['stuID'];
    		$stuIDpasswd = $stu['SIDpasswd'];
    		sae_debug($stuID);
    		sae_debug($stuIDpasswd);
    		//sae_debug('stuid');
    		$jw = new jwgl();
    		$jw->setuse($stuID,$stuIDpasswd);
    		if($jw->login() == false)
    		{
    			sae_debug('login error');
    			//Header("Location: loginform.html"); 
    		}
    		else
    			$results = $jw->get_grade();  //保存查询结果
    		$count = count($results);
    		sae_debug($count);
    		foreach($results as $values)
    		{
    		//var_dump($values);
    			//echo '<br>-------------------------------------------<br>';
    			//$temp = $temp. "学年:".$values['学年']." 学期:".$values["学期"]." 课程名称:".$values['课程名称']." 成绩:".$values['成绩'];
    			$temp = $temp." 课程名称:".$values['课程名称']." 成绩:".$values['成绩'];
    		}
    		sae_debug($temp);
    		$retMsg = $temp;
    	}
    	else
    	{
    		//若数据库中没有数据
    		$retMsg = 'http://tstcwx.sinaapp.com/login.php?openid='.$fromUserName;
    	}
    }
    //输出消息的XML模版
    $retTmp = "<xml>
    		<ToUserName><![CDATA[%s]]></ToUserName>
    		<FromUserName><![CDATA[%s]]></FromUserName>
    		<CreateTime>%s</CreateTime>
    		<MsgType><![CDATA[text]]></MsgType>
    		<Content><![CDATA[%s]]></Content>
    		</xml>";
    
    $resultStr = sprintf($retTmp,$fromUserName,$toUserName,time(),$retMsg);
    //输出XML描述的消息
    echo $resultStr;

    版权声明:本文为博主原创文章,未经博主允许不得转载。

    转载于:https://www.cnblogs.com/bingfeng13/p/4669001.html

    展开全文
  • 微信公共平台消息封装一个,便于开发使用。具体效果自己测试
  • 本文主要介绍,解决PHP微信开发时数据缓存的问题,这里用Cache 举例说明,具有参考价值,感兴趣的小伙伴可以参考下
  • * 微信公众平台操作 */ class WeChat { private $_appid; private $_appsecret; //微信公众平台请求开发者的服务器需要token private $_token; //标识qrcodeticket的类型,是永久还是临时 con....
  • PHP:关于微信开发

    2019-11-21 17:19:24
    <?php // 定义token ... // 实例化当前的微信类 $wechat = new Wechat(); // 判断是通过微信后台点击提交按钮进行验证,还是通过微信客户端输入内容进行响应 if($_GET['echostr']){ //验证 ...
  • 小编分别从两种(PHP和java)不同语言分别给大家介绍了几款微信开发框架,首先介绍一下PHP的平台。1,豆信基于thinkphp3.2.3开发的开源系统,源码免费,接收捐赠,不能商用,特点是高度封装,灵活拓展,便捷开发,...
  • POST只能保存标准的数据类型,对于XML、SOAP或Application/Octet-steam之的内容则无法解析。 而$GLOBALS[“HTTP_RAW_POST_DATA”]和$_POST是一样的,如果POST过来的数据PHP能够识别,则可以用$GLOB
  • 在URL中填写服务器地址,这个地址就是接受微信推送事件的一个接口,我是使用thinkPHP框架开发的程序,在其中一个Module(Decoration)的Action目录下新建一个,比如叫: WechatAction.class.php
  • 本文实例讲述了微信公众号开发微信公共平台消息回复。分享给大家供大家参考。具体如下: 微信公众号开发代码我在网上看到了有不少,其实都是大同小义了都是参考官方给出的demo文件进行修改的,这里就给各位分享...
  • 主要介绍了PHP封装的微信公众平台接口开发操作,结合完整实例形式分析了php微信开发所涉及的配置、验证、接收、响应、文本、语音、图片等相关操作技巧,需要的朋友可以参考下

空空如也

1 2 3 4 5 ... 20
收藏数 483
精华内容 193
关键字:

微信开发php类