天天看點

PHP 微信H5支付 流程

什麼是微信H5支付

H5支付是指商戶在微信用戶端外的移動端網頁展示商品或服務,使用者在前述頁面确認使用微信支付時,商戶發起本服務呼起微信用戶端進行支付

主要用于觸屏版的手機浏覽器請求微信支付的場景。可以友善的從外部浏覽器喚起微信支付

微信官方也提供了一個體驗連結,請在微信外浏覽器打開

開發流程

1、使用者在商戶側完成下單,使用微信支付進行支付

2、由商戶背景向微信支付發起下單請求(調用統一下單接口)注:交易類型trade_type=MWEB

3、統一下單接口傳回支付相關參數給商戶背景,如支付跳轉url(參數名“mweb_url”),商戶通過mweb_url調起微信支付中間頁

4、中間頁進行H5權限的校驗,安全性檢查(此處常見錯誤請見下文)

5、如支付成功,商戶背景會接收到微信側的異步通知

6、使用者在微信支付收銀台完成支付或取消支付,傳回商戶頁面(預設為傳回支付發起頁面)

7、商戶在展示頁面,引導使用者主動發起支付結果的查詢

8、商戶背景判斷是否接到收微信側的支付結果通知,如沒有,背景調用訂單查詢接口确認訂單狀态

9、展示最終的訂單支付結果給使用者

網上的對于微信H5支付的資源感覺少之又少,可能是因為微信H5支付出來時間不久吧,很多PHP微信支付接入教程都比較複雜,且需要配置和引入較多的檔案,本人通過整理後給出一個單檔案版的,希望可以給各位想接入微信H5支付的帶來些許幫助和借鑒意義。以下為本篇文章的重點:

PHP代碼
<?php
/**
 * 微信H5支付PHP版本demo 部分代碼來自網絡
 * 部落格:https://qq52o.me
 */
$money= 1;                     //充值金額 微信支付機關為分
$userip = get_client_ip();     //獲得使用者裝置IP
$appid  = "";                  //應用APPID
$mch_id = "";                  //微信支付商戶号
$key    = "";                 //微信商戶API密鑰
$out_trade_no = date('YmdHis').rand(1000,9999);//平台内部訂單号
$nonce_str = createNoncestr();//随機字元串
$body = "H5充值";//内容
$total_fee = $money; //金額
$spbill_create_ip = $userip; //IP
$notify_url = "http://qq52o.me/wxpay/notify.php"; //回調位址
$trade_type = 'MWEB';//交易類型 具體看API 裡面有詳細介紹
$scene_info ='{"h5_info":{"type":"Wap","wap_url":"http://qq52o.me","wap_name":"支付"}}';//場景資訊 必要參數
$signA ="appid=$appid&attach=$out_trade_no&body=$body&mch_id=$mch_id&nonce_str=$nonce_str&notify_url=$notify_url&out_trade_no=$out_trade_no&scene_info=$scene_info&spbill_create_ip=$spbill_create_ip&total_fee=$total_fee&trade_type=$trade_type";
$strSignTmp = $signA."&key=$key"; //拼接字元串  注意順序微信有個測試網址 順序按照他的來 直接點下面的校正測試 包括下面XML  是否正确
$sign = strtoupper(MD5($strSignTmp)); // MD5 後轉換成大寫
$post_data = "<xml>
                    <appid>$appid</appid>
                    <mch_id>$mch_id</mch_id>
                    <body>$body</body>
                    <out_trade_no>$out_trade_no</out_trade_no>
                    <total_fee>$total_fee</total_fee>
                    <spbill_create_ip>$spbill_create_ip</spbill_create_ip>
                    <notify_url>$notify_url</notify_url>
                    <trade_type>$trade_type</trade_type>
                    <scene_info>$scene_info</scene_info>
                    <attach>$out_trade_no</attach>
                    <nonce_str>$nonce_str</nonce_str>
                    <sign>$sign</sign>
            </xml>";//拼接成XML 格式
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信傳參位址
$dataxml = postXmlCurl($post_data,$url); //背景POST微信傳參位址  同時取得微信傳回的參數 
$objectxml = (array)simplexml_load_string($dataxml, 'SimpleXMLElement', LIBXML_NOCDATA); //将微信傳回的XML 轉換成數組
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;
}
function postXmlCurl($xml,$url,$second = 30){
    $ch = curl_init();
    //設定逾時
    curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    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);
    //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);
        echo "curl出錯,錯誤碼:$error"."<br>";
    }
}
function get_client_ip($type = 0) {
    $type       =  $type ? 1 : 0;
    $ip         =   'unknown';
    if ($ip !== 'unknown') return $ip[$type];
    if($_SERVER['HTTP_X_REAL_IP']){//nginx 代理模式下,擷取用戶端真實IP
        $ip=$_SERVER['HTTP_X_REAL_IP'];
    }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {//用戶端的ip
        $ip     =   $_SERVER['HTTP_CLIENT_IP'];
    }elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {//浏覽目前頁面的使用者計算機的網關
        $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $pos    =   array_search('unknown',$arr);
        if(false !== $pos) unset($arr[$pos]);
        $ip     =   trim($arr[0]);
    }elseif (isset($_SERVER['REMOTE_ADDR'])) {
        $ip     =   $_SERVER['REMOTE_ADDR'];//浏覽目前頁面的使用者計算機的ip位址
    }else{
        $ip=$_SERVER['REMOTE_ADDR'];
    }
    // IP位址合法驗證
    $long = sprintf("%u",ip2long($ip));
    $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
    return $ip[$type];
}
?>
           

