文件
freeshop/includes/PaymentCodePay.php
2026-08-16 17:03:10 +08:00

177 行
6.5 KiB
PHP

<?php
class CodePayGateway implements PaymentGatewayInterface
{
private $type;
private $gateway;
private $pid;
private $key;
private $lastHttpCode = 0;
private $lastRaw = '';
private $lastError = '';
public function __construct()
{
$this->type = getSetting('pay_codepay_type', 'epay');
$this->gateway = rtrim(getSetting('pay_codepay_url', ''), '/');
$this->pid = getSetting('pay_codepay_pid', '');
$this->key = getSetting('pay_codepay_key', '');
}
public function getName()
{
return '码支付/易支付';
}
public function getType() { return $this->type; }
public function getGateway() { return $this->gateway; }
public function getPid() { return $this->pid; }
public function createOrder(array $order)
{
$outTradeNo = $order['order_no'];
$money = sprintf('%.2f', (float) ($order['amount'] ?? 0));
$name = $order['subject'] ?? '积分充值';
$notify = $order['notify_url'] ?? '';
$return = $order['return_url'] ?? '';
$channel = $order['channel'] ?? 'alipay';
if ($this->type === 'codepay') {
return $this->createCodePay($outTradeNo, $money, $name, $notify, $return, $channel);
}
return $this->createEpay($outTradeNo, $money, $name, $notify, $return, $channel);
}
private function createEpay($outTradeNo, $money, $name, $notify, $return, $channel)
{
$typeMap = ['alipay' => 'alipay', 'wxpay' => 'wepay', 'qq' => 'qq'];
$type = $typeMap[$channel] ?? 'alipay';
$params = [
'pid' => $this->pid,
'type' => $type,
'out_trade_no' => $outTradeNo,
'notify_url' => $notify,
'return_url' => $return,
'name' => $name,
'money' => $money,
];
$params['sign'] = $this->epaySign($params);
$params['sign_type'] = 'MD5';
$url = $this->gateway . '/submit.php?' . http_build_query($params);
return ['url' => $url, 'form' => ''];
}
private function createCodePay($outTradeNo, $money, $name, $notify, $return, $channel)
{
$typeMap = ['alipay' => '1', 'wxpay' => '2', 'qq' => '3'];
$type = $typeMap[$channel] ?? '1';
$param = $outTradeNo;
$params = [
'id' => $this->pid,
'pay_id' => $outTradeNo,
'price' => $money,
'param' => $param,
'type' => $type,
'notify_url' => $notify,
'return_url' => $return,
];
$params['sign'] = $this->codepaySign($params);
$params['sign_type'] = 'MD5';
$url = $this->gateway . '/codepay_gateway?' . http_build_query($params);
return ['url' => $url, 'form' => ''];
}
private function epaySign($params)
{
$data = $params;
unset($data['sign'], $data['sign_type']);
ksort($data);
$str = '';
foreach ($data as $k => $v) {
$str .= $k . '=' . $v . '&';
}
$str = rtrim($str, '&') . $this->key;
return md5($str);
}
private function codepaySign($params)
{
$str = $this->pid . $params['price'] . $params['type'] . $params['param'] . $this->key;
return md5($str);
}
public function verifyNotify(array $params)
{
if ($this->type === 'codepay') {
$calc = md5($this->pid . ($params['price'] ?? '') . ($params['type'] ?? '') . ($params['param'] ?? '') . $this->key);
return hash_equals($calc, (string) ($params['sign'] ?? ''));
}
$data = $params;
unset($data['sign'], $data['sign_type']);
ksort($data);
$str = '';
foreach ($data as $k => $v) {
$str .= $k . '=' . $v . '&';
}
$str = rtrim($str, '&') . $this->key;
return hash_equals(md5($str), (string) ($params['sign'] ?? ''));
}
public function getTradeNo(array $params)
{
return $params['trade_no'] ?? ($params['pay_no'] ?? ($params['param'] ?? ''));
}
public function isPaid(array $params)
{
if ($this->type === 'codepay') {
return ($params['trade_status'] ?? '') === 'TRADE_SUCCESS'
|| ($params['status'] ?? '') === '1'
|| isset($params['pay_no']);
}
return ($params['trade_status'] ?? '') === 'TRADE_SUCCESS'
|| ($params['status'] ?? '') === 'success';
}
public function respondSuccess()
{
echo $this->type === 'epay' ? 'success' : 'ok';
exit;
}
private function post($url, $params)
{
$this->lastHttpCode = 0;
$this->lastRaw = '';
$this->lastError = '';
$body = http_build_query($params);
if (function_exists('curl_init')) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
CURLOPT_CONNECTTIMEOUT => 15,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
]);
$r = curl_exec($ch);
$this->lastHttpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($r === false) {
$this->lastError = curl_error($ch);
$r = '';
}
curl_close($ch);
$this->lastRaw = (string) $r;
return (string) $r;
}
$ctx = stream_context_create(['http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => $body,
'timeout' => 20,
'follow_location' => true,
'max_redirects' => 3,
]]);
$r = @file_get_contents($url, false, $ctx);
if ($r === false) {
$this->lastError = 'file_get_contents failed';
$r = '';
}
$this->lastRaw = (string) $r;
return (string) $r;
}
public function getLastHttpCode() { return $this->lastHttpCode; }
public function getLastRaw() { return $this->lastRaw; }
public function getLastError() { return $this->lastError; }
}