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

PHP 整合 PayPal 支付完整實作指南

     編輯:PHP 綜合知識

整合流程概覽

  1. 前端表單提交至 PayPal
  2. 用戶在 PayPal 完成付款
  3. PayPal 同步通知 (IPN) 至後端驗證
  4. 後端更新訂單狀態、發貨、發送通知
  5. 用戶返回商網站 (PDT/Return URL)

第一階段:前端支付表單

<form method="post" action="https://www.paypal.com/cgi-bin/webscr">
    <!-- 測試環境用 https://www.sandbox.paypal.com/cgi-bin/webscr -->
    
    <input type="hidden" name="cmd" value="_xclick" />
    <input type="hidden" name="business" value="merchant@example.com" />
    
    <input type="hidden" name="item_name" value="產品名稱" />
    <input type="hidden" name="item_number" value="ORD-202312001" />
    <input type="hidden" name="amount" value="99.00" />
    <input type="hidden" name="currency_code" value="USD" />
    <input type="hidden" name="quantity" value="1" />
    
    <!-- 回調 URL -->
    <input type="hidden" name="return" value="https://yoursite.com/payment/success" />
    <input type="hidden" name="cancel_return" value="https://yoursite.com/payment/cancel" />
    <input type="hidden" name="notify_url" value="https://yoursite.com/payment/ipn" />
    <input type="hidden" name="rm" value="2" /> <!-- POST 方式返回 -->
    
    <!-- 自定義參數 (會原樣回傳) -->
    <input type="hidden" name="custom" value="user_id=123|order_id=456" />
    
    <button type="submit">前往 PayPal 付款</button>
</form>

第二階段:IPN 即時付款通知驗證

<?php
class PayPalIPN {
    private $useSandbox = true;
    private $ipnUrl;
    private $verified = false;
    private $data = [];
    
    public function __construct($sandbox = true) {
        $this->useSandbox = $sandbox;
        $this->ipnUrl = $sandbox 
            ? 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr'
            : 'https://ipnpb.paypal.com/cgi-bin/webscr';
    }
    
    public function verify() {
        // 1. 取得原始 POST 資料
        $rawPost = file_get_contents('php://input');
        if (empty($rawPost)) return false;
        
        // 2. 解析並儲存
        parse_str($rawPost, $this->data);
        
        // 3. 回傳驗證給 PayPal (必須加上 cmd=_notify-validate)
        $validationPost = $rawPost . '&cmd=_notify-validate';
        
        // 4. 使用 cURL 發送驗證
        $ch = curl_init($this->ipnUrl);
        curl_setopt_array($ch, [
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $validationPost,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        // 5. 判斷結果
        if ($httpCode === 200 && $response === 'VERIFIED') {
            $this->verified = true;
            return true;
        }
        
        // 記錄失敗
        error_log("IPN 驗證失敗: HTTP $httpCode, Response: $response");
        return false;
    }
    
    public function isVerified() { return $this->verified; }
    public function getData() { return $this->data; }
    
    // 便利存取器
    public function __get($key) {
        return $this->data[$key] ?? null;
    }
}

// 使用範例:ipn.php
$ipn = new PayPalIPN(true); // 測試環境
if ($ipn->verify() && $ipn->isVerified()) {
    // 關鍵業務檢查
    if ($ipn->payment_status === 'Completed' && 
        $ipn->receiver_email === 'merchant@example.com' &&
        $ipn->mc_currency === 'USD') {
        
        $orderId = $ipn->item_number;
        $amount = (float)$ipn->mc_gross;
        $custom = $ipn->custom; // user_id=123|order_id=456
        
        // TODO: 更新資料庫訂單狀態、發送確認信、觸發發貨流程
        // 防重複處理:檢查訂單狀態、交易 ID (txn_id) 是否已處理
        
        error_log("IPN 成功處理訂單: $orderId, 金額: $amount");
    }
}
// 回應 200 OK 給 PayPal (否則會重試)
http_response_code(200);
?>

第三階段:PDT 付款資料傳輸 (用戶返回頁面)

<?php
// success.php - 用戶付款完成返回頁面
$tx = $_GET['tx'] ?? '';
$amt = $_GET['amt'] ?? '';
$cm = $_GET['cm'] ?? '';

if ($tx) {
    // 可選:再次驗證 PDT (需 PDT Identity Token)
    $ch = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => "cmd=_notify-synch&tx=$tx&at=YOUR_PDT_TOKEN",
        CURLOPT_RETURNTRANSFER => true,
    ]);
    $response = curl_exec($ch);
    curl_close($ch);
    
    if (strpos($response, 'SUCCESS') === 0) {
        echo "付款成功!訂單處理中...";
    } else {
        echo "付款驗證中,請稍後查看訂單狀態";
    }
} else {
    echo "歡迎回來,請查看訂單狀態";
}
?>

關鍵安全檢查清單

檢查項目說明
驗證 receiver_email 確認款項進入正確商家帳戶
驗證 mc_currency 防止幣別竄改 (USD ≠ TWD)
驗證 payment_status = Completed 僅處理完成付款,忽略 Pending/Failed
防重複處理 用 txn_id 或 item_number 去重
金額核對 比對 mc_gross 與訂單金額
HTTPS 端點 IPN/Return URL 必須 HTTPS
IP 白名單 (可選) 限制 PayPal 官方 IP 範圍

測試工具

  • PayPal Sandbox:developer.paypal.com 建立測試帳戶
  • IPN Simulator:Sandbox 後台模擬發送 IPN 測試端點
  • ngrok:本地開發暴露 HTTPS 端點 ngrok http 80

現代替代:PayPal Checkout (Smart Payment Buttons)

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID¤cy=USD"></script>
<div id="paypal-button-container"></div>
<script>
paypal.Buttons({
    createOrder: function(data, actions) {
        return actions.order.create({
            purchase_units: [{amount: {value: '99.00'}}]
        });
    },
    onApprove: function(data, actions) {
        return actions.order.capture().then(function(details) {
            alert('付款完成: ' + details.payer.name.given_name);
            // AJAX 通知後端驗證
        });
    }
}).render('#paypal-button-container');
</script>

傳統表單+IPN 方式適合簡單整合,新專案建議採用 PayPal Checkout JS SDK 提供更佳用戶體驗與安全性。

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