本文详细介绍了如何通过 PayPal 完成 Checkout 收银台支付 和 Subscription 订阅计划。我们将分步骤分析流程并提供代码实现,帮助开发者顺利集成 PayPal 支付功能。
以下是支付过程的详细拆解流程,类似于支付宝的收银台:
本地应用组装好参数并请求 Checkout 接口,接口同步返回一个支付 URL。
本地应用重定向至该 URL,用户登录 PayPal 账户并确认支付。支付后,用户跳转至设置好的本地应用地址。
本地请求 PayPal 执行付款接口发起扣款。
PayPal 发送异步通知至本地应用,本地应用进行验签操作。
验签成功后,执行支付完成后的业务逻辑,如修改订单状态、增加销量、发送邮件等。
订阅支付的流程如下:
创建一个 订阅计划。
激活该计划。
使用已激活的计划去创建订阅申请。
跳转至订阅申请链接获取用户授权并完成首期付款,支付后携带 token 跳转至本地应用地址。
回跳后请求执行订阅。
接收到订阅授权的异步回调后,验证支付成功并执行支付完成后的业务。
$ composer require paypal/rest-api-sdk-php:* // 使用最新版本
$ touch config/paypal.php
配置内容如下:
<?php
return [
'sandbox' => [
'client_id' => env('PAYPAL_SANDBOX_CLIENT_ID', ''),
'secret' => env('PAYPAL_SANDBOX_SECRET', ''),
'notify_web_hook_id' => env('PAYPAL_SANDBOX_NOTIFY_WEB_HOOK_ID', ''),
'checkout_notify_web_hook_id' => env('PAYPAL_SANDBOX_CHECKOUT_NOTIFY_WEB_HOOK_ID', ''),
],
'live' => [
'client_id' => env('PAYPAL_CLIENT_ID', ''),
'secret' => env('PAYPAL_SECRET', ''),
'notify_web_hook_id' => env('PAYPAL_NOTIFY_WEB_HOOK_ID', ''),
'checkout_notify_web_hook_id' => env('PAYPAL_CHECKOUT_NOTIFY_WEB_HOOK_ID', ''),
],
];
$ mkdir -p app/Services && touch app/Services/PayPalService.php
<?php
namespace App\Services;
use PayPal\Api\Payment;
use PayPal\Api\PaymentExecution;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Api\Amount;
use PayPal\Api\ItemList;
use PayPal\Api\Item;
use PayPal\Api\Payer;
class PayPalService
{
public function checkout(Order $order)
{
try {
$payer = new Payer();
$payer->setPaymentMethod('paypal');
$item = new Item();
$item->setName($order->product->title)
->setDescription($order->no)
->setCurrency($order->product->currency)
->setQuantity(1)
->setPrice($order->total_amount);
$itemList = new ItemList();
$itemList->setItems([$item]);
$amount = new Amount();
$amount->setCurrency($order->product->currency)
->setTotal($order->total_amount);
$transaction = new Transaction();
$transaction->setAmount($amount)
->setItemList($itemList)
->setDescription($order->no);
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl(route('payment.paypal.return', ['success' => 'true', 'no' => $order->no]))
->setCancelUrl(route('payment.paypal.return', ['success' => 'false', 'no' => $order->no]));
$payment = new Payment();
$payment->setIntent('sale')
->setPayer($payer)
->setRedirectUrls($redirectUrls)
->setTransactions([$transaction]);
$payment->create($this->apiContext);
return $payment->getApprovalLink();
} catch (\Exception $e) {
return null;
}
}
}
$ php artisan make:controller PaymentsController
<?php
namespace App\Http\Controllers;
use App\Models\Order;
class PaymentController extends Controller
{
public function payByPayPalCheckout(Order $order)
{
$approvalUrl = app('paypal')->checkout($order);
if (!$approvalUrl) {
return json_encode(['code' => 500, 'msg' => 'Interval Error.', 'url' => '']);
}
return json_encode(['code' => 201, 'msg' => 'success.', 'url' => $approvalUrl]);
}
}
<?php
namespace App\Services;
use PayPal\Api\Plan;
use PayPal\Api\PaymentDefinition;
use PayPal\Api\ChargeModel;
use PayPal\Api\MerchantPreferences;
class PayPalService
{
public function createPlan(Order $order)
{
$plan = new Plan();
$plan->setName($order->no)
->setDescription($order->product->title)
->setType('INFINITE'); // 可选(FIXED | INFINITE)
$paymentDefinition = new PaymentDefinition();
$paymentDefinition->setAmount(new Currency([
'value' => $order->product->price,
'currency' => $order->product->currency
]));
$merchantPreferences = new MerchantPreferences();
$merchantPreferences->setReturnUrl(route('subscriptions.paypal.return', ['success' => 'true', 'no' => $order->no]))
->setCancelUrl(route('subscriptions.paypal.return', ['success' => 'false', 'no' => $order->no]))
->setAutoBillAmount("yes");
$plan->setPaymentDefinitions([$paymentDefinition]);
$plan->setMerchantPreferences($merchantPreferences);
$output = $plan->create($this->apiContext);
$patch = new Patch();
$patch->setOp('replace')
->setPath('/')
->setValue(new PayPalModel('{"state":"ACTIVE"}'));
$patchRequest = new PatchRequest();
$patchRequest->addPatch($patch);
$output->update($patchRequest, $this->apiContext);
return $output;
}
}
$ php artisan make:controller SubscriptionsController
<?php
namespace App\Http\Controllers;
use App\Models\Order;
class SubscriptionsController extends Controller
{
public function createPlan(Order $order)
{
$plan = app('paypal')->createPlan($order);
$approvalUrl = app('paypal')->createAgreement($plan, $order);
return json_encode(['code' => 201, 'msg' => 'success.', 'url' => $approvalUrl]);
}
}
如何处理 PayPal 异常回调?
在接收到 PayPal 的回调时,需验证回调的有效性。使用
verify方法来确认回调是否来自 PayPal。
如何配置 PayPal Webhook?
登录到 PayPal 开发者中心,添加
Webhook并选择相应的事件类型。
使用门槛极低,微信支付宝均可开通使用。支持开通各类海外平台:ChatGPT、Claude、Google Play、Apple Store、OpenAI、X、Patreon、MidJourney、Amazon、POE、Microsoft、Facebook、GitHub、Telegram、PayPal等各类海淘订阅平台。使用邀请码:ACCPAY,立享消费0手续费,减免开卡费用。
通过本文,您已经掌握了如何使用 PayPal 完成 Checkout 收银台支付 和 Subscription 订阅支付 的集成。根据您的需求,选择适合的支付方式,顺利实现 PayPal 集成。
