PHP實現個人免簽約微信支付介面原理+原始碼

TANKING發表於2023-02-26

什麼是個人免籤支付

個人免籤支付就是給個人用的支付介面,一般的支付介面都需要營業執照才能申請,個人很難申請的到,或者是沒有資質去申請,要和支付商進行簽約的。免籤,顧名思義就是不需要簽約。那麼個人免籤支付就有市場了,就是為了解決個人無法輕易申請到支付介面的問題。

免籤的方案有很多種
  1. APP監聽收款碼的支付結果,然後修改頁面的支付結果。
  2. 二次清算。款先到擁有官方支付介面的商戶中,由商戶給你結算。
  3. Xposed微信外掛實現全自動監聽建立收款碼、以及收款過程,容易封號。

方案其實有很多種,但是以上的方案都有不少的缺點,當然這些方案仍有不少人在用,沒辦法,確實是解決問題的一種辦法。而本次文章我也是透過簡單的技術開發實現第一種APP監聽收款碼的免籤支付方式。

APP監聽收款碼的支付結果

整個過程很簡單:

訪問URL -> 檢查資料庫2分鐘內未支付的訂單金額 -> 如果2分鐘內未支付的訂單金額中存在當前訂單一樣的金額,需要在當前金額基礎上+0.01元用於區分訂單的唯一性 -> 使用者掃碼支付 -> 安卓手機APP監聽到這筆訂單的收款 -> 將收款金額非同步傳送到伺服器 -> 伺服器修改資料庫該筆訂單金額的支付狀態 -> 掃碼頁面一直在輪詢訂單的支付狀態,發現已支付就修改頁面的支付結果 -> 完成支付。

影片演示

點選連結播放演示影片:https://share.weiyun.com/XliTd63d

上程式碼

index.php

該頁面是用於建立訂單的,其中 $order_price = 0.01; 就是建立一筆0.01元的訂單。建立訂單前,程式會查詢資料庫來確定當前金額是否存在未支付的訂單,如果存在,需支付的金額會在當前訂單金額基礎上+0.01元。

為什麼要這麼做?因為APP監聽只能監聽到收到了多少錢,無法監聽到訂單號,所以無法區分這個金額是你支付的還是其他人支付的。

所以在當前訂單有效期內,你需要注意兩件事,第一,你這個程式的訪問量一定不能太高,不允許高併發的情況出現,適合小眾,小規模,小流量的業務使用,一旦人多了,短時間內訂單量多了,很難做到精準的監聽支付結果。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0,viewport-fit=cover">
    <meta charset="utf-8">
    <script src="./js/jquery.min.js"></script>
    <link rel="stylesheet" href="./css/style.css">
    <title>微信讚賞碼免簽約支付實現原理Demo</title>
</head>

