147 lines
4.2 KiB
PHP
147 lines
4.2 KiB
PHP
<?php
|
||
/**
|
||
* 支付网关抽象层
|
||
*
|
||
* 统一支付宝、微信支付的接口,供结算页面调用。
|
||
* 每种支付方式实现 PaymentGatewayInterface 接口。
|
||
*
|
||
* 支付流程:
|
||
* 1. 用户选择支付方式 → 创建支付订单(Payment::createOrder)
|
||
* 2. 跳转到支付页面/显示二维码(Payment::getPayUrl / getQrCode)
|
||
* 3. 支付平台异步通知 → Payment::handleNotify
|
||
* 4. 用户完成支付 → 跳转回 return_url
|
||
*/
|
||
if (!defined('IN_APP')) exit('Forbidden');
|
||
|
||
// 显式加载网关实现(类名与文件名不一致,自动加载器无法定位)
|
||
require_once __DIR__ . '/PaymentAlipay.php';
|
||
require_once __DIR__ . '/PaymentWechat.php';
|
||
|
||
interface PaymentGatewayInterface
|
||
{
|
||
/**
|
||
* 创建支付订单,返回支付 URL 或表单 HTML。
|
||
* @param array $order ['order_no', 'amount', 'subject', 'notify_url', 'return_url']
|
||
* @return array ['url' => '...', 'form' => '...'] 至少包含一个
|
||
*/
|
||
public function createOrder(array $order);
|
||
|
||
/**
|
||
* 验证异步通知签名和数据。
|
||
* @param array $params POST/GET 参数
|
||
* @return bool 是否有效
|
||
*/
|
||
public function verifyNotify(array $params);
|
||
|
||
/**
|
||
* 从通知中获取交易号。
|
||
*/
|
||
public function getTradeNo(array $params);
|
||
|
||
/**
|
||
* 从通知中获取支付状态(是否成功)。
|
||
*/
|
||
public function isPaid(array $params);
|
||
|
||
/**
|
||
* 响应支付平台(输出 "success" 等)。
|
||
*/
|
||
public function respondSuccess();
|
||
|
||
/**
|
||
* 获取网关名称。
|
||
*/
|
||
public function getName();
|
||
}
|
||
|
||
/**
|
||
* 支付管理器:注册网关、创建订单、处理回调。
|
||
*/
|
||
class Payment
|
||
{
|
||
/** @var array 已注册的支付网关 [code => instance] */
|
||
private static $gateways = [];
|
||
|
||
/**
|
||
* 注册支付网关。
|
||
* @param string $code 如 'alipay', 'wechat'
|
||
* @param PaymentGatewayInterface $gateway
|
||
*/
|
||
public static function register($code, PaymentGatewayInterface $gateway)
|
||
{
|
||
self::$gateways[$code] = $gateway;
|
||
}
|
||
|
||
/**
|
||
* 获取已注册的支付网关。
|
||
* @param string $code
|
||
* @return PaymentGatewayInterface|null
|
||
*/
|
||
public static function get($code)
|
||
{
|
||
return self::$gateways[$code] ?? null;
|
||
}
|
||
|
||
/**
|
||
* 获取所有可用支付方式列表。
|
||
* @return array [['code'=>'alipay','name'=>'支付宝','enabled'=>bool], ...]
|
||
*/
|
||
public static function availableMethods()
|
||
{
|
||
$list = [];
|
||
foreach (self::$gateways as $code => $gw) {
|
||
$list[] = [
|
||
'code' => $code,
|
||
'name' => $gw->getName(),
|
||
'enabled' => true, // TODO: 可根据配置判断是否启用
|
||
];
|
||
}
|
||
return $list;
|
||
}
|
||
|
||
/**
|
||
* 根据配置自动初始化并注册所有启用的支付网关。
|
||
* 在 init.php 中调用一次即可。
|
||
*/
|
||
public static function initGateways()
|
||
{
|
||
$alipayEnabled = getSetting('pay_alipay_enabled', '0') === '1';
|
||
$wechatEnabled = getSetting('pay_wechat_enabled', '0') === '1';
|
||
|
||
if ($alipayEnabled) {
|
||
self::register('alipay', new AlipayGateway());
|
||
}
|
||
if ($wechatEnabled) {
|
||
self::register('wechat', new WechatGateway());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建支付记录到数据库。
|
||
* @return int pay_log ID
|
||
*/
|
||
public static function createPayLog($orderId, $method, $amount, $tradeNo = '')
|
||
{
|
||
db()->prepare(
|
||
'INSERT INTO ' . tn('pay_logs') . ' (order_id,pay_method,amount,trade_no,status,created_at) VALUES (?,?,?,?,?,NOW())'
|
||
)->execute([$orderId, $method, $amount, $tradeNo, 'pending']);
|
||
return (int)db()->lastInsertId();
|
||
}
|
||
|
||
/**
|
||
* 更新支付日志状态。
|
||
*/
|
||
public static function updatePayStatus($logId, $status, $tradeNo = '')
|
||
{
|
||
$sql = 'UPDATE ' . tn('pay_logs') . ' SET status=?, updated_at=NOW()';
|
||
$params = [$status];
|
||
if ($tradeNo) {
|
||
$sql .= ', trade_no=?';
|
||
$params[] = $tradeNo;
|
||
}
|
||
$sql .= ' WHERE id=?';
|
||
$params[] = $logId;
|
||
db()->prepare($sql)->execute($params);
|
||
}
|
||
}
|