ThinkPHP 5接入PayPal 支付,PayPal的流程是服務器請求Paypal的接口下單(需要傳訂單id/支付成功的重定向地址/支付失敗的重定向地址),接會返回一個支付地址,項目服務器把地址返給用戶,用戶打開鏈接登錄Paypal完成付款,然后Paypal給重定向到指定地址。
在paypal官網開通商戶號,設置通知地址。
開通沙箱模式用于測試,后臺會給沙箱模式生成商戶賬號和用戶賬號,請注意區分。
申請和開通網上有教程不在贅述。
具體實現步驟如下
1.安裝包
composer require paypal/rest-api-sdk-php:*
2.具體實現代碼
<?phpnamespace app\api\controller;use app\common\controller\Api;
use app\common\model\ShopOrder;
use PayPal\Api\Amount;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\Transaction;
use PayPal\Api\PaymentExecution;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Rest\ApiContext;
use PayPal\Api\RedirectUrls;
use think\Log;
class Paypal extends Api
{protected $noNeedLogin = ['*'];protected $noNeedRight = ['*'];private $apiContext;public function __construct(){parent::__construct();// 初始化PayPal API上下文$this->apiContext = new ApiContext(new OAuthTokenCredential('AV8d**************************N-jbpRvV-K0_dLuEA5d8uodUowab6jdWtM', // 客戶端ID'EByrRAncAi*****************************RSqIRA' // 客戶端密鑰));$this->apiContext->setConfig(['mode' => 'sandbox', // 或者 'live'// 其他配置...]);}/*** 下單接口* @return \think\response\Json|void* @throws \think\db\exception\DataNotFoundException* @throws \think\db\exception\ModelNotFoundException* @throws \think\exception\DbException*/public function createPaypalPaymentUrl(){// 獲取前端傳遞的order_Id$orderId = input('post.order_id');// 查詢訂單信息(這里你需要根據自己的數據庫結構進行查詢)// 假設我們得到了一個包含訂單詳情的數組$orderInfo$orderInfo = ShopOrder::where('id', $orderId)->where('status', '1')->find();if (empty($orderInfo)) {$this->error('訂單不存在或不是待支付狀態');}// 設置Payer信息,表明付款人是通過PayPal付款$payer = new Payer();$payer->setPaymentMethod("paypal");// 設置交易金額$amount = new Amount();$amount->setCurrency("AUD")->setTotal(number_format($orderInfo['actual_money'], 2, '.', ''));// 創建Transaction對象,并使用訂單ID作為發票號$transaction = new Transaction();$transaction->setAmount($amount)->setDescription("Slem order pay") // 描述可選->setInvoiceNumber($orderInfo->order_num); // 使用訂單order_num作為發票號// 創建RedirectUrls對象$redirectUrls = new RedirectUrls();$redirectUrls->setReturnUrl("https://*******.cn/api/paypal/paymentSuccess") // 支付成功后的回調地址->setCancelUrl("https://********/api/paypal/paymentCancel"); // 用戶取消支付后的回調地址// 創建Payment對象$payment = new Payment();$payment->setIntent("sale")->setPayer($payer)->setRedirectUrls($redirectUrls)->setTransactions([$transaction]);try {// 創建支付請求$payment->create($this->apiContext);// 獲取approval_url,這是用戶需要訪問來完成支付的URLforeach ($payment->getLinks() as $link) {if ($link->getRel() == 'approval_url') {// 返回支付鏈接給客戶端return json(['code' => 1, 'data' => $link->getHref()]);
// $data = ['status' => 'success', 'approval_url' => $link->getHref()];
// $this->success(__('SUccess'),$data);}}} catch (\Exception $ex) {// 輸出詳細的錯誤信息return json(['status' => 'error','message' => 'Error creating PayPal payment: ' . $ex->getMessage(),'details' => $ex->getTraceAsString(),'response' => $payment->toArray()]);}}/*** 支付成功跳轉的頁面* 建議前端出個html后臺做渲染,本方法只為展示流程* @return \think\response\Json*/public function paymentSuccess(){// 獲取PayPal傳遞過來的參數$paymentId = input('get.paymentId');$payerId = input('get.PayerID');if (empty($paymentId) || empty($payerId)) {return json(['status' => 'error', 'message' => 'Missing payment ID or payer ID']);}try {// 獲取支付信息$payment = Payment::get($paymentId, $this->apiContext);// 創建PaymentExecution對象并設置payer_id$execution = new PaymentExecution();$execution->setPayerId($payerId);// 執行支付請求$result = $payment->execute($execution, $this->apiContext);// 檢查支付狀態if ($result->getState() === 'approved') {// 使用發票號(即訂單ID)來查找訂單$invoiceNumber = $payment->getTransactions()[0]->getInvoiceNumber();$order = ShopOrder::where('order_num', $invoiceNumber)->find();if (!empty($order)) {// 更新訂單狀態為已支付$order->payment = 'paypal';$order->status = '2';$order->save();// 你可以在這里添加更多的業務邏輯,比如發送確認郵件等// 返回成功信息給前端return json(['status' => 'success', 'message' => 'Payment successful']);} else {return json(['status' => 'error', 'message' => 'Order not found']);}} else {return json(['status' => 'error', 'message' => 'Payment not approved']);}} catch (\Exception $ex) {// 錯誤處理Log::error('PayPal Error: ' . $ex->getMessage());return json(['status' => 'error','message' => 'Error executing payment: ' . $ex->getMessage(),'details' => $ex->getTraceAsString()]);}}/*** 支付取消跳轉的頁面* @return \think\response\Json*/public function paymentCancel(){// 獲取訂單ID或其他相關信息(如果需要)$orderId = input('get.order_id'); // 如果PayPal回調包含order_idif (!empty($orderId)) {try {// 根據訂單ID查找訂單信息$order = ShopOrder::where('id', $orderId)->find();if (!empty($order)) {// 你可以在這里添加更多的業務邏輯,比如記錄取消原因、發送通知等// 更新訂單狀態為已取消或保持不變,視業務需求而定// 這里假設我們不改變訂單狀態,僅記錄取消事件Log::info("Payment cancelled for order ID: " . $orderId);// 返回取消信息給前端return json(['status' => 'info', 'message' => 'Payment cancelled.']);} else {return json(['status' => 'error', 'message' => 'Order not found.']);}} catch (\Exception $ex) {// 錯誤處理Log::error('Error handling payment cancellation: ' . $ex->getMessage());return json(['status' => 'error','message' => 'An error occurred while processing your request.','details' => $ex->getTraceAsString()]);}} else {// 如果沒有提供訂單ID,則簡單地告知用戶支付已被取消return json(['status' => 'info', 'message' => 'Payment cancelled.']);}}
}