<?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 think\Exception; /** * 微信公共類文件 * @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 = "\cert\apiclient_cert.pem"; const SSLKEY_PATH = "\cert\apiclient_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."×tamp=".$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; } /**************************微信會員卡 結束****************************/ /**********************微信卡券 結束********/ } ?>