Php/アプリストア連携/返金API/GooglePlayStore/RTDN
提供: 初心者エンジニアの簡易メモ
Google Play Consoleでの設定
- Google Play Consoleにログイン
- 「Monetization」 > 「Monetization setup」に移動
- 「Real-time developer notifications」セクションで通知を受け取るエンドポイントURLを設定
php実行準備
Firebase JWTを使用する場合
composer require firebase/php-jwt
phpサンプル
require_once 'vendor/autoload.php';
use phpseclib3\Crypt\PublicKeyLoader;
// Google Playの公開鍵を取得(キャッシュ推奨)
function getGooglePublicKey($keyId) {
$jwksUrl = 'https://www.googleapis.com/oauth2/v3/certs';
// キャッシュの実装(上記と同じ)
foreach ($jwks['keys'] as $key) {
if ($key['kid'] === $keyId) {
return PublicKeyLoader::load($key)->toString('PKCS8');
}
}
return null;
}
// JWTの検証
function verifyJwt($jwt) {
list($header, $payload, $signature) = explode('.', $jwt);
$header = json_decode(base64_decode($header), true);
$payload = json_decode(base64_decode($payload), true);
// 公開鍵を取得
$publicKey = getGooglePublicKey($header['kid']);
if (!$publicKey) {
return false;
}
// 署名検証
$data = "$header.$payload";
$signature = base64_decode(str_replace(['-', '_'], ['+', '/'], $signature));
$result = openssl_verify($data, $signature, $publicKey, 'SHA256');
return $result === 1 ? $payload : false;
}
// メイン処理
function handleRtdnNotification() {
// リクエストボディを取得
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!$data || !isset($data['message']['data'])) {
http_response_code(400);
exit;
}
// JWTをデコード
$jwt = base64_decode($data['message']['data']);
$payload = verifyJwt($jwt);
if (!$payload) {
http_response_code(401);
exit;
}
// 通知タイプに応じて処理
$notificationType = $payload['eventType'];
$subscriptionId = $payload['subscriptionNotification']['subscriptionId'];
$purchaseToken = $payload['subscriptionNotification']['purchaseToken'];
switch ($notificationType) {
case 'SUBSCRIPTION_CANCELED':
// 定期購入がキャンセルされた
handleSubscriptionCanceled($subscriptionId, $purchaseToken);
break;
case 'SUBSCRIPTION_PURCHASED':
// 新しい定期購入
handleSubscriptionPurchased($subscriptionId, $purchaseToken);
break;
case 'SUBSCRIPTION_RENEWED':
// 定期購入が更新された
handleSubscriptionRenewed($subscriptionId, $purchaseToken);
break;
case 'SUBSCRIPTION_REVOKED':
// 返金または管理者によるキャンセル
handleSubscriptionRevoked($subscriptionId, $purchaseToken);
break;
case 'SUBSCRIPTION_RESTARTED':
// ユーザーがキャンセル後に再開
handleSubscriptionRestarted($subscriptionId, $purchaseToken);
break;
default:
// 未知の通知タイプ
http_response_code(400);
exit;
}
// 成功レスポンス
http_response_code(200);
}
// 返金処理(SUBSCRIPTION_REVOKED)
function handleSubscriptionRevoked($subscriptionId, $purchaseToken) {
// 1. Google Play Developer APIを使用して購入情報を取得
$purchaseInfo = getSubscriptionPurchaseInfo($subscriptionId, $purchaseToken);
// 2. 返金理由を確認
$revocationReason = $purchaseInfo['revocationReason'] ?? null;
// 3. ユーザーアカウントを更新(アクセス権限を削除など)
$userId = getUserIdFromPurchaseToken($purchaseToken);
revokeUserAccess($userId);
// 4. データベースに返金記録を保存
logRefund($userId, $subscriptionId, $purchaseToken, $revocationReason);
// 5. 必要に応じてユーザーに通知
sendRefundNotification($userId);
}
// Google Play Developer APIから購入情報を取得
function getSubscriptionPurchaseInfo($subscriptionId, $purchaseToken) {
// 実際にはここでGoogle Play Developer APIを呼び出す
// 必要な認証情報などを設定
// 簡易実装(実際にはAPI呼び出しが必要)
return [
'revocationReason' => 1, // 1: 返金, 2: 管理者によるキャンセル
// その他の購入情報...
];
}
// その他のヘルパー関数...
// メイン処理を実行
handleRtdnNotification();
