最近在寫一個面向國外買家的一個商城項目,既然面向國外,那就要用到PayPal
這個支付平臺。由於在對接PayPal
的過程當中遇到了一些問題,花費了一些時間,因此把對接的過程記下來,也但願能幫助到用到PayPal
的朋友。 php
我集成的是paypal/rest-api-sdk-php
。PayPal
的api
有 v1
和v2
兩個版本,我用的這個是v1
版本。 前端
如下皆以代碼的形式展示,沒有截圖,但我儘可能用代碼講解明白。
假設你已經有了用laravel
寫的一個項目:laravel
Step:1
安裝擴展包composer require paypal/rest-api-sdk-php
Step:2
建立payment.php
配置文件在Config
目錄新建payment.php
配置文件,內容以下json
return [ 'paypal' => [ /** set your paypal credential **/ 'client_id' =>'paypal client_id', 'secret' => 'paypal secret ID', /** * SDK 配置 */ 'settings' => array( /** * 沙盒測試'sandbox' 或者 'live' */ 'mode' => 'sandbox', /** * 請求超時時間 */ 'http.ConnectionTimeOut' => 1000, /** * 是否開啓日誌:true開啓,false不開啓 */ 'log.LogEnabled' => true, /** * 日誌存儲的文件 */ 'log.FileName' => storage_path() . '/logs/paypal.log', /** * 日誌級別 'DEBUG', 'INFO', 'WARN' or 'ERROR' * */ 'log.LogLevel' => 'INFO' ), ], '2checkout' => [ // ] ];
Step:3
建立路由// 第一步:顯示錶單,這是一個簡單的表單頁面,咱們把金額輸入,而後點擊提交 Route::get('paypal-form', 'Payment\PayPalController@payPalShow')->name('paypal-form'); // 第二步:第一步提交後發送請求,請求該方法,該方法用於建立訂單,建立支付流程 Route::post('paypal-pay', 'Payment\PayPalController@pay')->name('payment.paypay.pay'); // 第三步:異步回調 Route::post('paypal-notify', 'Payment\PayPalController@payPalNotify')->name('payment.paypal.notify'); // 第三步:前端回調 Route::get('paypal-return', 'Payment\PayPalController@payPalReturn')->name('payment.paypal.return'); // 第三步:取消 Route::get('paypal-cancel', 'Payment\PayPalController@payPalCancel')->name('payment.paypal.cancel');
Step:3
建立控制器<?php namespace App\Http\Controllers\Payment; use App\Http\Controllers\BaseController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Input; use PayPal\Api\Amount; use PayPal\Api\Item; use PayPal\Api\ItemList; use PayPal\Api\Payer; use PayPal\Api\Payment; use PayPal\Api\PaymentExecution; use PayPal\Api\RedirectUrls; use PayPal\Api\Transaction; use PayPal\Auth\OAuthTokenCredential; use PayPal\Rest\ApiContext; class PayPalController extends BaseController { private $_api_context; public function __construct() { $payPal_config = config('payment.payPal'); // 初始化 PayPal Api context $this->_api_context = new ApiContext(new OAuthTokenCredential( $payPal_config['client_id'], $payPal_config['secret'] )); $this->_api_context->setConfig($payPal_config['setting']); } // 顯示錶單 public function payPalShow() { return view('payment.paypal'); } // 第二步,請求這裏 public function pay(Request $request) { $payer = new Payer(); $payer->setPaymentMethod('paypal'); // 產品名稱,幣種,數量,單個產品金額 $item1 = new Item(); $item1->setName('item1') ->setCurrency('USD') ->setQuantity(1) ->setPrice($request->get('amount')); // 將全部產品集合到 ItemList中 $item_list = new ItemList(); $item_list->setItems([$item1]); $amount = new Amount(); $amount->setCurrency('USD') ->setTotal($request->get('amount')); // 生成交易 $transaction = new Transaction(); $transaction->setAmount($amount) ->setItemList($item_list) ->setDescription('你的交易') ->setNotifyUrl(route('notify_url')) // 注意,這裏設置異步回調地址 ->setInvoiceNumber($order->order_number); // 這裏設置訂單號 // 設置前端回調地址和取消支付地址 $redirect_urls = new RedirectUrls(); $redirect_urls->setReturnUrl(route('payment.paypal.return')) ->setCancelUrl(route('payment.paypal.cancel')); $payment = new Payment(); $payment->setIntent('Sale') ->setPayer($payer) ->setRedirectUrls($redirect_urls) ->setTransactions(array($transaction));
try { // 這裏生成支付流程 $payment->create($this->_api_context); } catch (\PayPal\Exception\PayPalConnectionException $ex) { if (config('app.debug')) { session()->put('error','Connection timeout'); return redirect()->route('paypal-form'); /** echo "Exception: " . $ex->getMessage() . PHP_EOL; **/ /** $err_data = json_decode($ex->getData(), true); **/ /** exit; **/ } else { session()->put('error','Some error occur, sorry for inconvenient'); return redirect()->route('paypal-form'); } } foreach($payment->getLinks() as $link) { if($link->getRel() == 'approval_url') { $redirect_url = $link->getHref(); break; } } // $payment->getId()獲得的是支付流水號 session()->put('paypal_payment_id', $payment->getId()); if(isset($redirect_url)) { // 跳轉到支付頁面 return redirect()->away($redirect_url); } session()->put('error','Unknown error occurred'); return session()->route('paypal-form'); } public function payPalReturn(Request $request) { // 支付成功後,在前端頁面跳轉回來時,url地址中會帶有paymentID 和 PayerID $payment_id = session()->get('paypal_payment_id'); session()->forget('paypal_payment_id'); if (empty(Input::get('PayerID')) || empty(Input::get('token'))) { session()->put('error','Payment failed'); return redirect()->route('paypal-form'); } $payment = Payment::get($payment_id, $this->_api_context); $execution = new PaymentExecution(); $execution->setPayerId(Input::get('PayerID')); $result = $payment->execute($execution, $this->_api_context); // 當拿到的狀態時approved表示支付成功 if ($result->getState() == 'approved') { session()->put('success','Payment success'); return redirect()->route('paypal-form'); } session()->put('error','Payment failed'); return redirect()->route('paypal-form'); } public function payPalNotify() { Log::info(12312, Input::get()); // 這裏寫咱們的業務邏輯,訂單狀態更新,物流信息等等. } }
Step:4
建立表單<form class="form-horizontal" method="POST" id="payment-form" role="form" action="{!! URL::route('paypal-pay') !!}" > {{ csrf_field() }} <div class="form-group{{ $errors->has('amount') ? ' has-error' : '' }}"> <label for="amount" class="col-md-4 control-label">Amount</label> <div class="col-md-6"> <input id="amount" type="text" class="form-control" name="amount" value="{{ old('amount') }}" autofocus> @if ($errors->has('amount')) <span class="help-block"> <strong>{{ $errors->first('amount') }}</strong> </span> @endif </div> </div> <div class="form-group"> <div class="col-md-6 col-md-offset-4"> <button type="submit" class="btn btn-primary"> Paywith Paypal </button> </div> </div> </form>
以上既是我作商城項目時PayPal
的對接流程,由於英語很差的問題,開發起來會出現不少問題,
若是英文好,想知道更多的用法,能夠看PayPal
的開發者文檔,還有demo
演示。api