首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

ThinkPHP 整合支付寶即時到帳接口完整實戰教學

     編輯:PHP 綜合知識

專案需求

系統需接入支付寶「即時到帳」接口,實現在線支付功能。本文從接口包整理、配置管理、控制器實作、回調處理、訂單狀態同步完整記錄實戰過程。

一、接口包整理與規範化

1. 下載官方包

地址:`https://b.alipay.com/order/productDetail.htm?productId=2012111200373124`

選擇:`create_direct_pay_by_user-PHP-UTF-8`

2. 核心檔案重命名(符合 ThinkPHP 命名規範)

將 `lib/` 目錄下 4 個核心檔案複製至 `Extend/Vendor/Alipay/` 並重命名:

原檔名重命名說明
alipay_core.function.phpCorefunction.php核心函數庫
alipay_md5.function.phpMd5function.phpMD5 簽名函數
alipay_notify.class.phpNotify.php異步通知處理類
alipay_submit.class.phpSubmit.php請求提交類

3. 移除內部 require_once

編輯 `Submit.php`、`Notify.php`,刪除:

require_once("alipay_core.function.php");
require_once("alipay_md5.function.php");

統一由 ThinkPHP `vendor()` 自動載入。

二、配置檔管理

`Conf/Config.php`:

// 支付寶基礎配置
'alipay_config' => array(
    'partner' => '20********50',      // PID
    'key' => '9t***********ie',       // 安全校驗碼
    'sign_type' => strtoupper('MD5'),
    'input_charset' => strtolower('utf-8'),
    'cacert' => getcwd() . '\\cacert.pem',
    'transport' => 'http',
),

// 業務參數配置
'alipay' => array(
    'seller_email' => 'pay@xxx.com',           // 賣家支付寶帳號
    'notify_url' => 'https://www.xxx.com/Pay/notifyurl',   // 異步通知
    'return_url' => 'https://www.xxx.com/Pay/returnurl',   // 同步跳轉
    'successpage' => 'User/myorder?ordtype=payed',        // 成功頁
    'errorpage' => 'User/myorder?ordtype=unpay',          // 失敗頁
),

三、PayAction 控制器完整實作

<?php
class PayAction extends Action
{
    public function _initialize()
    {
        vendor('Alipay.Corefunction');
        vendor('Alipay.Md5function');
        vendor('Alipay.Notify');
        vendor('Alipay.Submit');
    }

    // 發起支付請求
    public function doalipay()
    {
        $alipay_config = C('alipay_config');
        
        $payment_type = "1";
        $notify_url = C('alipay.notify_url');
        $return_url = C('alipay.return_url');
        $seller_email = C('alipay.seller_email');
        
        // 從表單獲取(必填)
        $out_trade_no = $_POST['trade_no'];      // 商戶訂單號(唯一)
        $subject = $_POST['ordsubject'];         // 訂單名稱
        $total_fee = $_POST['ordtotal_fee'];     // 付款金額
        $body = $_POST['ordbody'];               // 訂單描述
        $show_url = $_POST['ordshow_url'];       // 商品展示地址
        
        $anti_phishing_key = "";
        $exter_invoke_ip = get_client_ip();
        
        $parameter = array(
            "service" => "create_direct_pay_by_user",
            "partner" => trim($alipay_config['partner']),
            "payment_type" => $payment_type,
            "notify_url" => $notify_url,
            "return_url" => $return_url,
            "seller_email" => $seller_email,
            "out_trade_no" => $out_trade_no,
            "subject" => $subject,
            "total_fee" => $total_fee,
            "body" => $body,
            "show_url" => $show_url,
            "anti_phishing_key" => $anti_phishing_key,
            "exter_invoke_ip" => $exter_invoke_ip,
            "_input_charset" => trim(strtolower($alipay_config['input_charset'])),
        );
        
        $alipaySubmit = new AlipaySubmit($alipay_config);
        $html_text = $alipaySubmit->buildRequestForm($parameter, "post", "確認支付");
        echo $html_text;
    }

    // 異步通知(服務器通知)
    public function notifyurl()
    {
        $alipay_config = C('alipay_config');
        $alipayNotify = new AlipayNotify($alipay_config);
        $verify_result = $alipayNotify->verifyNotify();
        
        if ($verify_result) {
            // 獲取通知參數
            $out_trade_no = $_POST['out_trade_no'];
            $trade_no = $_POST['trade_no'];
            $trade_status = $_POST['trade_status'];
            $total_fee = $_POST['total_fee'];
            $notify_id = $_POST['notify_id'];
            $notify_time = $_POST['notify_time'];
            $buyer_email = $_POST['buyer_email'];
            
            $parameter = compact('out_trade_no', 'trade_no', 'total_fee', 
                               'trade_status', 'notify_id', 'notify_time', 'buyer_email');
            
            if ($_POST['trade_status'] == 'TRADE_FINISHED') {
                // 處理完成
            } elseif ($_POST['trade_status'] == 'TRADE_SUCCESS') {
                if (!checkorderstatus($out_trade_no)) {
                    orderhandle($parameter);
                }
            }
            echo "success";  // 必須輸出,否則支付寶會重試
        } else {
            echo "fail";
        }
    }

