PHP Classes

How to Use A PHP Cloudflare Turnstile Package to Avoid Accesses From Robots to Sites Using the Package Cloudflare Turnstile: Verify human users with Cloudflare Turnstile

Recommend this page to a friend!
  Info   Documentation   View files Files   Install with Composer Install with Composer   Download Download   Reputation   Support forum   Blog    
Last Updated Ratings Unique User Downloads Download Rankings
2025-01-23 (2 months ago) RSS 2.0 feedNot yet rated by the usersTotal: Not yet counted Not yet ranked
Version License PHP version Categories
cloudflare-turnstile 1.0MIT/X Consortium ...5Web services, Validation, PHP 7
Description 

Author

This package can verify human users with Cloudflare Turnstile.

It can create a configuration to verify the challenges of the Cloudflare Turnstile using its API.

The package can call the API and return whether the user passed the human verification challenges.

Picture of Eric Sizemore
  Performance   Level  
Name: Eric Sizemore <contact>
Classes: 18 packages by
Country: United States United States
Innovation award
Innovation award
Nominee: 5x

Winner: 3x

Instructions

Documentation

PHP Cloudflare Turnstile Client

Build Status Code Coverage Scrutinizer Code Quality PHP Version Continuous Integration Type Coverage Psalm Level Mutation testing badge Latest Stable Version Downloads per Month License Coding Standards Coding Standards

ericsizemore/cloudflare-turnstile - A PHP library for server-side validation of Cloudflare Turnstile challenges. This library is PSR-18 compatible and framework-agnostic.

> [!IMPORTANT] > WIP: This library is not yet finished. Not recommended for production yet.

>[!NOTE] > This library requires additional libraries to work successfully. Please see below.

---

Requirements

  • PHP >= 8.2
  • Composer
  • One of each: * PSR-7 HTTP Message implementation * PSR-17 HTTP Factory implementation * PSR-18 HTTP Client implementation

Installation

This library is decoupled from any HTTP messaging client by using PSR-7, PSR-17, and PSR-18.

You can install the package via composer:

# First, install the base package
composer require esi/cloudflare-turnstile

# Then install your preferred PSR implementations. See 'PSR Implementation Libraries' below. For example:

# Option 1: Using Symfony components (recommended for Symfony projects)
composer require symfony/http-client:^7.0 symfony/psr-http-message-bridge:^7.0 nyholm/psr7:^1.0

# Option 2: Using Guzzle (recommended for Laravel projects)
composer require guzzlehttp/guzzle:^7.0

# Option 3: Using Laminas
composer require laminas/laminas-diactoros:^3.0 php-http/curl-client:^2.0

# Option 4: Using PHPHttp
composer require nyholm/psr7:^1.0 php-http/curl-client:^2.0

# Option 5: Using Buzz
composer require kriswallsmith/buzz:^1.3 nyholm/psr7:^1.0

# There are various combinations. Guzzle is all in one, while there are various combinations between Symfony, Laminas, PHPHttp, NyHolm, etc.

PSR Implementation Libraries

Below are some recommended libraries that implement the required PSR interfaces. You'll need one implementation of each PSR to use this library.

PSR-7: HTTP Message Interface

HTTP message and URI interface implementations:

PSR-17: HTTP Factories

Factory interfaces for PSR-7:

PSR-18: HTTP Client

HTTP Client implementations:

Notes
  • Guzzle provides all required PSR implementations in one package.
  • Symfony HTTP Client requires a PSR-7 implementation (like Nyholm) to work as PSR-18.
  • PHP-HTTP Curl/Socket Client requires a PSR-7/17 implementation to be installed (like Nyholm or guzzlehttp/psr7).
  • Some combinations might require additional bridges or adapters.

PSR Implementation Compatibility Matrix

