ポップアップ型だとカゴ落ちしそう
"ポップアップをブロックしているブラウザだとエラーになる"
とのこと。まずいので 3Dセキュアを リダイレクト型で使う
まず、payjpのphpライブラリを最新にしないと$token->tdsFinish();
が動かないので注意する。
流れ
kigengire2 で 決済
↓
tokenCheck で tokenのチェック
↓
comp で 3D認証を完了させる
まずは、payjp-phpを最新版に
vim composer.json
"require": {
"payjp/payjp-php": "1.*",
},
composer update payjp/payjp-php
1.7にアップデートされる
注意点
・サーバー側、view側のそれぞれAPIKEYが必要。テストと、本番用を揃えること
じゃないとtokenエラーになる
kigengire2.ctp
<script type="text/javascript">
function onCreatedToken(response) {
console.log(response);
document.querySelector('#created-token').textContent = response.id;
}
</script>
<h1>支払いフォーム例</h1>
<p>
payjp_test_key: <?=PAY_JP_TEST_KEY;?><br>
</p>
<form action="/payjp3ds/tokenCheck" method="post">
<p>おにぎり 100円</p>
<div style="display: flex; gap: 1rem; align-items: center;">
<div>
<script
type="text/javascript"
src="https://checkout.pay.jp"
class="payjp-button"
data-payjp-key="<?php echo htmlspecialchars(PAY_JP_TEST_KEY); // `pk_` から始まる公開鍵を設定してください。 ?>"
data-payjp-three-d-secure="true"
data-payjp-three-d-secure-workflow="redirect"
data-payjp-extra-attribute-email="<?=u('email');?>"
data-payjp-partial="true"
data-payjp-on-created="onCreatedToken"
></script>
</div>
<div>
<small>※ <?php echo htmlspecialchars('<input type="hidden" name="payjp-token">'); ?> の value に token が自動的にセットされます。</small><br />
<small>※ 生成されたトークン: <span id="created-token"></span></small>
</div>
</div>
<br />
<input type="hidden" name="csrf_token" value="<?php echo bin2hex(random_bytes(16)); ?>" />
<button type="submit">支払う</button>
</form>
tokenCheck.php
public function tokenCheck()
{
$secretKey = PAY_JP_TEST_SECRET;
$publicKey = PAY_JP_TEST_KEY;
$back_url = 'https://your.com/payjp3ds/comp/';
// トークンを取得
$payjpToken = $_POST['payjp-token'] ?? '';
// セッションに保存
$_SESSION['tds_input_data'] = [
'payjp_token' => $payjpToken,
];
$header = [
'alg' => 'HS256',
'typ' => 'JWT'
];
$payload = [
'url' => $back_url,
];
function base64url_encode($data) {
// 通常のBase64エンコード
$b64 = base64_encode($data);
// '+' → '-' , '/' → '_' , '=' を削除
return rtrim(strtr($b64, '+/', '-_'), '=');
}
$base64Header = base64url_encode(json_encode($header));
$base64Payload = base64url_encode(json_encode($payload));
$signature = hash_hmac(
'sha256',
$base64Header . '.' . $base64Payload,
$secretKey,
true
);
$base64Signature = base64url_encode($signature);
$jws = $base64Header . '.' . $base64Payload . '.' . $base64Signature;
header("Location: https://api.pay.jp/v1/tds/{$payjpToken}/start?publickey={$publicKey}&back_url={$jws}");
die();
}
comp.php
public function comp()
{
//3Dセキュア認証
\Payjp\Payjp::setApiKey(PAY_JP_TEST_SECRET);
$token = \Payjp\Token::retrieve($_SESSION['tds_input_data']['payjp_token']);
// 3Dセキュアフロー完了します。忘れがちなので注意してください。
$token->tdsFinish();
pr("3Dセキュア認証完了しました。");
die();
}
これで3D認証まではOK。
次は支払いとかやろう。
顧客化
hoge.php
public function _addCustomer()
{
//3Dセキュア認証
\Payjp\Payjp::setApiKey($this->config['secret']);
$token = \Payjp\Token::retrieve($_SESSION['tds_input_data']['payjp_token']);
// 3Dセキュアフロー完了します。忘れがちなので注意してください。
$token->tdsFinish();
if($token->used == false){
$customer = \Payjp\Customer::create(array(
"card" => $token->id
));
} else {
echo "トークンは使用済みです";
die();
}
return $customer->id;
}