Skip to content

PHP Server SDK

공식 PHP 서버 측 SDK입니다. Packagist에 captchala/captchala-php 로 배포되어 있습니다.

SDK가 대신 처리해 주는 세 가지 작업:

  1. Validate — 브라우저 SDK에서 받은 pt_ pass token 을 검증합니다.
  2. Issue — 다가올 챌린지를 특정 액션 / IP / UID 에 바인딩하는 일회용 sct_ server token 을 발급합니다.
  3. Moderate — 대시보드가 사용하는 동일한 OpenAI 호환 파이프라인을 통한 멀티모달(텍스트 + 이미지) 콘텐츠 모더레이션을 수행합니다.

설치

bash
composer require captchala/captchala-php

PHP ≥ 8.0ext-json 이 필요합니다. cURL이 사용 가능하면 cURL을, 그렇지 않으면 file_get_contents 로 폴백합니다.

Validate (pt_ 토큰)

최종 사용자의 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_tokenbind_uid 와 함께 발급했다면, 반환된 uid 를 실제로 기대하는 사용자와 비교하십시오:

php
if ($result->getUid() !== $expectedUserId) {
    http_response_code(400);
    exit('user mismatch');
}

Server token 발급

가치가 높은 플로우(로그인, 회원가입, 결제)에서 권장되는 패턴은 다음과 같습니다: 백엔드가 일회용 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()];  // 브라우저로 전달

콘텐츠 모더레이션

멀티모달 — OpenAI 호환 형식의 텍스트 및 이미지 URL 조합을 입력으로 받습니다:

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, transport failure, ...
    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() 를 방어적으로 순회하십시오.

결과 클래스

ClassMethods
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