--- title: PHP Server SDK --- # PHP Server SDK 公式の PHP サーバーサイド SDK。Packagist に [`captchala/captchala-php`](https://packagist.org/packages/captchala/captchala-php) として公開されています。 SDK が引き受ける 3 つの役割: 1. **Validate** — ブラウザ SDK が返した `pt_` pass トークンを検証します。 2. **Issue** — ワンタイムの `sct_` server トークンを発行し、これから出す challenge を特定のアクション / IP / UID に紐付けます。 3. **Moderate** — テキストと画像を含むマルチモーダルのコンテンツモデレーション。ダッシュボードと同じ OpenAI 互換パイプラインを使用します。 ## インストール ```bash composer require captchala/captchala-php ``` **PHP ≥ 8.0** と `ext-json` が必要です。cURL が使える環境では cURL を使い、なければ `file_get_contents` にフォールバックします。 ## Validate(`pt_` トークン) エンドユーザーの IP を第 3 引数として渡してください(`CF-Connecting-IP` / `X-Forwarded-For`、最終的には `REMOTE_ADDR` にフォールバック)。任意ですが **指定を推奨**します — 追加のリスクチェックに使われます。 ```php use Captchala\Client; $client = new Client('your_app_key', 'your_app_secret'); $result = $client->validate($_POST['captcha_token'], false, captchala_client_ip()); if (!$result->isValid()) { http_response_code(400); exit($result->getError()); // e.g. "token_expired" } // Verification passed; proceed with the request. // $result->getCaptchaArgs() has platform / user_ip / referer / pkg / solved_at / risk_score // Real end-user IP behind a CDN / proxy function captchala_client_ip(): string { foreach (['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR'] as $h) { if (!empty($_SERVER[$h])) { $ip = trim(explode(',', $_SERVER[$h])[0]); if (filter_var($ip, FILTER_VALIDATE_IP)) return $ip; } } return ''; } ``` 手元に IP がない場合は `$client->validate($_POST['captcha_token'])` を使ってください — 検証は問題なく行われ、IP ベースの追加リスクシグナルが付かないだけです。 元の `server_token` を `bind_uid` 付きで発行した場合は、返ってきた `uid` と実際に期待するユーザーを照合してください。 ```php if ($result->getUid() !== $expectedUserId) { http_response_code(400); exit('user mismatch'); } ``` ## server トークンの発行 ログイン・新規登録・決済などの重要フローでは、次のパターンを推奨します。バックエンドがワンタイムの `sct_` トークンを発行し、ブラウザに渡し、ブラウザはそれを `serverToken` prop として渡します。各トークンは単回使用・アクションスコープで、発行時に IP / UID へバインドすることもできます。 ```php $issue = $client->issueServerToken( action: 'login', bindingIp: $request->ip(), ttl: 300, // 秒。デフォルト 300 maxUses: 5, // SDK 側の再試行回数 bindUid: $user->id, // 検証時に ValidateResult::getUid() と突き合わせる ); if (!$issue->isOk()) { return ['error' => $issue->getError()]; // rate_limit_exceeded、invalid_action など } return ['server_token' => $issue->getToken()]; // ブラウザに渡す ``` ## コンテンツモデレーション マルチモーダル — テキストと画像 URL を OpenAI 互換のフォーマットで混在させて渡せます。 ```php $result = $client->moderationCheck([ ['type' => 'text', 'text' => $userComment], ['type' => 'image_url', 'image_url' => ['url' => $uploadedImageUrl]], ], userId: $user->id); if (!$result->isOk()) { // リクエスト側のエラー: invalid_credentials、no_content、通信失敗など return ['error' => $result->getError()]; } if ($result->isFlagged()) { // 上流モデルがフラグ。理由はカテゴリで確認する if ($result->hasCategory('violence', 'csam')) { // ハードブロック } } ``` プレーンテキスト向けショートカット: ```php $result = $client->moderationText('user comment here', userId: $user->id); ``` カテゴリはモデル側で定義されます(例: `violence`、`hate`、`sexual`、`self-harm`)。固定セットを決め打ちせず、`getCategories()` をディフェンシブに走査してください。 ## 結果クラス | クラス | メソッド | |---|---| | `ValidateResult` | `isValid()`、`getError()`、`getUid()`、`getChallengeId()`、`getAction()`、`isOffline()`、`isClientOnly()`、`getWarning()`、`toArray()` | | `IssueResult` | `isOk()`、`getToken()`、`getExpiresIn()`、`getIssuedAt()`、`getError()`、`getMessage()`、`toArray()` | | `ModerationResult` | `isOk()`、`isFlagged()`、`hasCategory(...$names)`、`getCategories()`、`getContentType()`、`getRaw()`、`getError()`、`getMessage()`、`toArray()` | ## リンク - [Packagist](https://packagist.org/packages/captchala/captchala-php) · [GitHub](https://github.com/Captcha-La/captchala-php) - [Web SDK 概要](/ja/web-sdk) · [API リファレンス](/ja/api-reference)