secretKey = $secretKey ?: _CRED_TURNSTILE_SECRET_KEY_; $this->timeout = $timeout; } /** * Valide un token Turnstile * * @param string $token Le token à valider * @param string $remoteip L'adresse IP du client (optionnel) * @param string $idempotencyKey Clé d'idempotence pour éviter les doublons (optionnel) * @return array Résultat de la validation */ public function validate($token, $remoteip = null, $idempotencyKey = null) { // Validation des paramètres d'entrée if (empty($token) || !is_string($token)) { return [ 'success' => false, 'error' => 'Token manquant ou invalide', 'error_codes' => ['missing-input-response'] ]; } if (strlen($token) > 2048) { return [ 'success' => false, 'error' => 'Token trop long', 'error_codes' => ['invalid-input-response'] ]; } // Préparation de la requête $url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; $postData = [ 'secret' => $this->secretKey, 'response' => $token ]; if (!empty($remoteip)) { $postData['remoteip'] = $remoteip; } if (!empty($idempotencyKey)) { $postData['idempotency_key'] = $idempotencyKey; } // Configuration cURL $ch = curl_init($url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->timeout); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/x-www-form-urlencoded' ]); // Exécution de la requête $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); // Gestion des erreurs cURL if ($response === false) { error_log('Turnstile validation cURL error: ' . $curlError); return [ 'success' => false, 'error' => 'Erreur de connexion au service Turnstile', 'error_codes' => ['internal-error'] ]; } // Vérification du code HTTP if ($httpCode !== 200) { error_log('Turnstile validation HTTP error: ' . $httpCode); return [ 'success' => false, 'error' => 'Erreur du service Turnstile (HTTP ' . $httpCode . ')', 'error_codes' => ['internal-error'] ]; } // Décodage de la réponse JSON $result = json_decode($response, true); if (json_last_error() !== JSON_ERROR_NONE) { error_log('Turnstile validation JSON decode error: ' . json_last_error_msg()); return [ 'success' => false, 'error' => 'Erreur de parsing de la réponse Turnstile', 'error_codes' => ['internal-error'] ]; } // Validation du succès if (!isset($result['success'])) { error_log('Turnstile validation missing success field in response'); return [ 'success' => false, 'error' => 'Réponse invalide du service Turnstile', 'error_codes' => ['internal-error'] ]; } return $result; } /** * Valide un token avec gestion d'erreurs formatée pour l'affichage * * @param string $token Le token à valider * @param string $remoteip L'adresse IP du client (optionnel) * @return array Résultat formaté pour l'affichage */ public function validateForDisplay($token, $remoteip = null) { $result = $this->validate($token, $remoteip); if ($result['success']) { return [ 'valid' => true, 'message' => '', 'data' => $result ]; } // Mapping des erreurs pour l'affichage utilisateur $errorMessages = [ 'missing-input-secret' => 'Configuration Turnstile invalide.', 'invalid-input-secret' => 'Configuration Turnstile invalide.', 'missing-input-response' => 'Vérification de sécurité manquante. Veuillez cocher la case "Je ne suis pas un robot".', 'invalid-input-response' => 'Vérification de sécurité invalide. Veuillez réessayer.', 'bad-request' => 'Requête de vérification invalide.', 'timeout-or-duplicate' => 'Vérification de sécurité expirée. Veuillez réessayer.', 'internal-error' => 'Erreur temporaire du service de sécurité. Veuillez réessayer dans quelques instants.' ]; $errorCodes = isset($result['error-codes']) ? $result['error-codes'] : ['internal-error']; $errorCode = reset($errorCodes); // Premier code d'erreur $message = isset($errorMessages[$errorCode]) ? $errorMessages[$errorCode] : 'Erreur de vérification de sécurité inconnue.'; return [ 'valid' => false, 'message' => $message, 'error_codes' => $errorCodes, 'data' => $result ]; } /** * Vérifie si Turnstile est correctement configuré * * @return bool True si configuré, false sinon */ public static function isConfigured() { return defined('_CRED_TURNSTILE_SECRET_KEY_') && _CRED_TURNSTILE_SECRET_KEY_ !== '' && _CRED_TURNSTILE_SECRET_KEY_ !== 'YOUR_SECRET_KEY_HERE' && defined('_CRED_TURNSTILE_SITE_KEY_') && _CRED_TURNSTILE_SITE_KEY_ !== '' && _CRED_TURNSTILE_SITE_KEY_ !== 'YOUR_SITE_KEY_HERE'; } }