Skip to content

PHP 服务端 SDK

官方 PHP 服务端 SDK —— Packagist 包名 captchala/captchala-php

SDK 帮你做三件事:

  1. 校验(Validate)—— 验证浏览器 SDK 返回的 pt_ pass token。
  2. 签发(Issue)—— 签发一次性 sct_ server token,将本次挑战绑定到具体 action / IP / UID。
  3. 审核(Moderate)—— 多模态(文本 + 图片)内容审核,走 dashboard 同款 OpenAI 兼容管道。

安装

bash
composer require captchala/captchala-php

依赖:PHP ≥ 8.0ext-json。优先用 cURL,缺失则 fallback 到 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());   // 例: token_expired
}
// 验证通过, 继续业务流程
// $result->getCaptchaArgs() 含 platform / user_ip / referer / pkg / solved_at / risk_score

// 取 CDN / 反代背后的真实终端用户 IP
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 传给组件。token 单次消费, 绑定 action, 可选绑定 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()) {
    // 上游模型判定违规, 看是哪个 category
    if ($result->hasCategory('violence', 'csam')) {
        // 硬阻断
    }
}

纯文本快捷方式:

php
$result = $client->moderationText('user comment here', userId: $user->id);

Category 列表由上游模型决定(如 violencehatesexualself-harm),用 getCategories() 防御性遍历, 不要硬编码固定集合。

Result 类

方法
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