devsofttech_hms_ci4/app/Controllers/Captcha.php

89 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\ResponseInterface;
class Captcha extends BaseController
{
/**
* Generate an image CAPTCHA, save the code to session, and stream image.
*/
public function generate(): ResponseInterface
{
// 1. Generate random code (unambiguous uppercase characters)
$characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
$code = '';
$length = 5;
$max = strlen($characters) - 1;
for ($i = 0; $i < $length; $i++) {
$code .= $characters[random_int(0, $max)];
}
// 2. Save code in session
session()->set('login_captcha', $code);
// 3. Create GD image
$width = 140;
$height = 40;
$image = imagecreatetruecolor($width, $height);
// Background color (#f8fafc)
$bgColor = imagecolorallocate($image, 248, 250, 252);
imagefilledrectangle($image, 0, 0, $width, $height, $bgColor);
// Add subtle background noise dots
for ($i = 0; $i < 60; $i++) {
$dotColor = imagecolorallocate($image, random_int(190, 230), random_int(190, 230), random_int(200, 240));
imagesetpixel($image, random_int(0, $width - 1), random_int(0, $height - 1), $dotColor);
}
// Add 3 subtle noise lines
for ($i = 0; $i < 3; $i++) {
$lineColor = imagecolorallocate($image, random_int(180, 220), random_int(180, 220), random_int(190, 230));
imageline($image, random_int(0, $width), random_int(0, $height), random_int(0, $width), random_int(0, $height), $lineColor);
}
// Color palette for characters
$colors = [
imagecolorallocate($image, 15, 23, 42), // slate-900
imagecolorallocate($image, 30, 58, 138), // blue-900
imagecolorallocate($image, 88, 28, 135), // purple-900
imagecolorallocate($image, 19, 78, 74), // teal-900
imagecolorallocate($image, 136, 19, 55), // rose-900
];
// Draw each character with spacing and slight vertical jitter
$spacing = (int) (($width - 24) / $length);
for ($i = 0; $i < $length; $i++) {
$char = $code[$i];
$charColor = $colors[$i % count($colors)];
$x = 12 + ($i * $spacing);
$y = random_int(10, 14);
imagestring($image, 5, $x, $y, $char, $charColor);
// Draw 1px horizontal offset for bold readability
imagestring($image, 5, $x + 1, $y, $char, $charColor);
}
// Add a thin border
$borderColor = imagecolorallocate($image, 203, 213, 225);
imagerectangle($image, 0, 0, $width - 1, $height - 1, $borderColor);
// Capture PNG stream
ob_start();
imagepng($image);
$imageData = (string) ob_get_clean();
imagedestroy($image);
return $this->response
->setContentType('image/png')
->setHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
->setHeader('Pragma', 'no-cache')
->setHeader('Expires', '0')
->setBody($imageData);
}
}