turnstile-php
turnstile-php copied to clipboard
PHP library for Turnstile, is Cloudflare’s smart CAPTCHA alternative. It can be embedded into any website without sending traffic through Cloudflare and works without showing visitors a CAPTCHA.
Turnstile PHP client library
Inspired on recaptcha
Table of contents
- Installation
- Getting started
- Usage
- Turnstile
- Client
- Examples http clients
- Guzzle http client
- Symfony http client and Nyholm PSR-7
- Symfony http client and Guzzle PSR-7
- Symfony http client and Guzzle PSR-7 and Discovery
- Curl http client and Nyholm PSR-7
- Discovery http client
- Examples http clients
- secret key
- idempotency key
- verify
- response
- error codes to description
Installation
composer require usarise/turnstile
Getting started
Installation symfony http client and nyholm psr7 and usarise turnstile
composer require symfony/http-client nyholm/psr7 usarise/turnstile
TurnstileExample.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\HttpClient\Psr18Client;
use Turnstile\Error\Code;
use Turnstile\Turnstile;
// Get real API keys at https://dash.cloudflare.com/?to=/:account/turnstile
$siteKey = '1x00000000000000000000AA'; // Always passes (Dummy Testing)
$secretKey = '1x0000000000000000000000000000000AA'; // Always passes (Dummy Testing)
if ($token = $_POST['cf-turnstile-response'] ?? null) {
$turnstile = new Turnstile(
client: new Psr18Client(),
secretKey: $secretKey,
);
$response = $turnstile->verify(
$token, // The response provided by the Turnstile client-side render on your site.
$_SERVER['REMOTE_ADDR'], // With usage CloudFlare: $_SERVER['HTTP_CF_CONNECTING_IP']
);
if ($response->success) {
echo 'Success!';
} else {
$errors = $response->errorCodes;
var_dump($errors);
var_dump(Code::toDescription($errors));
}
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Turnstile example</title>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</head>
<body>
<form action="" method="POST">
<!-- The following line controls and configures the Turnstile widget. -->
<div class="cf-turnstile" data-sitekey="<?php echo $siteKey; ?>" data-theme="light"></div>
<!-- end. -->
<button type="submit" value="Submit">Verify</button>
</form>
</body>
</html>
Response to string
var_dump((string) $response);
Response to array
var_dump($response->toArray());
Response object to array
var_dump($response->toArray(strict: true));
Usage Turnstile
Construct
use Turnstile\Client\Client;
use Turnstile\Turnstile;
$turnstile = new Turnstile(
client: new Client(...),
secretKey: 'secret key',
idempotencyKey: 'idempotency key',
);
Simplified construct
PSR-18 Clients like php-http/discovery
$turnstile = new Turnstile(
client: new Psr18Client(),
secretKey: 'secret key',
idempotencyKey: 'idempotency key',
);
Usage Client
Construct
use Turnstile\Client\Client;
use Turnstile\TurnstileInterface;
$client = new Client(
client: ..., // implementation Psr\Http\Client\ClientInterface
requestFactory: ..., // implementation Psr\Http\Message\RequestFactoryInterface (default: requestFactory = client)
streamFactory: ..., // implementation Psr\Http\Message\StreamFactoryInterface (default: streamFactory = requestFactory)
siteVerifyUrl: TurnstileInterface::SITE_VERIFY_URL, // https://challenges.cloudflare.com/turnstile/v0/siteverify (default)
);
Examples http clients
Guzzle http client
Installation
composer require guzzlehttp/guzzle
Usage
use GuzzleHttp\Client as GuzzleHttpClient;
use GuzzleHttp\Psr7\HttpFactory;
use Turnstile\Client\Client;
$client = new Client(
new GuzzleHttpClient(),
new HttpFactory(),
);
Symfony http client and Nyholm PSR-7
Installation symfony http client and nyholm psr7
composer require symfony/http-client nyholm/psr7
Usage
use Symfony\Component\HttpClient\Psr18Client;
use Turnstile\Client\Client;
$client = new Client(
new Psr18Client(),
);
Simplified construct
use Symfony\Component\HttpClient\Psr18Client;
$client = new Psr18Client();
Symfony http client and Guzzle PSR-7
Installation symfony http client and guzzlehttp psr7
composer require symfony/http-client guzzlehttp/psr7
Usage
use GuzzleHttp\Psr7\HttpFactory;
use Symfony\Component\HttpClient\Psr18Client;
use Turnstile\Client\Client;
$client = new Client(
new Psr18Client(
responseFactory: new HttpFactory(),
),
);
Simplified construct
use GuzzleHttp\Psr7\HttpFactory;
use Symfony\Component\HttpClient\Psr18Client;
$client = new Psr18Client(
responseFactory: new HttpFactory(),
);
Symfony http client and Guzzle PSR-7 and Discovery
Installation symfony http client and guzzlehttp psr7 and php http discovery
composer require symfony/http-client guzzlehttp/psr7 php-http/discovery
Usage
use Symfony\Component\HttpClient\Psr18Client;
use Turnstile\Client\Client;
$client = new Client(
new Psr18Client(),
);
Simplified construct
use Symfony\Component\HttpClient\Psr18Client;
$client = new Psr18Client();
Curl http client and Nyholm PSR-7
Installation nyholm psr7 and php http curl client
composer require nyholm/psr7 php-http/curl-client
Usage
use Http\Client\Curl\Client as CurlClient;
use Nyholm\Psr7\Factory\Psr17Factory;
use Turnstile\Client\Client;
$psr17Factory = new Psr17Factory();
$client = new Client(
client: new CurlClient(
responseFactory: $psr17Factory,
streamFactory: $psr17Factory,
),
requestFactory: $psr17Factory,
);
Discovery http client
Installation php http discovery
composer require php-http/discovery
Usage
use Http\Discovery\Psr18Client;
use Turnstile\Client\Client;
$client = new Client(
new Psr18Client(),
);
Simplified construct
use Http\Discovery\Psr18Client;
$client = new Psr18Client();
Usage secret key
The widget’s secret key. The secret key can be found under widget settings in the Cloudflare dashboard under Turnstile.
Real keys
API keys at https://dash.cloudflare.com/?to=/:account/turnstile
Test keys
1x0000000000000000000000000000000AA Always passes
2x0000000000000000000000000000000AA Always fails
3x0000000000000000000000000000000AA Yields a “token already spent” error
Example
use Turnstile\Client\Client;
use Turnstile\Turnstile;
// Real API keys at https://dash.cloudflare.com/?to=/:account/turnstile
$secretKey = '1x0000000000000000000000000000000AA';
$turnstile = new Turnstile(
client: $client,
secretKey: $secretKey,
);
Usage idempotency key
If an application requires to retry failed requests, it must utilize the idempotency functionality.
You can do so by providing a UUID as the idempotencyKey parameter and then use $turnstile->verify(...) with the same token the required number of times.
Example with Ramsey UUID
Installation
composer require ramsey/uuid
Usage
use Ramsey\Uuid\Uuid;
use Turnstile\Client\Client;
use Turnstile\Turnstile;
$turnstile = new Turnstile(
client: $client,
secretKey: $secretKey, // The site’s secret key.
idempotencyKey: (string) Uuid::uuid4(), // The UUID to be associated with the response.
);
$response = $turnstile->verify(
$token, // The response that will be associated with the UUID (idempotencyKey)
);
if ($response->success) {
// ...
}
$response = $turnstile->verify(
$token, // The response associated with UUID (idempotencyKey)
);
if ($response->success) {
// ...
}
Usage verify
Sample
$response = $turnstile->verify(
token: $_POST['cf-turnstile-response'], // The response provided by the Turnstile client-side render on your site.
);
Remote IP
The remoteIp parameter helps to prevent abuse by ensuring the current visitor is the one who received the token.
This is currently not strictly validated.
Basic usage
$response = $turnstile->verify(
token: $_POST['cf-turnstile-response'], // The response provided by the Turnstile client-side render on your site.
remoteIp: $_SERVER['REMOTE_ADDR'], // The visitor’s IP address.
);
With usage CloudFlare
$response = $turnstile->verify(
token: $_POST['cf-turnstile-response'], // The response provided by the Turnstile client-side render on your site.
remoteIp: $_SERVER['HTTP_CF_CONNECTING_IP'], // The visitor’s IP address.
);
Extended
$response = $turnstile->verify(
...
challengeTimeout: 300, // Number of allowed seconds after the challenge was solved.
expectedHostname: $_SERVER['SERVER_NAME'], // Expected hostname for which the challenge was served.
expectedAction: 'login', // Expected customer widget identifier passed to the widget on the client side.
expectedCdata: 'sessionid-123456789', // Expected customer data passed to the widget on the client side.
);
Usage response
Success status
$response->success
Error codes
$response->errorCodes
Challenge timestamp
$response->challengeTs
Hostname
$response->hostname
Action
$response->action
Customer data
$response->cdata
To string
String with raw json data
(string) $response
To array
Decoded json data
$response->toArray()
Object to array
Array of processed json data based on properties of Response class:
success, errorCodes, challengeTs, hostname, action, cdata
$response->toArray(strict: true)
Usage error codes to description
Convert error codes to a description in a suitable language (default english)
use Turnstile\Error\{Code, Description};
var_dump(
Code::toDescription(
codes: $response->errorCodes,
descriptions: Description::TEXTS, // Default
),
);