<body onload="clock(120)">
    
    <?php
    
        // 資料庫配置
        include './Db.php';
        
        // 例項化類
        $db = new DB_API($config);
        
        // 訂單號
        $order_num = date('Ymd').time();
        
        // 訂單金額
        $order_price = 0.01;
        
        // 獲取未支付訂單列表
        $getOrderList = $db->set_table('mqpay_order')->findAll(['order_status' => 1]);
        
        // 遍歷訂單
        $orderNoExpire = array();
        for ($i = 0; $i < count($getOrderList); $i++) {
            
            // 訂單時間
            $order_time = json_decode(json_encode($getOrderList[$i]))->order_time;
            
            // 訂單金額
            $order_money = json_decode(json_encode($getOrderList[$i]))->order_money;
            
            // 獲取2分鐘未支付的訂單
            if(countTimes(time(),strtotime($order_time)) <= 2){
                
                // 如果存在
                $orderNoExpire[] = $order_money;
    
            }
        }
        
        // 判斷是否有2分鐘未支付的訂單
        if(count($orderNoExpire) == 0){
            
            $needPay = $order_price;
        }else{
            
            // 獲取2分鐘未支付的訂單的最大金額+0.01
            $needPay = max($orderNoExpire) + 0.01;
            
        }
        
        // 建立訂單
        creatOrder($order_num,$order_price,$needPay,$db);
        
        
        // 建立訂單
        function creatOrder($order_num,$order_price,$needPay,$db){
            
            // 訂單引數
            $createOrder = [
                'order_num' => $order_num,
                'order_price' => $order_price,
                'order_money' => $needPay,
            ];
            
            // 建立
            $createOrderResult = $db->set_table('mqpay_order')->add($createOrder);
            if($createOrderResult){
                
                // 成功
                echo '<div class="payInfoCard">
                    <div class="header">裡客雲科技</div>
                    <div class="moneyCard">
                        <div class="text">支付金額</div>
                        <div class="money"><span class="rmb">¥</span>'.$needPay.'</div>
                        <!--二維碼-->
                        <img src="./img/zsm.jpg" id="zsmQrcode" class="zsmQrcode" />
                        <p class="payWarning">請識別上方讚賞碼</p>
                        <p class="payWarning">點選<span class="blueFont">其他金額</span>輸入'.$needPay.'元</p>
                        <p class="payWarningMini">輸入的金額必須要完全一致</p>
                        <p id="orderExpireTime"></p>
                        <p id="orderNum" style="display:none;">'.$order_num.'</p>
                        <p id="needPay" style="display:none;">'.$needPay.'</p>
                    </div>
                </div>
                
                <!--提示-->
                <p class="payTips">我們透過機器人監測本次支付<br/>支付後會立刻顯示支付結果<br/>支付後沒顯示支付結果請聯絡人工處理<br/>人工微訊號:sansure2016</p>';
            }else{
                
                // 失敗
                echo '<div class="payInfoCard">
                    <div class="header">裡客雲科技</div>
                    <div class="moneyCard" style="padding:20px 20px;">
                        建立訂單失敗!
                    </div>
                </div>';
            }
        }
        
        
        // 計算時間戳的差值
        function countTimes($begin,$end){
            
            $begintimes = $begin;
            $endtimes = $end;
            $timediff = abs($endtimes - $begintimes);
            $days = intval($timediff / 86400);
            $remain = $timediff % 86400;
            $hours = intval($remain / 3600);
            $remain = $remain % 3600;
            $mins = intval($remain / 60);
            $secs = $remain % 60;
            return $mins;
        }
        
    ?>
    
    <script>
    
        // 每2秒獲取一次支付結果
        var checkPayInterval = setInterval('checkPay()',2000);
        
        // 獲取支付結果
        function checkPay(){
            
            // 獲取訂單號和支付金額
            var orderNum = $("#orderNum").text();
            var needPay = $("#needPay").text();
            
            $.ajax({
                type: "GET",
                url: "./checkPay.php?order_num="+orderNum+"&order_money="+needPay,
                success: function(res){
  
                    // 判斷支付結果
                    if(res.code == 200){
                        
                        console.log('支付成功');
                        $("#zsmQrcode").prop("src","./img/success.png");
                        $('#orderExpireTime').css('display','none');
                        clearInterval(checkPayInterval);
  
                    }else{
                        
                        console.log(res.msg);
                    }
                }
            });
        }
        
        // 倒數計時
        function clock(times){
            
            // 獲取時分秒
            var h=parseInt(times/3600);
            var m=parseInt((times%3600)/60);
            var s=(times%3600)%60;
            
            // 在頁面中顯示倒數計時
            $('#orderExpireTime').html(m+"分"+s+"秒後過期");
            
            // 倒數計時
            if(times > 0){
                times = times-1;
                setTimeout(function (){
                    clock(times);
                }, 1000);
            }else{
                
                // 顯示訂單過期
                $("#zsmQrcode").prop("src","./img/expire.png");
                $('#orderExpireTime').text('訂單已過期,請重新整理頁面!');
                
                // 結束輪詢
                clearInterval(checkPayInterval);
                
                console.log('訂單過期,停止監聽');
            }
        }
    </script>
</body>

</html>

checkPay.php

這個是用於訂單頁面實時監聽支付結果的,每2秒就查一次資料庫獲取訂單的支付結果,2分鐘後未支付會停止查詢。

<?php

    // 頁面編碼
    header("Content-type:application/json");
    
    // 資料庫配置
    include './Db.php';

    // 例項化類
    $db = new DB_API($config);
    
    // 獲取訂單號和支付金額
    $order_num = $_GET['order_num'];
    $order_money = $_GET['order_money'];
    
    // 根據訂單號和訂單金額來查詢支付結果
    $getOrderPayStatus = $db->set_table('mqpay_order')->find(['order_num'=>$order_num,'order_money'=>$order_money]);
    
    // 判斷支付結果
    if($getOrderPayStatus){
        
        // 支付狀態
        $order_status = json_decode(json_encode($getOrderPayStatus))->order_status;
        
        if($order_status == 2){
            
            // 支付成功
            $payResult = array(
                'code' => 200,
                'msg' => '支付成功'
            );
        }else{
            
            // 未支付
            $payResult = array(
                'code' => 202,
                'msg' => '未支付'
            );
        }
        
    }else{
        
        // 無結果
        $payResult = array(
            'code' => 201,
            'msg' => '未支付'
        );
    }
    
    // 返回JSON
    echo json_encode($payResult,JSON_UNESCAPED_UNICODE);
    
