Files
2026-08-08 15:53:53 +08:00

83 lines
3.0 KiB
PHP

<?php
namespace Core\Payment;
/**
* 支付宝网关
* - demo:返回模拟支付入口
* - live:电脑网站支付(alipay.trade.page.pay),RSA2 签名
*/
class AlipayGateway extends Gateway
{
public function pay(array $order): array
{
$simulate = site_url('order/demo/' . $order['order_no']);
$hasCred = !empty($this->config['appid']) && !empty($this->config['private_key']);
if ($this->isDemo() || !$hasCred) {
return [
'mode' => 'demo',
'channel' => 'alipay',
'simulate' => $simulate,
'config_missing' => !$hasCred,
];
}
$biz = [
'out_trade_no' => $order['order_no'],
'product_code' => 'FAST_INSTANT_TRADE_PAY',
'total_amount' => $this->money($order['amount']),
'subject' => $order['product_name'] ?: '商品购买',
];
$params = [
'app_id' => $this->config['appid'],
'method' => 'alipay.trade.page.pay',
'format' => 'JSON',
'charset' => 'utf-8',
'sign_type' => 'RSA2',
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
'notify_url' => site_url('pay/notify/alipay'),
'return_url' => site_url('order/success/' . $order['order_no']),
'biz_content' => json_encode($biz, JSON_UNESCAPED_UNICODE),
];
$params['sign'] = $this->sign($params);
$gateway = $this->config['gateway'] ?: 'https://openapi.alipay.com/gateway.do';
return ['mode' => 'redirect', 'channel' => 'alipay', 'url' => $gateway . '?' . http_build_query($params)];
}
/** RSA2 签名 */
private function sign(array $params): string
{
ksort($params);
$str = '';
foreach ($params as $k => $v) {
if ($v === '' || $v === null) continue;
$str .= $k . '=' . $v . '&';
}
$str = rtrim($str, '&');
$key = $this->normalizeKey($this->config['private_key'] ?? '', false);
openssl_sign($str, $sign, $key, OPENSSL_ALGO_SHA256);
return base64_encode($sign);
}
private function normalizeKey(string $key, bool $isPublic): string
{
$key = trim($key);
if (strpos($key, '-----BEGIN') === 0) return $key;
$head = $isPublic ? "-----BEGIN PUBLIC KEY-----\n" : "-----BEGIN RSA PRIVATE KEY-----\n";
$foot = $isPublic ? "\n-----END PUBLIC KEY-----" : "\n-----END RSA PRIVATE KEY-----";
return $head . chunk_split($key, 64, "\n") . $foot;
}
public function verifyNotify(array $data): ?string
{
if (empty($data['out_trade_no'])) return null;
$status = $data['trade_status'] ?? '';
if ($status === 'TRADE_SUCCESS' || $status === 'TRADE_FINISHED') {
// 生产环境应使用支付宝公钥对签名做严格验签后再返回
return $data['out_trade_no'];
}
return null;
}
}