
本教程旨在指导开发者如何安全、高效地集成 paypal 支付功能,避免使用不安全的 get 请求和不完整的 post 方法。文章将详细阐述 paypal 标准支付流程中服务器端“创建订单”和“捕获订单”的两个关键步骤,并结合官方 checkout-php-sdk 提供实现思路。通过将核心支付逻辑迁移至服务器,并与前端审批流程协同,确保交易数据的完整性与安全性,最终实现一个健壮的在线支付系统。
在构建在线支付系统时,安全性是首要考虑因素。传统的通过 GET 请求将所有交易参数暴露在 URL 中,或直接在客户端发起不完整的 POST 请求,都可能导致数据篡改、支付失败或安全漏洞。PayPal 官方推荐的集成方式是采用服务器端 API 调用结合前端审批流程,以确保交易的完整性和安全性。
原始问题中提供的第一个 PHP 代码片段通过 http_build_query 构建一个 GET 请求 URL,将所有订单信息(如商品名称、金额、收件人邮箱等)作为查询参数传递。这种方式存在严重的安全隐患:
第二个代码片段尝试使用 cURL 发起 POST 请求到 PayPal API v2,但仅创建了订单而未完成支付捕获。这导致用户在 PayPal 页面批准支付后,款项并未实际转移,订单状态仍处于未支付。
正确的 PayPal 集成策略应遵循其标准支付流程,将核心交易逻辑(订单创建和支付捕获)放在服务器端处理。
立即学习“PHP免费学习笔记(深入)”;
PayPal 标准支付要求在服务器端实现两个关键的 API 调用:
这两个步骤通过 PayPal 官方提供的 SDK(例如 PHP 的 Checkout-PHP-SDK)来实现,并与前端的 JavaScript SDK 协同工作。
首先,确保您的 PHP 环境已配置妥当,并安装 PayPal Checkout-PHP-SDK。 通过 Composer 进行安装:
composer require paypal/paypal-checkout-sdk
接着,您需要配置 PayPal API 凭据(Client ID 和 Client Secret)。这些凭据可以在您的 PayPal 开发者账户中获取,并根据环境(Sandbox 或 Live)进行切换。
// 示例:PayPalClient.php (用于获取客户端实例)
<?php
namespace App\Services;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment; // 或 LiveEnvironment
class PayPalClient
{
public static function client(): PayPalHttpClient
{
// 根据实际环境选择
$clientId = env('PAYPAL_CLIENT_ID');
$clientSecret = env('PAYPAL_CLIENT_SECRET');
$environment = new SandboxEnvironment($clientId, $clientSecret); // 生产环境使用 LiveEnvironment
return new PayPalHttpClient($environment);
}
}这个路由负责初始化一个 PayPal 订单,并将订单 ID 和批准链接返回给前端。前端将使用这些信息引导用户到 PayPal 完成审批。
功能要点:
示例代码:
// app/Http/Controllers/PayPalController.php (或您的支付控制器)
<?php
namespace App\Http\Controllers;
use App\Services\PayPalClient; // 假设您已定义 PayPalClient 服务
use Illuminate\Http\Request;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
class PayPalController extends Controller
{
public function createOrder(Request $request)
{
// 1. 从请求中获取订单数据 (例如:购物车商品、总金额等)
// 实际应用中,这些数据应从您的数据库或会话中获取,以防止客户端篡改
$items = [
// ... 您的商品列表 ...
[
'name' => '商品A',
'quantity' => '1',
'unit_amount' => [
'currency_code' => 'USD',
'value' => '10.00'
]
]
];
$totalAmount = '10.00'; // 根据商品计算总金额
$request = new OrdersCreateRequest();
$request->prefer('return=representation'); // 请求完整的响应体
$request->body = [
'intent' => 'CAPTURE', // 意图:直接捕获支付
'purchase_units' => [[
'amount' => [
'currency_code' => 'USD',
'value' => $totalAmount,
'breakdown' => [
'item_total' => [
'currency_code' => 'USD',
'value' => $totalAmount
]
]
],
'items' => $items,
]],
'application_context' => [
'return_url' => route('paypal.success'), // 支付成功后的回调URL
'cancel_url' => route('paypal.cancel'), // 支付取消后的回调URL
'brand_name' => '您的商店名称',
'shipping_preference' => 'NO_SHIPPING', // 如果不需要收货地址
'user_action' => 'PAY_NOW', // 用户在PayPal页面上看到“立即支付”按钮
]
];
try {
$client = PayPalClient::client(); // 获取 PayPal 客户端实例
$response = $client->execute($request);
// 返回订单ID和审批链接给前端
return response()->json([
'id' => $response->result->id,
'links' => $response->result->links
]);
} catch (\Exception $e) {
// 错误处理:记录日志、返回错误信息
return response()->json(['error' => $e->getMessage()], 500);
}
}
}这个路由在用户完成 PayPal 审批后被前端调用,用于实际执行资金捕获。这是支付流程中至关重要的一步,确保资金从买家账户转移到卖家账户。
功能要点:
示例代码:
// app/Http/Controllers/PayPalController.php (或您的支付控制器)
<?php
namespace App\Http\Controllers;
use App\Services\PayPalClient;
use Illuminate\Http\Request;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
class PayPalController extends Controller
{
public function captureOrder(Request $request, $orderId)
{
$request = new OrdersCaptureRequest($orderId);
$request->prefer('return=representation');
try {
$client = PayPalClient::client();
$response = $client->execute($request);
// 2. 支付成功,处理业务逻辑
if ($response->result->status === 'COMPLETED') {
$captureId = $response->result->purchase_units[0]->payments->captures[0]->id;
// 存储 $captureId 到数据库
// 例如:Order::where('paypal_order_id', $orderId)->update(['status' => 'paid', 'paypal_capture_id' => $captureId]);
// 更新订单状态
// 发送确认邮件
// 减少库存
// ...
return response()->json([
'status' => 'COMPLETED',
'capture_id' => $captureId,
'message' => '支付成功,订单已完成处理。'
]);
} else {
// 支付状态不是 COMPLETED,可能需要进一步处理(例如:PENDING, DENIED 等)
return response()->json([
'status' => $response->result->status,
'message' => '支付未完成或处于待处理状态。'
], 400);
}
} catch (\Exception $e) {
// 错误处理:记录日志,可能需要退款或记录失败信息
return response()->json(['error' => $e->getMessage()], 500);
}
}
}前端负责渲染 PayPal 支付按钮,并与上述两个服务器端路由进行交互。
主要步骤:
示例 HTML/JavaScript:
<!DOCTYPE html>
<html>
<head>
<title>PayPal Checkout</title>
</head>
<body>
<h1>商品结算</h1>
<div id="paypal-button-container"></div>
<!-- 引入 PayPal JavaScript SDK -->
<!-- 替换 YOUR_CLIENT_ID 为您的 PayPal 客户端 ID -->
<!-- `currency` 参数根据您的业务需求设置 -->
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_PAYPAL_CLIENT_ID¤cy=USD"></script>
<script>
paypal.Buttons({
// 设置创建订单的回调函数
createOrder: function(data, actions) {
// 调用您的服务器端 "创建订单" 路由
return fetch('/api/paypal/create-order', { // 替换为您的实际路由
method: 'post',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content') // 如果使用 Laravel
},
body: JSON.stringify({
// 可以在这里传递一些客户端数据,但核心订单详情应在服务器端生成
// 例如:'cartId': 'user_cart_id'
})
})
.then(function(response) {
if (!response.ok) {
throw new Error('Failed to create PayPal order');
}
return response.json();
})
.then(function(order) {
return order.id; // 返回 PayPal 订单 ID
})
.catch(function(error) {
console.error('Error creating PayPal order:', error);
alert('创建订单失败,请稍后再试。');
// 可以在这里显示更友好的错误消息给用户
});
},
// 设置订单批准后的回调函数
onApprove: function(data, actions) {
// 调用您的服务器端 "捕获订单" 路由
return fetch(`/api/paypal/capture-order/${data.orderID}`, { // 替换为您的实际路由
method: 'post',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content') // 如果使用 Laravel
}
})
.then(function(response) {
if (!response.ok) {
throw new Error('Failed to capture PayPal order');
}
return response.json();
})
.then(function(details) {
if (details.status === 'COMPLETED') {
alert('支付成功!交易ID: ' + details.capture_id);
// 重定向到成功页面或更新 UI
window.location.href = '/order-success?orderId=' + data.orderID;
} else {
alert('支付未完成或失败。状态: ' + details.status);
// 处理非完成状态
}
})
.catch(function(error) {
console.error('Error capturing PayPal order:', error);
alert('支付捕获失败,请联系客服。');
});
},
// 设置取消支付的回调函数
onCancel: function(data) {
console.log('Payment cancelled by user', data);
alert('支付已取消。');
// 重定向到取消页面或更新 UI
},
// 设置支付错误的回调函数
onError: function(err) {
console.error('Payment error', err);
alert('支付过程中发生错误,请稍后再试。');
// 重定向到错误页面或更新 UI
}
}).render('#paypal-button-container'); // 将按钮渲染到指定的容器
</script>
</body>
</html>通过遵循 PayPal 官方推荐的服务器端集成模式,即实现“创建订单”和“捕获订单”两个核心路由,并与 PayPal JavaScript SDK 协同,您可以构建一个既安全又用户友好的在线支付系统。这种方法将敏感的交易逻辑和数据处理保留在服务器端,有效规避了客户端请求可能带来的安全风险,并确保了支付流程的完整性和可靠性。务必利用官方 SDK 简化开发,并始终将安全性和数据完整性放在首位。
以上就是PHP PayPal 安全集成:实现基于服务器端的订单创建与捕获的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号