PHP支付SDK怎么对接

wen PHP项目 2

本文目录导读:

PHP支付SDK怎么对接

  1. 第一步:前期准备(非常重要)
  2. 第二步:安装 SDK
  3. 第三步:后端发起支付请求(生成订单)
  4. 第四步:接收异步回调(核心步骤)
  5. 第五步:常见问题与避坑指南
  6. 代码结构建议

在PHP中对接支付SDK(如支付宝、微信支付、PayPal等)的流程大同小异,核心步骤主要分为申请商户号、下载SDK、配置参数、发起支付和接收回调

以下是通用的对接方法论,并附上针对国内主流支付(支付宝/微信)的具体代码示例和避坑指南。


第一步:前期准备(非常重要)

  1. 申请商户账号:去支付宝开放平台或微信支付商户平台注册。
  2. 获取密钥
    • 支付宝:获取 AppID、应用私钥、支付宝公钥,需要下载支付宝官方密钥工具生成 RSA2 密钥对。
    • 微信支付:获取 AppID、商户号(MchID)、APIv3 密钥(APIv3 Key)、证书序列号(以及商户私钥)。
  3. 配置回调域名:在支付平台后台配置“支付回调(Notify)”和“跳转(Return)”的公网 URL。

第二步:安装 SDK

建议使用官方 SDK,或基于官方 API 封装的 Composer 包。

支付宝(Ant)

composer require alipaysdk/easysdk
# 或老版本
composer require alipay/alipay-sdk-php

微信支付

composer require wechatpay/wechatpay
# 或基于官方API v3封装的常用包
composer require wechatpay/wechatpay-guzzle-middleware

第三步:后端发起支付请求(生成订单)

原理:后端将订单参数加密发送给支付平台,支付平台返回一个支付链接或表单,将其返回给前端。

示例 1:支付宝(电脑网站支付 / 手机网站支付)

此时后端需要生成一个 form 表单或直接返回字符串。

<?php
// 引入 SDK
use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Config;
class AlipayService 
{
    private $config;
    public function __construct() 
    {
        // 配置参数(建议从配置文件读取)
        $this->config = new Config();
        $this->config->protocol = 'https';
        $this->config->gatewayHost = 'openapi.alipay.com';
        $this->config->signType = 'RSA2';
        $this->config->appId = '你的APP_ID'; 
        $this->config->merchantPrivateKey = '你的私钥内容'; 
        $this->config->alipayPublicKey = '支付宝公钥内容'; 
        $this->config->notifyUrl = 'https://你的域名.com/payment/notify';
        $this->config->encryptKey = '';
    }
    public function pagePay($orderNo, $amount, $subject) 
    {
        Factory::setOptions($this->config);
        // 调用支付宝接口
        $result = Factory::payment()->pagePay()
            ->optional('total_amount', $amount)
            ->optional('subject', $subject)
            ->optional('out_trade_no', $orderNo)
            ->optional('product_code', 'FAST_INSTANT_TRADE_PAY')
            ->page('https://你的域名.com/payment/return'); // 同步跳转地址
        // $result->body 包含自动提交的 HTML 表单,直接输出到页面即可跳转
        return $result->body; 
    }
}
// 前端此时接收到的是一段可以自动提交的 HTML 表单
?>

示例 2:微信支付(Native 扫码支付 / JSAPI 公众号支付)

此时后端会返回一个 Code URLprepay_id

<?php
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;
class WechatPayService 
{
    private $appid;
    private $mchid;
    private $apiv3Key;
    private $merchantPrivateKeyFilePath;
    private $merchantCertificateSerial;
    public function __construct() 
    {
        // 必须使用绝对路径
        $this->appid = '你的APPID';
        $this->mchid = '你的商户号';
        $this->apiv3Key = 'APIv3密钥';
        // 加载商户私钥(apiclient_key.pem)
        $merchantPrivateKeyFilePath = '/path/to/apiclient_key.pem';
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        $merchantCertificateSerial = '证书序列号';
        $this->instance = Builder::factory([
            'mchid' => $this->mchid,
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => ['path/to/wechatpay_platform_cert.pem'], // 平台证书(用于验签和加密)
        ]);
    }
    public function nativePay($orderNo, $amount, $description) 
    {
        // amount 单位是“分”
        $resp = $this->instance->chain('/v3/pay/transactions/native')
            ->post(['json' => [
                'appid' => $this->appid,
                'mchid' => $this->mchid,
                'description' => $description,
                'out_trade_no' => $orderNo,
                'notify_url' => 'https://你的域名.com/payment/notify',
                'amount' => ['total' => $amount, 'currency' => 'CNY'],
            ]]);
        // 返回给前端,让前端生成二维码
        return $resp['code_url'];
    }
}

