'; } function captcha_widget() { if (!captcha_enabled()) return ''; return '
'; } // Ask Google whether the captcha in this POST was solved function captcha_verify_response() { if (!captcha_enabled()) return TRUE; $response = $_POST['g-recaptcha-response'] ?? ''; if (!is_string($response) || $response === '') return FALSE; $secret = (string)config('RECAPTCHA_SECRET'); if ($secret === '') { error_log('xxx: RECAPTCHA_SECRET is not set, so every captcha check fails'); return FALSE; } $context = stream_context_create(array('http' => array( 'method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded\r\n", 'content' => http_build_query(array( 'secret' => $secret, 'response' => $response, 'remoteip' => $_SERVER['REMOTE_ADDR'] ?? '', )), 'timeout' => 10, ))); $reply = @file_get_contents('https://www.google.com/recaptcha/api/siteverify', FALSE, $context); if ($reply === FALSE) { error_log('xxx: could not reach the reCAPTCHA server'); return FALSE; } $result = json_decode($reply); return is_object($result) && !empty($result->success); } /* * For story submissions: a solved captcha counts for CAPTCHA_PASS_SECONDS * in this session, so the preview and the submit need only one captcha. * captcha_used() ends the pass once a story is saved. */ function captcha_passed() { return !empty($_SESSION['captcha_ok']) && $_SESSION['captcha_ok'] > time() - CAPTCHA_PASS_SECONDS; } function captcha_check() { if (captcha_passed()) return TRUE; if (captcha_verify_response()) { $_SESSION['captcha_ok'] = time(); return TRUE; } return FALSE; } function captcha_used() { unset($_SESSION['captcha_ok']); } ?>