| PSR-18 HTTP Client | PSR-7/17 Implementation | Additional Requirements | |---------------------|-------------------------|-------------------------| | Guzzle | Built-in | None | | Symfony HTTP Client | Nyholm PSR-7 | psr-http-message-bridge | | PHP-HTTP Curl | Any PSR-7/17 | None | | Buzz | Any PSR-7/17 | None | | Socket Client | Any PSR-7/17 | None |

Example Installation

Using Symfony components:

composer require esi/cloudflare-turnstile symfony/http-client:^7.0 symfony/psr-http-message-bridge:^7.0 nyholm/psr7:^1.0

Using Guzzle:

composer require esi/cloudflare-turnstile guzzlehttp/guzzle:^7.0

Using Laminas:

composer require esi/cloudflare-turnstile laminas/laminas-diactoros:^3.0 php-http/curl-client:^2.0

Usage

Basic Usage

use Esi\CloudflareTurnstile\Turnstile;
use Esi\CloudflareTurnstile\Exceptions\ValueObjectInvalidValueException;
use Esi\CloudflareTurnstile\ValueObjects\SecretKey;
use Esi\CloudflareTurnstile\ValueObjects\Token;
use Esi\CloudflareTurnstile\VerifyConfiguration;
use Psr\Http\Client\ClientExceptionInterface;

/
 * // Using Guzzle
 * use GuzzleHttp\Client;
 * use GuzzleHttp\Psr7\HttpFactory;
 * 
 * $client = new Client();
 * $factory = new HttpFactory();
 * $turnstile = new Turnstile($client, $factory, $factory, new SecretKey('your-secret-key'));
 * 
 * // Using Symfony HTTP Client
 * use Symfony\Component\HttpClient\Psr18Client;
 * use Nyholm\Psr7\Factory\Psr17Factory;
 * 
 * $client = new Psr18Client();
 * $factory = new Psr17Factory();
 * $turnstile = new Turnstile($client, $factory, $factory, new SecretKey('your-secret-key'));
 * 
 * // Using PHP-HTTP Curl Client
 * use Http\Client\Curl\Client;
 * use Nyholm\Psr7\Factory\Psr17Factory;
 * 
 * $factory = new Psr17Factory();
 * $client = new Client();
 * $turnstile = new Turnstile($client, $factory, $factory, new SecretKey('your-secret-key'));
 */
 
// Initialize with your preferred PSR-18 client and PSR-17 factories
$httpClient = new \Your\Preferred\HttpClient();
$requestFactory = new \Your\Preferred\RequestFactory();
$streamFactory = new \Your\Preferred\StreamFactory();

try {
    // Create the Turnstile client
    $turnstile = new Turnstile(
        $httpClient,
        $requestFactory,
        $streamFactory,
        new SecretKey('your-secret-key')
    );

    // Create configuration with the response token from the frontend
    $config = new VerifyConfiguration(
        new Token('response-token-from-widget')
    );

    $response = $turnstile->verify($config);
    
    if ($response->isSuccess()) {
        // Verification successful
        echo 'Challenge passed!';
    } else {
        // Verification failed
        echo 'Challenge failed: ' . implode(', ', $response->getErrorCodes());
    }
} catch (ValueObjectInvalidValueException $e) {
    // Handle an invalid value being passed to Token, IpAddress, or SecretKey
    echo 'Config Error: ' . $e->getMessage();
} catch (\RuntimeException $e) {
    // Handle JSON decode errors
    echo 'Error: ' . $e->getMessage();
} catch (ClientExceptionInterface $e) {
    // Handle HTTP client errors
    echo 'HTTP Error: ' . $e->getMessage();
}

Advanced Usage

Using all available options.

use Esi\CloudflareTurnstile\Turnstile;
use Esi\CloudflareTurnstile\Exceptions\ValueObjectInvalidValueException;
use Esi\CloudflareTurnstile\ValueObjects\IdempotencyKey;
use Esi\CloudflareTurnstile\ValueObjects\IpAddress;
use Esi\CloudflareTurnstile\ValueObjects\SecretKey;
use Esi\CloudflareTurnstile\ValueObjects\Token;
use Esi\CloudflareTurnstile\VerifyConfiguration;

