PHP项目支付回调与验签完整指南
基础架构设计
<?php
// 支付回调处理类
class PaymentCallbackHandler {
private $config;
public function __construct($config) {
$this->config = $config;
}
/**
* 统一入口处理回调
*/
public function handle($gateway) {
try {
// 1. 获取原始数据
$rawData = $this->getRawData();
// 2. 格式转换
$data = $this->parseData($rawData);
// 3. 验签
if (!$this->verifySignature($data)) {
throw new \Exception('签名验证失败');
}
// 4. 检查订单状态
$order = $this->checkOrder($data);
// 5. 处理业务逻辑
return $this->processOrder($order, $data);
} catch (\Exception $e) {
$this->logError($e->getMessage());
return $this->failureResponse();
}
}
/**
* 获取原始请求数据
*/
private function getRawData() {
return file_get_contents('php://input');
}
/**
* 解析不同格式的数据
*/
private function parseData($rawData) {
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
if (strpos($contentType, 'application/json') !== false) {
return json_decode($rawData, true);
} elseif (strpos($contentType, 'application/xml') !== false) {
return $this->xmlToArray($rawData);
} else {
// 表单格式
parse_str($rawData, $data);
return $data;
}
}
/**
* XML转数组
*/
private function xmlToArray($xml) {
$xmlObj = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
return json_decode(json_encode($xmlObj), true);
}
/**
* 记录日志
*/
private function logError($message) {
error_log(date('Y-m-d H:i:s') . ' - 回调错误: ' . $message . PHP_EOL, 3,
__DIR__ . '/logs/payment_callback.log');
}
/**
* 成功响应
*/
protected function successResponse() {
return json_encode(['code' => 'SUCCESS', 'message' => '处理成功']);
}
/**
* 失败响应
*/
protected function failureResponse($message = 'FAIL') {
return json_encode(['code' => 'FAIL', 'message' => $message]);
}
}
?>
各大支付平台验签实现
1 微信支付验签
<?php
class WechatPayHandler extends PaymentCallbackHandler {
/**
* 微信支付验签
*/
protected function verifySignature($data) {
$sign = $data['sign'] ?? '';
unset($data['sign']);
// 按字典序排序
ksort($data);
// 生成签名串
$stringA = '';
foreach ($data as $key => $value) {
if ($value !== '' && !is_null($value) && $key !== 'sign') {
$stringA .= $key . '=' . $value . '&';
}
}
$stringSignTemp = $stringA . 'key=' . $this->config['api_key'];
$signature = strtoupper(md5($stringSignTemp));
return $signature === $sign;
}
/**
* 处理微信回调逻辑
*/
protected function processOrder($order, $data) {
// 微信回调业务逻辑
return $this->successResponse();
}
}
?>
2 支付宝验签
<?php
class AlipayHandler extends PaymentCallbackHandler {
/**
* 支付宝RSA2验签
*/
protected function verifySignature($data) {
$sign = $data['sign'];
unset($data['sign']);
unset($data['sign_type']);
// 生成待签名字符串
$content = $this->buildSignContent($data);
// 验证签名
$publicKey = openssl_pkey_get_public($this->config['public_key']);
$result = openssl_verify(
$content,
base64_decode($sign),
$publicKey,
OPENSSL_ALGO_SHA256
);
return $result === 1;
}
/**
* 构造签名字符串
*/
private function buildSignContent($data) {
ksort($data);
$content = '';
foreach ($data as $key => $value) {
if ($value !== '' && !is_null($value) && $value !== 'null') {
$content .= $key . '=' . $value . '&';
}
}
return rtrim($content, '&');
}
}
?>
3 Stripe Webhook验签
<?php
class StripeHandler extends PaymentCallbackHandler {
/**
* Stripe验签
*/
public function handle($gateway = 'stripe') {
$payload = $this->getRawData();
$sigHeader = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? '';
try {
$event = \Stripe\Webhook::constructEvent(
$payload,
$sigHeader,
$this->config['webhook_secret']
);
return $this->processStripeEvent($event);
} catch (\UnexpectedValueException $e) {
// 无效的payload
return $this->failureResponse('Invalid payload');
} catch (\Stripe\Exception\SignatureVerificationException $e) {
// 签名验证失败
return $this->failureResponse('Invalid signature');
}
}
private function processStripeEvent($event) {
// 处理不同类型的Stripe事件
switch ($event->type) {
case 'payment_intent.succeeded':
// 支付成功
return $this->successResponse();
case 'payment_intent.payment_failed':
// 支付失败
return $this->failureResponse('Payment failed');
default:
return $this->successResponse();
}
}
}
?>
完整的业务实现示例
<?php
// 支付回调控制器
class PaymentController {
/**
* 处理支付回调
*/
public function callback($gateway, $orderNo) {
// 验证请求IP(可选)
$this->checkIP();
// 初始化回调处理
$handler = $this->createHandler($gateway);
$result = $handler->handle();
// 设置响应格式
header('Content-Type: application/json');
echo $result;
}
/**
* 创建处理器
*/
private function createHandler($gateway) {
switch ($gateway) {
case 'wechat':
return new WechatPayHandler($this->getConfig('wechat'));
case 'alipay':
return new AlipayHandler($this->getConfig('alipay'));
case 'stripe':
return new StripeHandler($this->getConfig('stripe'));
default:
throw new \Exception("Unsupported gateway: {$gateway}");
}
}
/**
* 检查IP有效性
*/
private function checkIP() {
// 实现IP白名单验证
}
/**
* 获取配置
*/
private function getConfig($gateway) {
// 从配置文件获取支付网关配置
return require APP_PATH . "/config/{$gateway}.php";
}
}
?>
安全最佳实践
<?php
class PaymentSecurity {
/**
* 回调处理安全防护
*/
public static function secureCallback() {
// 1. HTTPS强制
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
throw new \Exception('必须使用HTTPS');
}
// 2. 时间限制(防止重放攻击)
self::checkTimestamp();
// 3. 订单幂等性处理
self::checkIdempotent();
// 4. 日志记录
self::logCallback();
}
/**
* 检查时间戳
*/
private static function checkTimestamp() {
$timestamp = $_POST['timestamp'] ?? time();
if (abs(time() - $timestamp) > 300) { // 5分钟有效
throw new \Exception('请求过期');
}
}
/**
* 幂等性检查
*/
private static function checkIdempotent() {
// 使用Redis或数据库做锁
$lockKey = "payment_callback:" . $_POST['order_id'];
if (!RedisCache::getLock($lockKey, 60)) {
throw new \Exception('重复请求');
}
}
/**
* 记录回调日志
*/
private static function logCallback() {
$logData = [
'ip' => $_SERVER['REMOTE_ADDR'],
'data' => $_POST,
'time' => date('Y-m-d H:i:s')
];
// 写入日志
file_put_contents(
LOG_PATH . '/callback_' . date('Ymd') . '.log',
json_encode($logData) . PHP_EOL,
FILE_APPEND
);
}
}
?>
响应格式示例
<?php
// 成功响应
$successResponse = [
'code' => 'SUCCESS',
'message' => '处理成功',
'timestamp' => time()
];
// 异步处理响应
$asyncResponse = [
'code' => 'PENDING',
'message' => '异步处理中'
];
// 失败响应
$failResponse = [
'code' => 'FAIL',
'message' => '处理失败',
'error_code' => 'INVALID_SIGN'
];
?>
测试用例
<?php
class PaymentCallbackTest extends PHPUnit\Framework\TestCase {
/**
* 测试微信验签
*/
public function testWechatSignature() {
$config = [
'api_key' => 'your_api_key'
];
$handler = new WechatPayHandler($config);
// 构造测试数据
$data = [
'appid' => 'wx123',
'mch_id' => '123456',
'out_trade_no' => 'ORDER20240001',
'result_code' => 'SUCCESS'
];
// 计算签名
ksort($data);
$stringA = '';
foreach ($data as $key => $value) {
$stringA .= $key . '=' . $value . '&';
}
$data['sign'] = strtoupper(md5($stringA . 'key=' . $config['api_key']));
// 验证
$this->assertTrue($handler->verifySignature($data));
}
}
?>
这些示例涵盖了PHP支付回调的核心实现,包括:

- 基础架构 - 统一处理入口和异常处理
- 各大支付平台 - 微信、支付宝、Stripe的具体实现
- 安全防护 - IP验证、重放攻击防护、幂等性
- 最佳实践 - 日志记录、错误处理、测试
根据实际业务需求,你可能需要调整具体的配置和业务逻辑,记得在生产环境中使用正式密钥并做好安全防护。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播