32
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Stripe でカスタムフォームを表示してカード決済(単品購入&定期購入)

Last updated at Posted at 2019-05-28

##やりたいこと
・ 単品/定期購入をセレクトボックスで選択
・ クレカ情報を入力
・ Stripeで決済

##環境
・PHP
・Javascript

##参考
Stripe Elements公式

##1. Stripe Elements読み込み##

index.html
<script src="https://js.stripe.com/v3/"></script>

公式ドキュメントではStripeによる不正検知の精度を上げるため
サイト内すべてのファイルで読み込むことを推奨しています。

##2. フォームを表示##

index.html
<form action="charge.php" method="post" id="payment-form">
    <ul>
        <li>
            <select id="product" name="product" class="product">
            <option value="定期購入">定期購入</option>
            <option value="単品購入">単品購入</option>
            </select>
        </li>        
        <li><input type="email" name="email" class="email" placeholder="Email"></li>
        <li><input type="text" name="name" class="name" placeholder="名前"></li>  
                
        <!-- Stripe Elements -->
        <li><div id="card-number" class="stripe-input"></div></li>
        <li><div id="card-expiry" class="stripe-input"></div></li>
        <li><div id="card-cvc" class="stripe-input"></div></li>
        <li><div id="stripe_err" role="alert"></div></li>
                
        <li><button type="submit"> ご購入手続き </button></li>
    </ul>
</form>

簡単なフォームと最低限のcssを追加しました。
Stripe Elementsの部分にカード情報入力フォームを表示することになります。
あとからcssで見た目の調整をするためそれぞれのdivにclass="stripe-input"を指定しています。
スクリーンショット 2019-05-27 13.46.35.png
この状態で表示してもStripeElementsは表示されません。
##3. フォームにStripeElementsをマウント##

index.html(JS)
<script type="text/javascript">
    // StripeのAPIキーを読み込み
    var stripe = Stripe('pk_test_XXXXXXXX');

    // Elementsインスタンスを作成
    var elements = stripe.elements();

    // Elementsのスタイルを指定(ここはお好みで)
    var style = {
        base: {
        color: '#32325d',
        fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
        fontSize: '13px'
    },
    invalid: { //値が不正のときに文字色を変える
        color: '#fa755a',
        iconColor: '#fa755a'
    }
    };

    // フォームのidを指定してElementsをマウント
    const cardNumber = elements.create('cardNumber', {style: style,placeholder: 'カード番号 1111 1111 1111 1111'});
    cardNumber.mount('#card-number');
    const cardExpiry = elements.create('cardExpiry',{style: style,placeholder: '有効期限 MM/YY'});
    cardExpiry.mount('#card-expiry');
    const cardCvc = elements.create('cardCvc', {style: style,placeholder: 'セキュリティ番号'});
    cardCvc.mount('#card-cvc');

    // カード番号のリアルタイムバリデーション
    cardNumber.addEventListener('change', function(event) {
        var displayError = document.getElementById('stripe_err');
        if (event.error) {
            displayError.textContent = event.error.message;
        } else {
            displayError.textContent = '';
        }
    });

    // Submitボタンでエラーをチェック
    var form = document.getElementById('payment-form');
    form.addEventListener('submit', function(event) {
        event.preventDefault();
        stripe.createToken(cardNumber).then(function(result) {
            if (result.error) {
                var errorElement = document.getElementById('stripe_err');
                errorElement.textContent = result.error.message;
            } else {
                // Send the token to your server.
                stripeTokenHandler(result.token);
            }
        });
    });

    // フォーム送信処理 (stripeTokenをhiddenで送信)
    function stripeTokenHandler(token) {
        // Insert the token ID into the form so it gets submitted to the server
        var form = document.getElementById('payment-form');
        var hiddenInput = document.createElement('input');
        hiddenInput.setAttribute('type', 'hidden');
        hiddenInput.setAttribute('name', 'stripeToken');
        hiddenInput.setAttribute('value', token.id);
        form.appendChild(hiddenInput);

        // Submit the form
       form.submit();
    }   
</script>

スクリーンショット 2019-05-28 11.09.24.png

StripeElementsを表示できました。
このままだとフォームの枠が無い状態なので、cssを追加します。

.stripe-input {
    width: 200px;
    padding:8px;
    margin-bottom:5px;
    border: 1px solid #BBBBBB;
    border-radius:5px;
}

スクリーンショット 2019-05-28 11.05.36.png

このように、他のフォームとスタイルを合わせて表示させることができました!

##4. 決済処理##
フォームから実行するphpを作成します。
Stripeをインストールしておきます。PHPならcomposerがおすすめ。
ルートディレクトリで composer require stripe/stripe-php だけでOKです。
また、定期購入決済を利用する場合はプランをダッシュボードで作っておく必要があります。

charge.php
require 'vendor/autoload.php';

// シークレットキーを設定
\Stripe\Stripe::setApiKey("sk_test_XXXXXXXXXX");

// トークンとプロダクト(定期/単品どちらか)を変数に格納
$token = $_POST['stripeToken'];
$product = $_POST['product'];

if($product == '単品購入'){
    
    //単品購入なら単品チャージ
    try {
        $responce = \Stripe\Charge::create(array(
        "amount" => 1000, //価格
        "currency" => "jpy",
        "source" => $token,
        "description" => "単品購入",
        ));
    }catch (\Stripe\Error\Card $e) {
        // 決済できなかったときの処理
        console.log($e);
        die('決済が完了しませんでした');
    }
    
}else{
    
    //顧客情報を作成
    try{
        $customer = \Stripe\Customer::create(array(
        'email' => $_POST['email'],
        'source' => $token,
        'metadata' =>['Name' =>$_POST['name']]
        ));
        
    }catch (\Stripe\Error\Card $e) {
        console.log($e);
        die('顧客情報の登録が完了しませんでした');
    }
    
    //定期購入登録
    try{
        $responce = \Stripe\Subscription::create([
        'customer' => $customer['id'],
        'items' => [['plan' => 'plan_XXXXXX']],//予め作成した定期購入プランのIDを指定します
        ]);
        
    }catch (\Stripe\Error\Card $e) {
        console.log($e);
        die('定期購入の登録が完了しませんでした');
    }   
}

エラー処理などは割愛して簡略化していますが、決済処理はたったこれだけでOKです。
実装がシンプルでデザインの自由度も高く、初心者でもとっつきやすいです。

32
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?