?>

notify.php

這個是非同步回撥,在APP監聽軟體需要配置這個檔案的URL和傳遞的引數,將監聽到的金額POST給你的伺服器然後修改資料庫的支付結果,以實現支付回撥的目的。

<?php

    // 頁面編碼
    header("Content-type:application/json");

    // 原文
    $orderMsg = $_GET['orderMsg'];
    
    // 資料庫配置
    include './Db.php';

    // 例項化類
    $db = new DB_API($config);
    
    // 訂單金額、需支付的金額、通知原文、db例項
    updateOrder($orderMsg,$db);
    
    // 修改支付結果
    function updateOrder($orderMsg,$db){
        
        // 擷取
        // 示例:二維碼讚賞到賬1.00元
        // 擷取【到賬】後面的
        $money_1 = substr($orderMsg, strripos($orderMsg, "到賬") + 6);
        
        // 擷取【元】前面的
        $money_2 = substr($money_1, 0, strrpos($money_1, "元"));
        
        // 更新訂單
        $updateOrderResult = $db->set_table('mqpay_order')->update(['order_status'=>1,'order_money'=>$money_2],['order_status'=>2,'order_paytime'=>time(),'order_msg'=>$orderMsg]);

        if($updateOrderResult){
            
            // 成功
            $ret = array(
                'code' => 200,
                'msg' => '支付成功',
                'order_num' => $order_num,
                'order_money' => $money_2,
                'order_msg' => $orderMsg
            );
        }else{
            
            // 失敗
            $ret = array(
                'code' => 200,
                'msg' => '支付失敗',
                'order_num' => $order_num
            );
        }
    }
    
    // 返回JSON
    echo json_encode($ret,JSON_UNESCAPED_UNICODE);
    
?>

完整程式碼

以上3個檔案是核心程式碼,僅作技術分析實現原理。完整的程式碼涉及到樣式、圖片、資料庫操作類、以及資料庫表SQL語句、監聽APP原始碼及安裝包。

image.png

Demo

頁面也是非常簡單的,也是由本人設計,頁面精簡美觀。
演示地址:http://demo.likeyunba.com/pay/zsm/ (僅開放一段時間,以後會撤下來)

image.png

監聽APP配置

監聽APP配置也挺簡單的,只需要將notify.php的線上URL配置至APP即可。具體操作請看截圖:

1、開啟APP,選擇【傳送通道】點選【Webhook】,選擇【GET請求】 ,輸入notify.php 所在伺服器的URL,下面的引數填寫【orderMsg=[msg]】即可。

image.png

2、選擇【轉發規則】,點選【應用】,新增轉發規則,【APP包名】,選擇【是】,包名輸入【com.tencent.mm】,選擇的傳送通道是上一步你建立的通道,下方的模板直接選擇通知內容即可。

image.png

到這裡,APP基本完成配置,然後將這個APP的自動啟動開啟,以及加入電池最佳化白名單,保證這個APP能一直在後臺執行不被殺死。

讚賞碼獲取

為什麼用讚賞碼而不用收款碼?因為收款碼更容易被風控,收款碼更加適合面對面掃碼收款,而不適合線上遠端收款,因為你的每一筆支付,都會記錄付款ip地址,定位等資訊,掃碼次數多了,就會被系統判斷遠端付款,容易觸發風控。讚賞碼是用於網路上的讚賞使用,相對來說是比收款碼安全的。

image.png

獲得自己的讚賞碼後,將讚賞碼的那部分裁剪出來,替換掉原始碼中 zsm.jpg 這個檔案就行了。讚賞碼是可以設定讚賞的引導語的,可以將引導語修改為【請點選其他金額輸入】,引導使用者。

原始碼下載

這個原始碼只有單頁面,沒有後臺,只適合個人單頁部署使用或者研究、學習、二次開發,不適合開箱即用,當然其實你有點基礎,也算是開箱即用,上傳到伺服器,修改資料庫配置,匯入資料庫表,配置好讚賞碼,配製好APP非同步回撥,也是可以用來做單頁的收款的,只要你的金額是固定的,確實是開箱即用。

開源地址:https://github.com/likeyun/liKeYun_MqPay

作者

TANKING

相關文章