zoukankan      html  css  js  c++  java
  • ThinkPHP5 微信接口对接公共类

    <?php
    
    // .-----------------------------------------------------------------------------------
    // | Software: [wechat framework]
    // | Version: 2017.7
    // | Site: 
    // |-----------------------------------------------------------------------------------
    // | Author: bug <3164145970@qq.com>
    // | Copyright (c) 2017, . All Rights Reserved.
    // |-----------------------------------------------------------------------------------
    /**
     * 基于thinkphp5的微信自定义接口开发
     * @package wechat
     * @author bug <3164145970@qq.com>
     * @createtime 2017-07-26 10:48:30
     * @description 
     */
    // |-----------------------------------------------------------------------------------
    
    namespace util;
    use thinkException;
    /**
     * 微信公共类文件
     * @package util
     * @author bug <3164145970@qq.com>
     * @createtime 2017-07-26 11:10:14
     * 
     */
    class WeChat
    {
    /**********************基础配置  开始********/
        /**
         * 微信公众号AppId
         * @var string
         */
        private  $appid;
    
        /**
         * 微信公众号AppSecret
         * @var string
         */
        private  $appsecret;
        /**
         * 微信公众号验证服务器token
         * @var string
         */
        private  $token;
        /**
         * 微信公众号EncodingAESKey
         * @var string
         */
        private  $encoding_aeskey;
        /**
         * 微信公众号商户号
         * @var string
         */
        private  $mch_id;
        /**
         * 微信公众号商户支付密钥
         * @var string
         */
        private  $key;
        //=======【证书路径设置】=====================================
        /**
         * TODO:设置商户证书路径
         * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载,
         * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书)
         * @var path
         */
        const SSLCERT_PATH = "certapiclient_cert.pem";
        const SSLKEY_PATH = "certapiclient_key.pem";
        //=======【curl代理设置】===================================
        /**
         * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0
         * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器,
         * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置)
         * @var unknown_type
         */
        const CURL_PROXY_HOST = "0.0.0.0";//"10.152.18.220";
        const CURL_PROXY_PORT = 0;//8080;
        //=======【上报信息配置】===================================
        /**
         * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】,
         * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少
         * 开启错误上报。
         * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报
         * @var int
         */
        const REPORT_LEVENL = 1;
        /**
         * 微信公共类构造方法
         * @author bug <3164145970@qq.com>
         * @createtime 2017-07-26 11:10:14
         * @param string  $appid   微信公众号AppId
         * @param string  $appsecret 微信公众号AppSecret
         * @param string  $token   微信公众号验证服务器token
         * @param string  $encoding_aeskey   微信公众号EncodingAESKey
         * @param string  $mch_id   微信公众号商户号
         * @param string  $key   微信公众号商户支付密钥
         */
        public function __construct(){
            $this->appid = config('crm_config.wechat_appid');//获取配置文件中的微信公众号AppId
            $this->appsecret = config('crm_config.wechat_secret');//获取配置文件中的微信公众号AppSecret
            $this->token = config('crm_config.token');//获取配置文件中的微信公众号验证服务器token
            $this->encoding_aeskey = config('crm_config.encoding_aeskey');//获取配置文件中的微信公众号EncodingAESKey
            $this->mch_id = config('crm_config.wechat_mch_id');//获取配置文件中的微信公众号商户号
            $this->key = config('crm_config.wechat_key');//获取配置文件中的微信公众号商户支付密钥
        }
    /**********************基础配置  结束********/
    
    /**********************开始开发  开始********/
        /**
         * token验证服务器
         * @author bug <3164145970@qq.com>
         * @createtime 2017-07-26 11:10:14
         * @param string  $nonce   随机数 
         * @param string  $timestamp 时间戳
         * @param string  $echostr 随机字符串
         * @param string  $signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
         * @return  echostr参数内容或false
         */
        public function token($nonce,$timestamp,$echostr,$signature){
            //参数字典序排序 
            $array = array(); 
            $array = array($nonce, $timestamp, $this->token); 
            sort($array); 
            //验证 
            $str = sha1( implode( $array ) );//sha1加密 
            //对比验证处理好的str与signature,若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。 
            if( $str == $signature && $echostr ){ 
                return $echostr; 
            } 
            else{ 
                return false;
            }
    
        }
    
        /**
        * 通过appid和appsecret获取access_token 或从缓存获取基础支持access_token
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-26 11:07:24
        * @param type true强制获取access_token,用于本地存储的access_token在微信服务器已过期,但在本地服务器未过期时
        * @return  string 获取到的凭证
        */
        private function access_token($type){
            // //session开始
            // if(!isset($_SESSION)){
            //     session_start();
            // }
            // //判断缓存中是否存在access_token,如果存在取出来返回
            // if(!$type&&isset($_SESSION['access_token'])&&$_SESSION['access_token']['endtime']>time()){
            //     $result = array('status'=>1,'data'=>$_SESSION['access_token']['val']);
            //     return $result;
    
            // }
            // //配置请求url,加入appid和appsecret参数
            // $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$this->appid.'&secret='.$this->appsecret;
            // //获取请求结果,并将请求结果转换成json
            // $data = string_json($url);  
            // if(array_key_exists('errcode', $data)){
            //     $result = array('status'=>40014,'data'=>$data);
            //     return $result;
            // }
            // /**将新获取的access_token缓存到服务器 开始**/
            // session_set_cookie_params($data['expires_in']); //设置access_token在服务器session中缓存时间
            // $access_token['val'] = $data['access_token'];
            // $access_token['endtime'] = time()+$data['expires_in'];
            // $_SESSION['access_token']= $access_token;
            // /**将新获取的access_token缓存到服务器 结束**/
            // //返回结果
            // $result = array('status'=>2,'data'=>$data['access_token']);
            // return $result;
    
    
            // access_token 应该全局存储与更新,以下代码以写入到文件中做示例
            $datas = json_decode(file_get_contents(dirname(__FILE__)."/json/access_token.json"));
            if (!$type && $datas->expire_time > time()) {
                $result = array('status'=>1,'data'=>$datas->access_token);
                return $result;
            }
    
            //配置请求url,加入appid和appsecret参数
            // 如果是企业号用以下URL获取access_token
            // $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
            $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$this->appid.'&secret='.$this->appsecret;
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            if(array_key_exists('errcode', $data)){
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
    
            //将access_token 写入文件
            $datas->expire_time = time()+$data['expires_in'];
            $datas->access_token = $data['access_token'];
            $fp = fopen(dirname(__FILE__)."/json/access_token.json", "w");
            fwrite($fp, json_encode($datas));
            fclose($fp);
            //返回结果
            $result = array('status'=>2,'data'=>$data['access_token']);
            return $result;
        }
         /**
        * 接口调用上限清零
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-30 13:44:55
        * @param post_data 请求数据
        * @return json 请求结果
        */
        public function clear_quota(){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            $post_data['appid'] = $this->appid;
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/clear_quota?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->clear_quota();
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
        /**
        * 获取微信服务器IP地址
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-26 13:51:20
        * @return json ip_list 微信服务器IP地址
        */
        public  function ip_list(){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token='.$access_token['data'];
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            if(array_key_exists('errcode', $data)){
                //access_token 过期重新获取并重新回调当前函数
                if($data['errcode']==42001   || $data['errcode']==40001){
                    $access_token = $this->access_token(true);
                    return $this->ip_list();
                }
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
    /**********************开始开发  结束********/
    
    /**********************自定义菜单  开始********/
        /**
        * 自定义菜单创建接口
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-26 14:24:40
        * @param post_data 请求数据
        * @return json 请求结果
        */
        public function create_menu($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->create_menu($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
        /**
        * 自定义菜单查询接口
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-26 14:17:05
        * @return json 菜单列表
        */
        public function get_menu(){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/menu/get?access_token='.$access_token['data'];
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            if(array_key_exists('errcode', $data)){
                //access_token 过期重新获取并重新回调当前函数
                if($data['errcode']==42001   || $data['errcode']==40001){
                    $access_token = $this->access_token(true);
                    return $this->get_menu();
                }
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
        /**
        * 自定义菜单删除接口
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-26 14:17:05
        * @return json 请求结果
        */
        public function delete_menu(){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/menu/delete?access_token='.$access_token['data'];
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->delete_menu();
            }
            $status = $data['errcode']==0?1:40014;
            //返回结果
            $result = array('status'=>$status,'data'=>$data);
            return $result;
    
        }
        /**
        * 获取自定义菜单配置接口
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-26 14:17:05
        * @return json 菜单列表
        */
        public function menu_config(){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token='.$access_token['data'];
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            if(array_key_exists('errcode', $data)){
                //access_token 过期重新获取并重新回调当前函数
                if($data['errcode']==42001   || $data['errcode']==40001){
                    $access_token = $this->access_token(true);
                    return $this->menu_config();
                }
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
    /**********************自定义菜单  结束********/
    
    /**********************消息管理  开始********/
        
        /**
        * 消息/事件推送处理
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 15:58:42
        * @param poststr xml 推送数据字符串
        * @return [type] [description]
        */
        public function responseMsg($poststr){
            
             //如果推送消息 或者推送事件存在,进行处理
            if(!empty($poststr)){
                libxml_disable_entity_loader(true);
                $postObj = simplexml_load_string($poststr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $msgType = $postObj->MsgType;
                //判断事件类型,进行对应事件类型处理
                switch ($msgType) {
                    case 'text':
                         $resultStr =  $this->handleText($postObj);
                        break;
                    case 'image':
                        $resultStr =  $this->handleImage($postObj);
                        break;
                    case 'voice':
                        $resultStr =  $this->handleVoice($postObj);
                        break;
                    case 'video':
                        $resultStr =  $this->handleVideo($postObj);
                        break;
                    case 'shortvideo':
                        $resultStr =  $this->handleShortVideo($postObj);
                        break;
                    case 'location':
                        $resultStr =  $this->handleLocation($postObj);
                        break;
                    case 'link':
                        $resultStr =  $this->handleLink($postObj);
                        break;
                    case 'event':
                        $resultStr =  $this->handleEvent($postObj);
                        break;
                    default:
                        $resultStr =  "Unknow msg type: ".$msgType;
                        break;
                }
    
                return $resultStr;
            }
        }
    
        /**---------------------------------------------------------接收消息-接收普通消息 开始-------------------------------------------------------------**/
    
        /**
        * 接收文本消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 17:22:58
        * @param postObj object 推送事件对象
        * @return [type] [description]
        */ 
        public function handleText($postObj){
            $contentStr = "您发送了文本消息:".$postObj->Content;
            return $this->responseText($postObj,$contentStr);
        }
        /**
        * 接收图片消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 17:22:58
        * @param postObj object 推送事件对象
        * @return [type] [description]
        */ 
        public function handleImage($postObj){
            $contentStr = "您发送了图片,图片链接:".$postObj->PicUrl.",图片消息媒体id:".$postObj->MediaId.",消息id:".$postObj->MsgId;
            return $this->responseText($postObj,$contentStr);
        }
        /**
        * 接收语音消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 17:22:58
        * @param postObj object 推送事件对象
        * @return [type] [description]
        */ 
        public function handleVoice($postObj){
            $contentStr = "您发送了语音,语音消息媒体id:".$postObj->MediaId.",语音格式:".$postObj->Format.",消息id".$postObj->MsgId.",Recognition:".$postObj->Recognition;
            return $this->responseText($postObj,$contentStr);
        }
        /**
        * 接收视频消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 17:22:58
        * @param postObj object 推送事件对象
        * @return [type] [description]
        */ 
        public function handleVideo($postObj){
            $contentStr = "您发送了视频,语音消息媒体id:".$postObj->MediaId.",视频消息缩略图的媒体id:".$postObj->ThumbMediaId.",消息id".$postObj->MsgId;
            return $this->responseText($postObj,$contentStr);
        }
        /**
        * 接收小视频消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 17:22:58
        * @param postObj object 推送事件对象
        * @return [type] [description]
        */ 
        public function handleShortVideo($postObj){
            $contentStr = "您发送了小视频,语音消息媒体id:".$postObj->MediaId.",视频消息缩略图的媒体id:".$postObj->ThumbMediaId.",消息id".$postObj->MsgId;
            return $this->responseText($postObj,$contentStr);
        }
        /**
        * 接收地理位置消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 17:22:58
        * @param postObj object 推送事件对象
        * @return [type] [description]
        */ 
        public function handleLocation($postObj){
            $contentStr = "您发送了地理位置,地理位置维度:".$postObj->Location_X.",地理位置经度:".$postObj->Location_Y.",地图缩放大小:".$postObj->Scale.",地理位置信息:".$postObj->Label.",消息id:".$postObj->MsgId;
            return $this->responseText($postObj,$contentStr);
        }
            /**
        * 接收链接消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 17:22:58
        * @param postObj object 推送事件对象
        * @return [type] [description]
        */ 
        public function handleLink($postObj){
            $contentStr = "您发送了链接,消息标题:".$postObj->Title.",消息描述:".$postObj->Description.",消息链接:".$postObj->Url.",消息id:".$postObj->MsgId;
            return $this->responseText($postObj,$contentStr);
        }
    
        /**---------------------------------------------------------接收消息-接收普通消息 结束-------------------------------------------------------------**/
    
        /**---------------------------------------------接收消息-接收事件推送 开始-------------------------------------------------------------**/
        /**
        * 接收事件推送
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 17:22:58
        * @param postObj object 推送事件对象
        * @return [type] [description]
        */ 
        public function handleEvent($postObj){
            $event = $postObj->Event;
            switch ($event) {
                case 'subscribe'://关注
                    break;
                case 'unsubscribe'://取消关注
                    break;
                case 'scancode_waitmsg'://扫描二维码
                    break;
                case 'SCAN':
                    break;
                case 'LOCATION':
                    break;
                case 'VIEW':
                    break;
                default:
                    # code...
                    break;
            }
            $contentStr = "您触发了事件:".$event;
            return $this->responseText($postObj,$contentStr);
        }
        /**------------------------------------------------------------接收消息-接收事件推送 结束-------------------------------------------------------------**/
    
        /**------------------------------------------------------发送消息-被动回复用户消息 开始-------------------------------------------------------------**/
        /**
        * 推送事件回复文本消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 16:05:33 
        * @param object 接收的推送对象
        * @param content string 回复的文本消息
        * @return [type] [description]
        */
        public function responseText($object,$content)
        {
            $textTpl = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[text]]></MsgType>
                        <Content><![CDATA[%s]]></Content>
                        </xml>";
            $resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(),$content);
            return $resultStr;
        }
    
        /**
        * 推送事件回复图片消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 16:05:33 
        * @param object 接收的推送对象
        * @param MediaId 通过素材管理中的接口上传多媒体文件,得到的id
        * @return [type] [description]
        */
        public function responseImage($object,$media_id)
        {
            $textTpl = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[image]]></MsgType>
                        <Image>
                        <MediaId><![CDATA[media_id]]></MediaId>
                        </Image>
                        </xml>";
            $resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(),$media_id);
            return $resultStr;
        }
    
        /**
        * 推送事件回复语音消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 16:05:33 
        * @param object 接收的推送对象
        * @param MediaId 通过素材管理中的接口上传多媒体文件,得到的id
        * @return [type] [description]
        */
        public function responseVoice($object,$media_id)
        {
            $textTpl = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[voice]]></MsgType>
                        <Voice>
                        <MediaId><![CDATA[%s]]></MediaId>
                        </Voice>
                        </xml>";
            $resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(),$media_id);
            return $resultStr;
        }
    
        /**
        * 推送事件回复视频消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 16:05:33 
        * @param object 接收的推送对象
        * @param media_id 通过素材管理中的接口上传多媒体文件,得到的id
        * @param title 视频消息的标题
        * @param description 视频消息的描述
        * @return
        */
        public function responseVideo($object,$media_id,$title='',$description='')
        {
            $textTpl = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[video]]></MsgType>
                        <Video>
                        <MediaId><![CDATA[%s]]></MediaId>
                        <Title><![CDATA[%s]]></Title>
                        <Description><![CDATA[%s]]></Description>
                        </Video> 
                        </xml>";
            $resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(),$media_id,$title,$description);
            return $resultStr;
        }
         /**
        * 推送事件回复音乐消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 16:05:33 
        * @param object 接收的推送对象
        * @param media_id 缩略图的媒体id,通过素材管理中的接口上传多媒体文件,得到的id
        * @param title 音乐标题
        * @param description 音乐描述
        * @param music_url 音乐链接
        * @param hqmusic_url 高质量音乐链接,WIFI环境优先使用该链接播放音乐
        * @return 
        */
        public function responseMusic($object,$media_id,$title='',$description='',$music_url='',$hqmusic_url='')
        {
            $textTpl = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[music]]></MsgType>
                        <Music>
                        <Title><![CDATA[TITLE]]></Title>
                        <Description><![CDATA[DESCRIPTION]]></Description>
                        <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>
                        <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>
                        <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>
                        </Music>
                        </xml>";
            $resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(),$title,$description,$music_url,$hqmusic_url,$media_id);
            return $resultStr;
        }
        /**
        * 推送事件回复图文消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-16 16:05:33 
        * @param object 接收的推送对象
        * @param articles 图文消息数组
        * @param article_count 图文消息个数,限制为8条以内
        * @param title 图文消息标题
        * @param description 图文消息描述
        * @param pic_url 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200
        * @param url 点击图文消息跳转链接
        * @return 
        */
        public function responseNews($object,$articles)
        {
            $article_count = count($articles);
            $textTpl = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[news]]></MsgType>
                        <ArticleCount>%s</ArticleCount>
                        <Articles>";
            $textTpl = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(),$article_count);
            $article_tpl ="<item>
                            <Title><![CDATA[%s]]></Title> 
                            <Description><![CDATA[%s]]></Description>
                            <PicUrl><![CDATA[%s]]></PicUrl>
                            <Url><![CDATA[%s]]></Url>
                            </item>";
            foreach ($articles as $value) {
                $article_str = sprintf($article_tpl,$value['title'],$value['description'],$value['picurl'],$value['url']);
                $textTpl .= $article_str;
            }              
            $textTpl .= "</Articles>
                        </xml>";
            return $textTpl;
        }
        /**--------------------------------------------------------发送消息-被动回复用户消息 结束-------------------------------------------------------------**/
    
        /**
        * 客服接口-发消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-28 09:27:56
        * @param openid string 微信用户唯一凭证openid
        * @param type string 1 文本 2图文
        * @param data json 请求数据集
        * @return [type] [description]
        */
        public function custom_send($openid,$type,$msg,$customservice=''){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='.$access_token['data'];
            $post_data['touser'] = $openid;
            $post_data['msgtype'] = $type;
            switch ($type) {
                case 'text'://发送文本消息
                    $post_data['text']['content'] = $msg;
                    break;
                case 'image'://发送图片消息
                    $post_data['image']['media_id'] = $msg;
                    break;
                case 'voice'://发送语音消息
                    $post_data['voice']['media_id'] = $msg;
                    break;
                case 'video'://发送视频消息,参数media_id,thumb_media_id,title,description
                    $post_data['video'] = $msg;
                    break;
                case 'music'://发送音乐消息,参数title,description,musicurl,hqmusicurl,thumb_media_id
                    $post_data['music'] = $msg;
                    break;
                case 'news'://发送图文消息(点击跳转到外链) 图文消息条数限制在8条以内,注意,如果图文数超过8,则将会无响应
                    $post_data['news']['articles'] =$msg;
                    break;
                case 'mpnews'://发送图文消息(点击跳转到图文消息页面) 图文消息条数限制在8条以内,注意,如果图文数超过8,则将会无响应
                    $post_data['mpnews']['media_id'] = $msg;
                    break;
                case 'wxcard'://发送卡券
                    $post_data['wxcard']['card_id'] = $msg;
                    break;
                case 'miniprogrampage'://发送小程序卡片,参数title,appid,pagepath,thumb_media_id
                    $post_data['miniprogrampage'] = $msg;
                    break;
                default:
                    $post_data['msgtype'] = 'text';
                    $post_data['text']['content'] = '这是一个默认图文消息:无消息类型';
                    break;
            }
            //请注意,如果需要以某个客服帐号来发消息(在微信6.0.2及以上版本中显示自定义头像),则需在JSON数据包的后半部分加入customservice参数
            if(!empty($customservice)){
                $post_data['customservice']['kf_account'] = $customservice;
            }
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001 || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->custom_send($openid,$type,$msg,$customservice);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result; 
        }
    
    
        /**
        * 获取模板列表
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-25 14:43:54
        * @param access_token 微信调用接口唯一凭证 
        * @return json
        */
        public function template_list(){
             //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token='.$access_token['data'];
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            if(array_key_exists('errcode', $data)){
                //access_token 过期重新获取并重新回调当前函数
                if($data['errcode']==42001  || $data['errcode']==40001){
                    $access_token = $this->access_token(true);
                    return $this->template_list();
                }
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
        /**
        * 模板接口-发消息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-01 15:50:11
        * @param data json 请求数据集
        * @return [type] [description]
        */
        public function template_send($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001 || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->template_send($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
    /**********************消息管理  结束********/
    
    /**********************微信网页授权  开始********/
        
        /**
        * 通过微信授权code获取微信用户access_token
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-27 11:26:30
        * @param code 微信用户授权获取的code
        * @return json 返回结果
        */
        public function user_access_token($code){
    
            //session开始
            if(!isset($_SESSION)){
                session_start();
            }
            //如果code已经被使用过了返回缓存里面的微信用户access_token相关信息
            if(isset($_SESSION['user_access_token'])&&$code==$_SESSION['user_access_token']['code']){
                $data = $_SESSION['user_access_token'];
                $result = array('status'=>2,'data'=>$data);
                return $result;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$this->appid.'&secret='.$this->appsecret.'&code='.$code.'&grant_type=authorization_code';
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url); 
            //获取当前时间
            $time = time();
            if(array_key_exists('errcode', $data)){
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            session_set_cookie_params(60*5); //设置access_token在服务器session中缓存时间
            //添加access_token过期时间
            $data['access_endtime'] = $time+$data['expires_in'];
            //添加refresh_token过期时间
            $data['refresh_endtime'] = $time+60*60*24*30;
            $data['code'] = $code;
            $_SESSION['user_access_token'] = $data;
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
        /**
        * 刷新微信用户access_token
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-27 11:26:27
        * @param refresh_token 微信用户用来刷新access_token用的
        * @param state int 微信用户获取access_token的state
        * @return json 返回结果
        */
        public function user_refresh_token($refresh_token,$state=0){
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid='.$this->appid.'&grant_type=refresh_token&refresh_token='.$refresh_token;
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            //获取当前时间
            $time = time();
            if(array_key_exists('errcode', $data)){
                if($data['errcode']==42002){
                    //如果超时重定向首页重新获取refresh_token
                    header("location: https://open.weixin.qq.com/connect/oauth2/authorize?appid=".config('crm_config.wechat_appid')."&redirect_uri=".urlencode(config('crm_config.user_accesstoken_uri'))."&response_type=code&scope=snsapi_base&state=".$state."#wechat_redirect");exit;
                }
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            //添加access_token过期时间
            $data['access_endtime'] = $time+$data['expires_in'];
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
        /**
        * 拉取用户信息(需scope为 snsapi_userinfo)
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-27 11:26:27
        * @param string access_token 微信用户授权获取的access_token
        * @param string openid 微信用户唯一凭证
        * @return json 返回结果
        */
        public function userinfo($access_token,$openid){
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token.'&openid='.$openid.'&lang=zh_CN';
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            if(array_key_exists('errcode', $data)){
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }    
        /**
        * 检验授权凭证(access_token)是否有效
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-07-27 11:26:27
        * @param string access_token 微信用户授权获取的access_token
        * @param string openid 微信用户唯一凭证
        * @return json 返回结果
        */
        public function auth($access_token,$openid){
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/sns/auth?access_token='.$access_token.'&openid='.$openid;
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            //返回结果
            $status = $data['errcode']==0?1:40014;
            $result = array('status'=>$status,'data'=>$data);
            return $result;
            
        }   
    /**********************微信网页授权  结束********/
    
    /**********************微信自定义分享  开始********/
        
        /**
        * 获取微信自定已分享配置参数包
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-05 14:21:04
        * @return array 配置参数包
        */
        public function getSignPackage() {
            $jsapiTicket = $this->getJsApiTicket();
    
            // 注意 URL 一定要动态获取,不能 hardcode.
            $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
            $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
    
            $timestamp = time();
            $nonceStr = $this->createNonceStr();
            // 这里参数的顺序要按照 key 值 ASCII 码升序排序
            $string = "jsapi_ticket=".$jsapiTicket."&noncestr=".$nonceStr."&timestamp=".$timestamp."&url=".$url;
    
            $signature = sha1($string);
    
            $signPackage = array(
              "appId"     => $this->appid,
              "nonceStr"  => $nonceStr,
              "timestamp" => $timestamp,
              "url"       => $url,
              "signature" => $signature,
              "rawString" => $string
            );
            return $signPackage; 
          }
    
        /**
        * 微信自定义分享随机字符串
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-05 14:22:15
        * @param length int 随机字符串长度
        * @return str string 随机字符串
        */
        private function createNonceStr($length = 16) {
            $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            $str = "";
            for ($i = 0; $i < $length; $i++) {
              $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
            }
            return $str;
          }
    
        /**
        * 微信自定义分享获取jsapiticket
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-05 14:23:30
        * @return jsapi_ticket string 微信jsapi调用凭证
        */
        private function getJsApiTicket() {
            // jsapi_ticket 应该全局存储与更新,以下代码以写入到文件中做示例
          
            $data = json_decode(file_get_contents(dirname(__FILE__)."/json/jsapi_ticket.json"));
            if ($data->expire_time < time()) {
              $access_token = $this->access_token(false);
              if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
                }
              // 如果是企业号用以下 URL 获取 ticket
              // $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=".$access_token['data'];
              $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".$access_token['data'];
              $res = json_decode(https_get($url));
              if(!isset($res->ticket)){
                    $access_token = $this->access_token(true);
                    $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".$access_token['data'];
                    $res = json_decode(https_get($url));
              }
              $ticket = $res->ticket;
              if ($ticket) {
                $data->expire_time = time() + 7200;
                $data->jsapi_ticket = $ticket;
                $fp = fopen(dirname(__FILE__)."/json/jsapi_ticket.json", "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
              }
            } else {
              $ticket = $data->jsapi_ticket;
            }
    
            return $ticket;
          }
    /**********************微信自定义分享  结束********/
    
    /**********************素材管理  开始********/
        
        /**
        * 获取永久素材列表
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-02 16:44:24
        * @param type string 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news)
        * @param offset int 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
        * @param count int 返回素材的数量,取值在1到20之间
        * @return [type] [description]
        */
        public function material_list($type,$offset=0,$count=20){
             //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //组装参数
            $post_data['type'] = $type;
            $post_data['offset'] = $offset;
            $post_data['count'] = $count;
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
            //access_token 过期重新获取并重新回调当前函数
            if(isset($data['errcode']) && ($data['errcode']==42001 || $data['errcode']==40001)){
                $access_token = $this->access_token(true);
                return $this->create_menu($type,$offset,$count);
            }
            //返回结果
            if(!isset($data['errcode'])){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
    /**********************素材管理  结束********/
    
    /**********************用户管理  开始********/
        /**
        * 获取关注用户个人信息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-25 14:43:54
        * @param access_token string 微信调用接口唯一凭证 
        * @param  openid string 用户的openid
        * @return json
        */
        public function user_info($openid=''){
             //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$access_token['data'].'&openid='.$openid.'&lang=zh_CN ';
    
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            if(array_key_exists('errcode', $data)){
                //access_token 过期重新获取并重新回调当前函数
                if($data['errcode']==42001 || $data['errcode']==40001 ){
                    $access_token = $this->access_token(true);
                    return $this->user_info($openid);
                }
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
    
        /**
        * 批量获取用户信息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-16 14:20:46
        * @param data json 请求数据集
        * @return [type] [description]
        */
        public function user_list_info($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if(isset($data['errcode'])&&($data['errcode']==42001 || $data['errcode']==40001)){
                $access_token = $this->access_token(true);
                return $this->user_list_info($post_data);
            }
            //返回结果
            if(isset($data['user_info_list'])){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
    
        /**
        * 获取关注用户列表
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-25 14:43:54
        * @param access_token string 微信调用接口唯一凭证 
        * @param  next_openid string 上次请求最后一个用户的openid
        * @return json
        */
        public function user_list($next_openid=''){
             //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
    
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/cgi-bin/user/get?access_token='.$access_token['data'];
            if(!empty($next_openid)){
                $url.='&next_openid='.$next_openid;
            }
            //获取请求结果,并将请求结果转换成json
            $data = string_json($url);  
            if(array_key_exists('errcode', $data)){
                //access_token 过期重新获取并重新回调当前函数
                if($data['errcode']==42001  || $data['errcode']==40001){
                    $access_token = $this->access_token(true);
                    return $this->user_list($next_openid);
                }
                $result = array('status'=>40014,'data'=>$data);
                return $result;
            }
            //返回结果
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
    /**********************用户管理  结束********/
    
    /**********************新版客服  开始********/
        
        /**
        * 添加客服账号
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-02 15:39:36
        * @param post_data 请求数据 
        * @param kf_account string 完整客服帐号,格式为:帐号前缀@公众号微信号,帐号前缀最多10个字符,必须是英文、数字字符或者下划线,后缀为公众号微信号,长度不超过30个字符 
        * @param nickname 客服昵称,最长16个字
        * @return [type] [description]
        */
        public function customservice_add($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/customservice/kfaccount/add?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->customservice_add($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
        /**
        * 获取聊天记录
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-08-01 17:20:03
        * @param starttime int 起始时间,unix时间戳
        * @param endtime int 结束时间,unix时间戳,每次查询时段不能超过24小时
        * @param msgid int 消息id顺序从小到大,从1开始
        *  @param number int 每次获取条数,最多10000条
        * @return json 返回结果
        */
        public function customservice_getmsglist($starttime,$endtime,$msgid,$number){
             //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/customservice/msgrecord/getmsglist?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = array('starttime'=>$starttime,
                                'endtime'=>$endtime,
                                'msgid'=>$msgid,
                                'number'=>$number);
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
            //access_token 过期重新获取并重新回调当前函数
            if(isset($data['errcode']) && ($data['errcode']==42001  || $data['errcode']==40001)){
                $access_token = $this->access_token(true);
                return $this->customservice_getmsglist($starttime,$endtime,$msgid,$number);
            }
            //返回结果
            if(isset($data['recordlist'])){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
    /**********************新版客服  结束********/
    
    /**********************微信支付  开始********/
        
        /**
        * 统一下单,WxPayUnifiedOrder中out_trade_no、body、total_fee、trade_type必填
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-09 16:22:38
        * @param WxPayUnifiedOrder $inputObj
        * @param int $timeOut
        * @throws WxPayException
        * @return [type] [description]
        */
        public function unifiedOrder($data, $timeOut = 6){
            //配置请求url
            $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            //检查请求参数
            if(!isset($data['out_trade_no'])){
                $result = array('status'=>40010,'data'=>'缺少统一支付接口必填参数out_trade_no!');
                return $result;
            }
            if(!isset($data['body'])){
                $result = array('status'=>40010,'data'=>'缺少统一支付接口必填参数body!');
                return $result;
            }
            if(!isset($data['total_fee'])){
                $result = array('status'=>40010,'data'=>'缺少统一支付接口必填参数total_fee!');
                return $result;
            }
            if(!isset($data['trade_type'])){
                $result = array('status'=>40010,'data'=>'缺少统一支付接口必填参数trade_type!');
                return $result;
            }
            if($data['trade_type'] == 'JSAPI' && !isset($data['openid'])){
                $result = array('status'=>40010,'data'=>'统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!');
                return $result;
            }
            if($data['trade_type'] == "NATIVE" && !isset($data['product_id'])){
                $result = array('status'=>40010,'data'=>'统一支付接口中,缺少必填参数product_id!trade_type为NATIVE时,product_id为必填参数!');
                return $result;
            }
    
            //异步通知url未设置,则使用配置文件中的url
            if(!isset($data['notify_url'])){
                $data['notify_url'] = config('crm_config.wechat_notify_url');
            }
    
            $data['appid'] = $this->appid;//微信支付分配的公众账号ID(企业号corpid即为此appId)
            $data['mch_id'] = $this->mch_id;//微信支付分配的商户号
            $data['spbill_create_ip'] = get_client_ip();//APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP
            $data['nonce_str'] = $this->createNonceStr(32);
            $data['sign'] = $this->makeSign($data);
            $xml = arr_xml($data);
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            $datas = xml_arr($response);//将xml转为array
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas)){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
    
        /**
        * 查询订单,WxPayOrderQuery中out_trade_no、transaction_id至少填一个
        *  appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 11:37:20
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        public function orderQuery($data, $timeOut = 6){
            $url = "https://api.mch.weixin.qq.com/pay/orderquery";
            //检测必填参数
            if(!array_key_exists('out_trade_no', $data) && !array_key_exists('transaction_id', $data)) {
                $result = array('status'=>40010,'data'=>'订单查询接口中,out_trade_no、transaction_id至少填一个!');
                return $result;
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            $datas = xml_arr($response);//将xml转为array
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas) ){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
        /**
        * 关闭订单,WxPayCloseOrder中out_trade_no必填
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 11:48:48
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        public function closeOrder($data, $timeOut = 6){
            $url = "https://api.mch.weixin.qq.com/pay/closeorder";
            //检测必填参数
            if(!array_key_exists('out_trade_no', $data)) {
                $result = array('status'=>40010,'data'=>'订单关闭接口中,out_trade_no必填!');
                return $result;
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            $datas = xml_arr($response);//将xml转为array
    
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
    
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas) ){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
    
        }
    
        /**
        * 申请退款,WxPayRefund中out_trade_no、transaction_id至少填一个且
        * out_refund_no、total_fee、refund_fee、op_user_id为必填参数
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 13:42:49
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        public function refund($data, $timeOut = 6){
            $url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
             //检测必填参数
            if(!array_key_exists('out_trade_no', $data) && !array_key_exists('transaction_id', $data)) {
                $result = array('status'=>40010,'data'=>'退款申请接口中,out_trade_no、transaction_id至少填一个!');
                return $result;
            }
            if(!array_key_exists('out_refund_no', $data)) {
                $result = array('status'=>40010,'data'=>'退款申请接口中,缺少必填参数out_refund_no!');
                return $result;
            }
            if(!array_key_exists('total_fee', $data)) {
                $result = array('status'=>40010,'data'=>'退款申请接口中,缺少必填参数total_fee!');
                return $result;
            }
            if(!array_key_exists('refund_fee', $data)) {
                $result = array('status'=>40010,'data'=>'退款申请接口中,缺少必填参数refund_fee!');
                return $result;
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            /**
             * 仅针对老资金流商户使用
             *REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款)
             *REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款
             */
            $data['refund_account'] = 'REFUND_SOURCE_RECHARGE_FUNDS';//退款资金来源
            $data['sign'] = $this->makeSign($data);//签名
            $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, true, $timeOut);
            $datas = xml_arr($response);//将xml转为array
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas) ){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;  
        }
    
        /**
        * 查询退款
        * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,
        * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
        * WxPayRefundQuery中out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 13:56:23
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        public function refundQuery($data, $timeOut = 6){
            $url = "https://api.mch.weixin.qq.com/pay/refundquery";
            //检测必填参数
            if(!array_key_exists('out_refund_no', $data) && !array_key_exists('out_trade_no', $data) && !array_key_exists('transaction_id', $data) && !array_key_exists('refund_id', $data) ) {
                $result = array('status'=>40010,'data'=>'退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个');
                return $result;
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            $datas = xml_arr($response);//将xml转为array
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas) ){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
        /**
        * 下载对账单,WxPayDownloadBill中bill_date为必填参数
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 14:04:10
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        public function downloadBill($data, $timeOut = 6){
            $url = "https://api.mch.weixin.qq.com/pay/downloadbill";
            //检测必填参数
            if(!array_key_exists('bill_date', $data)) {
                $result = array('status'=>40010,'data'=>'对账单接口中,缺少必填参数bill_date!');
                return $result;
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            $datas = xml_arr($response);//将xml转为array
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas) ){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
        /**
        * 提交被扫支付API
        * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,
        * 由商户收银台或者商户后台调用该接口发起支付。
        * WxPayWxPayMicroPay中body、out_trade_no、total_fee、auth_code参数必填
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 14:06:11
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        public function micropay($data, $timeOut = 6){
            $url = "https://api.mch.weixin.qq.com/pay/micropay";
            //检测必填参数
            if(!array_key_exists('body', $data)) {
                $result = array('status'=>40010,'data'=>'提交被扫支付API接口中,缺少必填参数body!');
                return $result;
            }
            if(!array_key_exists('out_trade_no', $data)) {
                $result = array('status'=>40010,'data'=>'提交被扫支付API接口中,缺少必填参数out_trade_no!');
                return $result;
            }
            if(!array_key_exists('total_fee', $data)) {
                $result = array('status'=>40010,'data'=>'提交被扫支付API接口中,缺少必填参数total_fee!');
                return $result;
            }
            if(!array_key_exists('auth_code', $data)) {
                $result = array('status'=>40010,'data'=>'提交被扫支付API接口中,缺少必填参数auth_code!');
                return $result;
            }
            //组装参数
            $data['spbill_create_ip'] = get_client_ip();//终端ip
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            $datas = xml_arr($response);//将xml转为array
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas) ){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
        /**
        * 微信扫码支付模式一成功返回参数包装
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-16 16:22:40
        * @param $data 参数集
        * @return [type] [description]
        */
        public function native_pkg($data){
            $data['nonce_str'] =$this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            return $data;
        }
    
        /**
        * 撤销订单API接口,WxPayReverse中参数out_trade_no和transaction_id必须填写一个
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 14:06:11
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        public function reverse($data, $timeOut = 6){
            $url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
            //检测必填参数
            if(!array_key_exists('out_trade_no', $data) && !array_key_exists('transaction_id', $data)) {
                $result = array('status'=>40010,'data'=>'撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个');
                return $result;
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            $datas = xml_arr($response);//将xml转为array
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas) ){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
        /**
        * 测速上报,该方法内部封装在report中,使用时请注意异常流程
        * interface_url、return_code、result_code、user_ip、execute_time_必填
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 11:18:44
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        private function report($data, $timeOut = 1)
        {
            $url = "https://api.mch.weixin.qq.com/payitil/report";
            //检测必填参数
            if(!array_key_exists('interface_url', $data)){
                throw new Exception("接口URL,缺少必填参数interface_url!");
            }
            if(!array_key_exists('return_code', $data)){
                throw new Exception("返回状态码,缺少必填参数return_code!");
            }
            if(!array_key_exists('result_code', $data)){
                throw new Exception("业务结果,缺少必填参数result_code!");
            }
            if(!array_key_exists('user_ip', $data)){
                throw new Exception("访问接口IP,缺少必填参数user_ip!");
            }
            if(!array_key_exists('execute_time_', $data)){
                throw new Exception("接口耗时,缺少必填参数execute_time_!");
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['user_ip'] = get_client_ip();//终端ip
            $data['time'] = date("YmdHis");//商户上报时间  
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
             $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            return $response;
        }
    
        /**
        * 生成二维码规则,模式一生成支付二维码
        * appid、mchid、spbill_create_ip、nonce_str不需要填入2017-09-11 14:20:05
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 14:20:05
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        private function bizpayurl($data, $timeOut = 6){
    
            //检测必填参数
            if(!array_key_exists('product_id', $data)) {
                $result = array('status'=>40010,'data'=>'生成二维码,缺少必填参数product_id!');
                return $result;
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['time_stamp'] = time();//时间戳
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            $result = array('status'=>1,'data'=>$data);
            return $result;
        }
    
        /**
        * 转换短链接
        * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),
        * 减小二维码数据量,提升扫描速度和精确度。
        * appid、mchid、spbill_create_ip、nonce_str不需要填入
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 14:41:02
        * @param $data 参数集
        * @param $timeOut 超时
        * @return 成功时返回,其他抛异常
        */
        public function shorturl($data, $timeOut = 6){
            $url = "https://api.mch.weixin.qq.com/tools/shorturl";
            //检测必填参数
            if(!array_key_exists('long_url', $data)) {
                $result = array('status'=>40010,'data'=>'需要转换的URL,签名用原串,传输需URL encode!');
                return $result;
            }
            //组装参数
            $data['appid'] = $this->appid;//公众账号ID
            $data['mch_id'] = $this->mch_id;//商户号
            $data['nonce_str'] = $this->createNonceStr(32);//随机字符串
            $data['sign'] = $this->makeSign($data);//签名
            $xml = arr_xml($data);
            
            $startTimeStamp = milli_time();//请求开始时间
            $response = $this->postXml($xml, $url, false, $timeOut);
            $datas = xml_arr($response);//将xml转为array
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas);
                return $result;
            }
            //判断签名是否存在,及签名是否正确
            if(!array_key_exists('sign', $datas) ){
                $result = array('status'=>40011,'data'=>'签名错误!');
                return $result;
            }
            $this->reportCostTime($url, $startTimeStamp, $datas);//上报请求花费时间
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
        /**
        * 支付结果通用通知
        * 直接回调函数使用方法: notify(you_function);
        * 回调类成员函数方法:notify(array($this, you_function));
        * $callback  原型为:function function_name($data){}
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 14:41:02
        * @param function $callback
        */
        public function notify(){
            //获取通知的数据
            $xml = file_get_contents('php://input');
            //将xml转为array
            $datas = xml_arr($xml);
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas['return_msg']);
                return $result;
            }
            //判断业务结果是否成功
            if($datas['result_code'] != 'SUCCESS'){
                $result = array('status'=>40011,'data'=>$datas['err_code_des']);
                return $result;
            }
            //判断签名是否存在
            if(!array_key_exists('sign', $datas)){
                $result = array('status'=>40011,'data'=>'缺少签名参数!');
                return $result;
            }
            //签名验证
            $data = $datas;
            unset($data['sign']);
            if($this->makeSign($data)!=$datas['sign']){
                $result = array('status'=>40011,'data'=>'签名验证失败!');
                return $result;
            }
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
        /**
        * 退款结果通知
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-22 17:10:21
        * @param array
        */
        public function refund_notify(){
            //获取通知的数据
            $xml = file_get_contents('php://input');
            log_result("//////////// start //////////////");
            log_result($xml);
            //将xml转为array
            $datas = xml_arr($xml);
            log_result("datas:".json_encode($datas));
            //判断请求结果是否成功
            if($datas['return_code'] != 'SUCCESS'){
                $result = array('status'=>40014,'data'=>$datas['return_msg']);
                log_result($datas['return_code'] != 'SUCCESS');
                return $result;
            }
    
            //对加密字符串进行解密
            $req_info = base64_decode($datas['req_info']);//对加密串A做base64解码,得到加密串B
            log_result("req_info:".$req_info);
            $md5_key = md5($this->key);//对商户key做md5,得到32位小写key
            log_result("md5_key:".$md5_key);
            $info = aes_decode($req_info,$md5_key);//用key*对加密串B做AES-256-ECB解密
            log_result("info:".$info);
            $datas = array_merge($datas,$info);//合并数组 返回结果
            log_result("//////////// end //////////////");
            //返回结果
            $result = array('status'=>1,'data'=>$datas);
            return $result;
        }
    
        /**
        * 共享收货地址js函数需要的参数
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 16:37:27
        * @param 
        * @return 获取共享收货地址js函数需要的参数,json格式可以直接做参数使用
        */
        public  function editAddressParameters(){
            $data = array();
            $data["appid"] = $this->appid;
            $data["url"] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
            $time = time();
            $data["timestamp"] = "$time";
            $data["noncestr"] = "1234568";
            $data["accesstoken"] = $this->access_token(false);
            ksort($data);
            $params = $this->toUrlParams($data);
            $addrSign = sha1($params);
            
            $afterData = array(
                "addrSign" => $addrSign,
                "signType" => "sha1",
                "scope" => "jsapi_address",
                "appId" => $this->appid,
                "timeStamp" => $data["timestamp"],
                "nonceStr" => $data["noncestr"]
            );
            $parameters = json_encode($afterData);
            return $parameters;
        }
    
        
        /**
        * 生成扫描支付URL,模式一
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-16 10:40:10
        * @param $productId 产品编号
        * @return [type] [description]
        */
        public function getPrePayUrl($productId)
        {
            $data['product_id'] = $productId;
            $result = $this->bizpayurl($data);
            if($result['status']!=1){
                return $result;
            }
            $url = "weixin://wxpay/bizpayurl?" . $this->toUrlParams($result['data'],true);
            $result['data'] = $url;
            return $result;
        }
    
    
        /**
        * 生成二维码
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-16 11:15:17
        * @param $data 参数集
        * @return [type] [description]
        */
        public function qrcode($data){
            error_reporting(E_ERROR);
            require_once 'phpqrcode/phpqrcode.php';
            $url = urldecode($data);
            header('Content-Type: image/png');
            ob_clean();
            $errorCorrectionLevel = "L"; // 纠错级别:L、M、Q、H
            $matrixPointSize = "4"; //生成图片大小 :1到10
            QRcode::png($url, false, $errorCorrectionLevel, $matrixPointSize);
            exit();
        }
    
        /**
        *  格式化参数格式化成url参数
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 09:58:58
        * @param $data 参数集
        * @param $sign 是否考虑sign
        * @return 
        */
        private function toUrlParams($data,$sign=false)
        {
            $buff = "";
            foreach ($data as $k => $v)
            {
                if($sign && $v != "" && !is_array($v)){
                    $buff .= $k . "=" . $v . "&";
                }else{
                  if($k != "sign" && $v != "" && !is_array($v)){
                    $buff .= $k . "=" . $v . "&";
                    }  
                }
                
            }
            
            $buff = trim($buff, "&");
            return $buff;
        }
        
        /**
        * 生成签名
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 10:01:14
        * @param 
        * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
        */
        public function makeSign($data)
        {
            //签名步骤一:按字典序排序参数
            ksort($data);
            $string = $this->toUrlParams($data);
            //签名步骤二:在string后加入KEY
            $string = $string . "&key=".$this->key;
            //签名步骤三:MD5加密
            $string = md5($string);
            //签名步骤四:所有字符转为大写
            $result = strtoupper($string);
            return $result;
        }
        /**
        * 以post方式提交xml到对应的接口url
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 10:08:11
        * @param string $xml  需要post的xml数据
        * @param string $url  url
        * @param bool $useCert 是否需要证书,默认不需要
        * @param int $second   url执行超时时间,默认30s
        * @return [type] [description]
        */
        private function postXml($xml, $url, $useCert = false, $second = 30)
        {
    
            header("Content-type: text/html; charset=utf-8");
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_TIMEOUT, $second);
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
           
            //如果有配置代理这里就设置代理
            if(self::CURL_PROXY_HOST != "0.0.0.0" && self::CURL_PROXY_PORT != 0){
              curl_setopt($ch,CURLOPT_PROXY, self::CURL_PROXY_HOST);
              curl_setopt($ch,CURLOPT_PROXYPORT, self::CURL_PROXY_PORT);
            }
            if($useCert == true){
              //设置证书
              //使用证书:cert 与 key 分别属于两个.pem文件
              curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
              curl_setopt($ch,CURLOPT_SSLCERT, dirname(__FILE__).self::SSLCERT_PATH);
              curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
              curl_setopt($ch,CURLOPT_SSLKEY, dirname(__FILE__).self::SSLKEY_PATH);
            }
            $data = curl_exec($ch);
            if (curl_errno($ch)) {
              return curl_error($ch);
            }
            curl_close($ch);
            return $data;
            // $ch = curl_init();
            // //设置超时
            // curl_setopt($ch, CURLOPT_TIMEOUT, $second);
            
            // //如果有配置代理这里就设置代理
            // if(self::CURL_PROXY_HOST != "0.0.0.0" && self::CURL_PROXY_PORT != 0){
            //   curl_setopt($ch,CURLOPT_PROXY, self::CURL_PROXY_HOST);
            //   curl_setopt($ch,CURLOPT_PROXYPORT, self::CURL_PROXY_PORT);
            // }
            // curl_setopt($ch,CURLOPT_URL, $url);
            // curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
            // curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
            // //设置header
            // curl_setopt($ch, CURLOPT_HEADER, FALSE);
            // //要求结果为字符串且输出到屏幕上
            // curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
          
            // if($useCert == true){
            //   //设置证书
            //   //使用证书:cert 与 key 分别属于两个.pem文件
            //   curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
            //   curl_setopt($ch,CURLOPT_SSLCERT, dirname(__FILE__).self::SSLCERT_PATH);
            //   curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
            //   curl_setopt($ch,CURLOPT_SSLKEY, dirname(__FILE__).self::SSLKEY_PATH);
            // }
            // //post提交方式
            // curl_setopt($ch, CURLOPT_POST, TRUE);
            // curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
            //运行curl
            // $data = curl_exec($ch);
            //返回结果
            // if($data){
            //   curl_close($ch);
            //   return $data;
            // } else { 
            //   $error = curl_errno($ch);
            //   curl_close($ch);
            //   return $error;
            // }
      }
        /**
        * 上报数据, 上报的时候将屏蔽所有异常流程
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-09-11 11:10:20
        * @param string $usrl
        * @param int $startTimeStamp
        * @param array $data
        * @return [type] [description]
        */
        private  function reportCostTime($url, $startTimeStamp, $data)
        {
            //如果不需要上报数据
            if(self::REPORT_LEVENL == 0){
                return;
            } 
            //如果仅失败上报
            if(self::REPORT_LEVENL == 1 &&
                 array_key_exists("return_code", $data) &&
                 $data["return_code"] == "SUCCESS" &&
                 array_key_exists("result_code", $data) &&
                 $data["result_code"] == "SUCCESS")
             {
                return;
             }
             
            //上报逻辑
            $endTimeStamp = milli_time();
            $result['interface_url'] = $url;
            $result['execute_time_'] = $endTimeStamp - $startTimeStamp;
            
            //返回状态码
            if(array_key_exists("return_code", $data)){
                $result['return_code'] = $data["return_code"];
            }
            //返回信息
            if(array_key_exists("return_msg", $data)){
                $result['return_msg'] = $data["return_msg"];
            }
            //业务结果
            if(array_key_exists("result_code", $data)){
                $result['result_code'] = $data["result_code"];
            }
            //错误代码
            if(array_key_exists("err_code", $data)){
                $result['err_code'] = $data["err_code"];
            }
            //错误代码描述
            if(array_key_exists("err_code_des", $data)){
                $result['err_code_des'] = $data["err_code_des"];
            }
            //商户订单号
            if(array_key_exists("out_trade_no", $data)){
                $result['out_trade_no'] = $data["out_trade_no"];
            }
            //设备号
            if(array_key_exists("device_info", $data)){
                $result['device_info'] = $data["device_info"];
            }
            
            try{
                $this->report($result);
            } catch (Exception $e){
                //不做任何处理
            }
        }
    /**********************微信支付  结束********/
    
    /**********************微信卡券  开始********/
        /**
        * 微信卡券获取api_ticket
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-17 13:30:13
        * @return api_ticket string 微信卡券调用凭证
        */
        private function api_ticket() {
            // api_ticket 应该全局存储与更新,以下代码以写入到文件中做示例
          
            $data = json_decode(file_get_contents(dirname(__FILE__)."/json/api_ticket.json"));
            if ($data->expire_time < time()) {
              $access_token = $this->access_token(false);
              if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
              }
              $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card&access_token=".$access_token['data'];
              $res = json_decode(https_get($url));
              if(!isset($res->ticket)){
                    $access_token = $this->access_token(true);
                    $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card&access_token=".$access_token['data'];
                    $res = json_decode(https_get($url));
              }
              $ticket = $res->ticket;
              if ($ticket) {
                $data->expire_time = time() + 7200;
                $data->ticket = $ticket;
                $fp = fopen(dirname(__FILE__)."/json/api_ticket.json", "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
              }
            } else {
              $ticket = $data->ticket;
            }
    
            return $ticket;
        }
    
        /**
        * 卡券签名
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-17 16:43:44
        * @param 
        * @return [type] [description]
        */
        public function card_sign($card_id){
            $api_ticket = $this->api_ticket();
            $timestamp = time();
            $nonce_str = $this->createNonceStr();
            $arr        = array($api_ticket,$timestamp,$nonce_str,$card_id);
            sort($arr, SORT_STRING);
            $signature  = sha1(implode($arr));
            $signPackage = array(
                "timestamp" => $timestamp,
                "nonce_str" => $nonce_str,
                "signature" => $signature,
                );
            return $signPackage;
        }
    
        /**
        * 查看卡券详情
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-17 13:59:51
        * @param post_data 请求数据 卡券ID
        * @return json 请求结果
        */
        public function get_card($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/card/get?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->get_card($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
        /**
        * 批量查询卡券列表
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-17 14:02:10
        * @param post_data 请求数据  
        * offset 查询卡列表的起始偏移量,从0开始,即offset: 5是指从从列表里的第六个开始读取。
        * count 需要查询的卡片的数量(数量最大50)。
        * status_list 支持开发者拉出指定状态的卡券列表“CARD_STATUS_NOT_VERIFY”,待审核;“CARD_STATUS_VERIFY_FAIL”,审核失败;“CARD_STATUS_VERIFY_OK”,通过审核;“CARD_STATUS_DELETE”,卡券被商户删除;“CARD_STATUS_DISPATCH”,在公众平台投放过的卡券;
        * @return json 请求结果
        */
        public function card_list($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/card/batchget?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->get_card($card_id);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result;
        }
    /**************************微信会员卡  开始****************************/
        
        /**
        * 拉取会员信息(积分查询)接口
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-27 09:24:15
        * @param card_id 查询会员卡的cardid  
        * @param code 所查询用户领取到的code值  
        * @return [type] [description]
        */
        public function membercard_info($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/card/membercard/userinfo/get?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->membercard_info($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result; 
        }
    
        /**
        * 更新会员信息
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-27 15:08:46
        * @param 
        * @return [type] [description]
        */
        public function membercard_update($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/card/membercard/updateuser?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->membercard_update($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result; 
        }
    
        /**
        * 激活会员卡
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-27 11:45:44
        * @param 
        * @return [type] [description]
        */
        public function membercard_active($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/card/membercard/activate?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->membercard_active($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result; 
        }
    
        /**
        * 设置开卡字段接口
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-27 13:54:02
        * @param 
        * @return [type] [description]
        */
        public function activateuserform($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/card/membercard/activateuserform/set?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->activateuserform($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result; 
        }
    
        /**
        * 更改会员卡信息接口
        * @author bug  <3164145970@qq.com>
        * @createtime 2017-10-27 09:36:18
        * @param 提交修改的数据集
        * @return [type] [description]
        */
        public function card_update($post_data){
            //获取access_token
            $access_token= $this->access_token(false);
            if($access_token['status']!=1 && $access_token['status']!=2){
                return $access_token;
            }
            //配置请求url,加入access_token参数
            $url = 'https://api.weixin.qq.com/card/update?access_token='.$access_token['data'];
            //将json数组转换成字符串数组
            $post_data = json_encode($post_data,JSON_UNESCAPED_UNICODE);
            //获取请求结果,并将请求结果转换成json
            $data = json_decode(https_request($url,$post_data),true);  
    
            //access_token 过期重新获取并重新回调当前函数
            if($data['errcode']==42001   || $data['errcode']==40001){
                $access_token = $this->access_token(true);
                return $this->card_update($post_data);
            }
            //返回结果
            if($data['errcode']==0&&$data['errmsg']=='ok'){
                $result = array('status'=>1,'data'=>$data);
                return $result;
            }
            $result = array('status'=>40014,'data'=>$data);
            return $result; 
        }
    
    /**************************微信会员卡  结束****************************/
    /**********************微信卡券  结束********/
    }
    ?>
     
  • 相关阅读:
    py程序----两个判断回文的程序
    Python特性
    python-基本数据类型
    shell编程第一天
    iptables防火墙
    纤维参数测量
    线性代数及其应用(最小二乘、PCA、SVD)
    水流方向检测
    微信跳一跳-MATLAB实现
    相机标定opencv实现
  • 原文地址:https://www.cnblogs.com/jiafeimao-dabai/p/9559939.html
Copyright © 2011-2022 走看看