本文目录导读:

在PHP中对接支付SDK(如支付宝、微信支付、PayPal等)的流程大同小异,核心步骤主要分为申请商户号、下载SDK、配置参数、发起支付和接收回调。
以下是通用的对接方法论,并附上针对国内主流支付(支付宝/微信)的具体代码示例和避坑指南。
第一步:前期准备(非常重要)
- 申请商户账号:去支付宝开放平台或微信支付商户平台注册。
- 获取密钥:
- 支付宝:获取 AppID、应用私钥、支付宝公钥,需要下载支付宝官方密钥工具生成 RSA2 密钥对。
- 微信支付:获取 AppID、商户号(MchID)、APIv3 密钥(APIv3 Key)、证书序列号(以及商户私钥)。
- 配置回调域名:在支付平台后台配置“支付回调(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 URL 或 prepay_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元 = 传入
00。 - 微信支付(分):1元 = 传入
100。微信支付如果传入小数会报错。
- 支付宝(元):1元 = 传入
- 回调必须返回特定字符串:
- 支付宝:必须输出
success或failure(注意是全小写)。 - 微信支付:必须返回
{"code":"SUCCESS", "message":"成功"}且 HTTP 状态码必须是 200,如果返回非200或响应错误,微信会连续重试多次,可能会导致订单被重复处理。
- 支付宝:必须输出
- 验证金额与订单号:在回调中,务必拿支付平台返回的
amount和order_no与数据库中的记录进行比对,防止“订单金额篡改”攻击(即支付1分钱购买100元商品)。 - 订单状态幂等性:由于网络原因,同一个支付结果可能回调多次,在回调处理中,必须判断数据库订单状态如果已支付则直接返回 success,避免重复执行发放积分、发货等操作。
- 证书路径:在 PHP 中经常遇到“证书路径错误”,务必使用绝对路径(如
dirname(__FILE__) . '/cert/apiclient_key.pem'),避免相对路径在 CLI 和 Web 环境下不一致。
代码结构建议
如果你不想重复造轮子,强烈建议封装一个 PayInterface,内部定义 createOrder() 和 verifyNotify()。
interface PayInterface
{
public function createOrder($orderData); // 返回跳转链接或二维码
public function verifyNotify($requestParams); // 验签并处理业务
}
所有主流支付平台(支付宝、微信)都有非常完善的 PHP SDK 和调试工具(如支付宝沙箱环境)。建议先跑通沙箱测试,再切换到正式环境,遇到问题先检查“证书/密钥”是否正确配置。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播