Skip to content

PHP Server SDK

官方 PHP 伺服器端 SDK — 於 Packagist 發佈為 captchala/captchala-php

SDK 為您處理三項任務:

  1. 驗證(Validate) — 校驗來自瀏覽器 SDK 的 pt_ pass token。
  2. 簽發(Issue) — 簽發一次性 sct_ server token,將即將發起的 challenge 綁定到特定 action / IP / UID。
  3. 內容審核(Moderate) — 多模態(文字 + 圖片)內容審核,與控制台共用同一條 OpenAI 相容管線。

安裝

bash
composer require captchala/captchala-php

需要 PHP ≥ 8.0 並啟用 ext-json。可用時使用 cURL,否則回退至 file_get_contents

驗證(pt_ token)

請將終端使用者的 IP 作為第三個參數傳入(取自 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 token

高價值流程(登入、註冊、支付)建議採用以下模式: 後端簽發一次性 sct_ token,交給瀏覽器,瀏覽器作為 serverToken prop 傳遞。 每個 token 為單次使用、限定 action,亦可於簽發時綁定 IP / UID。

php
$issue = $client->issueServerToken(
    action:    'login',
    bindingIp: $request->ip(),
    ttl:       300,         // seconds; default 300
    maxUses:   5,           // SDK retry budget
    bindUid:   $user->id,   // pair with ValidateResult::getUid() on verify
);

if (!$issue->isOk()) {
    return ['error' => $issue->getError()];   // rate_limit_exceeded, invalid_action, ...
}

return ['server_token' => $issue->getToken()];  // hand to browser

內容審核

多模態 — 接受 OpenAI 相容格式下混合的文字與圖片 URL:

php
$result = $client->moderationCheck([
    ['type' => 'text', 'text' => $userComment],
    ['type' => 'image_url', 'image_url' => ['url' => $uploadedImageUrl]],
], userId: $user->id);

if (!$result->isOk()) {
    // request error: invalid_credentials, no_content, transport failure, ...
    return ['error' => $result->getError()];
}

if ($result->isFlagged()) {
    // upstream model flagged; inspect categories for the why
    if ($result->hasCategory('violence', 'csam')) {
        // hard block
    }
}

純文字快捷寫法:

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