You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 8集成PayPal支付的服务端SDK使用及交易校验问题咨询

Laravel 8 集成 PayPal 服务端实现方案

整体逻辑

将原来客户端侧的订单创建、金额配置、订单捕获逻辑全部迁移到服务端处理,前端仅负责触发流程和接收最终结果,从根源避免客户端篡改价格、伪造支付成功状态的问题。

第一步:服务端依赖安装与配置

  • 安装PayPal官方服务端SDK
composer require paypal/paypal-checkout-sdk 1.*
  • 在.env文件中添加PayPal配置参数
PAYPAL_CLIENT_ID=你的PayPal客户端ID
PAYPAL_CLIENT_SECRET=你的PayPal客户端密钥
PAYPAL_MODE=sandbox # 生产环境改为live
  • 新建PayPal服务类 app/Services/PayPalService.php 统一处理请求初始化
<?php

namespace App\Services;

use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Core\ProductionEnvironment;

class PayPalService
{
    public $client;

    public function __construct()
    {
        $environment = config('app.paypal_mode') === 'sandbox' 
            ? new SandboxEnvironment(config('app.paypal_client_id'), config('app.paypal_client_secret'))
            : new ProductionEnvironment(config('app.paypal_client_id'), config('app.paypal_client_secret'));
        $this->client = new PayPalHttpClient($environment);
    }
}
  • 在config/app.php中添加配置读取项
'paypal_client_id' => env('PAYPAL_CLIENT_ID'),
'paypal_client_secret' => env('PAYPAL_CLIENT_SECRET'),
'paypal_mode' => env('PAYPAL_MODE'),

第二步:新增服务端接口

2.1 创建订单接口

  • 新增路由 routes/api.php
Route::post('/paypal/create-order', [PayPalController::class, 'createOrder']);
  • 新建控制器 app/Http/Controllers/PayPalController.php 实现创建逻辑
    注意:套餐ID可以从当前登录用户的订阅信息或者请求参数中读取,价格、商品名绝对不能从前端传递,必须从数据库查询
<?php

namespace App\Http\Controllers;

use App\Services\PayPalService;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use Illuminate\Support\Facades\Auth;

class PayPalController extends Controller
{
    protected $paypal;

    public function __construct(PayPalService $paypal)
    {
        $this->paypal = $paypal;
        // 可选:做登录校验
        $this->middleware('auth');
    }

    public function createOrder()
    {
        // 从数据库查询当前用户要购买的套餐信息,示例代码根据实际业务修改
        $plan = Auth::user()->setup->plan;

        $request = new OrdersCreateRequest();
        $request->prefer('return=representation');
        $request->body = [
            'intent' => 'CAPTURE',
            'purchase_units' => [
                [
                    'description' => $plan->name,
                    'amount' => [
                        'currency_code' => 'USD', // 改成你的实际币种
                        'value' => $plan->price
                    ]
                ]
            ],
            'application_context' => [
                'shipping_preference' => 'NO_SHIPPING',
                'return_url' => url('/payment/success'), // 可选,不需要可以不用
                'cancel_url' => url('/payment/cancel') // 可选
            ]
        ];

        try {
            $response = $this->paypal->client->execute($request);
            return response()->json([
                'id' => $response->result->id
            ]);
        } catch (\Exception $e) {
            return response()->json(['error' => '订单创建失败'], 500);
        }
    }
}

2.2 订单捕获与校验接口

  • 新增路由 routes/api.php
Route::post('/paypal/capture-order', [PayPalController::class, 'captureOrder']);
  • 在PayPalController中添加捕获逻辑,此处必须做三重校验:订单状态、交易金额、币种
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
use App\Models\Transaction;

public function captureOrder(\Illuminate\Http\Request $request)
{
    $request->validate([
        'order_id' => 'required|string'
    ]);
    $orderId = $request->order_id;

    // 先查询当前用户要购买的套餐价格,用于后续校验
    $plan = Auth::user()->setup->plan;
    $expectAmount = (string)$plan->price;
    $expectCurrency = 'USD'; // 和创建订单时的币种保持一致

    $request = new OrdersCaptureRequest($orderId);
    $request->prefer('return=representation');

    try {
        $response = $this->paypal->client->execute($request);
        $result = $response->result;

        // 校验1:订单状态必须是已完成
        if ($result->status !== 'COMPLETED') {
            return response()->json(['error' => '支付未完成'], 400);
        }

        // 校验2:交易金额和币种必须和预期一致
        $capturedAmount = $result->purchase_units[0]->payments->captures[0]->amount->value;
        $capturedCurrency = $result->purchase_units[0]->payments->captures[0]->amount->currency_code;
        if ($capturedAmount !== $expectAmount || $capturedCurrency !== $expectCurrency) {
            return response()->json(['error' => '交易金额不匹配'], 400);
        }

        // 校验通过,处理后续业务逻辑:给用户开通权益、保存交易记录等
        Transaction::create([
            'user_id' => Auth::id(),
            'plan_id' => $plan->id,
            'transaction_id' => $result->purchase_units[0]->payments->captures[0]->id,
            'amount' => $capturedAmount,
            'currency' => $capturedCurrency,
            'status' => 'success'
        ]);
        // 此处添加开通会员、更新订阅状态等业务代码

        return response()->json(['status' => 'success', 'message' => '支付成功']);

    } catch (\Exception $e) {
        return response()->json(['error' => '支付捕获失败:' . $e->getMessage()], 500);
    }
}

第三步:前端代码改造

替换原来的客户端创建、捕获订单逻辑,改为调用自己的服务端接口:

paypal.Buttons({
    style: {
        layout:  'vertical',
        color:   'blue',
        shape:   'rect',
        label:   'pay',
    },
    createOrder: function(data, actions) {
        // 调用自己的服务端接口创建订单,返回订单ID
        return fetch('/api/paypal/create-order', {
            method: 'POST',
            headers: {
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
                'Content-Type': 'application/json'
            }
        }).then(function(res) {
            return res.json();
        }).then(function(orderData) {
            return orderData.id;
        });
    },
    onApprove: function(data, actions) {
        // 调用自己的服务端接口捕获、校验订单
        return fetch('/api/paypal/capture-order', {
            method: 'POST',
            headers: {
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                order_id: data.orderID
            })
        }).then(function(res) {
            return res.json();
        }).then(function(result) {
            if (result.status === 'success') {
                alert('支付成功');
                // 跳转成功页或者刷新页面更新状态
            } else {
                alert('支付失败:' + result.error);
            }
        });
    }
}).render('#paypal-button-container');

可选增强

可以额外配置PayPal Webhook监听支付相关事件,避免前端回调中断导致的业务逻辑未执行问题,进一步提升可靠性。

内容的提问来源于stack exchange,提问作者user17417786

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 05:24:07