世の中のインターネット向けサービスの多くでPHPが使われています(2017年12月現在、83.1%がPHPとされています)。WordPressは世界中の約30%のサイトで動いているなんてレポートもあります(via W3Techs - extensive and reliable web technology surveys)。
そうしたサイトの中に決済機能を持たせたいと思ったらぜひSquare EコマースAPIを使ってみてください。今回はその使い方を紹介します。
コードは goofmint/SquareCommercePHPDemo: SquareのEコマースAPIをPHPで行うデモです。 にて公開しています。
処理の流れ
基本的な処理の流れです。Squareでは開発者がクレジットカード番号に触れないで済む仕組みを提供しています。注文処理を開始する際にまずクレジットカード情報をSquareに送信し、トークン化します(nonceと呼びます)。そのnonceと決済額を合わせて課金処理を行います。
トークン化はWebブラウザ(JavaScript)で行います。PHP側ではnonceを受け取り、課金処理を行うだけです。
nonce生成
まずnonce生成について紹介します。HTMLは次のような形になります。 #card-nonce
に取得したnonceが入ります。フォームの送信先は process-card.php
になっていますが、ボタンを押した時にまず requestCardNonce(event)
が実行されます。
このフォームの時点ではクレジットカード情報を入力する input タグがありません。後述するJavaScriptによって生成されます。
<form id="nonce-form" novalidate action="/process-card.php" method="post">
カードで支払います
<table><tbody>
<tr>
<td>カード番号:</td>
<td><div id="sq-card-number"></div></td>
</tr>
<tr>
<td>CVV:</td>
<td><div id="sq-cvv"></div></td>
</tr>
<tr>
<td>有効期限:</td>
<td><div id="sq-expiration-date"></div></td>
</tr>
<tr>
<td>郵便番号:</td>
<td><div id="sq-postal-code"></div></td>
</tr>
<tr>
<td colspan="2">
<button id="sq-creditcard" class="button-credit-card" onclick="requestCardNonce(event)">
カードで支払う
</button>
</td>
</tr>
</tbody></table>
<input type="hidden" id="card-nonce" name="nonce">
</form>
もし、MasterpassやApple Payを使う場合には、さらに次のように記述しておきます。
<div id="sq-walletbox">
デジタル通貨で支払う
<div id="sq-apple-pay-label" class="wallet-not-enabled">Apple Pay for Web が有効ではありません</div>
<button id="sq-apple-pay" class="button-apple-pay"></button>
<div id="sq-masterpass-label" class="wallet-not-enabled">Masterpassが有効ではありません</div>
<button id="sq-masterpass" class="button-masterpass"></button>
</div>
Square決済フォームの表示
Squareの決済フォームを表示するには、まずスクリプトタグで以下のJavaScriptを読み込みます。
<script type="text/javascript" src="https://js.squareup.com/v2/paymentform"></script>
次にJavaScriptファイルを作成し、それを読み込みます。
<script type="text/javascript" src="/sqpaymentform.js"></script>
sqpaymentform.js
の内容は次のようになります。詳細はコメントを参照してください。二箇所 REPLACE_ME となっている部分があるので、それは Square Developer Portal で取得できるものと置き換えてください。
var applicationId = "REPLACE_ME"; // アプリケーションIDと置き換えます
var locationId = "REPLACE_ME"; // 店舗IDと置き換えます
// ボタンを押したタイミングで実行される関数
function requestCardNonce(event) {
event.preventDefault();
paymentForm.requestCardNonce();
}
var paymentForm = new SqPaymentForm({
// 以下は初期設定です
applicationId: applicationId,
locationId: locationId,
inputClass: 'sq-input',
inputStyles: [{
fontSize: '.9em'
}],
// Apple Pay用
applePay: {
elementId: 'sq-apple-pay'
},
// MasterPass用
masterpass: {
elementId: 'sq-masterpass'
},
// クレジットカード情報のプレイスホルダー
cardNumber: {
elementId: 'sq-card-number',
placeholder: '•••• •••• •••• ••••'
},
cvv: {
elementId: 'sq-cvv',
placeholder: 'CVV'
},
expirationDate: {
elementId: 'sq-expiration-date',
placeholder: 'MM/YY'
},
postalCode: {
elementId: 'sq-postal-code'
},
// 各種コールバック
callbacks: {
// Apple Pay / MasterPassの有効/無効チェック
methodsSupported: function (methods) {
var applePayBtn = document.getElementById('sq-apple-pay');
var applePayLabel = document.getElementById('sq-apple-pay-label');
var masterpassBtn = document.getElementById('sq-masterpass');
var masterpassLabel = document.getElementById('sq-masterpass-label');
// Apple Payが有効だったら表示する
if (methods.applePay === true) {
applePayBtn.style.display = 'inline-block';
applePayLabel.style.display = 'none' ;
}
// Masterpassが有効だったら表示する
if (methods.masterpass === true) {
masterpassBtn.style.display = 'inline-block';
masterpassLabel.style.display = 'none';
}
},
createPaymentRequest: function () {
},
// nonce 生成後に呼ばれるメソッド
cardNonceResponseReceived: function(errors, nonce, cardData) {
if (errors) {
// エラーがあった場合
console.log("エラーが発生しました。:");
errors.forEach(function(error) {
console.log(' ' + error.message);
});
return;
}
// nonceの値をhiddenの中に入れます
document.getElementById('card-nonce').value = nonce;
// 本来のフォームを送信します
document.getElementById('nonce-form').submit();
},
// サポート外のぶらず艶アクセ視した場合
unsupportedBrowserDetected: function() {
},
// イベントハンドリング
inputEventReceived: function(inputEvent) {
},
// フォームを読み込んだ後のコールバック
paymentFormLoaded: function() {
}
}
});
フォームを読み込む
後は最低限のデザインを整えるCSSを読み込みます。
/* Define how SqPaymentForm iframes should look */
.sq-input {
border: 1px solid rgb(223, 223, 223);
outline-offset: -2px;
margin-bottom: 5px;
display: inline-block;
}
/* Define how SqPaymentForm iframes should look when they have focus */
.sq-input--focus {
outline: 5px auto rgb(59, 153, 252);
}
/* Define how SqPaymentForm iframes should look when they contain invalid values */
.sq-input--error {
outline: 5px auto rgb(255, 97, 97);
}
/* Customize the "Pay with Credit Card" button */
.button-credit-card {
min-width: 200px;
min-height: 20px;
padding: 0;
margin: 5px;
line-height: 20px;
box-shadow: 2px 2px 1px rgb(200, 200, 200);
background: rgb(255, 255, 255);
border-radius: 5px;
border: 1px solid rgb(200, 200, 200);
font-weight: bold;
cursor:pointer;
}
/* Customize the "{{Wallet}} not enabled" message */
.wallet-not-enabled {
min-width: 200px;
min-height: 40px;
max-height: 64px;
padding: 0;
margin: 10px;
line-height: 40px;
background: #eee;
border-radius: 5px;
font-weight: lighter;
font-style: italic;
font-family: inherit;
display: block;
}
/* Customize the Apple Pay on the Web button */
.button-apple-pay {
min-width: 200px;
min-height: 40px;
max-height: 64px;
padding: 0;
margin: 10px;
background-image: -webkit-named-image(apple-pay-logo-white);
background-color: black;
background-size: 100% 60%;
background-repeat: no-repeat;
background-position: 50% 50%;
border-radius: 5px;
cursor:pointer;
display: none;
}
/* Customize the Masterpass button */
.button-masterpass {
min-width: 200px;
min-height: 40px;
max-height: 40px;
padding: 0;
margin: 10px;
background-image: url(https://static.masterpass.com/dyn/img/btn/global/mp_chk_btn_147x034px.svg);
background-color: black;
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: 50% 50%;
border-radius: 5px;
border-color: rgb(255, 255, 255);
cursor:pointer;
display: none;
}
#sq-walletbox {
float:left;
margin:5px;
padding:10px;
text-align: center;
vertical-align: top;
font-weight: bold;
}
#sq-ccbox {
float:left;
margin:5px;
padding:10px;
text-align: center;
vertical-align: top;
font-weight: bold;
}
これで画面が完成です。
process-card.php の修正
実際に決済処理を行う process-card.php では以下の行を修正します。これは Square Developer Portal で取得できるアクセストークンと置き換えるだけです。本番であれば Personal Access Token の値を、開発環境であればサンドボックスのアクセストークン Sandbox Access Token を使います。
// 元
$access_token = 'REPLACE_ME';
// 修正後
$access_token = 'sandbox-sq0...ZBQ';
実際の決済処理は以下のコードで行われています。
$transactions_api = new \SquareConnect\Api\TransactionsApi();
$request_body = array (
"card_nonce" => $nonce,
"amount_money" => array (
"amount" => 100,
"currency" => "JPY"
),
"idempotency_key" => uniqid()
);
$result = $transactions_api->charge($location->getId(), $request_body);
echo "<pre>";
print_r($result);
echo "</pre>";
試す
では実際に試してみます。以下のコマンドで簡易的なPHPアプリケーションサーバが http://localhost:8080/ で立ち上がります。
$ php -S localhost:8080
Webブラウザで http://localhost:8080/ を開いて、以下の情報を入力してみましょう。
名前 | 値 |
---|---|
カード番号 | 4532759734545858 |
有効期限 | 12/20 |
CVV | 111 |
郵便番号 | 111111 |
カードで支払うボタンを押すと、まずSquareのサーバにクレジットカード情報が送信されて、代わりに nonce を受け取ります。そして、そのまま nonce をPHPへ送信して決済処理を実行します。
特に問題がなければTransactionオブジェクトのダンプが表示されます。
このような手順でPHP向けのWebアプリケーションに決済処理を追加できます。Webフォームのデザインは自由に設計できますので、既存のサービスに組み込んでも違和感なく使えるはずです。実装例としては、例えばWordPressにEコマース機能を追加する WooCommerce — WordPress プラグイン があります。こちらを使うと簡単にSquareの決済機能が使えるようになります。ぜひ試してみてください。
今回のコードは goofmint/SquareCommercePHPDemo: SquareのEコマースAPIをPHPで行うデモです。 にて公開しています。もし試してみて分からないところがあれば Teratail にて質問してください!