// Initialize with your preferred PSR-18 client and PSR-17 factories
$httpClient = new \Your\Preferred\HttpClient();
$requestFactory = new \Your\Preferred\RequestFactory();
$streamFactory = new \Your\Preferred\StreamFactory();

try {
    // Create the Turnstile client
    $turnstile = new Turnstile(
        $httpClient,
        $requestFactory,
        $streamFactory,
        new SecretKey('your-secret-key')
    );

    // Create configuration with all available options
    $config = new VerifyConfiguration(
        new Token('response-token-from-widget'),
        new IpAddress('127.0.0.1'),              // Optional: Client IP address
        new IdempotencyKey('unique-request-id'), // Optional: Idempotency key
        [                                        // Optional: Custom data
            'action' => 'login',
            'cdata' => 'custom-verification-data'
        ]
    );

    $response = $turnstile->verify($config);

    if ($response->isSuccess()) {
        // Verification successful
        echo 'Challenge passed!';
    } else {
        // Verification failed
        echo 'Challenge failed: ' . implode(', ', $response->getErrorCodes());
    }
} catch (ValueObjectInvalidValueException $e) {
    // Handle an invalid value being passed to Token, IpAddress, or SecretKey
    echo 'Config Error: ' . $e->getMessage();
} catch (\RuntimeException $e) {
    // Handle JSON decode errors
    echo 'Error: ' . $e->getMessage();
} catch (ClientExceptionInterface $e) {
    // Handle HTTP client errors
    echo 'HTTP Error: ' . $e->getMessage();
}

Reading the response.

The response object provides several methods to access verification details:

$response = $turnstile->verify($config);

// Basic verification status
$success = $response->isSuccess();

// Timestamp of the challenge
$timestamp = $response->getChallengeTs();

// Hostname where the challenge was solved
$hostname = $response->getHostname();

// Any error codes returned
$errorCodes = $response->getErrorCodes();

// Optional action name (if set in widget)
$action = $response->getAction();

// Optional custom data (if provided)
$customData = $response->getCdata();

// Enterprise only: metadata
$metadata = $response->getMetadata();

// Access the raw response data
$rawData = $response->getRawData();

Framework Integration Examples

See docs/laravel.md and docs/symfony.md.

More Information

Frequently Asked Questions

See docs/faq.md.

Performance Considerations

See docs/performance.md.

Troubleshooting

See docs/troubleshooting.md.

About

Credits

Contributing

See CONTRIBUTING.

Bugs and feature requests are tracked on GitHub.

Contributor Covenant Code of Conduct

See CODE_OF_CONDUCT.md

Backward Compatibility Promise

See backward-compatibility.md for more information on Backwards Compatibility.

Changelog

See the CHANGELOG for more information on what has changed recently.

License

See the LICENSE for more information on the license that applies to this project.

TODO

See TODO for more information on what is planned for future releases.

Security

See SECURITY for more information on the security disclosure process.


  Files folder image Files (48)  
File Role Description
Files folder image.github (2 files, 2 directories)
Files folder imagedocs (5 files)
Files folder imagesrc (3 files, 2 directories)
Files folder imagetests (2 directories)
Accessible without login Plain text file .php-cs-fixer.dist.php Example Example script
Accessible without login Plain text file .scrutinizer.yml Data Auxiliary data
Accessible without login Plain text file backward-compatibility.md Data Auxiliary data
Accessible without login Plain text file CHANGELOG.md Data Auxiliary data
Accessible without login Plain text file CODE_OF_CONDUCT.md Data Auxiliary data
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file composer.lock Data Auxiliary data
Accessible without login Plain text file CONTRIBUTING.md Data Auxiliary data
Accessible without login Plain text file infection.json5 Data Auxiliary data
Accessible without login Plain text file LICENSE Lic. License text
Accessible without login Plain text file phpstan.neon Data Auxiliary data
Accessible without login Plain text file phpunit.xml Data Auxiliary data
Accessible without login Plain text file psalm.xml Data Auxiliary data
Accessible without login Plain text file README.md Doc. Documentation
Plain text file rector.php Class Class source
Accessible without login Plain text file renovate.json Data Auxiliary data
Accessible without login Plain text file SECURITY.md Data Auxiliary data
Accessible without login Plain text file TODO.md Data Auxiliary data

  Files folder image Files (48)  /  .github  
