Laravel中集成PayPal

更新日期: 2019-03-21阅读: 2.7k标签: Laravel

最近在写一个面向国外买家的一个商城项目,既然面向国外,那就要用到PayPal这个支付平台。因为在对接PayPal的过程中遇到了一些问题,花费了一些时间,所以把对接的过程记下来,也希望能帮助到用到PayPal的朋友。

我集成的是paypal/rest-api-sdk-php。PayPal的api有 v1和v2两个版本,我用的这个是v1版本。

以下皆以代码的形式展现,没有截图,但我尽量用代码讲解明白。假设你已经有了用laravel写的一个项目:


Step:1安装扩展包

composer require paypal/rest-api-sdk-php


Step:2创建payment.php配置文件

在Config目录新建payment.php配置文件,内容如下

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演示。


链接: https://www.fly63.com/article/detial/2946

分享 10 个你可能不知道的 Laravel Eloquent 小技巧

Laravel 是一个功能丰富的框架。但是,你无法从官方文档中找到所有可用的功能。以下是一些你可能不知道的功能。获取原始属性:当修改一条 Eloquent 模型记录的时候你可以通过调用

laravel常用路径保存

laravel框架常用目录路径:app_path(),app_path函数返回app目录的绝对路径:$path = app_path();你还可以使用app_path函数为相对于app目录的给定文件生成绝对路径:$path = app_path(\\\'Http/Controllers/Controller.php\\\');

Laravel 框架 Model 对象转 json 字符串丢失更新

Laravel 的 Illuminate\\\\Database\\\\Eloquent\\\\Model 实现了 JsonSerializable 接口,所以在调用 json_encode 进行序列化时,会调用 Model::jsonSerialize 方法,他这个方法返回的数据是:

Laravel 中创建 Zip 压缩文件并提供下载

如果您需要您的用户支持多文件下载的话,最好的办法是创建一个压缩包并提供下载。看下在 Laravel 中的实现。事实上,这不是关于 Laravel 的,而是和 PHP 的关联更

Laravel中9个不经常用的小技巧

更新父表的timestamps:如果你想在更新关联表的同时,更新父表的timestamps,你只需要在关联表的model中添加touches属性。

十五个常用的 Laravel 集合(Collection)

Laravel Eloquent 通常返回一个集合作为结果,集合包含很多有用的、功能强大的方法。你可以很方便的对集合进行过滤、修改等操作。本次教程就一起来看一看集合的常用方法及功能。

十个推荐使用的 Laravel 的辅助函数

Laravel 包含各种全局辅助函数。 laravel 中包含大量辅助函数,您可以使用它们来简化开发工作流程。 在这里,我将编写10个最好的 laravel 帮助函数,用于使我的开发更容易。 您必须考虑在必要时使用它们。

Laravel 向公共模板赋值

开发过程中许多时候都会向公共模板赋值,比如顶部导航栏,页面底部等等,不可能在每个控制器中都赋值一遍。Laravel 中解决办法如下:

Composer,laravel下载和更新

有两种方式启用本镜像服务:系统全局配置: 即将配置信息添加到 Composer 的全局配置文件 config.json 中。单个项目配置: 将配置信息添加到某个项目的composer.json 文件中。

Laravel 如何优雅地实现输出结构统一的功能?

一般的项目需求都会要求统一的输出结构,特别是对于api应用而言。因此,如果有beforeResponse的功能,则可以在数据输出之前对response进行统一格式化处理。假设这么一种场景

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!