Skip to content

PHP Server SDK

公式の PHP サーバーサイド SDK。Packagist に 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.0ext-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_tokenbind_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);

カテゴリはモデル側で定義されます(例: violencehatesexualself-harm)。固定セットを決め打ちせず、getCategories() をディフェンシブに走査してください。

結果クラス

クラスメソッド
ValidateResultisValid()getError()getUid()getChallengeId()getAction()isOffline()isClientOnly()getWarning()toArray()
IssueResultisOk()getToken()getExpiresIn()getIssuedAt()getError()getMessage()toArray()
ModerationResultisOk()isFlagged()hasCategory(...$names)getCategories()getContentType()getRaw()getError()getMessage()toArray()

リンク

MIT-licensed examples · CaptchaLa is operated independently