如何使用stripe

Digital goods are an increasingly valuable commodity. Whether you're a designer selling templates or font files, a developer charging for packages of code or a musician selling MP3s, selling digital goods online is often far easier than physical goods – with much lower production costs and no delivery charges.

数字商品是越来越有价值的商品。 无论您是销售模板或字体文件的设计师,还是要为代码包付费的开发人员,还是销售MP3的音乐家,在线销售数字商品通常都比实际商品容易得多,而且生产成本要低得多,而且无需交纳运费。

In this article I'll show how you can implement a simple store selling digital goods using PHP along with Stripe, a payment provider who aims to make it easier than ever to take online payments since you don't need to set up special merchant accounts or deal with complex payment gateways.

在本文中,我将向您展示如何使用PHP以及Stripe(一家支付服务提供商)来实现一个简单的商店来销售数字商品,Stripe的目的是比以往任何时候都更容易进行在线支付,因为您不需要设置特殊的商家帐户或处理复杂的支付网关。

在你开始之前 (Before you Begin)

You'll first need to set up an account with Stripe. Please note that the service is currently only available in the US, UK, Ireland and Canada. You may wish to check the blog or follow them on Twitter to be kept up to date in regards to avalability in other countries.

首先,您需要使用Stripe设置一个帐户。 请注意,该服务目前仅在美国,英国,爱尔兰和加拿大提供。 您可能希望查看博客或在Twitter上关注它们,以了解有关其他国家/地区的可用性的最新信息。

Setting up an account for testing takes no time at all, and doesn't require any complex financial questionnaires or information. You'll need to take a note of your test API key and publishable key for later.

设置测试帐户完全不需要时间,也不需要任何复杂的财务调查表或信息。 您需要记下测试API密钥和可发布密钥,以备后用。

配置 (Setting Up)

For this example application I'm going to use Laravel. It'll take care of some of the bread-and-butter stuff such as routing, templating and initiating the downloads, but the example shouldn't be too difficult to adapt for other frameworks (or indeed, no framework at all). Note that you can clone the entire example from Github.

对于此示例应用程序,我将使用Laravel 。 它将处理一些繁琐的工作,例如路由,模板化和启动下载,但是该示例对于适应其他框架(或者根本没有框架)应该并不难。 请注意,您可以从Github克隆整个示例。

Get started by installing Laravel via Composer:

通过Composer安装Laravel入门:

composer create-project laravel/laravel stripe-downloads --prefer-dist

composer create-project laravel/laravel stripe-downloads --prefer-dist

Include the following in the require section of your composer.json file, and run composer update:

composer.json文件的require部分中包括以下内容,然后运行composer update

"abodeo/laravel-stripe": "dev-master"

"abodeo/laravel-stripe": "dev-master"

This provides a simple wrapper to the Stripe SDK, allowing it to be used from within Laravel without having to worry about require'ing the appropriate files.

这为Stripe SDK提供了一个简单的包装器,使它可以在Laravel中使用,而不必担心require编写适当的文件。

Publish the configuration file using:

使用以下方法发布配置文件:

php artisan config:publish abodeo/laravel-stripe

php artisan config:publish abodeo/laravel-stripe

Then enter your API key and publishable key in app/config/packages/abodeo/laravel-stripe/stripe.php

然后在app/config/packages/abodeo/laravel-stripe/stripe.php输入您的API密钥和可发布密钥

Finally add the package to your list of service providers (app/config/app.php):

最后,将该软件包添加到您的服务提供商列表( app/config/app.php ):

'Abodeo\LaravelStripe\LaravelStripeServiceProvider',

'Abodeo\LaravelStripe\LaravelStripeServiceProvider',

设置数据库 (Setting up the Database)

Configure and create your database, then run the following to create a migration:

配置并创建数据库,然后运行以下命令来创建迁移:

php artisan migrate:make create_downloads_table

php artisan migrate:make create_downloads_table

Here's the relevant section (of the up() function), to create a table for the downloads we're going to sell:

这是up()函数的相关部分,为我们将要出售的下载内容创建表格:

Schema::create('downloads', function($table)
{
    $table->increments('id')->unsigned();        
    $table->string('name', 255);      
    $table->string('filepath', 255);      
    $table->integer('price');            
    $table->timestamps();
});

