Skip to content

HumanChallenge

Viames Marino edited this page May 2, 2026 · 1 revision

Pair framework: HumanChallenge

Pair\Services\HumanChallenge is the provider-neutral anti-bot helper for Pair forms.

It can select Cloudflare Turnstile or Google reCAPTCHA from configuration and gives applications one rendering and verification API. Use it when a form should support either Turnstile or a conventional CAPTCHA without hard-coding the provider in the module.

Configuration

Provider selection is controlled by PAIR_HUMAN_CHALLENGE_PROVIDER:

  • auto selects Turnstile when Turnstile keys are present, then reCAPTCHA when reCAPTCHA keys are present, otherwise disables the challenge
  • turnstile forces Cloudflare Turnstile
  • recaptcha or captcha forces Google reCAPTCHA
  • none, off, false, or disabled disables rendering and validation

Turnstile uses:

  • CLOUDFLARE_TURNSTILE_SITE_KEY
  • CLOUDFLARE_TURNSTILE_SECRET_KEY
  • CLOUDFLARE_TURNSTILE_VERIFY_URL
  • CLOUDFLARE_TURNSTILE_RESPONSE_FIELD
  • CLOUDFLARE_TURNSTILE_TIMEOUT
  • CLOUDFLARE_TURNSTILE_CONNECT_TIMEOUT

Google reCAPTCHA uses:

  • GOOGLE_RECAPTCHA_SITE_KEY
  • GOOGLE_RECAPTCHA_SECRET_KEY
  • GOOGLE_RECAPTCHA_VERIFY_URL
  • GOOGLE_RECAPTCHA_RESPONSE_FIELD
  • GOOGLE_RECAPTCHA_TIMEOUT
  • GOOGLE_RECAPTCHA_CONNECT_TIMEOUT

Rendering

Register the provider script once on pages that render the widget:

use Pair\Services\HumanChallenge;

$challenge = new HumanChallenge();
$challenge->loadScript($this->app, ['language' => 'it']);

Render the widget in a form:

print $challenge->widgetHtml([
	'action' => 'contact_form',
]);

Turnstile widgets rendered through HumanChallenge default to appearance=interaction-only and theme=auto. reCAPTCHA widgets default to the visible checkbox.

Pair forms can render the same widget with a form control:

$form->humanChallenge()->action('contact_form');

Verification

Validate the provider token on the server before doing the write:

use Pair\Services\HumanChallenge;

$challenge = new HumanChallenge();

$result = $challenge->assertPost($_POST, $_SERVER['REMOTE_ADDR'] ?? null, [
	'expectedAction' => 'contact_form',
	'expectedHostname' => $_SERVER['HTTP_HOST'] ?? '',
]);

assertPost() throws a PairException with ErrorCodes::HUMAN_CHALLENGE_ERROR when the selected provider rejects the token or when optional action/hostname checks fail.

Clone this wiki locally