本屌一貫抱着開源精神的態度,爲你們分享文章和技巧,固然~分享出來的代碼都是能夠直接copy in。。。。望你們看完後點贊打賞收藏!謝謝~!若是有寫的不對或者描述不正確的,歡迎你們給我留言指出錯誤,我將當即修改,以避免誤導大衆!php
此篇文章如題,實現商戶向我的支付,零錢入帳。下面我仍是老規矩,一行代碼一行註釋,請你們注意看,在文章最後會附上完整代碼!~定義函數,首先進行基本信息的定義html
/** * 微信企業付款 * @param [type] $openid 商戶appid下,某用戶的openid * @param [type] $username 收款用戶真實姓名。 * @param [type] $desc 企業付款操做說明信息。必填。 * @param [type] $money 企業付款金額,單位爲分 * @author appyjj <--1121099600@qq.com--> */ function pay($openid='', $username='', $desc='', $money=0){ $apiUrl = $this->APPURL;//企業付款接口url $Parameters=array(); $Parameters['amount'] = $money;//企業付款金額,單位爲分 $Parameters['check_name'] = 'NO_CHECK';//NO_CHECK:不校驗真實姓名 FORCE_CHECK:強校驗真實姓名(未實名認證的用戶會校驗失敗,沒法轉帳) OPTION_CHECK:針對已實名認證的用戶才校驗真實姓名(未實名認證用戶不校驗,能夠轉帳成功) $Parameters['desc'] = $desc;//企業付款操做說明信息。必填。 $Parameters['mch_appid'] = $this->APPID;//微信分配的公衆帳號ID $Parameters['mchid'] = $this->MCHID;//微信支付分配的商戶號 $Parameters['nonce_str'] = $this->createNoncestr();//隨機字符串,不長於32位 $Parameters['openid'] = $openid;//商戶appid下,某用戶的openid $Parameters['partner_trade_no'] = 'saso'.time().rand(10000, 99999);//商戶訂單號,需保持惟一性 $Parameters['re_user_name'] = $username;//收款用戶真實姓名。 若是check_name設置爲FORCE_CHECK或OPTION_CHECK,則必填用戶真實姓名 $Parameters['spbill_create_ip'] = $_SERVER['SERVER_ADDR'];//調用接口的機器Ip地址 $Parameters['sign'] = $this->getSign($Parameters);//簽名 $xml = $this->arrayToXml($Parameters); $res = $this->postXmlSSLCurl($xml,$apiUrl); $return = $this->xmlToArray($res); var_dump($return); //return $res; }
格式化參數,在簽名過程當中須要使用到json
function formatBizQueryParaMap($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if($urlencode) { $v = urlencode($v); } //$buff .= strtolower($k) . "=" . $v . "&"; $buff .= $k . "=" . $v . "&"; } $reqPar; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff)-1); } return $reqPar; }
此處代碼很簡單~不作過多註釋。就一個排序、循環和字符串長度判斷。
生成簽名---這裏很重要~擼主也弄了好一會~請你們務必認真看註釋api
function getSign($Obj) { foreach ($Obj as $k => $v) { $Parameters[$k] = $v; } //簽名步驟一:按字典序排序參數 ksort($Parameters); $String = $this->formatBizQueryParaMap($Parameters, false); //echo '【string1】'.$String.'</br>'; //簽名步驟二:在string後加入KEY $String = $String."&key=1231231231234321abcdxingaaabb235";//此處請填寫商戶平臺中的 API密鑰 //echo "【string2】".$String."</br>"; //簽名步驟三:MD5加密 $String = md5($String); //echo "【string3】 ".$String."</br>"; //簽名步驟四:全部字符轉爲大寫 $result_ = strtoupper($String); //echo "【result】 ".$result_."</br>"; return $result_; }
排序的規則,沒理解的請看這: ◆ 參數名ASCII碼從小到大排序(字典序); ◆ 若是參數的值爲空不參與簽名; ◆ 參數名區分大小寫; ◆ 驗證調用返回或微信主動通知簽名時,傳送的sign參數不參與簽名,將生成的簽名與該sign值做校驗。 ◆ 微信接口可能增長字段,驗證簽名時必須支持增長的擴展字段 第二步,在stringA最後拼接上key獲得stringSignTemp字符串,並對stringSignTemp進行MD5運算,再將獲得的字符串全部字符轉換爲大寫,獲得sign值signValue。 舉例:
假設傳送的參數以下:數組
appid: wxd930ea5d5a258f4f mch_id: 10000100 device_info: 1000 body: test nonce_str: ibuaiVcKdpRxkhJA 第一步:對參數按照key=value的格式,並按照參數名ASCII字典序排序以下: stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";
第二步:拼接API密鑰:微信
stringSignTemp="stringA&key=192006250b4c09247ec02edce69f6a2d" sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7"
最終獲得最終發送的數據:app
<xml> <appid>wxd930ea5d5a258f4f</appid> <mch_id>10000100</mch_id> <device_info>1000<device_info> <body>test</body> <nonce_str>ibuaiVcKdpRxkhJA</nonce_str> <sign>9A0A8659F005D6984697E2CA0A9CF3B7</sign> <xml>
**以上示例摘抄自微信支付官方文檔**
產生隨機字符串,長度不超過32位微信公衆平臺
function createNoncestr( $length = 32 ) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; //這裏不用修改,照抄便可 $str =""; for ( $i = 0; $i < $length; $i++ ) { $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; }
太過簡單,不作敘述!
數組轉xmlcurl
function arrayToXml($arr) { $xml = "<xml>"; foreach ($arr as $key=>$val) { if (is_numeric($val)) { $xml.="<".$key.">".$val."</".$key.">"; } else $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } $xml.="</xml>"; return $xml; }
xml轉數組函數
function xmlToArray($xml) { //將XML轉爲array $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $array_data; }
好的,下面是最後一步,請求
使用證書,以POST的方式提交xml到對應接口的URL
function postXmlSSLCurl($xml,$url,$second=30) { $ch = curl_init(); //超時時間 curl_setopt($ch,CURLOPT_TIMEOUT,$second); //這裏設置代理,若是有的話 //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8'); //curl_setopt($ch,CURLOPT_PROXYPORT, 8080); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); //設置header curl_setopt($ch,CURLOPT_HEADER,FALSE); //要求結果爲字符串且輸出到屏幕上 curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE); //設置證書 //使用證書:cert 與 key 分別屬於兩個.pem文件 //默認格式爲PEM,能夠註釋 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, $this->SSLCERT_PATH); //默認格式爲PEM,能夠註釋 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, $this->SSLKEY_PATH); //post提交方式 curl_setopt($ch,CURLOPT_POST, true); curl_setopt($ch,CURLOPT_POSTFIELDS,$xml); $data = curl_exec($ch); //返回結果 if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); echo "curl出錯,錯誤碼:$error"."<br>"; curl_close($ch); return false; } }
程序執行的時候每每沒有一次性成功的~下面給你們附上返回的錯誤信息對照查詢表
更詳細的信息~請參考微信官方說明文檔:[傳送門][2]
下面是完整代碼示例
直接copy後,修改一下參數既可使用!
<?php /** * 微信支付企業付款接口 */ ini_set('display_errors', 0); header("Content-type:text/html;chartset=utf-8"); $wxPay = new wxPay(); $wxPay->pay('這裏填寫收款人的openid', '姓名', '這裏是描述(若是報utf8的錯誤,請把這裏改成數字,此參數最好是傳值過來)', 100); //最後這裏的100爲金額 (單位爲分:即100 = 1元) class wxPay{ //=======【證書路徑設置】===================================== //證書路徑,注意應該填寫絕對路徑 protected $SSLCERT_PATH = 'cert/apiclient_cert.pem';//請各位大爺本身修改一下路徑 protected $SSLKEY_PATH = 'cert/apiclient_key.pem';//請各位大爺本身修改一下路徑 //=======【基本信息設置】===================================== //微信公衆號身份的惟一標識。審覈經過後,在微信發送的郵件中查看 protected $APPID = 'wx123123123123';//填寫您的appid。微信公衆平臺裏的 //受理商ID,身份標識 protected $MCHID = '123123123';//商戶id //商戶支付密鑰Key。審覈經過後,在微信發送的郵件中查看 protected $KEY = '192006250b4c09247ec02edce69f6a2d'; //JSAPI接口中獲取openid,審覈後在公衆平臺開啓開發模式後可查看 protected $APPSECRET = '123123123123123123123123123123'; //JSAPI接口地址 protected $APPURL = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'; /** * 微信企業付款 * @param [type] $openid 商戶appid下,某用戶的openid * @param [type] $username 收款用戶真實姓名。 * @param [type] $desc 企業付款操做說明信息。必填。 * @param [type] $money 企業付款金額,單位爲分 * @author appyjj <--1121099600@qq.com--> */ function pay($openid='', $username='', $desc='', $money=0){ $apiUrl = $this->APPURL;//企業付款接口url $Parameters=array(); $Parameters['amount'] = $money;//企業付款金額,單位爲分 $Parameters['check_name'] = 'NO_CHECK';//NO_CHECK:不校驗真實姓名 FORCE_CHECK:強校驗真實姓名(未實名認證的用戶會校驗失敗,沒法轉帳) OPTION_CHECK:針對已實名認證的用戶才校驗真實姓名(未實名認證用戶不校驗,能夠轉帳成功) $Parameters['desc'] = $desc;//企業付款操做說明信息。必填。 $Parameters['mch_appid'] = $this->APPID;//微信分配的公衆帳號ID $Parameters['mchid'] = $this->MCHID;//微信支付分配的商戶號 $Parameters['nonce_str'] = $this->createNoncestr();//隨機字符串,不長於32位 $Parameters['openid'] = $openid;//商戶appid下,某用戶的openid $Parameters['partner_trade_no'] = 'saso'.time().rand(10000, 99999);//商戶訂單號,需保持惟一性 $Parameters['re_user_name'] = $username;//收款用戶真實姓名。 若是check_name設置爲FORCE_CHECK或OPTION_CHECK,則必填用戶真實姓名 $Parameters['spbill_create_ip'] = $_SERVER['SERVER_ADDR'];//調用接口的機器Ip地址 $Parameters['sign'] = $this->getSign($Parameters);//簽名 $xml = $this->arrayToXml($Parameters); $res = $this->postXmlSSLCurl($xml,$apiUrl); $return = $this->xmlToArray($res); var_dump($return); //return $res; } /** * 做用:格式化參數,簽名過程須要使用 */ function formatBizQueryParaMap($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if($urlencode) { $v = urlencode($v); } //$buff .= strtolower($k) . "=" . $v . "&"; $buff .= $k . "=" . $v . "&"; } $reqPar; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff)-1); } return $reqPar; } /** * 做用:生成簽名 */ function getSign($Obj) { foreach ($Obj as $k => $v) { $Parameters[$k] = $v; } //簽名步驟一:按字典序排序參數 ksort($Parameters); $String = $this->formatBizQueryParaMap($Parameters, false); //echo '【string1】'.$String.'</br>'; //簽名步驟二:在string後加入KEY $String = $String."&key=guoyaojituanfengliaoxing82093235"; //echo "【string2】".$String."</br>"; //簽名步驟三:MD5加密 $String = md5($String); //echo "【string3】 ".$String."</br>"; //簽名步驟四:全部字符轉爲大寫 $result_ = strtoupper($String); //echo "【result】 ".$result_."</br>"; return $result_; } /** * 做用:產生隨機字符串,不長於32位 */ function createNoncestr( $length = 32 ) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } /** * 做用:array轉xml */ function arrayToXml($arr) { $xml = "<xml>"; foreach ($arr as $key=>$val) { if (is_numeric($val)) { $xml.="<".$key.">".$val."</".$key.">"; } else $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } $xml.="</xml>"; return $xml; } /** * 做用:將xml轉爲array */ function xmlToArray($xml) { //將XML轉爲array $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $array_data; } /** * 做用:使用證書,以post方式提交xml到對應的接口url */ function postXmlSSLCurl($xml,$url,$second=30) { $ch = curl_init(); //超時時間 curl_setopt($ch,CURLOPT_TIMEOUT,$second); //這裏設置代理,若是有的話 //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8'); //curl_setopt($ch,CURLOPT_PROXYPORT, 8080); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); //設置header curl_setopt($ch,CURLOPT_HEADER,FALSE); //要求結果爲字符串且輸出到屏幕上 curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE); //設置證書 //使用證書:cert 與 key 分別屬於兩個.pem文件 //默認格式爲PEM,能夠註釋 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, $this->SSLCERT_PATH); //默認格式爲PEM,能夠註釋 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, $this->SSLKEY_PATH); //post提交方式 curl_setopt($ch,CURLOPT_POST, true); curl_setopt($ch,CURLOPT_POSTFIELDS,$xml); $data = curl_exec($ch); //返回結果 if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); echo "curl出錯,錯誤碼:$error"."<br>"; curl_close($ch); return false; } } }
ok!此文半抄半寫~總之代碼沒問題的~!分享創造動力,擼主繼續幹活了!