Note that price is an integer, because internally we're only going to deal with cents / pence. Filepath will refer to the location of the file relative to the app/storage directory.

请注意, price是整数,因为在内部,我们仅处理美分/便士。 Filepath将引用文件相对于app/storage目录的位置。

The corresponding model is very simple:

相应的模型非常简单:

// app/models/Download.php
class Download extends Eloquent {
    protected $fillable = array('name', 'filepath', 'price');
}

Finally, let's seed the database with some sample downloads:

最后,让我们通过一些样本下载为数据库播种:

class DownloadsSeeder extends Seeder {

    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $data = array(
            array(
                'name'            =>    'Sample download 1',
                'filepath'    =>    'downloads/one.zip',
                'price'            =>    500,
            ),
            array(
                'name'            =>    'Sample download 2',
                'filepath'    =>    'downloads/two.zip',
                'price'            =>    1000,
            ),
        );

        foreach ($data as $properties) {

            $download = new Download($properties);
            $download->save();            

        }
    }

}

一个简单的主页 (A Simple Homepage)

Let's create a simple homepage which allows people to select which download they'd like to purchase:

让我们创建一个简单的主页,使人们可以选择想要购买的下载文件:

Route::get('/', function()
{
    $downloads = Download::get();    
    return View::make('index', array('downloads' => $downloads));
});

And the view:

和视图:

// app/views/index.blade.php
<h1>Select your download:</h1>

<table class="table table-bordered">
@foreach ($downloads as $download)
    <tr>
        <td>{{ $download->name }}</td>
        <td>&pound;{{ round($download->price/100) }}</td>
        <td><a href="/buy/{{ $download->id }}" class="btn btn-primary">Buy</a></td>
    </tr>
@endforeach
</table>

付款 (Taking Payment)

Stripe provides two methods for taking card details. The first is a simple button, generated using Javascript which launches a payment form in a popup like so:

Stripe提供了两种获取卡详细信息的方法。 第一个是使用Javascript生成的简单按钮,它会在弹出窗口中启动付款表单,如下所示:

The second and more complex method allows to create the form yourself. That's the method I'm going to use in this example. Here's the route:

第二种也是更复杂的方法允许您自己创建表单。 这就是本例中要使用的方法。 这是路线:

Route::get('/buy/{id}', function($id)
{
    $download = Download::find($id);    
    return View::make('buy', array('download' => $download));
});

And the view:

和视图:

// app/views/buy.blade.php
<form action="" method="POST" id="payment-form" role="form">

  <div class="payment-errors alert alert-danger" style="display:none;"></div>

  <input type="hidden" name="did" value="{{ $download->id }}" />

  <div class="form-group">
    <label>
      <span>Card Number</span>
      <input type="text" size="20" data-stripe="number" class="form-control input-lg" />
    </label>
  </div>

  <div class="form-group">
    <label>
      <span>CVC</span>
      <input type="text" size="4" data-stripe="cvc" class="form-control input-lg" />
    </label>
  </div>

  <div class="form-group">  
    <label>
      <span>Expires</span>      
    </label>
    <div class="row">
      <div class="col-lg-1 col-md-1 col-sm-2 col-xs-3">
        <input type="text" size="2" data-stripe="exp-month" class="input-lg" placeholder="MM" />
      </div>  
      <div class="col-lg-1 col-md-1 col-sm-2 col-xs-3">
        <input type="text" size="4" data-stripe="exp-year" class="input-lg" placeholder="YYYY" />
      </div>
    </div>
  </div>

    <div class="form-group">
      <button type="submit" class="btn btn-primary btn-lg">Submit Payment</button>
  </div>
</form>

The eagle-eyed among you will notice that the card-related inputs are missing one crucial attribute – name. Without this, no data can possibly be passed to our server when the form gets submitted. How can this be?

你们中鹰眼的人会注意到,与卡相关的输入缺少一个关键属性name 。 没有这个,提交表单时,任何数据都不可能传递到我们的服务器。 怎么会这样?

Actually, this is deliberate. We don't want any credit card data being sent to our application.

实际上,这是故意的。 我们不希望任何信用卡数据发送到我们的应用程序。

