Choisir ton intégration

Sur WordPress, commence par l’extension et ses connecteurs. Ce guide concerne une application PHP personnalisée. Le core nécessite PHP 7.4+ et un navigateur avec JavaScript ; utilise une version PHP maintenue pour ton déploiement.

Installer le core et le client

composer require willybahuaud/gaitcha
npm --prefix vendor/willybahuaud/gaitcha ci
npm --prefix vendor/willybahuaud/gaitcha run build
mkdir -p public/assets
cp vendor/willybahuaud/gaitcha/dist/gaitcha.min.js public/assets/

Le build du client nécessite Node.js et npm. Si ton installation Composer ne contient pas les sources de build, construis le client depuis la même version du dépôt Gaitcha. Garde le client et le serveur sur une version compatible ; héberge le bundle sur ton site.

Configurer le serveur

Crée gaitcha-config.php hors du répertoire public. Fournis un secret aléatoire d’au moins 32 caractères via ton environnement, et un répertoire inscriptible privé pour l’anti-rejeu.

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Gaitcha\Config;
use Gaitcha\FileTokenStore;

$secret = getenv('GAITCHA_SECRET');
if (!$secret || strlen($secret) < 32) {
    throw new RuntimeException('GAITCHA_SECRET is missing or too short.');
}

return new Config([
    'secret' => $secret,
    'pow' => true,
    'anti_replay' => true,
    'token_store' => new FileTokenStore(__DIR__ . '/var/tokens.json'),
]);

Crée le répertoire var avant la première requête. Le stockage fichier convient à un trafic modéré. Pour plusieurs instances, implémente TokenStoreInterface sur un stockage partagé dont checkAndAdd() est atomique.

Exposer l’initialisation

Exemple public/captcha-init.php, avec le fichier de configuration au niveau parent. La preuve de travail exige de transmettre le JSON décodé à handleInit().

<?php
use Gaitcha\AbstractEndpoint;

$config = require dirname(__DIR__) . '/gaitcha-config.php';

/** Adaptateur JSON pour le serveur de cette application. */
final class SiteCaptchaEndpoint extends AbstractEndpoint {
    /**
     * Initialize the challenge through the core API.
     * @param array $request Decoded JSON body.
     * @return array
     */
    public function initialize(array $request): array {
        return $this->handleInit($request);
    }

    /**
     * Envoie les données du challenge.
     * @param array $data Données générées par Gaitcha.
     * @return void
     */
    protected function sendJsonResponse(array $data): void {
        echo json_encode($data);
    }
}

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    header('Allow: POST');
    exit;
}
$request = json_decode((string) file_get_contents('php://input'), true);
$endpoint = new SiteCaptchaEndpoint($config);
echo json_encode($endpoint->initialize(is_array($request) ? $request : []));

Ne mets pas cet endpoint en cache. Applique une limite de taille de requête et une limitation de débit adaptées à ton hébergement.

Ajouter le widget

<form
  data-gaitcha
  data-gaitcha-endpoint="/captcha-init.php"
  data-gaitcha-label="Je suis humain"
  method="post"
  action="/submit.php"
>
  <label for="message">Message</label>
  <textarea id="message" name="message" required></textarea>
  <button type="submit">Envoyer</button>
</form>
<script src="/assets/gaitcha.min.js" defer></script>

Le client initialise automatiquement les formulaires data-gaitcha. L’endpoint doit être sur la même origine. Pour un placement précis, crée un conteneur et référence son ID via data-gaitcha-container.

Valider avant de traiter

Dans public/submit.php, utilise la même configuration que pour l’initialisation. Ne déclenche aucune action métier avant l’acceptation.

<?php
use Gaitcha\ValidationOrchestrator;

$config = require dirname(__DIR__) . '/gaitcha-config.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit;
}
$result = (new ValidationOrchestrator($config))->validate($_POST);
if (!$result->isAccepted()) {
    http_response_code(422);
    exit('Verification failed. Please retry.');
}

// Valider les champs métier avant d'enregistrer ou d'envoyer un email.

Le captcha ne remplace ni les règles de validation des champs, ni la protection CSRF lorsque ton application en a besoin, ni la limitation de débit.

Styles et thèmes

Deux réglages indépendants permettent d’accorder le widget à ton formulaire :

  • Style : default (classique) utilise des coins arrondis, une ombre légère et des accents colorés. minimal est monochrome, avec des bordures fines et sans ombre.
  • Thème : light (par défaut), dark ou auto, qui suit la préférence du système du visiteur.

Les six combinaisons fonctionnent avec la même validation. Tu peux comparer les deux styles dans la démo.

<form data-gaitcha data-gaitcha-endpoint="/gaitcha-init.php" data-gaitcha-style="minimal" data-gaitcha-theme="auto">
  <!-- Les champs du formulaire -->
</form>

En JavaScript, passe style: 'minimal' et theme: 'auto' dans les options de Gaitcha.init(form, endpoint, options). Dans WordPress, ces réglages se trouvent dans Réglages → Gaitcha et s’appliquent à tous les connecteurs.

Le widget embarque son CSS et limite ses variables à .gaitcha-widget. Le badge devient compact dans les conteneurs étroits. Commence par ces réglages avant de surcharger les styles : le CSS du widget utilise !important pour résister à celui des constructeurs de formulaires.

Formulaires AJAX

Après un rejet AJAX, appelle instance.reset() ou Gaitcha.reset(form). Cela décoche la case, efface le journal et demande un nouveau jeton. Conserve les champs saisis par le visiteur et explique comment réessayer.

Réglages utiles

OptionDéfaut du coreRôle
secretObligatoireSignature HMAC, 32 caractères minimum
ttl120Validité du jeton en secondes
score_threshold0.5Seuil du score comportemental
powfalseChallenge avant émission du jeton
pow_difficulty18Difficulté, de 8 à 26 bits
pow_challenge_ttl90Validité du challenge en secondes
anti_replayfalseEmpêche la réutilisation avec un stockage fourni
no_js_fallbackrejectTraitement d’un jeton absent
debugfalseDétails de diagnostic ; à désactiver en production

Les rejets possibles incluent token_absent, token_invalid, token_expired, token_already_used, score_insufficient et log_malformed. N’affiche pas simplement « tu es un robot » : donne un moyen de réessayer.

Référence : README du core, fonctionnement et confidentialité.

Si l’intégration bloque, commence par le guide de dépannage.

Une question ou un cas particulier ?

Ouvrir une discussion sur GitHub