1.所需參數
字段名 | 變量名 | 必填 | 示例值 | 類型 | 描述 | |
---|---|---|---|---|---|---|
公眾賬號appid | mch_appid | 是 | wx8888888888888888 | String | 公眾號的appId | |
商戶號 | mchid | 是 | 1900000109 | String(32) | 微信支付平台商戶號 就是平台賬號 |
|
隨機字符串 | nonce_str | 是 | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS | String(32) | 隨機字符串,隨便隨機個什么<32位 | |
商戶訂單號 | partner_trade_no | 是 | 10000098201411111234567890 | String | 訂單號,保持唯一性,自定義一個隨機訂單號 | |
用戶 openid |
openid | 是 | oxTWIuGaIt6gTKsQRLau2M0yL16E | String | 商戶appid下,某用戶的openid | |
校驗用戶姓名選項 | check_name | 是 | NO_CHECK 不檢驗 (小額推薦) FORCE_CHEC 強制檢驗 OPTION_CHECK 自動檢驗 |
String | NO_CHECK:不校驗真實姓名 FORCE_CHECK:強校驗真實姓名(未實名認證的用戶會校驗失敗,無法轉賬) OPTION_CHECK:針對已實名認證的用戶才校驗真實姓名(未實名認證用戶不校驗,可以轉賬成功) |
|
收款用戶姓名 | re_user_name | 可選 | 馬花花 (如果上一個參數為強制檢驗此為必填項) |
String | 收款用戶真實姓名。 如果check_name設置為FORCE_CHECK或OPTION_CHECK,則必填用戶真實姓名 |
|
金額 | amount | 是 | 100 單位為分 100就是100分. |
int | 企業付款金額,單位為分 | |
企業付款描述信息 | desc | 是 | 獎金啊,提現成功啊 退款成功啊什么的 |
String | 企業付款操作說明信息。必填。 | |
Ip地址 | spbill_create_ip | 是 | 192.168.0.1 | String(32) | 調用接口的機器Ip地址服務器ip | |
支付密鑰
|
key
|
是
|
F5YguNW77Ao4N5yu5wZ8Lb00NKO987ks
|
String(32) |
設置在商戶平台上的支付密鑰 | |
簽名
|
sign |
|
C380BEC2BFD727A4B6845133519F3AD6 |
String(32) |
上面的內容的一個綜合的加密結果
|
2.還需要支付時使用的證書
3.簽名的規則
意思就是將上述的除了支付秘鑰和簽名的9-10項(因為收款用戶姓名是根據驗證選項而決定是否需要的)
按照ASCII的從小到大排序之后的字符串
例如:$str = "amount=100&check_name=NO_CHECK&desc=獎金啊,提現成功啊 退款成功啊什么的&mch_appid=wx8888888888888888&mchid=1900000109&nonce_str=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&openid=oxTWIuGaIt6gTKsQRLau2M0yL16E&partner_trade_no=10000098201411111234567890&spbill_create_ip=192.168.0.1";
- 簽名是不是一直變動的呢?是的 每一個簽名都是不一樣的,別想着存起來一直用!怎么算呢?官方有一個文檔,對於會的人來說就是廢話,對於不會的來說就是天書。總的來說分為3部,官方有一個簽名生成工具https://pay.weixin.qq.com/wiki/tools/signverify/。
- 將你本次請求的所有參數(當然除了簽名),按照一定的順序排序成一個字符串,順序一會再說,先說格式,比如本次的這次請求有9個參數:
$str = "amount=100&check_name=NO_CHECK&desc=獎金啊,提現成功啊 退款成功啊什么的&mch_appid=wx8888888888888888&mchid=1900000109&nonce_str=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&openid=oxTWIuGaIt6gTKsQRLau2M0yL16E&partner_trade_no=10000098201411111234567890&spbill_create_ip=192.168.0.1";
仔細觀察不難發現,字符串排列是有順序的 為鍵值首字母的排列順序。而官方為了聽起來霸氣,講的是根據 參數按照參數名ASCII碼從小到大排序(字典序),使用URL鍵值對的格式排序嚇的我一哆嗦啊! 不就字母順序表么!不過仔細一看發現不對了,比如 mchid和 mch_appid這尼瑪前三個字母一樣啊,一位一位排序下來出現一個 i 和 _怎么辦呢? 這時候就用到ASCII碼表了,不過看官也不用去查了 上面的可以直接粘去用了 而ASCII碼表的順序呢就是按照0123456789:;< = > ? @ ABCDEFGHIJKLMNOPQRSTUVWXYZ [ \ ] ^ _ ` abcdefghijklmnopqrstuvwxyz { | }~的順序排列 那么我門就知道mch_appid應該在 mchid 前面了。 - 排序完這9個參數 之后再用&加上特殊參數 微信支付平台上設置的支付密鑰就是
$str = "amount=100&check_name=NO_CHECK&desc=獎金啊,提現成功啊 退款成功啊什么的&mch_appid=wx8888888888888888&mchid=1900000109&nonce_str=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&openid=oxTWIuGaIt6gTKsQRLau2M0yL16E&partner_trade_no=10000098201411111234567890&spbill_create_ip=192.168.0.1&key=F5YguNW77Ao4N5yu5wZ8Lb00NKO987ks" - 之后就簡單了先md5加密下然后轉為大寫 簽名就OK了
$sign = strtoupper(md5($str));
然后我們就要將這些參數填充到xml格式的字符串中去了
4.開始擼碼吧
/** * 格式化參數格式化成url參數 */ public function ToUrl($arr) { $buff = ""; foreach ($arr as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } //將亂序的數組 public function ToSign($arr,$key) { //簽名步驟一:按字典序排序參數 ksort($arr); $string = ToUrl($arr); //簽名步驟二:在string后加入KEY $string = $string . "&key=".$key; //簽名步驟三:MD5加密 $string = md5($string); //簽名步驟四:所有字符轉為大寫 // $result1 = strtoupper($string); return $string; } /** * 輸出xml字符 * @throws WxPayException **/ public static function ToXml($arr) { if(!is_array($arr) || count($arr) <= 0) { echo '數據異常'; } $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; } /** * zll 生成唯一訂單號 */ public function order_sn(){ $str = "qyfk".uniqid(); return $str; } /** * zll 將信息提交到微信服務器,發起企業付款 */ public function qyzf_post($url,$xml,$config,$second=30){ $ch = curl_init(); curl_setopt($ch,CURLOPT_TIMEOUT,$second); curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); // curl_setopt($ch,CURLOPT_SSLCERT,"/home/lizi/addons/grow/template/mobile/cash/apiclient_cert.pem"); // curl_setopt($ch,CURLOPT_SSLKEY,"/home/lizi/addons/grow/template/mobile/cash/apiclient_key.pem"); $str = 'D:/www/';//證書必須使用絕對路徑,否則報錯,錯誤貌似是52什么的 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT,$str.trim($config['apiclient_cert'],'.')); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY,$str.trim($config['apiclient_key'],'.')); curl_setopt($ch,CURLOPT_POST, 1); curl_setopt($ch,CURLOPT_POSTFIELDS,$xml); $data = curl_exec($ch); if($data){ curl_close($ch); return $data; }else{ $error = curl_errno($ch); echo "call faild, errorCode:$error\n"; curl_close($ch); return false; } } /** * zll 企業付款 */ public function qiyezhifu($data){ //解釋amount為付款金額,單位分,貌似最低1元,desc為付款的描述(必填),ip就是服務器ip必填 //$data = array('wxappid'=>14,'openid'=>'oRyzq0LrtuqKqQdH-FubBqcMuTi8-','amount'=>100,'desc'=>'提現獎勵','ip'=>'123.207.19.254'); //獲取數據庫的支付配置信息 $config = get_pay_conf($data['wxappid']); if($config){ //對必備參數進行有效性判斷 if(empty($config['appid']) || empty($config['shh']) || empty($config['partnerkey']) || empty($data['amount']) || empty($config['apiclient_cert']) || empty($config['apiclient_key'])){ throw new Exception("支付配置中的appid或商戶號或支付秘鑰不能為空,或支付金額不能為空"); }else{ $da['mch_appid'] = $config['appid']; //appid $da['mchid'] = $config['shh']; //商戶號 $da['nonce_str'] = $this->getStr(32); //隨機字符串 $da['partner_trade_no'] = $this->order_sn(); //訂單號,保持唯一性即可 $da['openid'] = $data['openid']; //粉絲的openid $da['check_name'] = "NO_CHECK"; //NO_CHECK:不校驗真實姓名 FORCE_CHECK:強校驗真實姓名(未實名認證的用戶會校驗失敗,無法轉賬) OPTION_CHECK:針對已實名認證的用戶才校驗真實姓名(未實名認證用戶不校驗,可以轉賬成功) //$da['re_user_name'] = ""; //收款用戶真實姓名。 如果check_name設置為FORCE_CHECK或OPTION_CHECK,則必填用戶真實姓名 $da['amount'] = $data['amount']; //付款金額,單位分 $da['desc'] = $data['desc'] ? $data['desc']:"提現獎勵"; //企業付款描述信息 $da['spbill_create_ip'] = $data['ip'] ? $data['ip'] : "123.207.19.254"; //服務器ip $da['sign'] = $this->ToSign($da, $config['partnerkey']);//生成簽名 //$da['key'] = $config['partnerkey']; //支付秘鑰 //將數組轉為xml $xml = $this->ToXml($da); $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'; $this->qyzf_post($url,$xml,$config); } }else{ return false; } }
上面的代碼我是在thinkphp3.2框架里面寫的,所以方法之間的調用用的是$this->XXX();
其他的框架或原生的php可以進行修改方法調用方式即可