系統需接入支付寶「即時到帳」接口,實現在線支付功能。本文從接口包整理、配置管理、控制器實作、回調處理、訂單狀態同步完整記錄實戰過程。
地址:`https://b.alipay.com/order/productDetail.htm?productId=2012111200373124`
選擇:`create_direct_pay_by_user-PHP-UTF-8`
將 `lib/` 目錄下 4 個核心檔案複製至 `Extend/Vendor/Alipay/` 並重命名:
| 原檔名 | 重命名 | 說明 |
|---|---|---|
| alipay_core.function.php | Corefunction.php | 核心函數庫 |
| alipay_md5.function.php | Md5function.php | MD5 簽名函數 |
| alipay_notify.class.php | Notify.php | 異步通知處理類 |
| alipay_submit.class.php | Submit.php | 請求提交類 |
編輯 `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', // 失敗頁
),
<?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 "支付驗證失敗!";
}
}
}
// 檢查訂單狀態
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>
支付寶已推出新版 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 經典模式,核心邏輯(配置分離、回調驗證、幂等處理)適用於所有版本遷移。