File Role Description
Files folder imageISSUE_TEMPLATE (3 files)
Files folder imageworkflows (3 files)
  Accessible without login Plain text file FUNDING.yml Data Auxiliary data
  Accessible without login Plain text file pull_request_template.md Data Auxiliary data

  Files folder image Files (48)  /  .github  /  ISSUE_TEMPLATE  
File Role Description
  Accessible without login Plain text file 1-bug_report.yml Data Auxiliary data
  Accessible without login Plain text file 2-feature_request.yml Data Auxiliary data
  Accessible without login Plain text file config.yml Data Auxiliary data

  Files folder image Files (48)  /  .github  /  workflows  
File Role Description
  Accessible without login Plain text file continuous-integration.yml Data Auxiliary data
  Accessible without login Plain text file merge-me.yml Data Auxiliary data
  Accessible without login Plain text file release.yml Data Auxiliary data

  Files folder image Files (48)  /  docs  
File Role Description
  Accessible without login Plain text file faq.md Data Auxiliary data
  Accessible without login Plain text file laravel.md Data Auxiliary data
  Accessible without login Plain text file performance.md Data Auxiliary data
  Accessible without login Plain text file symfony.md Data Auxiliary data
  Accessible without login Plain text file troubleshooting.md Data Auxiliary data

  Files folder image Files (48)  /  src  
File Role Description
Files folder imageExceptions (1 file)
Files folder imageValueObjects (4 files)
  Plain text file Response.php Class Class source
  Plain text file Turnstile.php Class Class source
  Plain text file VerifyConfiguration.php Class Class source

  Files folder image Files (48)  /  src  /  Exceptions  
File Role Description
  Plain text file ValueObjectInvalidValueException.php Class Class source

  Files folder image Files (48)  /  src  /  ValueObjects  
File Role Description
  Plain text file IdempotencyKey.php Class Class source
  Plain text file IpAddress.php Class Class source
  Plain text file SecretKey.php Class Class source
  Plain text file Token.php Class Class source

  Files folder image Files (48)  /  tests  
File Role Description
Files folder imageIntegration (1 directory)
Files folder imageUnit (3 files, 1 directory)

  Files folder image Files (48)  /  tests  /  Integration  
File Role Description
Files folder imageHttpClient (2 files)

  Files folder image Files (48)  /  tests  /  Integration  /  HttpClient  
File Role Description
  Plain text file GuzzleIntegrationTest.php Class Class source
  Plain text file SymfonyClientIntegrationTest.php Class Class source

  Files folder image Files (48)  /  tests  /  Unit  
File Role Description
Files folder imageValueObjects (4 files)
  Plain text file ResponseTest.php Class Class source
  Plain text file TurnstileTest.php Class Class source
  Plain text file VerifyConfigurationTest.php Class Class source

  Files folder image Files (48)  /  tests  /  Unit  /  ValueObjects  
File Role Description
  Plain text file IdempotencyKeyTest.php Class Class source
  Plain text file IpAddressTest.php Class Class source
  Plain text file SecretKeyTest.php Class Class source
  Plain text file TokenTest.php Class Class source

The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page.
Install with Composer Install with Composer
 Version Control Unique User Downloads  
 100%
Total:0
This week:0