本文目录导读:

我来为你详细讲解支付宝支付在PHP中的完整流程。
支付流程概述
基本流程图
用户下单 → 生成订单 → 请求支付宝 → 支付宝处理 → 同步返回 → 异步通知 → 查询验证
环境准备
安装SDK
composer require alipay/alipay-sdk-php
配置文件
// config/alipay.php
return [
'app_id' => '你的应用ID',
'private_key' => '你的应用私钥',
'alipay_public_key' => '支付宝公钥',
'notify_url' => 'https://your-domain.com/pay/notify',
'return_url' => 'https://your-domain.com/pay/return',
'sign_type' => 'RSA2',
'gateway' => 'https://openapi.alipay.com/gateway.do',
'charset' => 'UTF-8'
];
完整实现代码
支付控制器类
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Config;
class AlipayController extends Controller
{
protected $alipayConfig;
public function __construct()
{
$this->alipayConfig = config('alipay');
$this->initAlipay();
}
/**
* 初始化支付宝
*/
private function initAlipay()
{
$config = new Config();
$config->protocol = 'https';
$config->gatewayHost = 'openapi.alipay.com';
$config->signType = $this->alipayConfig['sign_type'];
$config->appId = $this->alipayConfig['app_id'];
$config->merchantPrivateKey = $this->alipayConfig['private_key'];
$config->alipayPublicKey = $this->alipayConfig['alipay_public_key'];
Factory::setOptions($config);
}
/**
* 生成支付二维码(PC端)
*/
public function pagePay(Request $request)
{
$orderId = $request->input('order_id');
$amount = $request->input('amount');
$subject = $request->input('subject');
try {
// 创建支付请求
$result = Factory::payment()->page()->pay(
$subject, // 订单标题
$orderId, // 商户订单号
$amount, // 订单金额
$this->alipayConfig['notify_url'], // 异步通知地址
$this->alipayConfig['return_url'] // 同步跳转地址
);
// 跳转到支付宝页面
return redirect($result->body);
} catch (\Exception $e) {
return response()->json([
'code' => 500,
'message' => '创建支付失败: ' . $e->getMessage()
]);
}
}
/**
* APP支付
*/
public function appPay(Request $request)
{
$orderId = $request->input('order_id');
$amount = $request->input('amount');
$subject = $request->input('subject');
try {
// 创建APP支付
$result = Factory::payment()->app()->pay(
$subject,
$orderId,
$amount,
$this->alipayConfig['notify_url']
);
// 返回给客户端调用SDK拉起支付
return response()->json([
'code' => 0,
'data' => [
'order_str' => $result->body
],
'message' => 'success'
]);
} catch (\Exception $e) {
return response()->json([
'code' => 500,
'message' => '创建支付失败: ' . $e->getMessage()
]);
}
}
}
异步通知处理
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class AlipayNotifyController extends Controller
{
/**
* 支付宝异步通知
*/
public function notify(Request $request)
{
$params = $request->all();
// 日志记录,方便调试
Log::info('支付宝异步通知', $params);
// 验证签名和处理业务
$result = app('alipay')->verify($params);
if ($result) {
// 检查商户订单号
$orderId = $params['out_trade_no'];
$tradeNo = $params['trade_no'];
$tradeStatus = $params['trade_status'];
// 处理业务逻辑
$order = Order::where('order_no', $orderId)->first();
if ($order && $order->status == 'pending') {
if ($tradeStatus == 'TRADE_SUCCESS' || $tradeStatus == 'TRADE_FINISHED') {
// 验证金额
if (bccomp($order->amount, $params['total_amount'], 2) === 0) {
// 更新订单状态
$order->status = 'paid';
$order->transaction_id = $tradeNo;
$order->paid_at = now();
$order->save();
// 执行后续业务逻辑(如发货、增加会员等)
$this->afterPaymentSuccess($order);
}
}
}
// 只有返回"success"才表示处理成功
return 'success';
}
return 'fail';
}
/**
* 支付成功后的业务处理
*/
private function afterPaymentSuccess($order)
{
// 更新库存
// 发送邮件通知
// 生成发票等
// 示例:记录支付日志
PaymentLog::create([
'order_id' => $order->id,
'transaction_id' => $order->transaction_id,
'amount' => $order->amount,
'status' => 'success',
'paid_at' => now()
]);
}
}
同步返回处理
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AlipayReturnController extends Controller
{
/**
* 支付完成后的页面跳转
*/
public function return(Request $request)
{
$params = $request->all();
// 验证签名
$result = app('alipay')->verify($params);
if (!$result) {
return redirect('/order/fail')->with('error', '支付验证失败');
}
$orderId = $params['out_trade_no'];
$tradeStatus = $params['trade_status'];
// 获取订单信息
$order = Order::where('order_no', $orderId)->first();
// 查询订单状态
if ($tradeStatus == 'TRADE_SUCCESS') {
// 订单支付成功
return redirect('/order/success')->with([
'order_no' => $orderId,
'trade_no' => $params['trade_no']
]);
}
return redirect('/order/fail');
}
}
订单查询
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Alipay\EasySDK\Kernel\Factory;
class OrderQueryController extends Controller
{
/**
* 主动查询订单状态
*/
public function queryOrder(Request $request)
{
$orderId = $request->input('order_no');
try {
$result = Factory::payment()->common()->query($orderId);
if ($result->tradeStatus == 'TRADE_SUCCESS') {
// 支付成功,处理业务逻辑
return response()->json([
'code' => 0,
'data' => [
'order_no' => $result->outTradeNo,
'trade_no' => $result->tradeNo,
'total_amount' => $result->totalAmount,
'status' => 'success'
]
]);
}
return response()->json([
'code' => 1,
'message' => '订单未支付'
]);
} catch (\Exception $e) {
return response()->json([
'code' => 500,
'message' => '查询失败: ' . $e->getMessage()
]);
}
}
}
退款功能
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Alipay\EasySDK\Kernel\Factory;
class RefundController extends Controller
{
/**
* 发起退款
*/
public function refund(Request $request)
{
$orderId = $request->input('order_no');
$refundAmount = $request->input('refund_amount');
$refundReason = $request->input('refund_reason', '用户申请退款');
// 生成退款单号
$refundNo = 'REFUND_' . date('YmdHis') . rand(1000, 9999);
try {
$result = Factory::payment()->common()->refund(
$orderId, // 商户订单号
$refundNo, // 退款单号
$refundAmount, // 退款金额
$refundReason // 退款原因
);
// 更新退款信息
if ($result->code == '10000') {
RefundRecord::create([
'order_no' => $orderId,
'refund_no' => $refundNo,
'refund_amount' => $refundAmount,
'status' => 'success',
'refund_time' => now()
]);
return response()->json([
'code' => 0,
'message' => '退款成功',
'data' => [
'refund_no' => $refundNo
]
]);
}
} catch (\Exception $e) {
// 处理退款异常
Log::error('退款失败', [
'order_no' => $orderId,
'refund_no' => $refundNo,
'error' => $e->getMessage()
]);
return response()->json([
'code' => 500,
'message' => '退款失败: ' . $e->getMessage()
]);
}
}
}
前台订单控制器
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class OrderController extends Controller
{
/**
* 下单并支付
*/
public function createAndPay(Request $request)
{
$validator = Validator::make($request->all(), [
'product_id' => 'required|exists:products,id',
'quantity' => 'required|integer|min:1'
]);
if ($validator->fails()) {
return response()->json([
'code' => 400,
'message' => $validator->errors()->first()
]);
}
// 创建订单
$product = Product::find($request->product_id);
$order = Order::create([
'order_no' => 'ORDER_' . date('YmdHis') . rand(1000, 9999),
'product_id' => $product->id,
'quantity' => $request->quantity,
'amount' => $product->price * $request->quantity,
'status' => 'pending',
'created_at' => now()
]);
// 调用支付宝支付
$payController = new AlipayController();
// 如果是PC端
return app(AlipayController::class)->pagePay(new Request([
'order_id' => $order->order_no,
'amount' => $order->amount,
'subject' => $product->name
]));
}
}
路由配置
// routes/web.php
Route::post('/pay/alipay/page', 'AlipayController@pagePay')->name('pay.alipay.page');
Route::post('/pay/alipay/app', 'AlipayController@appPay')->name('pay.alipay.app');
Route::post('/pay/alipay/notify', 'AlipayNotifyController@notify')->name('pay.alipay.notify');
Route::get('/pay/alipay/return', 'AlipayReturnController@return')->name('pay.alipay.return');
Route::post('/order/query', 'OrderQueryController@queryOrder')->name('order.query');
Route::post('/order/refund', 'RefundController@refund')->name('order.refund');
// routes/api.php (APP使用)
Route::post('/pay/alipay/app-pay', 'AlipayController@appPay');
安全注意事项
签名验证
/**
* 安全验证
*/
private function verifyPay($params)
{
try {
// 验证签名
$result = app('alipay')->verify($params);
if (!$result) {
Log::warning('支付宝验证失败', $params);
return false;
}
// 检查应用ID是否匹配
if ($params['app_id'] != config('alipay.app_id')) {
Log::error('应用ID不匹配');
return false;
}
// 检查商户订单号是否存在
$order = Order::where('order_no', $params['out_trade_no'])->first();
if (!$order) {
Log::error('订单不存在: ' . $params['out_trade_no']);
return false;
}
// 检查金额是否一致
if (bccomp($order->amount, $params['total_amount'], 2) !== 0) {
Log::error('金额不匹配', [
'order_amount' => $order->amount,
'paid_amount' => $params['total_amount']
]);
return false;
}
// 检查是否处理过该订单
if ($order->status == 'paid') {
Log::info('订单已处理');
return ['status' => 'processed'];
}
return [
'status' => 'valid',
'order' => $order,
'params' => $params
];
} catch (\Exception $e) {
Log::error('支付验证异常: ' . $e->getMessage());
return false;
}
}
防护措施
/**
* 防止重复通知
*/
private function preventDuplicateNotification($orderId)
{
// 使用缓存或数据库唯一索引
$key = 'payment_notify_' . $orderId;
if (Cache::has($key)) {
return false; // 已处理过
}
// 设置短期缓存
Cache::put($key, true, 600); // 10分钟有效
return true;
}
数据库表结构
-- 订单表
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(64) NOT NULL UNIQUE,
product_id INT NOT NULL,
quantity INT NOT NULL,
amount DECIMAL(10,2) NOT NULL,
status ENUM('pending', 'paid', 'refunded') DEFAULT 'pending',
transaction_id VARCHAR(64),
paid_at DATETIME,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_order_status (status)
);
-- 支付日志表
CREATE TABLE payment_logs (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
transaction_id VARCHAR(64),
amount DECIMAL(10,2),
status VARCHAR(32),
raw_notify_data TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
测试环境配置
// 沙箱环境 $config->gatewayHost = 'openapi.alipaydev.com'; // 测试账号 // 商户APPID: 9021000122xxxxxx // 商户私钥: MIIEvQIBADANB... // 支付宝公钥: MIIBIjANBgkqh...
常见问题处理
签名验证失败
// 检查密钥格式
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
chunk_split($config['private_key'], 64, "\n") .
"-----END RSA PRIVATE KEY-----";
金额精度
// 使用高精度计算 $amount = number_format($amount, 2, '.', '');
通知处理超时
// 设置较短的超时时间,快速响应支付宝
set_time_limit(30);
// 先返回成功,异步处理业务
return response()->json([
'code' => 0,
'message' => 'success'
]);
最佳实践
- 测试环境使用沙箱:开发阶段使用支付宝沙箱环境
- 完善日志:记录所有支付相关请求和响应
- 异步处理:通知处理尽量异步化
- 幂等性:确保同一订单不会重复处理
- 金额验证:严格验证支付金额与订单金额一致
- 事务处理:订单状态更新使用数据库事务
这个流程涵盖了从发起支付到异步通知的完整过程,建议在开发时先在沙箱环境测试完整流程,确认无误后再切换到生产环境。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播