Files
freeshop/includes/Payment.php
T
2026-08-14 10:55:06 +08:00

147 lines
4.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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);
}
}