
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、前回の意外と簡単!Laravel で全文検索をつくるでは、Laravel
が提供する公式パッケージ「Laravel Scout」で全文検索する機能をつくってみました。
しかし、Laravel
には公式パッケージが他にも公開されていて、私達が開発する上で「うーん、ホントはほしいけど、自前でつくるのはちょっと怖いかも・・・」と考える機能も提供してくれています。
それは何かと言うと・・・・・・
課金システム
です。
つまり、毎月利用料を払うシステムで、身近な例で言うと「アマゾン・プライム」だとか、有料メルマガを思い浮かべるとわかりやすいかもしれません。
ということで、今回は「Laravel Cashier + Strip」で月額課金システムをつくってみます。
ぜひ皆さんのお役に立てましたら嬉しいです
(最後に、実際に開発したソースコード一式をダウンロードできますよ)
【追記:2020.08.25】Laravel Cashier
が更新されていたので、Laravel 7.x
+ Laravel Cashier v12.2.0
で加筆修正しました。
「ここ数年、開発は phpstorm を
サブスクして使ってます」
開発環境: Laravel 7.x/Laravel Cashier v12.2.0/Vue 2.6
目次 [非表示]
やりたいこと
まずはゴールとして以下の6つを実装することにします。
- 月額課金ができる
- 課金のプランは「プレミアム(1,000円/月)」と「ベーシック(500円/月)」の2種類
- 課金のキャンセルができる
- キャンセルしたものを元に戻すことができる
- プランの変更ができる
- クレジットカードの変更ができる
前提として
Laravel
の「php artisan make:auth」でログイン機能が有効になっていて、テストユーザーが登録されているものとします。
※詳しくは、【Laravel5.6】インストール直後にやること3点をご覧ください。
また、決済サービスのStripeにアカウントを作成しておいてください。( 私はすでに昔作ってしまったのでスクリーンショットはありません。ごめんなさい
Stripe
は日本語対応してますのでそれほど難しくないです)
※ ちなみに、ローカル環境でテストする場合でもstripe
が提供するjs
ライブラリにはhttps
で接続している必要があります。もしローカル環境にhttps
を導入する場合は、コピペでOK!ローカル環境にHTTPSを導入する(nginx編)を参考にしてみてください。
Stripeの設定をする
それでは、ここからStripe
にログインして設定をしていきます。
今回は説明なので、テスト・バージョンの設定になりますが、本番環境の場合はそれぞれ置き換えて実行してください。
APIキーを取得する
画面左側にある「開発者」というリンクをクリックします。
さらに「APIキー」をクリックします。
すると、「標準キー」の項目に「公開可能キー」と「シークレットキー」が表示されます。
これがいわゆる「APIキー」です。
この2つを以下のように.env
に登録しておきましょう。
STRIPE_KEY=************************
STRIPE_SECRET=***************************
ウェブフックのキーを取得する
続いてウェブフックのキーを取得します。
ウェブフックは課金やキャンセルが実行された直後にPOSTメソッドでLaravel
側にアクセスしてくるもので、課金の失敗や各種データの変更を管理してくれることになります。
では、メニューから「Webhook」をクリックします。
画面右上にある「+ エンドポイントを追加」をクリック。
すると、入力フォームがポップアップされるので、
- エンドポイントURL
- 送信イベント(すべてのイベントを受信をクリック。お好みで選んでもOK)
を入力して「エンドポイントを追加」ボタンをクリックしてください。
クリックすると登録した情報が表示されますので、その中から署名シークレットにある「署名シークレット」をコピーしてください。
そして、その署名シークレットは.env
に以下のように登録しておきましょう。
STRIPE_WEBHOOK_SECRET=****************************
【ご注意】
なお、ローカル環境ではstripe
からアクセスが届きませんので、うまくいきません。その場合、stripe
はStripe Cli
というテストツールを用意してくれていますので、こちらをインストールして使ってください。
イメージとしては、次のとおりです。
stripeのウェブフック
→ (Stripe Cliがウェブフックを仲介) → ローカル環境
つまり、Stripe Cli
は、stripe とローカル環境の「橋渡し」をしてくれる存在になります。
インストール方法は、ちなみに – 3:Stripe Clieをインストールする方法をご覧ください。
プランを追加する
課金のプラン「プレミアム」と「ベーシック」を追加します。
メニューの「商品」をクリックしてください。
そして、「+ 商品を追加」というボタンをクリック。
すると入力フォームが現れるので、まず商品名を入力します。
そして、その下には料金プランを入力する部分があるのでこれもお好みで入力してください。
入力が終わったらページ右上にある「商品を保存」ボタンをクリックすれば完了です。
続いて「ベーシック」プランも同様に追加したら、一覧に表示されている各商品名をクリックして詳細ページを表示させます。
するとそのページには以下のようにAPI ID
が表示されていますので、「ベーシック」と「プレミアム」それぞれのIDを取得し、.env
とconfig/services.php
に登録しておいてください。
.env
STRIPE_BASIC_ID=*****************
STRIPE_PREMIUM_ID=*****************
config/services.php
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
'webhook' => [
'secret' => env('STRIPE_WEBHOOK_SECRET'),
'tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300),
],
'plans' => [
env('STRIPE_BASIC_ID') => 'ベーシック',
env('STRIPE_PREMIUM_ID') => 'プレミアム'
]
],
インストール&準備をする
パッケージのインストール
では、続いてLaravel
で課金機能を開発していきましょう。
まずは専用パッケージLaravel Cashier
をインストールします。
composer require laravel/cashier
パッケージがインストールされたら、app/User.php
で課金機能が使えるようにBillable
トレイトを追加します。
<?php
namespace App;
// 省略
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Notifiable, Billable;
// 省略
これで、課金するためのメソッドが利用できるようになりました。
DBテーブルの準備
パッケージのインストールが完了したら、DBのテーブル環境を整えます。
以下のコマンドで実行してください。
php artisan migrate
※なお、旧バージョンではマイグレーションを自分でつくっていましたが現在はパッケージ内の「vendor/laravel/cashier/database/migrations」に含まれています。もし旧バージョンのテーブル作成方法をご覧になりたい方は、ちなみに – 2:旧バージョンのマイグレーションを参考にしてみてください。
コマンドを実行したらテーブルは以下のようになります。
課金ページをつくる
では、ここからは課金を実行するページを作っていきます。
構成としてはページは1つだけで、状態によってVue
で表示を切り替えることになります。
また、データの保存や課金の実行はすべてAjax
通信で行います。
ルートをつくる
では、routes/web.php
に課金ページのためのルートを追加してください。
Route::prefix('user')->middleware(['auth'])->group(function() {
// 課金
Route::get('subscription', 'User\SubscriptionController@index');
Route::get('ajax/subscription/status', 'User\Ajax\SubscriptionController@status');
Route::post('ajax/subscription/subscribe', 'User\Ajax\SubscriptionController@subscribe');
Route::post('ajax/subscription/cancel', 'User\Ajax\SubscriptionController@cancel');
Route::post('ajax/subscription/resume', 'User\Ajax\SubscriptionController@resume');
Route::post('ajax/subscription/change_plan', 'User\Ajax\SubscriptionController@change_plan');
Route::post('ajax/subscription/update_card', 'User\Ajax\SubscriptionController@update_card');
});
※ ログインしている人だけに表示するようauth
ミドルウェアを有効にしています。
なお、ウェブフックはこのままでは「CSRFブロック」が働いてアクセス拒否されてしまいますので、app/Http/Middleware/VerifyCsrfToken.php
を開いて解除しておいてください。
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
// 省略
protected $except = [
'stripe/*', //
追加
];
}
コントローラーをつくる
続いて、コントローラーです。
まず、ブラウザで表示するページのコントローラーを作ります。
以下のコマンドを実行してください。
php artisan make:controller User\\SubscriptionController
すると、app/Http/Controllers/User/SubscriptionController.php
が作成されるので、以下のように変更します。
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class SubscriptionController extends Controller
{
public function index(Request $request) {
$user = $request->user();
return view('user.subscription.index')->with([
'intent' => $user->createSetupIntent()
]);
}
}
【追記:2020.11.07】訪問ユーザーさんからご質問があった結果コードを修正しました。ありがとうございました!
続いて以下のコマンドでAjax
用のコントローラーを作成してください。
php artisan make:controller User\\Ajax\\SubscriptionController
app/Http/Controllers/User/Ajax/SubscriptionController.php
の中身を以下のように変更します。
<?php
namespace App\Http\Controllers\User\Ajax;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class SubscriptionController extends Controller
{
// 課金を実行
public function subscribe(Request $request) {
$user = $request->user();
if(!$user->subscribed('main')) {
$payment_method = $request->payment_method;
$plan = $request->plan;
$user->newSubscription('main', $plan)->create($payment_method);
$user->load('subscriptions');
}
return $this->status();
}
// 課金をキャンセル
public function cancel(Request $request) {
$request->user()
->subscription('main')
->cancel();
return $this->status();
}
// キャンセルしたものをもとに戻す
public function resume(Request $request) {
$request->user()
->subscription('main')
->resume();
return $this->status();
}
// プランを変更する
public function change_plan(Request $request) {
$plan = $request->plan;
$request->user()
->subscription('main')
->swap($plan);
return $this->status();
}
// カードを変更する
public function update_card(Request $request) {
$payment_method = $request->payment_method;
$request->user()
->updateDefaultPaymentMethod($payment_method);
return $this->status();
}
// 課金状態を返す
public function status() {
$status = 'unsubscribed';
$user = auth()->user();
$details = [];
if($user->subscribed('main')) { // 課金履歴あり
if($user->subscription('main')->cancelled()) { // キャンセル済み
$status = 'cancelled';
} else { // 課金中
$status = 'subscribed';
}
$subscription = $user->subscriptions->first(function($value){
return ($value->name === 'main');
})->only('ends_at', 'stripe_plan');
$details = [
'end_date' => ($subscription['ends_at']) ? $subscription['ends_at']->format('Y-m-d') : null,
'plan' => \Arr::get(config('services.stripe.plans'), $subscription['stripe_plan']),
'card_last_four' => $user->card_last_four
];
}
return [
'status' => $status,
'details' => $details
];
}
}
やっていることは、上から
- subscribe() ・・・ 新しい課金を登録
- cancel() ・・・ すでに課金されているものをキャンセル
- resume() ・・・ キャンセルされた課金を元に戻す
- change_plan() ・・・ プラン変更
- update_card() ・・・ クレジットカード変更
となります。
ここで重要なのが、subscribe()
内の以下の部分です。
$user->load('subscriptions');
この行がないと、課金状態の更新がされないため常にunsubscribed
ステータスが返ることになってしまいます。(←ちょっとハマりました)
ちなみに、コードの中で「main」という課金名が出てきますが、今回課金システムはひとつだけを想定しているのでこの名前にしています。(もしくはprimary
やdefault
などでもいいでしょう)
ビューをつくる
では、最後にビューです。
resources/views/user/subscription/index.blade.php
を作成して中身を以下のようにしてください。
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
padding: 15px;
}
#new-card, #update-card {
border: 1px solid #ccc;
padding: 8px;
}
</style>
</head>
<body>
<div id="app" class="container">
<h1 class="mb-4">Stripeを使った月額課金・サンプル</h1>
<div class="row">
<div class="offset-3 col-6">
<div class="card mb-4">
<div class="card-body bg-light">
<div v-if="!isSubscribed">
<div class="form-group">
<select class="form-control" v-model="plan">
<option v-for="(value,key) in planOptions" :value="key" v-text="value"></option>
</select>
</div>
<div class="form-group">
<input type="text" class="form-control" v-model="cardHolderName" placeholder="名義人(半角ローマ字)">
</div>
<div class="form-group">
<div id="new-card" class="bg-white"></div>
</div>
<div class="form-group text-right">
<button
type="button"
class="btn btn-primary"
data-secret="{{ $intent->client_secret }}"
@click="subscribe">
課金する
</button>
</div>
</div>
<div v-else-if="isSubscribed">
<div v-if="isCancelled">
キャンセル済みです。(終了:<span v-text="details.end_date"></span>)
<button class="btn btn-info" type="button" @click="resume">元に戻す</button>
</div>
<!-- 課金中 -->
<div v-else>
<div class="mb-3">現在、課金中です。</div>
<button class="btn btn-warning" type="button" @click="cancel">キャンセル</button>
<hr>
<div class="form-group">
課金中のプラン: <span v-text="details.plan"></span>
</div>
<div class="form-group">
<select class="form-control" v-model="plan">
<option v-for="(value,key) in planOptions" :value="key" v-text="value"></option>
</select><br>
<button class="btn btn-success" type="button" @click="changePlan">プランを変更する</button>
</div>
<hr>
<div class="form-group">
カード情報(下4桁): <span v-text="details.card_last_four"></span>
</div>
<div class="form-group">
<input type="text" class="form-control" v-model="cardHolderName" placeholder="名義人(半角ローマ字)">
</div>
<div class="form-group">
<div id="update-card" class="bg-white"></div><br>
<button
type="button"
class="btn btn-secondary"
data-secret="{{ $intent->client_secret }}"
@click="updateCard">
クレジットカードを変更する
</button>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-body">
<h5>テスト入力について</h5>
<hr>
<strong>名義人:</strong> 半角ローマ字ならなんでもOK<br>
<strong>カード番号:</strong> <a href="https://stripe.com/docs/testing#cards" target="_blank">テスト用のカード番号</a>に用意されています。なお、年/月は未来の日付ならいつでもOKで、CVCも数字ならなんでもOKです。
</div>
</div>
</div>
</div>
</div>
<script src="https://js.stripe.com/v3/"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
stripe: null,
stripeCard: null,
publicKey: '{{ config('services.stripe.key') }}',
status: '',
cardHolderName: '',
details: {},
plan: '',
planOptions: {!! json_encode(config('services.stripe.plans')) !!}
},
methods: {
async subscribe(e) {
const paymentMethod = await this.getPaymentMethod(e.target);
const url = '/user/ajax/subscription/subscribe';
const params = {
payment_method: paymentMethod,
plan: this.plan
};
axios.post(url, params)
.then(response => {
location.reload();
});
},
cancel() {
const url = '/user/ajax/subscription/cancel';
axios.post(url)
.then(this.setStatus);
},
resume() {
const url = '/user/ajax/subscription/resume';
axios.post(url)
.then(this.setStatus);
},
changePlan() {
const url = '/user/ajax/subscription/change_plan';
const params = { plan: this.plan };
axios.post(url, params)
.then(this.setStatus);
},
async updateCard(e) {
const paymentMethod = await this.getPaymentMethod(e.target);
const url = '/user/ajax/subscription/update_card';
const params = { payment_method: paymentMethod };
axios.post(url, params)
.then(response => {
location.reload();
});
},
setStatus(response) {
this.status = response.data.status;
this.details = response.data.details;
},
async getPaymentMethod(target) {
const clientSecret = target.dataset.secret;
const { setupIntent, error } = await this.stripe.confirmCardSetup(
clientSecret, {
payment_method: {
card: this.stripeCard,
billing_details: { name: this.cardHolderName }
}
}
);
if (error) {
console.log(error);
} else {
return setupIntent.payment_method;
}
}
},
computed: {
isSubscribed() {
return (this.status === 'subscribed' || this.status === 'cancelled');
},
isCancelled() {
return (this.status === 'cancelled');
}
},
watch: {
status(value) {
Vue.nextTick(() => {
if(!this.isCancelled) {
const selector = (value === 'unsubscribed') ? '#new-card' : '#update-card';
this.stripeCard = this.stripe.elements().create('card', {
hidePostalCode: true
});
this.stripeCard.mount(selector);
}
});
}
},
mounted() {
this.stripe = Stripe(this.publicKey);
const url = '/user/ajax/subscription/status';
axios.get(url)
.then(this.setStatus);
}
});
</script>
</body>
</html>
少しコードが長くなってしまいましたが、やっていることは、以下になります。
- Laravelから課金状態を Ajax で取得&その状態ごとに表示を切り替え
- 課金登録とクレジットカードを変更する場合は stripeから Intent を取得してから Ajax 送信
- それ以外の場合は単に Ajax で Laravel 側へ送信
そして、重要な部分はwatch
です。この中では、status
が変更したと同時にstripe.js
のクレジットカード入力ボックスを作成していますが、状態によってターゲットをその都度切り替えています。
なお、「前提として」でも書きましたが、
stripe.js
はhttps
での接続が必須となっていますので気をつけてください。
また、viewport
も必須とのことですので、忘れずに<head></head>
タグ内に追加しておいてください。
<meta name="viewport" content="width=device-width, initial-scale=1" />
テストしてみる
では実際にテストしてみましょう
ログインして、「https://******/user/subscription」にアクセスすると以下のようなフォームが表示されます。
まずは月額課金に登録してみます。
入力フォームを以下のようにして「課金する」ボタンをクリックします。
すると・・・・・・
登録が完了して表示が切り替わります。
では、続いて登録したばかりですが「キャンセル」ボタンをクリックして課金を止めてみましょう。
するとキャンセルが実行されるので、またすぐに元に戻してみましょう。
完了すると表示が切り替わるので、次はプランの変更をします。
現在プレミアムで登録しているので「ベーシック」を選択し「プランを変更する」ボタンをクリックします。
すると・・・・・
「プレミアム」と表示されていた部分がベーシックに変更になります。(ページをリロードしてもベーシックのままになっていることを確認してみてください)
では、次に登録されたクレジットカード番号を他のものに変更してみましょう。
現在は「4242…」から始まるVISA
のテスト番号で登録しているので、masterカード
に変更してみましょう。
これで送信すると・・・・・・
登録されているカードの下4桁が変更になりました。
成功です
お疲れ様でした
ちなみに – 1:テストのクレジットカード番号
Stripe
では以下のページで「テストのために使えるクレジットカード番号」をいくつか公開しています。
なお、有効期限は未来の日付ならいつでもOKで、CVC
はランダムな数字で問題ありません。
ちなみに – 2:旧バージョンのマイグレーション
現在はパッケージ内にマイグレーションが含まれていますので不要ですが、旧バージョンではテーブルを自分で作成していました。
加筆修正の際に削除しようかとも思いましたが、もしかすると必要としている方がいらっしゃるかもしれないのでこちらへ移動しました。
※つまり、最新版を使っている場合はこの作業は不要です。
まずはusers
テーブルにクレジットカード情報(の一部)が保存できるように項目を追加します。
以下のコマンドでマイグレーション・ファイルを作成してください。
php artisan make:migration add_stripe_to_users_table
すると、database/migrations/****_**_**_******_add_stripe_to_users_table.php
が作成されるので中身を以下のように変更します(太字が変更した部分です)
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddStripeToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('stripe_id')
->nullable()
->collation('utf8mb4_bin')
->after('remember_token');
$table->string('card_brand')
->nullable()
->after('stripe_id');
$table->string('card_last_four', 4)
->nullable()
->after('card_brand');
$table->timestamp('trial_ends_at')
->nullable()
->after('card_last_four');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('stripe_id');
$table->dropColumn('card_brand');
$table->dropColumn('card_last_four');
$table->dropColumn('trial_ends_at');
});
}
}
次に課金情報を保存しておくsubscriptions
テーブルを作成します。同じく以下のコマンドでマイグレーション・ファイルを作成してください。
php artisan make:migration create_subscriptions_table
そして、database/migrations/****_**_**_******_create_subscriptions_table.php
を開いて以下のようにします。
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSubscriptionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('subscriptions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->string('name');
$table->string('stripe_id')->collation('utf8mb4_bin');
$table->string('stripe_plan');
$table->integer('quantity');
$table->timestamp('trial_ends_at')->nullable();
$table->timestamp('ends_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('subscriptions');
}
}
これで必要なマイグレーションを2つ作成できました。
ちなみに – 3:Stripe Cliをインストールする方法
Stripe CLI をインストールする
基本的にインストールするにはStripe
が提供する以下のGitHub
ページでダウンロードして実行します。
(最新パッケージDLページ)
https://github.com/stripe/stripe-cli/releases/latest
Windows の場合
自分の環境に該当するファイルをダウンロード&展開し.exe
ファイルを実行します。
Linuxの場合
需要は少ないでしょうが、Stripe CLI
は私のような「Linux Love」な人間に向けてもパッケージを用意してくています。
こちらも該当パッケージをダウンロードして展開(コマンド例:tar -xvf stripe_X.X.X_linux_x86_64.tar.gz
)、そしてこの状態で./stripe
をコマンドで実行できるようになります。(つまり、通常のインストールというカンジではないですね)
なお、このままではどこからでもStripeコマンド
が実行できるようにはなっていないので、次のような場所に移動しておくといいでしょう。
sudo mv stripe /usr/local/bin/stripe
移動後、stripe -v
を実行して次のような表示が出たらうまくいっています。
stripe version 1.4.3
Stripe CLIにログインする
では、Stripe CLI
からログインしましょう。
※ Linux環境で実行しましたが、widnows
でも似たカンジだと思います。もし違いがあったら、ぜひ情報提供お願いいたします。m_ _m
以下のコマンドを実行してください。
stripe login
すると、次のような表示になりますので、このまま「Enterキー」を押します。
認証ページがブラウザで表示されるので、内容を確認して「アクセスを許可」ボタンをクリックしてください。
すると、以下のような表示になりログイン作業は完了です。
【超意訳】
おけーあなたのIDが設定されたよ
でも90日だけ有効だから、またログインよろしく
では、念のためStripe
のログインページでも接続ができているかチェックしておきましょう。
まず、ページ左にあるメニューの「開発者 > Webhook」をクリックします。
すると、ウェブフックの詳細ページが表示されるので「Stripe CLIのイベントを受信するデバイス」の項目をチェックしてみてください。
以下のようになっていればうまくいっています。
【追記:2021.03.11】
どうやらstripe listen
を実行しないと表示されないようです。
次の項目をみてコマンド実行してから確認してください。m(_ _)m
続いて、「ウェブフックURL」をStripe
に登録します。
登録の方法は、ウェブフックのキーを取得するを参考にしてみてください。
- なお、
STRIPE_WEBHOOK_SECRET
を登録する部分は次の項目で実行するので飛ばしておいてください) - また、
route
はすでにパッケージ側で登録してくれているので設定する必要はありません。もし独自のURLにしたい場合は「おまけ – 1:ウェブフックを独自のURLに設定する」をご覧ください。
ウェブフックを送信する
では、実際にテスト用のウェブフックを送信してみましょう。
以下のコマンドを実行してください。
stripe listen --forward-to example.test/stripe/webhook
※example.test/stripe/webhook
はローカル環境のURLです。適宜変更してください。
すると、以下のように専用の秘密鍵を表示してくれるので、この文字列を.env
のSTRIPE_WEBHOOK_SECRET
として登録します。
STRIPE_WEBHOOK_SECRET=******************************
この状態でウェブフックのテスト環境は完了しています。
後はブラウザでサブスクリプション登録するなどのイベントがあると以下のように自動で表示が追加されることになります。
おまけ – 1:ウェブフックを独自のURLに設定する
通常は問題ないと思いますが、何らかの理由でウェブフックを独自のURLにしたい場合も出てくるかと思います。
そんな場合は次のようにしてみてください。
コントローラーをつくる
まずLaravel Cashier
のCashierController
を継承したクラスをつくります。
今回はWebhookContoller
をつくってみます。
以下のコマンドを実行してください。
php artisan make:controller WebhookController
するとファイルが作成されるので、中身を次のように変更してください。
/app/Http/Controllers/WebhookController.php
namespace App\Http\Controllers;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
class WebhookController extends CashierController
{
public function receive($payload)
{
// ここで独自の処理ができます!
}
}
ルートをつくる
あとは、このコントローラーを通常通りweb.php
に登録すれば完了です。
Route::post('custom/stripe/webhook', '\App\Http\Controllers\WebhookController@receive');
※なお、新しいルートにウェブフックを登録した場合は、app/Http/Middleware/VerifyCsrfToken.php
のexcept
でCSRF
ブロックを解除しておきましょう。
protected $except = [
'custom/stripe/*',
];
おまけ – 2:HTTPSへウェブフック送信する
「https://******」へウェブフック送信をする場合は、コマンドを以下のように変更します。
stripe listen --forward-to https://example.test/custom/stripe/webhook --skip-verify
通常のコマンドとの違いは、URLに「https://」をつけていることと、「–skip-verify」オプションをつけていることです。
ダウンロードする
今回実際に開発したソースコード一式を以下からダウンロードすることができます。
Laravelで課金する方法(Laravel Cashier + Stripe)※ ただし、stripe
の設定や.env
、パッケージのインストールなどはご自身で準備する必要がありますのでご注意ください。
おわりに
実は移転する前のブログでLaravel Cashier
の記事を公開しているのですが、Laravel Cashier
だけでなくstripe
のAPIバージョンもアップデートされるなど変更点が多くなったため今回は、より詳しく記事をお届けしました。
【追記:2020.08.26】さらにLaravel Cashier
が更新されたので、再度記事を大幅にアップデートしました。
そして、前回と比較して一番いいなと思ったのは、「クレジットカードの入力ボックスを stripe.js が作成してくれる」という部分です。
以前はわざわざクレジットカード番号、有効期限(月と年)、CVC
の入力ボックスを作って独自に送信する流れでしたが、今はstripe.js
が一手に引き受けてくれるようになっていてちょっと感動しました。(しかも、入力もしやすいですね)
ということで、現在は個人であっても課金システムを導入することが難しい時代ではなくなりました。
ぜひ皆さんもトライしてみてはいかがでしょうか。
ではでは〜!
「サブスクって言葉、浸透しましたね
」