第四步:接收异步回调(核心步骤)

这是最容易出错的环节,支付成功后,支付平台会向你的 notify_url 发送一次 POST 通知,你需要验签(验证通知确实来自支付平台),然后修改订单状态,最后返回特定字符串

支付宝异步回调

<?php
use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Util\Signer;
public function notify() 
{
    // 1. 获取支付宝 POST 过来的数据
    // $postData = $_POST; // 注意需要去除空白字符等
    // 使用 SDK 验签(支付宝 SDK 通常有封装,或者直接使用内置的验签方法)
    $config = $this->config; // 复用上述配置
    Factory::setOptions($config);
    $result = Factory::payment()->common()->verifyNotify($_POST);
    if ($result === true) {
        // 2. 验签成功,业务处理
        // 商户订单号
        $outTradeNo = $_POST['out_trade_no'];
        // 支付宝交易号
        $tradeNo = $_POST['trade_no'];
        // 交易状态
        $tradeStatus = $_POST['trade_status'];
        // 订单金额(验签后,务必校验金额与数据库订单是否一致,防止篡改)
        $totalAmount = $_POST['total_amount'];
        if ($tradeStatus === 'TRADE_SUCCESS' || $tradeStatus === 'TRADE_FINISHED') {
            // 检查订单状态是否已支付,避免重复处理
            // 更新数据库状态为已支付
        }
        // 3. 响应支付宝:必须输出 "success"(不带引号),否则支付宝会不断重试
        return 'success';
    } else {
        // 验签失败
        return 'failure';
    }
}

微信支付异步回调

微信回调的数据是加密的,需要使用 APIv3 Key 解密。

<?php
public function notify(\Psr\Http\Message\RequestInterface $request) 
{
    // 1. 获取报文头信息
    $serialNo = $request->getHeader('Wechatpay-Serial')[0]; // 平台证书序列号
    $timestamp = $request->getHeader('Wechatpay-Timestamp')[0];
    $nonce = $request->getHeader('Wechatpay-Nonce')[0];
    $signature = $request->getHeader('Wechatpay-Signature')[0];
    // 2. 获取响应体
    $body = $request->getBody()->getContents();
    $data = json_decode($body, true);
    // 3. 解密资源字段($data['resource'])
    // 需要用到密钥 $data['resource']['ciphertext'] 和 $data['resource']['nonce'] 和 associated_data
    // 使用 SDK 库内置方法解密(假设使用官方中间件)
    // $decrypted = $this->instance->decryptApiV3($ciphertext, $nonce, $associatedData);
    // $transaction = json_decode($decrypted, true);
    // 4. 业务处理(与支付宝相同)
    // $outTradeNo = $transaction['out_trade_no'];
    // $transaction['trade_state'] === 'SUCCESS'
    // 5. 返回微信特定格式
    // 返回 HTTP 200 状态码,并返回以下 JSON
    return response()->json([
        'code' => 'SUCCESS',
        'message' => '成功'
    ], 200);
}

第五步:常见问题与避坑指南

  1. 金额单位陷阱
    • 支付宝(元):1元 = 传入 00
    • 微信支付(分):1元 = 传入 100微信支付如果传入小数会报错
  2. 回调必须返回特定字符串
    • 支付宝:必须输出 successfailure(注意是全小写)。
    • 微信支付:必须返回 {"code":"SUCCESS", "message":"成功"}HTTP 状态码必须是 200,如果返回非200或响应错误,微信会连续重试多次,可能会导致订单被重复处理。
  3. 验证金额与订单号:在回调中,务必拿支付平台返回的 amountorder_no 与数据库中的记录进行比对,防止“订单金额篡改”攻击(即支付1分钱购买100元商品)。
  4. 订单状态幂等性:由于网络原因,同一个支付结果可能回调多次,在回调处理中,必须判断数据库订单状态如果已支付则直接返回 success,避免重复执行发放积分、发货等操作。
  5. 证书路径:在 PHP 中经常遇到“证书路径错误”,务必使用绝对路径(如 dirname(__FILE__) . '/cert/apiclient_key.pem'),避免相对路径在 CLI 和 Web 环境下不一致。

代码结构建议

如果你不想重复造轮子,强烈建议封装一个 PayInterface,内部定义 createOrder()verifyNotify()

interface PayInterface 
{
    public function createOrder($orderData); // 返回跳转链接或二维码
    public function verifyNotify($requestParams); // 验签并处理业务
}

所有主流支付平台(支付宝、微信)都有非常完善的 PHP SDK 和调试工具(如支付宝沙箱环境)。建议先跑通沙箱测试,再切换到正式环境,遇到问题先检查“证书/密钥”是否正确配置。

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