PHP项目支付回调与验签

wen PHP项目 3

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支付回调的核心实现,包括:

PHP项目支付回调与验签

  1. 基础架构 - 统一处理入口和异常处理
  2. 各大支付平台 - 微信、支付宝、Stripe的具体实现
  3. 安全防护 - IP验证、重放攻击防护、幂等性
  4. 最佳实践 - 日志记录、错误处理、测试

根据实际业务需求,你可能需要调整具体的配置和业务逻辑,记得在生产环境中使用正式密钥并做好安全防护。

抱歉,评论功能暂时关闭!