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.0、ext-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 列表由上游模型决定(如 violence、hate、sexual、self-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