微信官方文檔:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_2php
1.第一步準備好商戶的證書,在商戶後臺下載json
2第二步準備好微信RSA公鑰api
微信官方地址:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_7數組
這裏簡單實例展現,須要的自行拆分封裝微信
$mch_id = 123456;//本身的商戶號 $str = md5(rand(1000,9999));//隨機字符串 $sign_type = "MD5";//加密類型 $key = "abcde";//商戶的key $stringA = "mch_id={$mch_id}&nonce_str={$str}&sign_type={$sign_type}&key={$key}"; $md5_str = MD5($stringA);//md5加密 $sign = strtoupper($md5_str);//轉大寫 $url = "https://fraud.mch.weixin.qq.com/risk/getpublickey";//微信生成RSA公鑰接口地址 $xml=<<<EOF <xml> <mch_id>{$mch_id}</mch_id> <nonce_str>{$str}</nonce_str> <sign_type>MD5</sign_type> <sign>$sign</sign> </xml> EOF; $apiclient_key = './Xcxpay/Certificate/Jw/apiclient_cert.pem';//證書路徑 在商戶平臺下載 $apiclient_cert = './Xcxpay/Certificate/Jw/apiclient_key.pem';//證書路徑 在商戶平臺下載 $ch = curl_init(); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//嚴格校驗 curl_setopt($ch, CURLOPT_HEADER, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); //使用證書:cert 與 key 分別屬於兩個.pem文件 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); // curl_setopt($ch,CURLOPT_SSLCERT, 'apiclient_key證書的路徑');//上面第一步在商戶後臺下載的證書 curl_setopt($ch,CURLOPT_SSLCERT, $apiclient_key);//上面第一步在商戶後臺下載的證書 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); // curl_setopt($ch,CURLOPT_SSLKEY, 'apiclient_cert證書的路徑');//上面第一步在商戶後臺下載的證書 curl_setopt($ch,CURLOPT_SSLKEY, $apiclient_cert);//上面第一步在商戶後臺下載的證書 curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); $data = curl_exec($ch); //返回結果 if($data){ curl_close($ch); } else { $error = curl_errno($ch); curl_close($ch); } libxml_disable_entity_loader(true); $result = json_decode(json_encode(simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA)), true); print_r($result);
成功後返回的數據app
把pub_key的內容保存成爲一個文件, 已 .pem後綴的文件 例如 wx_public.pem 等等須要用到這個文件curl
如:函數
再將wx_public.pem 格式轉換post
openssl rsa -RSAPublicKey_in -in 剛剛保存的文件 -pubout > 新的文件ui
獲得新的pem文件,等等要用到。這個文件主要是要來RAS加密 銀行卡號和姓名
新建一個類
class Wxyxk { public $value=array( 'mch_id'=>'', 'partner_trade_no'=>'', 'nonce_str'=>'', 'enc_bank_no'=>'', 'enc_true_name'=>'', 'bank_code'=>'', 'amount'=>'', 'desc'=>'', ); public $app_id; public $mch_id; public $key; public $url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank"; public $apiclient_cert; public $apiclient_key; public $public_pem; public function __construct($mch_id, $key) { $this->mch_id = $this->value['mch_id'] = $mch_id; $this->key = $key; } public function sendRed() { foreach($this->value as $k=>$v){ if(empty($v)){ return $k.' 不能爲空'; } } if(empty($this->apiclient_cert) || empty($this->apiclient_key) || empty($this->key)){ return '證書路徑和key不能爲空'; } $this->MakeSign(); $xml = $this->ToXml(); $result_xml = $this->postXmlCurl($xml,$this->url); $result = $this->FromXml($result_xml); // $this->wirteLog($this->setMsg($result)); return $result; } public function getOrderStatus($order_on) { $url = "https://api.mch.weixin.qq.com/mmpaysptrans/query_bank"; $rand_str = md5(rand(100000,99999)); $data = array("mch_id"=>$this->mch_id,"nonce_str"=>$rand_str,'partner_trade_no'=>$order_on); $str = "mch_id={$this->mch_id}&nonce_str={$rand_str}&partner_trade_no={$order_on}&key={$this->key}"; $sign = strtoupper(md5($str)); $data['sign'] = $sign; $xml = "<xml>"; foreach ($data as $key=>$val) { if (is_numeric($val)){ $xml .= "<".$key.">".$val."</".$key.">"; }else{ $xml .= "<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml .= "</xml>"; $result_xml = $this->postXmlCurl($xml, $url); $result = $this->FromXml($result_xml); return $result; } /** * 輸出xml字符 * @throws WxPayException **/ public function ToXml() { if(!is_array($this->value) || count($this->value) <= 0) { throw new WxPayException("數組數據異常!"); } $xml = "<xml>"; foreach ($this->value as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; } public function createXml($data) { if(!is_array($data) || count($data) <= 0) { throw new WxPayException("數組數據異常!"); } $xml = "<xml>"; foreach ($data as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; } public function createMakeSign($data) { $buff = ""; foreach ($data as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); $buff = $buff . "&key=".$this->key; $string = md5($buff); //簽名步驟四:全部字符轉爲大寫 $result = strtoupper($string); return $result; } /** * 生成簽名 * @return 簽名,本函數不覆蓋sign成員變量,如要設置簽名須要調用SetSign方法賦值 */ public function MakeSign() { //簽名步驟一:按字典序排序參數 ksort($this->value); $string = $this->ToUrlParams(); //簽名步驟二:在string後加入KEY $string = $string . "&key=".$this->key; //簽名步驟三:MD5加密 $string = md5($string); //簽名步驟四:全部字符轉爲大寫 $result = strtoupper($string); $this->value['sign'] = $result; return $result; } /** * 格式化參數格式化成url參數 */ public function ToUrlParams() { $buff = ""; foreach ($this->value as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } public function FromXml($xml) { if(!$xml){ throw new \Exception("xml數據異常!"); } //將XML轉爲array //禁止引用外部xml實體 libxml_disable_entity_loader(true); $this->values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $this->values; } /** * 以post方式提交xml到對應的接口url * * @param string $xml 須要post的xml數據 * @param string $url url * @param bool $useCert 是否須要證書,默認不須要 * @param int $second url執行超時時間,默認30s * @throws WxPayException */ private function postXmlCurl($xml, $url, $useCert = false, $second = 30) { $ch = curl_init(); //設置超時 curl_setopt($ch, CURLOPT_TIMEOUT, $second); 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, $this->apiclient_key); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, $this->apiclient_cert); // } //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); // throw new \Exception("curl出錯,錯誤碼:$error"); } } public function RAS($str) { $public_pem = file_get_contents($this->public_pem); openssl_public_encrypt($str,$decrypted,$public_pem,OPENSSL_PKCS1_OAEP_PADDING); return base64_encode($decrypted); } public function partnerTradeNo($value) { $this->value['partner_trade_no'] = $value; } public function nonceStr($value) { $this->value['nonce_str'] = $value; } public function encBankNo($value) { $this->value['enc_bank_no'] = $this->RAS($value); } public function encTrueName($value) { $this->value['enc_true_name'] = $this->RAS($value); } public function bankCode($value) { $this->value['bank_code'] = $value; } public function amount($value) { $this->value['amount'] = $value; } public function desc($value) { $this->value['desc'] = $value; } }
<?php require './Xcxpay/Wxyxk.php';//引入剛剛的類 $mch_id = '123456'; $key = "1111111111"; $model = new Wxyxk($mch_id,$key); $model->apiclient_key = './Xcxpay/Certificate/Jw/apiclient_cert.pem';//證書路徑 在商戶平臺下載 第一步獲取的證書 $model->apiclient_cert = './Xcxpay/Certificate/Jw/apiclient_key.pem';//證書路徑 在商戶平臺下載 第一步獲取的證書 $model->public_pem = "./Xcxpay/Certificate/Jw/wx_public8.pem";//第二步獲取的 微信RAS公匙 $model->partnerTradeNo($order_on);//訂單號 $model->nonceStr(md5(rand(1000,9999))); $model->encBankNo($employee_bank_info['bank_no']);//銀行卡號 $model->encTrueName($employee_bank_info['name']);//銀行卡持卡人姓名 $model->bankCode($employee_bank_info['bank_code']);//微信銀行卡id 見下圖 $model->amount($amount);//金額 $model->desc($declare);//訂單說明 $result = $model->sendRed();