Laravel 13 支付集成详解
摘要
本文将介绍在 Laravel 13 中集成 Stripe 和 PayPal 支付的方法,包括:
- Stripe 支付集成
- PayPal 支付集成
- 支付流程设计
- Webhook 处理
- 实战案例与最佳实践
本文适合希望集成支付功能的 Laravel 开发者。
1. Stripe 集成
1.1 安装 Stripe SDK
1
| composer require stripe/stripe-php
|
1.2 配置 Stripe
1 2 3 4 5 6
| 'stripe' => [ 'key' => env('STRIPE_KEY'), 'secret' => env('STRIPE_SECRET'), 'webhook_secret' => env('STRIPE_WEBHOOK_SECRET'), ],
|
1.3 支付意图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?php
namespace App\Services;
use Stripe\Stripe; use Stripe\PaymentIntent;
class StripeService { public function __construct() { Stripe::setApiKey(config('services.stripe.secret')); } public function createPaymentIntent(int $amount, string $currency = 'usd'): array { $intent = PaymentIntent::create([ 'amount' => $amount * 100, // 分为单位 'currency' => $currency, 'metadata' => [ 'order_id' => request()->order_id, ], ]); return [ 'client_secret' => $intent->client_secret, 'intent_id' => $intent->id, ]; } }
|
1.4 控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
namespace App\Http\Controllers;
use App\Services\StripeService; use Illuminate\Http\Request;
class PaymentController extends Controller { public function __construct( protected StripeService $stripe ) {} public function createIntent(Request $request) { $validated = $request->validate([ 'amount' => 'required|integer|min:1', 'order_id' => 'required|exists:orders,id', ]); $intent = $this->stripe->createPaymentIntent($validated['amount']); return response()->json($intent); } }
|
1.5 Webhook 处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <?php
namespace App\Http\Controllers;
use Illuminate\Http\Request; use Stripe\Webhook; use App\Models\Order;
class StripeWebhookController extends Controller { public function handle(Request $request) { $payload = $request->getContent(); $sigHeader = $request->header('Stripe-Signature'); $secret = config('services.stripe.webhook_secret'); try { $event = Webhook::constructEvent( $payload, $sigHeader, $secret ); } catch (\Exception $e) { return response()->json(['error' => $e->getMessage()], 400); } switch ($event->type) { case 'payment_intent.succeeded': $this->handlePaymentSuccess($event->data->object); break; case 'payment_intent.payment_failed': $this->handlePaymentFailed($event->data->object); break; } return response()->json(['status' => 'success']); } protected function handlePaymentSuccess($paymentIntent) { $orderId = $paymentIntent->metadata->order_id; Order::where('id', $orderId)->update([ 'status' => 'paid', 'paid_at' => now(), ]); } protected function handlePaymentFailed($paymentIntent) { $orderId = $paymentIntent->metadata->order_id; Order::where('id', $orderId)->update([ 'status' => 'failed', ]); } }
|
2. PayPal 集成
2.1 安装 PayPal SDK
1
| composer require paypal/rest-api-sdk-php
|
2.2 配置 PayPal
1 2 3 4 5 6
| 'paypal' => [ 'client_id' => env('PAYPAL_CLIENT_ID'), 'secret' => env('PAYPAL_SECRET'), 'mode' => env('PAYPAL_MODE', 'sandbox'), ],
|
2.3 PayPal 服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| <?php
namespace App\Services;
use PayPal\Rest\ApiContext; use PayPal\Auth\OAuthTokenCredential; use PayPal\Api\Amount; use PayPal\Api\Payer; use PayPal\Api\Payment; use PayPal\Api\RedirectUrls; use PayPal\Api\Transaction;
class PayPalService { protected $apiContext; public function __construct() { $this->apiContext = new ApiContext( new OAuthTokenCredential( config('services.paypal.client_id'), config('services.paypal.secret') ) ); $this->apiContext->setConfig([ 'mode' => config('services.paypal.mode'), ]); } public function createPayment(float $amount, string $currency = 'USD'): string { $payer = new Payer(); $payer->setPaymentMethod('paypal'); $amountObj = new Amount(); $amountObj->setTotal($amount); $amountObj->setCurrency($currency); $transaction = new Transaction(); $transaction->setAmount($amountObj); $redirectUrls = new RedirectUrls(); $redirectUrls->setReturnUrl(route('paypal.success')) ->setCancelUrl(route('paypal.cancel')); $payment = new Payment(); $payment->setIntent('sale') ->setPayer($payer) ->setTransactions([$transaction]) ->setRedirectUrls($redirectUrls); $payment->create($this->apiContext); return $payment->getApprovalLink(); } public function executePayment(string $paymentId, string $payerId): bool { $payment = Payment::get($paymentId, $this->apiContext); $execution = new PaymentExecution(); $execution->setPayerId($payerId); $result = $payment->execute($execution, $this->apiContext); return $result->getState() === 'approved'; } }
|
3. 实战案例
3.1 订单支付流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?php
namespace App\Services;
use App\Models\Order; use App\Services\StripeService;
class OrderPaymentService { public function __construct( protected StripeService $stripe ) {} public function process(Order $order): array { $intent = $this->stripe->createPaymentIntent( $order->total, $order->currency ); $order->update([ 'payment_intent_id' => $intent['intent_id'], 'payment_status' => 'pending', ]); return $intent; } }
|
4. 最佳实践
4.1 使用 Webhook
4.2 验证金额
1 2 3 4
| if ($request->amount !== $order->total) { throw new InvalidAmountException(); }
|
5. 总结
支付集成需要注意:
- 安全验证:Webhook 签名验证
- 金额验证:服务端验证金额
- 状态同步:及时更新订单状态
- 错误处理:完善的错误处理
参考资料