What we're going to do is intercept the submission of this form using Javascript. The card information will be extracted from the form – notice the data-stripe attributes – and securely sent to the Stripe servers along with our publishable key. Stripe are then responsible for validating those details and all being well, return to us a special token. Once we have received that token, we can inject it into the form and POST the results as normal – minus the card details.

我们要做的是使用Javascript拦截此表单的提交。 卡信息将从表格中提取-注意data-stripe属性-并与我们的可发布密钥一起安全地发送到Stripe服务器。 然后,Stripe负责验证这些详细信息,并且一切都很好,给我们一个特殊的令牌。 收到该令牌后,我们可以将其注入表格中并按正常方式发布结果-减去卡的详细信息。

Back on the server, we can then use this token in conjunction with our private (API) key to actually charge the user's card. Should that code get intercepted up to this point, it's useless without our private key so there's very little a hacker could do with it.

回到服务器上,然后我们可以将此令牌与我们的私钥(API)结合使用,以对用户的卡进行实际收费。 到目前为止,如果该代码被截取,没有我们的私钥是没有用的,因此黑客几乎无法使用它。

We start by initialising the Stripe Javascript:

我们首先初始化Stripe Javascript:

Stripe.setPublishableKey('@stripeKey');

In the code above, @stripeKey is a special Blade extension which outputs the publishable key. If you're not using the blade templating library, you may wish to do something like this instead:

在上面的代码中, @stripeKey是特殊的Blade扩展,它输出可发布的密钥。 如果您不使用刀片模板库,则可能希望执行以下操作:

Stripe.setPublishableKey('<?php print Config::get('stripe.publishableKey') ?>');

Next up, here's the submit handler for our form:

接下来,这是我们表单的提交处理程序:

$('#payment-form').submit(function(e) {
  var $form = $(this);

  $form.find('.payment-errors').hide();

  $form.find('button').prop('disabled', true);

  Stripe.createToken($form, stripeResponseHandler);

  return false;
});

The function to handle the response from Stripe:

处理Stripe响应的函数:

function stripeResponseHandler(status, response) {
      var $form = $('#payment-form');

      if (response.error) {

        $form.find('.payment-errors').text(response.error.message).show();
        $form.find('button').prop('disabled', false);
      } else {

        var token = response.id;

        $form.append($('<input type="hidden" name="stripeToken" />').val(token));

        $form.get(0).submit();
      }
  };

Note how the token gets injected into the form by dynamically creating a new hidden form element with the name stripeToken. This is the only payment-related data that gets submitted.

请注意,如何通过动态创建一个名为stripeToken的新的隐藏表单元素来将令牌注入到表单中。 这是唯一提交的与付款相关的数据。

Should you examine the response from the Stripe server, you'll notice that in addition to the token – the id property – there is a card dictionary object. Obviously this does not contain the card number or CVC, but it does include the type – Visa, Mastercard etc – and the last 4 digits of the card number. This is useful for generating invoices or receipts; it's quite common to include this information to indicate to the customer what card they used to pay.

如果您检查来自Stripe服务器的响应,您会注意到,除了令牌( id属性)之外,还有card词典对象。 显然,它不包含卡号或CVC,但确实包括类型-Visa,Mastercard等-卡号的后4位。 这对于生成发票或收据很有用; 包含此信息以向客户指示他们曾经使用过哪种卡是很常见的。

Let's build the POST form handler:

让我们构建POST表单处理程序:

Route::post('/buy/{id}', function($id)
    {
        // Set the API key    
        Stripe::setApiKey(Config::get('laravel-stripe::stripe.api_key'));

        $download = Download::find($id);

        // Get the credit card details submitted by the form
        $token = Input::get('stripeToken');

        // Charge the card
        try {
            $charge = Stripe_Charge::create(array(
                "amount" => $download->price,
                "currency" => "gbp",
                "card" => $token,
                "description" => 'Order: ' . $download->name)
            );

            // If we get this far, we've charged the user successfully

        Session::put('purchased_download_id', $download->id);
        return Redirect::to('confirmed');

        } catch(Stripe_CardError $e) {
          // Payment failed
        return Redirect::to('buy/'.$id)->with('message', 'Your payment has failed.');        
        }
    }

Let's go through this.

让我们来看一下。

First we're setting the API key for Stripe. When we handled the form client-side we were okay with exposing the publishable key, because the token is useless without the private API key.

首先,我们为Stripe设置API密钥。 当我们处理客户端表单时,我们可以公开可发布的密钥,因为没有私有 API密钥的令牌是无用的。

Next we get the download being purchased from its ID, so we can get the name (used in the transaction reference) and its price (in cents / pence etc).

接下来,我们将从其ID中购买要下载的下载,因此我们可以获得名称(在交易参考中使用)及其价格(以美分/便士等)。

The value of $token is what we got from Stripe in the Javascript above, which we then injected into the form.

$ token的值是我们从上面的Javascript中的Stripe获得的,然后将其注入到表单中。

Next we use Stripe_Charge::create to actually charge the card. The $currency setting isn't required, but it will default to USD even if you set up an account outside of the US.

接下来,我们使用Stripe_Charge::create对该卡进行实际充电。 不需要$ currency设置,但即使您在美国境外设置帐户,它也默认为USD。

If the payment succeeds, we put the ID of the purchased item in the session. We'll use this to control access in a moment.

如果付款成功,我们会将购买的商品的ID放入会话中。 稍后我们将使用它来控制访问。

If the payment fails – usually because the bank declined the transaction – a Stripe_CardError exception gets thrown.

如果付款失败(通常是由于银行拒绝了交易), Stripe_CardError引发Stripe_CardError异常。

You can test the payment process using the dummy card number 4242-4242-4242-4242, along with any three-digit CVC and any expiry date – provided it's in the future.

您可以使用虚拟卡号4242-4242-4242-4242以及任何三位数的CVC和任何到期日期(如果将来会出现这种情况)来测试付款过程。

The confirmation route is simple:

确认途径很简单:

Route::get('/confirmed', function()
{
    $download = Download::find(Session::get('purchased_download_id'));
    return View::make('confirmed', array('download' => $download));
});

The view, which allows the buyer to download their file by clicking the download button:

该视图允许买方通过单击下载按钮下载文件:

// app/views/confirmed.blade.php
<h1>Your Order has been Confirmed</h1>

<p>You can now download your file using the button below:</p>

<p><a href="/download/{{ $download->id }}" class="btn btn-lg btn-primary">Download</a></p>

传送文件 (Delivering the File)

Finally, we need to implement the download link. We don't want to simply link to a public file, since we're charging for access. Instead, we'll take the file from the application's storage directory – which isn't web accessible – and deliver if, and only if, the current user has successfully paid for it.

最后,我们需要实现下载链接。 我们不想简单地链接到公共文件,因为我们要为访问收费。 取而代之的是,我们将从应用程序的存储目录(该文件不可通过网络访问)中获取文件,并仅在当前用户成功付款后才提供。

Route::get('/download/{id}', function($id)
{
    $download = Download::find($id);        
    if ((Session::has('purchased_download_id') && (Session::get('purchased_download_id') == $id))) {
        Session::forget('purchased_download_id');
        return Response::download(storage_path().'/'.$download->filepath);    
    } else {
        App::abort(401, 'Access denied');
    }
});

This link can only be used once; in practice you'd probably want to make it possible to download a file again at a later date, but I'll leave you to come up with ways of doing that.

该链接只能使用一次; 在实践中,您可能希望以后可以再次下载文件,但我将让您提出解决方法。

摘要 (Summary)

In this article I've shown how simple it is to take payments using Stripe, without having to worry about merchant accounts, payment gateways or storing sensitive card information. We've implemented a working, albeit simple purchasing process for digital downloads. Hopefully you'll have seen enough to get started implementing it in your projects.

在本文中,我展示了使用Stripe进行付款非常简单,而不必担心商家帐户,付款网关或存储敏感卡信息。 尽管已经实现了数字下载的简单购买过程,但我们已经实施了一个可行的过程。 希望您已经看到足够多的知识,可以开始在项目中实现它了。

翻译自: https://www.sitepoint/selling-downloads-stripe-laravel/

如何使用stripe

更多推荐

如何使用stripe_使用Stripe和Laravel出售下载内容