第一步:准備工作
1、只有在微信開放平台認證過開發者資質的才能調用微信支付接口,所以首先就是要認證一下,很簡單,只不過微信會收取300元的審核費用
2、設置支付目錄
登錄微信支付商戶平台(pay.weixin.qq.com)-->產品中心-->開發配置,進行設置,設置后一般5分鍾內生效。
這是微信官方的文檔
3、設置授權域名
其實這一步如果之前做過微信登陸的就不用在做了,因為之前已經設置過了
之所以要設置授權域名是為了拿到openid,統一下單接口中要求必傳用戶openid,只有設置過授權域名的才能獲取有效的openid。(如果用戶登陸的時候拿到的是開放平台的unionid,那么你進行下單的時候,把unionid的屬性名換成openid,一樣可以成功支付)
第二步:正式開始
1、第一步
用戶點擊支付按鈕,發出請求
function bay(pid,uid,money,name){ $.ajax({ url:ajaxurl+'/Car/payh5', dataType: 'json', data:{ pid:pid,//商品id uid:uid,//用戶id money:money,//價格 name: name,//商品名稱 }, type: 'post', success: function (data) { var state=data.state; if(state==0){ var RETURN_MSG =data.RETURN_MSG; alert(RETURN_MSG); }else{ callpay(data); } } }); }
2、第二步
根據前端傳的參數,查詢用戶和商品的詳細信息,生成支付訂單
public function pay() { //獲取微信支付所需信息 /** * @param [sting] $appid [小程序APPID] * @param [sting] $openid [用戶openID] * @param [sting] $mch_id [商戶ID](微信商戶平台的id) * @param [sting] $key [商戶key](微信商戶平台的key) * @param [sting] $money [支付金額] * @param [sting] $body [商品描述] * @param [sting] $notify_url [回調地址]回調地址在后面寫 * @return [sting] $data [響應數據] */ $merchpay = new \WeiXinPay($appid,$openid,$mch_id,$key,$money,$body,$notify_status,$o_number); $data = $merchpay->Pay(); $data['appId']=$appid; echo $this->ajaxReturn($data); }
我在這里把添加訂單到自己數據表的步驟省略了,用的時候別忘了
之后,就是把參數轉化為xml,調用統一下單接口
class WeiXinPay{ private $appid; private $openid; private $mch_id; private $key; private $money; private $body; private $notify_status; private $order_id; public function __construct($appid,$openid,$mch_id,$key,$money,$body,$notify_status,$order_id) { $this->appid = $appid; $this->openid = $openid; $this->mch_id = $mch_id; $this->key = $key; $this->money = $money; $this->body = $body; $this->notify_status = $notify_status; $this->order_id = $order_id; } public function Pay() { $fee = $this->money;//舉例充值0.01 $appid = $this->appid;//支付APPID $body = $this->body; $mch_id = $this->mch_id; $nonce_str = $this->nonce_str();//隨機字符串 // $notify_url = $this->$notify_url; if($this->notify_status==1){ $notify_url ='http://'.$_SERVER['HTTP_HOST'].U('Car/notify'); }else{ $notify_url ='http://'.$_SERVER['HTTP_HOST'].U('Car/qnotify'); } // p($notify_url); $openid = $this->openid; $order_id = $this->order_id; $getServerIP= $this->getServerIP(); // $out_trade_no = $this->order_number($openid);//商戶訂單號 $out_trade_no = $order_id;//商戶訂單號 $spbill_create_ip = $getServerIP;//ip $total_fee = $fee*100;//因為充值金額最小是1 而且單位為分 如果是充值1元所以這里需要*100 $trade_type = 'JSAPI';//交易類型 默認 //這里是按照順序的 因為下面的簽名是按照順序 排序錯誤 肯定出錯 $post['appid'] = $appid; $post['body'] = $body; $post['mch_id'] = $mch_id; $post['nonce_str'] = $nonce_str;//隨機字符串 $post['notify_url'] = $notify_url; $post['openid'] = $openid; $post['out_trade_no'] = $out_trade_no; $post['spbill_create_ip'] = $spbill_create_ip;//終端的ip $post['total_fee'] = $total_fee;//總金額 最低為一塊錢 必須是整數 $post['trade_type'] = $trade_type; $sign = $this->sign($post);//簽名 $post_xml = '<xml> <appid>'.$appid.'</appid> <body>'.$body.'</body> <mch_id>'.$mch_id.'</mch_id> <nonce_str>'.$nonce_str.'</nonce_str> <notify_url>'.$notify_url.'</notify_url> <openid>'.$openid.'</openid> <out_trade_no>'.$out_trade_no.'</out_trade_no> <spbill_create_ip>'.$spbill_create_ip.'</spbill_create_ip> <total_fee>'.$total_fee.'</total_fee> <trade_type>'.$trade_type.'</trade_type> <sign>'.$sign.'</sign> </xml> '; //統一接口prepay_id $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $xml = $this->http_request($url,$post_xml); $array = $this->xml($xml);//全要大寫 // var_dump($array);exit; if($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS'){ $time = time(); $tmp='';//臨時數組用於簽名 $tmp['appId'] = $appid; $tmp['nonceStr'] = $nonce_str; $tmp['package'] = 'prepay_id='.$array['PREPAY_ID']; $tmp['signType'] = 'MD5'; $tmp['timeStamp'] = "$time"; $data['state'] = 1; $data['timeStamp'] = "$time";//時間戳 $data['nonceStr'] = $nonce_str;//隨機字符串 $data['signType'] = 'MD5';//簽名算法,暫支持 MD5 $data['package'] = 'prepay_id='.$array['PREPAY_ID'];//統一下單接口返回的 prepay_id 參數值,提交格式如:prepay_id=* $data['paySign'] = $this->sign($tmp);//簽名,具體簽名方案參見微信公眾號支付幫助文檔; $data['out_trade_no'] = $out_trade_no; }else{ $data['state'] = 0; $data['text'] = "錯誤"; $data['RETURN_CODE'] = $array['RETURN_CODE']; $data['RETURN_MSG'] = $array['RETURN_MSG']; } // var_dump($data);exit; $data = json_encode($data); return json_decode($data,true); }
在這個pay()方法中有調用了幾個方法
32位隨機字符串
private function nonce_str() { $result = ''; $str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz'; for ($i=0;$i<32;$i++){ $result .= $str[rand(0,48)]; } return $result; }
簽名 $data要先排好順序
private function sign($data) { $stringA = ''; foreach ($data as $key=>$value){ if(!$value) continue; if($stringA) $stringA .= '&'.$key."=".$value; else $stringA = $key."=".$value; } $wx_key = $this->key;//申請支付后有給予一個商戶賬號和密碼,登陸后自己設置key $stringSignTemp = $stringA.'&key='.$wx_key; return strtoupper(md5($stringSignTemp)); }
獲取xml
private function xml($xml) { $p = xml_parser_create(); xml_parse_into_struct($p, $xml, $vals, $index); xml_parser_free($p); $data = ""; foreach ($index as $key=>$value) { if($key == 'xml' || $key == 'XML') continue; $tag = $vals[$value[0]]['tag']; $value = $vals[$value[0]]['value']; $data[$tag] = $value; } return $data; }
curl請求
private function http_request($url,$data = null,$headers=array()) { $curl = curl_init(); if( count($headers) >= 1 ){ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); } curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); if (!empty($data)){ curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($curl); curl_close($curl); return $output; }
之后就是回調方法notify(),用來接收處理微信返回的參數
//微信支付回調 public function notify() { $post =$GLOBALS['HTTP_RAW_POST_DATA'];//接受POST數據XML個數 $post_data = $this->xmlToArray($post);//微信支付成功,返回回調地址url的數據:XML轉數組Array $postSign = $post_data['sign']; file_put_contents('log1.txt',$postSign); unset($post_data['sign']); // $post_data=unset($post_data['sign']); /* 微信官方提醒: * 商戶系統對於支付結果通知的內容一定要做【簽名驗證】, * 並校驗返回的【訂單金額是否與商戶側的訂單金額】一致, * 防止數據泄漏導致出現“假通知”,造成資金損失。 */ $str = $this->sign($post_data);//對數組數據拼接成key=value字符串 //判斷簽名 file_put_contents('log2.txt',$postSign); file_put_contents('log3.txt',$str); if($postSign!=$str){ echo '微信支付失敗';exit; } $where['o_number'] = $post_data['out_trade_no']; $order_status = M('new_order')->where($where)->find(); if($post_data['return_code']=='SUCCESS'&&$postSign){ /* * 首先判斷,訂單是否已經更新為ok,因為微信會總共發送8次回調確認 * 其次,訂單已經為ok的,直接返回SUCCESS * 最后,訂單沒有為ok的,更新狀態為ok,返回SUCCESS */ $updata['status'] = '2'; // $updata['time']=date('Y-m-d H:i:s',time()); if(M('new_order')->where($where)->save($updata)!=false){ $new_order=M('new_order')->where($where)->find(); M('new_order')->where(array('uid'=>$new_order['uid'],'status'=>1))->delete(); $this->return_success(); } echo exit('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'); }else{ echo '微信支付失敗'; } }
通知成功
public function return_success() { $return['return_code'] = 'SUCCESS'; $return['return_msg'] = 'OK'; $xml_post = '<xml> <return_code>'.$return['return_code'].'</return_code> <return_msg>'.$return['return_msg'].'</return_msg> </xml>'; echo $xml_post;exit; }
到這里基本上已經算結束了,之后就是根據微信返回的結果進行邏輯處理
這是微信官方的開發文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4
要是最后沒有收到支付通知,無法確定支付狀態,那就可以調用微信查詢訂單接口主動查詢訂單狀態,完成最后一步
查詢訂單接口:https://api.mch.weixin.qq.com/pay/orderquery
所需要的參數:
<xml> <appid>appid</appid> <mch_id>商戶號</mch_id> <nonce_str>隨機字符</nonce_str> <transaction_id>微信訂單號</transaction_id>/<out_trade_no>商戶訂單號</out_trade_no>(二選一) <sign>簽名</sign> </xml>
返回的參數:
當然了,這些返回的數據看着多,其實你只需要找到你要用的就可以了
比如你只要判斷是否支付成功,那么只需要用的trade_state參數就可以了
trade_state的值所代表的解釋:
SUCCESS—支付成功
REFUND—轉入退款
NOTPAY—未支付
CLOSED—已關閉
REVOKED—已撤銷(付款碼支付)
USERPAYING--用戶支付中(付款碼支付)
PAYERROR--支付失敗(其他原因,如銀行返回失敗)
轉載於:https://www.cnblogs.com/szharf/p/13541650.html