HTML代碼

<!DOCTYPE html>
<html >
<head>
 <meta charset="UTF-8">
 <title>微信支付</title>
 <style type="text/css">
 body{
 font-family: "Microsoft YaHei";
 }
 .pay-box{
 position: absolute;
 top: 50%;
 margin-top: -516px;
 left: 50%;
 margin-left: -320px;
 }
 .ico{
 width: 240px;
 height: 240px;
 border-radius: 120px;
 background: #3FB837;
 color: #fff;
 display: inline-block;
 font-size: 160px;
 line-height: 240px;
 }
 .txt{
 font-size: 42px;
 padding-top: 30px;
 color: #333;
 }
 .val{
 font-size: 80px;
 font-weight: bold;
 }
 .pay{
 width: 640px;
 height: 100px;
 margin-top: 100px;
 padding: 20px;
 border-radius: 10px;
 font-size:42px;
 color: #fff;
 background: #07BF05;
 border: 0px;
 text-align: center;
 }
 a{
 color: #fff;
 background: transparent !important;
 }
 </style>
</head>
<body>
 <div class="pay-box" style="text-align: center;">
 <div class="ico">
 ¥
 </div>
 <div class="txt">
 支付金額
 </div>
 <div class="val">
 ¥<span><?php echo $total_fee/100 ?></span> 
<!-- 這裡使用原生PHP echo輸出需要支付的價格 -->
 </div>
 <a class="pay" href="<?php echo $objectxml['mweb_url'] ?>" target="_blank" rel="external nofollow" ><button class="pay">确認支付</button></a> 
<!-- 這裡點選調起微信支付頁面 mweb_url  -->
 </div>
</body>
</html>
           

以上為微信H5支付demo的全部代碼,其中HTML部分中的mweb_url是為拉起微信支付收銀台的中間頁面,可通過通路該url來拉起微信用戶端,完成支付,mweb_url的有效期為5分鐘。

回調部分

因為微信支付相關回調代碼基本一樣,可參考PHP完成微信小程式線上支付功能一文中的回調代碼,有什麼問題可以聯系我QQ或者評論留言。下文補充了同步回調

如何使用

标題說的就是單PHP檔案完成微信支付,你可以把HTML代碼寫在PHP檔案的後面,或者在HTML檔案裡面引入PHP檔案,就可以使用了。

2018年3月21日補充:

根據公司需求,需要一個同步回調頁面,微信的支付是沒有同步回調的,去查微信支付文檔

正常流程使用者支付完成後會傳回至發起支付的頁面,如需傳回至指定頁面,則可以在MWEB_URL後拼接上redirect_url參數,來指定回調頁面。

我昨天想着是在生成mweb_url參數之前去拼接,結果證明是我想太多了!隻能怪老闆讓加班到8點,我到6點就走了 , 直接在生成之後加上回調頁面,文檔讀來讀去也是這個意思,看來以後讀文檔真的要認真了。

PHP部分:

需對redirect_url進行urlencode處理,将此部分代碼加入到上面代碼$post_dat之前就行。

$returnUrl = "https://www.wechatpay.com.cn";
$return_Url = urlencode($returnUrl);
           

HTML部分:

<a class="pay" href="<?php echo $objectxml['mweb_url'] ?>&redirect_url=<?php echo $return_Url; ?>" target="_blank" rel="external nofollow" ><button class="pay">确認支付</button></a>
           

通過統一下單接口獲到的MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096

則拼接後的位址為MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cn