
本文旨在指导开发者从不安全的get请求方式过渡到paypal推荐的、基于服务器端api的php支付集成方案。我们将详细阐述如何通过“创建订单”和“捕获订单”两个核心步骤,结合paypal checkout-php-sdk和前端审批流程,构建一个安全、可靠且符合最佳实践的paypal支付系统,有效防止数据篡改并确保交易的完整性。
在构建电子商务平台时,安全、可靠的支付集成至关重要。本文将深入探讨如何在PHP环境中,从不安全的GET请求方式转向PayPal推荐的服务器端API集成方案,确保支付流程的安全性与交易的完整性。
早期或简化的PayPal支付集成可能采用GET请求方式,通过构建URL查询字符串将订单信息直接传递给PayPal。例如:
<?php
public function checkoutGetMethod()
{
$query = [];
$query['cmd'] = '_cart';
$query['upload'] = 1;
$query['business'] = $this->getCredential(); // 商家PayPal邮箱
// 遍历商品信息
foreach ($this->getItems() as $id => $item) {
$id_index = $id + 1;
$query['item_name_' . $id_index] = $item['name'];
$query['amount_' . $id_index] = $item['amount'];
$query['quantity_' . $id_index] = $item['quantity'];
}
$query['custom'] = $this->getReference(); // 自定义参考ID
// ... 其他参数如客户信息、回调URL等
$query_string = http_build_query($query);
// 返回构建的PayPal支付URL
return "https://". ($this->isSandbox() ? 'sandbox' : 'www' ) .".paypal.com/cgi-bin/webscr?".$query_string;
}这种方法虽然实现简单,但存在严重的安全隐患:
为了解决上述安全问题,PayPal推荐采用基于服务器端API的集成方案。这种方案的核心在于将敏感的订单创建和支付捕获逻辑置于服务器端,并通过API进行安全通信。整个流程通常分为以下两个主要步骤:
立即学习“PHP免费学习笔记(深入)”;
此步骤在您的服务器端完成,负责向PayPal API提交订单的详细信息,例如购买单位、金额、商品列表、应用上下文(如回调URL)。PayPal会返回一个唯一的订单ID。
在用户在PayPal页面完成授权后,您的前端会收到一个授权令牌。此时,前端将此令牌发送回您的服务器端,服务器端再调用PayPal API执行“捕获订单”操作,实际完成资金的转移。
PayPal官方推荐使用其Checkout-PHP-SDK来简化API交互。以下是实现“创建订单”和“捕获订单”的服务器端PHP代码示例(概念性,具体实现需参考SDK文档):
首先,通过Composer安装PayPal Checkout-PHP-SDK:
composer require paypal/rest-api-sdk-php
在您的PHP应用中创建一个API端点(例如 /api/paypal/create-order),用于处理前端发起的订单创建请求。此路由应只返回JSON数据。
<?php
use PayPal\Rest\ApiContext;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Api\Amount;
use PayPal\Api\Details;
use PayPal\Api\Item;
use PayPal\Api\ItemList;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Api\Order; // For v2 API, use Order object
// 假设您已经配置了API上下文
// $apiContext = new ApiContext(
// new OAuthTokenCredential(
// 'YOUR_CLIENT_ID', // 您的PayPal应用客户端ID
// 'YOUR_CLIENT_SECRET' // 您的PayPal应用客户端密钥
// )
// );
// $apiContext->setConfig(['mode' => 'sandbox']); // 或 'live'
public function createPayPalOrder($items, $returnUrl, $cancelUrl, $notificationUrl, $apiContext)
{
// 使用PayPal v2 Orders API
// 这是一个概念性示例,实际使用时请参考PayPal PHP SDK v2 文档
// 通常会使用 PayPal\Checkout\Orders\Order 或相关对象
$purchaseUnits = [];
foreach ($items as $itemData) {
$purchaseUnit = [
'amount' => [
'currency_code' => 'USD', // 或您的货币代码
'value' => (string)($itemData['amount'] * $itemData['quantity']),
'breakdown' => [
'item_total' => [
'currency_code' => 'USD',
'value' => (string)($itemData['amount'] * $itemData['quantity'])
]
]
],
'items' => [[
'name' => $itemData['name'],
'unit_amount' => [
'currency_code' => 'USD',
'value' => (string)$itemData['amount']
],
'quantity' => (string)$itemData['quantity']
]]
];
$purchaseUnits[] = $purchaseUnit;
}
$orderData = [
'intent' => 'CAPTURE',
'purchase_units' => $purchaseUnits,
'application_context' => [
'return_url' => $returnUrl,
'cancel_url' => $cancelUrl,
'brand_name' => '您的商店名称',
'locale' => 'en-US', // 或 'zh-CN'
'shipping_preference' => 'NO_SHIPPING', // 如果不需要收货地址
'user_action' => 'PAY_NOW' // 或 'CONTINUE'
]
];
try {
// 实际调用SDK创建订单,此处为伪代码
// $order = Order::create($orderData, $apiContext);
// 假设通过cURL直接调用v2 API
$ch = curl_init('https://api-m.paypal.com/v2/checkout/orders');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->getAccessToken(), // 获取访问令牌的方法
'Prefer: return=representation'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($orderData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
if (isset($response['id'])) {
// 订单创建成功,返回订单ID和审批链接
$approvalLink = '';
foreach ($response['links'] as $link) {
if ($link['rel'] === 'approve') {
$approvalLink = $link['href'];
break;
}
}
return ['status' => 'success', 'order_id' => $response['id'], 'approval_link' => $approvalLink];
} else {
// 处理错误
return ['status' => 'error', 'message' => $response['message'] ?? 'Failed to create order'];
}
} catch (\Exception $ex) {
// 记录错误
return ['status' => 'error', 'message' => $ex->getMessage()];
}
}此函数将返回PayPal生成的订单ID和用户需要跳转的审批URL。
当用户在PayPal页面完成授权并返回您的网站时,前端会携带orderID(以及可能的payerID和token)。您的服务器端需要创建另一个API端点(例如 /api/paypal/capture-order)来完成支付捕获。
<?php
// ... 引入PayPal SDK相关类
public function capturePayPalOrder($orderId, $apiContext)
{
try {
// 实际调用SDK捕获订单,此处为伪代码
// $order = Order::get($orderId, $apiContext);
// $captureResult = $order->capture($apiContext);
// 假设通过cURL直接调用v2 API
$ch = curl_init('https://api-m.paypal.com/v2/checkout/orders/' . $orderId . '/capture');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->getAccessToken(), // 获取访问令牌的方法
'Prefer: return=representation'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{}'); // 捕获请求通常是空的POST体
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
if (isset($response['status']) && $response['status'] === 'COMPLETED') {
// 支付成功
$transactionId = $response['purchase_units'][0]['payments']['captures'][0]['id'];
// 1. 将PayPal交易ID (transactionId) 和其他支付详情存储到您的数据库
// 例如:$this->savePaymentDetails($orderId, $transactionId, $response);
// 2. 执行业务逻辑 (例如:发送订单确认邮件、更新库存、标记订单为已支付)
// 例如:$this->processOrderCompletion($orderId, $transactionId);
return ['status' => 'success', 'message' => 'Payment captured successfully', 'transaction_id' => $transactionId];
} else {
// 支付失败或未完成
return ['status' => 'error', 'message' => $response['message'] ?? 'Payment capture failed'];
}
} catch (\Exception $ex) {
// 记录错误
return ['status' => 'error', 'message' => $ex->getMessage()];
}
}注意事项:
服务器端API准备就绪后,前端需要使用PayPal JavaScript SDK来引导用户完成支付审批流程。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PayPal Checkout</title>
<!-- 引入 PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_PAYPAL_CLIENT_ID¤cy=USD"></script>
</head>
<body>
<h1>商品结账</h1>
<div id="paypal-button-container"></div>
<script>
paypal.Buttons({
// 创建订单
createOrder: function(data, actions) {
return fetch('/api/paypal/create-order', { // 调用您的服务器端创建订单API
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
items: [ // 示例商品数据
{ name: '商品A', amount: 10.00, quantity: 1 },
{ name: '商品B', amount: 5.00, quantity: 2 }
]
// 更多订单详情
})
}).then(function(res) {
return res.json();
}).then(function(orderData) {
if (orderData.status === 'success') {
return orderData.order_id; // 返回PayPal订单ID
} else {
// 处理服务器端创建订单失败的情况
console.error('Failed to create order:', orderData.message);
alert('订单创建失败,请重试。');
return null; // 阻止PayPal按钮继续
}
});
},
// 订单审批并捕获
onApprove: function(data, actions) {
return fetch('/api/paypal/capture-order', { // 调用您的服务器端捕获订单API
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
orderID: data.orderID // PayPal返回的订单ID
})
}).then(function(res) {
return res.json();
}).then(function(captureData) {
if (captureData.status === 'success') {
alert('支付成功!交易ID: ' + captureData.transaction_id);
// 跳转到成功页面或更新UI
window.location.href = '/order-success?transaction_id=' + captureData.transaction_id;
} else {
alert('支付失败:' + captureData.message);
// 处理支付失败情况
}
});
},
// 取消支付
onCancel: function(data) {
console.log('Payment cancelled', data);
alert('支付已取消。');
},
// 错误处理
onError: function(err) {
console.error('An error occurred during checkout', err);
alert('支付过程中发生错误,请稍后再试。');
}
}).render('#paypal-button-container'); // 渲染PayPal按钮
</script>
</body>
</html>通过从传统的GET请求方式转向PayPal推荐的服务器端API集成,您不仅能够显著提升支付流程的安全性,防止恶意篡改,还能更好地控制交易生命周期,并集成更复杂的业务逻辑。采用PayPal Checkout-PHP-SDK结合前端JavaScript SDK,是构建一个健壮、安全且符合PayPal最佳实践的支付系统的关键。务必遵循“创建订单”和“捕获订单”的两步流程,并妥善处理数据库存储、业务逻辑和错误处理,以确保无缝的用户体验和可靠的交易处理。
以上就是使用PHP安全集成PayPal支付:从GET到API驱动的解决方案的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号