Top View


Author shiro seike / せいけ しろう / 清家 史郎

Stripe Payment Links Webhooks For PHPer

2022/12/04

「ウェブサイトを持っていなくても Payment Links ならオンライン決済が可能に。
数回のクリックで簡単に支払いページが完成し、顧客とリンクを共有できます。コーディングは不要です。」

その説明の通り、Stripe Dashboardをポチポチすると支払いページが出来てしまうサービスです。
昔クレジットカードの支払いページを作っていた僕にこのサービスを紹介したいですね。

私達が作っているのは基本的にWebページで決済を行った後に
何らかのアクションを行いたい事がほとんどだと思います。

今回はStripeにて決済を行った後に発生するイベントを利用して、
その処理を後続のendpointに受け渡す部分の実装について触れたいと思います。
ユースケースとして、支払い後に何らかの情報をAmazon SESを通してメール送信する事と設定します。

HTTPのendpointであれば良いので、私は先日の記事で書いたAWS Lamndaを利用したPHPにて実装を行いました。
AWS のサービスとも連携がしやすいので決済の後に〇〇を行いたい、といった時に便利です。

Stripe Payment Linksにclient_reference_idを付与

どの人がデータ送信してくれたものなのかを特定したい為、システムからclient_reference_idを生成します。
このIDは構築側で設定できるので、一意になるように意識して生成するようにします。
その後 client_reference_id をURLに付与して、ブラウザに遷移させるようにします。

例として、構築システム側から以下のようなURLを生成したとします。

※このURLは例なので、実際には存在しません。

メールアドレスを送信したいという意図があるので、
prefilled_email も付与する事で予めメールアドレスを埋めるとともに
構築するシステムとの関連性をより強固にします。

このようなURLを生成して利用すると、構築システムとの関連性が構築出来ます。

Webhook側の準備

Stripe -> Endpointの繋ぎこみについては Stripeの岡本さんのワークショップがわかりやすいです。

Chapter1: Amazon EventBridgeクイックスタートで、AWSでStripeのイベントを受信しようにて示されてる手順の
「3-2: Lambda Functions URLをStripe Webhookに登録しよう」にて詳細内容が書かれております。

PHPにて処理を行いたいので、コンソールを使わずに構築してその後Stripe側に設定します。
仮に始めよう!PHP AWS Lambda with Laravel!で作成したURLを利用して構築すると過程して進めます。

今回はPayment Linkにて決済後にそのまま処理を行ってますが、
先行販売などが発生してバーストアクセスが発生する場合などは
一度Amazon SQSを挟んでキューイングさせる等柔軟に選択肢を取れる事が Stripe x AWSの強みかと思います。

PHPの環境準備

Stripeとの連携が必要なので、Stripe SDKを利用します。
composer 対応されているので、簡単に導入可能です。

$ composer require stripe/stripe-php

開発環境のクイックスタートも合わせて貼っておきます。

Webhook の署名をPHPにて確認する

早速Stripeから処理を受け取った後の処理を記述します。
実際のexample含めてドキュメントが充実しているので、助かりますね。

まずは署名の検証を行います。
署名を検証することで、Stripeからのリクエストで有ることを判断出来ます。

こちらは example が用意されているため、そちらを利用して構築します。

PHPの場合は以下のとおりです。
※event->typeの判定を変更しています。


///////////////
/* Section.1 */
///////////////

// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
\Stripe\Stripe::setApiKey('sk_test_XxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX');

// If you are testing your webhook locally with the Stripe CLI you
// can find the endpoint's secret by running `stripe listen`
// Otherwise, find your endpoint's secret in your webhook settings in the Developer Dashboard
$endpoint_secret = 'whsec_XxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX';

///////////////
/* Section.2 */
///////////////

$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;

try {
    $event = \Stripe\Webhook::constructEvent(
        $payload, $sig_header, $endpoint_secret
    );
} catch(\UnexpectedValueException $e) {
    // Invalid payload
    http_response_code(400);
    exit();
} catch(\Stripe\Exception\SignatureVerificationException $e) {
    // Invalid signature
    http_response_code(400);
    exit();
}

///////////////
/* Section.3 */
///////////////

// Handle the event
switch ($event->type) {
    case 'checkout.session.completed':
        $paymentIntent = $event->data->object; // contains a \Stripe\Che
        // SESの送信処理を書く
        break;
    // ... handle other event types
    default:
        echo 'Received unknown event type ' . $event->type;
}

http_response_code(200);

3つのSectionに分けて説明します。

Section.1 (Stripeの基本設定を行う)

自分自身のStripeアカウントとの設定を行います。
API_KEYとendpoint_secretは、それぞれStripeから取得出来る為、取得して設定します。

但しこのコードをそのまま利用してしまうと、環境によって変更などが出来ないことや、
コードにベタ書きしている事に対するセキュリティへの不安などがあるため、
Laravelを利用している場合などは .env に設定するなどの工夫を行いましょう。

※こちらの実際の値は絶対に公開しないようにしましょう。
私も XxxxxxxxxxxxX のようにマスキングした状態にしております。

Section.2 (StripeからのRequestを利用して署名検証を行う)

endpointに送信されたpayloadと、 HTTPHeaderに送信された署名($sig_header)を利用して検証を行います。
\Stripe\Webhook::constructEvent というStatic メソッドが用意されているので利用します。

Payload、sig_header、endpoint_secretを、API_KEYが設定された状態で Static メソッドをCallすると、
署名の検証まで行ってくれて、問題なければ決済が行われたデータなどが取得できます。

署名の検証に失敗した場合は、その後の処理は行われませんので、endpointに対する攻撃を防ぐ事が出来ます。

ここではPHPのinputや SERVERなどを利用するなど、少し気持ちが強めのコードが書かれていますので、Laravelで利用する時は_SERVERなどを利用するなど、少し気持ちが強めのコードが書かれていますので、 Laravelで利用する時は requestから取得するなど変更しておきましょう。

署名検証が失敗した場合などのログ取得や通知等も、私達がコーディングすべき場所です。

Section.3 (Stripeからの情報を利用して処理を構築する)

問題なく署名の検証まで行えると処理のデータが取得出来るので、
そこから顧客の特定やメールアドレスの取得を行います。

あとはPHPの世界の話になるので、PHPerの皆様は腕まくりをしてコードを書きましょう。

StripeのIPからのみ接続出来るようにする

Stripeの api.stripe.com IPは公開されているので、
こちらをチェックすると更に強固になります。

実際の実装時にはIPチェックまで実装したのですが、
期待の若手が実装してくれた部分ですので、
書いてくれると嬉しいな〜という圧というか希望というか懇願してみようと思います

IPリストだけおいておきます。

Stripe Payment Linksとの繋ぎこみは簡単!

見ていただいた通りほとんどコーディングすることなく、またコーディングする部分もexampleが充実しているので
気になるところを修正しながら簡単に構築出来ました。

決済の構築は扱う情報の重要度含めてとても気を使う部分です。
Stripeをうまく利用することで決済部分は任せてしまい、
ビジネスロジック部分に集中しましょう!

明日はStripe Sigmaの記事になりそうな予感…
お楽しみに!

shiro seike / せいけ しろう / 清家 史郎

shiro seike / せいけ しろう / 清家 史郎

Twitter X

Company:Fusic CO., LTD. Slides:slide.seike460.com blog:blog.seike460.com Program Language:PHP , Go Interest:Full Serverless Architecture