asd
This commit is contained in:
commit
3e4a056b14
67 files changed
+13926
No files matched your search
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Self-hosted CAPTCHA for the admin login: the image is drawn by the server
|
||||
* (GD), so no third-party service is called and the Content-Security-Policy
|
||||
* stays strict. The answer lives only in the session, as a hash, and is valid
|
||||
* once, for CAPTCHA_TTL seconds.
|
||||
*/
|
||||
|
||||
const CAPTCHA_TTL = 300;
|
||||
const CAPTCHA_LENGTH = 5;
|
||||
const CAPTCHA_ALPHABET = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789'; // no 0/O, 1/I/L
|
||||
|
||||
function captcha_available(): bool
|
||||
{
|
||||
return function_exists('imagecreatetruecolor') && function_exists('imagepng');
|
||||
}
|
||||
|
||||
/** Starts a new challenge (called when the login form is rendered). */
|
||||
function captcha_new(): void
|
||||
{
|
||||
start_session();
|
||||
if (!captcha_available()) {
|
||||
// Without GD: a text question, weaker than the image, so login never becomes impossible.
|
||||
error_log('[serubi] Ekstensi GD tidak tersedia: CAPTCHA memakai soal teks.');
|
||||
$a = random_int(2, 9);
|
||||
$b = random_int(2, 9);
|
||||
$_SESSION['captcha'] = ['code' => (string)($a + $b), 'question' => "Berapa $a + $b?", 'exp' => time() + CAPTCHA_TTL];
|
||||
return;
|
||||
}
|
||||
$code = '';
|
||||
for ($i = 0; $i < CAPTCHA_LENGTH; $i++) {
|
||||
$code .= CAPTCHA_ALPHABET[random_int(0, strlen(CAPTCHA_ALPHABET) - 1)];
|
||||
}
|
||||
$_SESSION['captcha'] = ['code' => $code, 'exp' => time() + CAPTCHA_TTL];
|
||||
}
|
||||
|
||||
/** Text question when the image cannot be drawn, else null. */
|
||||
function captcha_question(): ?string
|
||||
{
|
||||
return $_SESSION['captcha']['question'] ?? null;
|
||||
}
|
||||
|
||||
/** Checks the answer and always consumes the challenge (one attempt per image). */
|
||||
function captcha_check(string $answer): bool
|
||||
{
|
||||
start_session();
|
||||
$c = $_SESSION['captcha'] ?? null;
|
||||
unset($_SESSION['captcha']);
|
||||
if (!$c || time() > $c['exp']) {
|
||||
return false;
|
||||
}
|
||||
$answer = strtoupper(preg_replace('/\s+/', '', $answer));
|
||||
return $answer !== '' && hash_equals($c['code'], $answer);
|
||||
}
|
||||
|
||||
/** Outputs the PNG for the current challenge. */
|
||||
function captcha_render(): void
|
||||
{
|
||||
start_session();
|
||||
$code = (string)($_SESSION['captcha']['code'] ?? '');
|
||||
$w = 200;
|
||||
$h = 64;
|
||||
$img = imagecreatetruecolor($w, $h);
|
||||
imagefilledrectangle($img, 0, 0, $w, $h, imagecolorallocate($img, 244, 246, 250));
|
||||
// background noise
|
||||
for ($i = 0; $i < 9; $i++) {
|
||||
$c = imagecolorallocate($img, random_int(140, 200), random_int(150, 205), random_int(170, 215));
|
||||
imageline($img, random_int(0, $w), random_int(0, $h), random_int(0, $w), random_int(0, $h), $c);
|
||||
}
|
||||
// each glyph is drawn small (built-in font), then scaled and jittered
|
||||
$x = 14;
|
||||
foreach (str_split($code) as $ch) {
|
||||
$g = imagecreatetruecolor(10, 16);
|
||||
$bg = imagecolorallocate($g, 244, 246, 250);
|
||||
imagefill($g, 0, 0, $bg);
|
||||
imagecolortransparent($g, $bg);
|
||||
imagestring($g, 5, 1, 0, $ch, imagecolorallocate($g, random_int(10, 60), random_int(30, 70), random_int(90, 140)));
|
||||
$size = random_int(30, 38);
|
||||
imagecopyresized($img, $g, $x, random_int(4, $h - $size - 10) + 6, 0, 0, (int)($size * 0.66), $size, 10, 16);
|
||||
$x += random_int(31, 36);
|
||||
}
|
||||
// foreground noise over the text
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
imagesetthickness($img, 2);
|
||||
imageline($img, 0, random_int(10, $h - 10), $w, random_int(10, $h - 10), imagecolorallocate($img, 60, 80, 130));
|
||||
}
|
||||
for ($i = 0; $i < 220; $i++) {
|
||||
imagesetpixel($img, random_int(0, $w - 1), random_int(0, $h - 1), imagecolorallocate($img, random_int(60, 160), random_int(60, 160), random_int(60, 160)));
|
||||
}
|
||||
header('Content-Type: image/png');
|
||||
header('Cache-Control: no-store, max-age=0');
|
||||
imagepng($img);
|
||||
}
|
||||
Reference in new issue
Block a user