    // 同步跳轉(頁面返回)
    public function returnurl()
    {
        $alipay_config = C('alipay_config');
        $alipayNotify = new AlipayNotify($alipay_config);
        $verify_result = $alipayNotify->verifyReturn();
        
        if ($verify_result) {
            $out_trade_no = $_GET['out_trade_no'];
            $trade_no = $_GET['trade_no'];
            $trade_status = $_GET['trade_status'];
            $total_fee = $_GET['total_fee'];
            $notify_id = $_GET['notify_id'];
            $notify_time = $_GET['notify_time'];
            $buyer_email = $_GET['buyer_email'];
            
            $parameter = compact('out_trade_no', 'trade_no', 'total_fee', 
                               'trade_status', 'notify_id', 'notify_time', 'buyer_email');
            
            if (in_array($_GET['trade_status'], array('TRADE_FINISHED', 'TRADE_SUCCESS'))) {
                if (!checkorderstatus($out_trade_no)) {
                    orderhandle($parameter);
                }
                $this->redirect(C('alipay.successpage'));
            } else {
                $this->redirect(C('alipay.errorpage'));
            }
        } else {
            echo "支付驗證失敗!";
        }
    }
}

四、公共函數庫 `Common/common.php`


// 檢查訂單狀態
function checkorderstatus($ordid)
{
    $Ord = M('Orderlist');
    $ordstatus = $Ord->where('ordid='.$ordid)->getField('ordstatus');
    return $ordstatus == 1;
}

// 處理訂單:更新狀態、記錄支付資訊
function orderhandle($parameter)
{
    $ordid = $parameter['out_trade_no'];
    $data = array(
        'payment_trade_no' => $parameter['trade_no'],
        'payment_trade_status' => $parameter['trade_status'],
        'payment_notify_id' => $parameter['notify_id'],
        'payment_notify_time' => $parameter['notify_time'],
        'payment_buyer_email' => $parameter['buyer_email'],
        'ordstatus' => 1,  // 已支付
    );
    M('Orderlist')->where('ordid='.$ordid)->save($data);
}

// 生成唯一訂單號
function getordcode()
{
    $Ord = M('Orderlist');
    $numbers = range(10, 99);
    shuffle($numbers);
    $code = array_slice($numbers, 0, 4);
    $ordcode = implode('', $code);
    
    if ($Ord->where("ordcode='{$ordcode}'")->getField('ordcode')) {
        return getordcode();  // 遞歸直到唯一
    }
    return $ordcode;
}

五、前端支付表單範例

<form action="__URL__/doalipay" method="post">
    <input type="hidden" name="trade_no" value="<?php echo $order['ordcode']; ?>" />
    <input type="hidden" name="ordsubject" value="<?php echo $order['subject']; ?>" />
    <input type="hidden" name="ordtotal_fee" value="<?php echo $order['amount']; ?>" />
    <input type="hidden" name="ordbody" value="<?php echo $order['description']; ?>" />
    <input type="hidden" name="ordshow_url" value="<?php echo $order['show_url']; ?>" />
    <button type="submit">前往支付寶支付</button>
</form>

六、關鍵注意事項總結

  1. 絕對路徑:`notify_url`、`return_url` 必須使用完整 HTTP URL,支付寶服務器需能訪問
  2. 訂單號唯一:`out_trade_no` 業務層面保證唯一,建議:日期 + 隨機數 + 用戶 ID
  3. 金額精度:`total_fee` 单位為元,保留兩位小數,避免浮點數誤差
  4. 編碼一致:專案、資料庫、支付寶配置統一 UTF-8
  5. 幂等性:`checkorderstatus` 防止重複處理,支付寶可能多次通知
  6. 安全驗證:`verifyNotify()`/`verifyReturn()` 必須調用,防止偽造通知
  7. 日誌記錄:記錄所有通知參數、驗證結果、處理狀態,便於對帳排查
  8. 測試環境:使用支付寶沙箱環境測試,正式上線前全流程驗證

七、升級建議:新版 SDK

支付寶已推出新版 PHP SDK(Composer 安裝),建議新專案使用:

composer require alipay/alipay-sdk-php

// 使用範例
$aop = new AopClient();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = 'your_app_id';
$aop->rsaPrivateKey = 'your_private_key';
$aop->alipayPublicKey = 'alipay_public_key';
$aop->apiVersion = '1.0';
$aop->signType = 'RSA2';

$request = new AlipayTradePagePayRequest();
$request->setBizContent(json_encode(array(
    'out_trade_no' => $out_trade_no,
    'total_amount' => $total_fee,
    'subject' => $subject,
    'product_code' => 'FAST_INSTANT_TRADE_PAY',
)));
$request->setNotifyUrl($notify_url);
$request->setReturnUrl($return_url);

$result = $aop->pageExecute($request);
echo $result;  // 直接輸出表單 HTML

本文方案基於 ThinkPHP 3.0/3.1 經典模式,核心邏輯(配置分離、回調驗證、幂等處理)適用於所有版本遷移。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved