Files
Ty Clifford 16235369cb - Implemented the full Fat Bottom Grille storefront and staff dashboard.
Highlights include configurable menus, specials, cart/checkout, taxes, 
customer accounts with email 2FA, newsletters, analytics, refunds, 
PDF/CSV exports, Square/Mailgun adapters, and optional MySQL migration.

See README.md for setup and production configuration. Verified 
PHP/JavaScript syntax, responsive layouts, registration, 2FA, checkout, 
dashboard workflows, settings persistence, and PDF generation.
Real Square, Mailgun, and MySQL connections require credentials/server 
access. Square implementation follows the official Payments API and 
Refunds API.
2026-06-10 13:27:42 -04:00

57 lines
1.5 KiB
PHP

<?php
declare(strict_types=1);
namespace FatBottom\Core;
final class Security
{
public static function csrfToken(): string
{
if (empty($_SESSION['_csrf'])) {
$_SESSION['_csrf'] = bin2hex(random_bytes(32));
}
return (string) $_SESSION['_csrf'];
}
public static function verifyCsrf(): void
{
$submitted = $_POST['_token'] ?? '';
if (!is_string($submitted) || !hash_equals(self::csrfToken(), $submitted)) {
Http::abort(419, 'Your session expired. Please go back and try again.');
}
}
public static function newCaptcha(): array
{
$left = random_int(2, 9);
$right = random_int(1, 9);
$_SESSION['_captcha_answer'] = $left + $right;
return [$left, $right];
}
public static function verifyCaptcha(array $input): bool
{
if (!empty($input['website'])) {
return false;
}
$expected = (int) ($_SESSION['_captcha_answer'] ?? -1);
unset($_SESSION['_captcha_answer']);
return isset($input['captcha']) && (int) $input['captcha'] === $expected;
}
public static function clean(string $value): string
{
return trim(strip_tags($value));
}
public static function slug(string $value): string
{
$value = strtolower(trim($value));
$value = preg_replace('/[^a-z0-9]+/', '-', $value) ?? '';
return trim($value, '-') ?: bin2hex(random_bytes(4));
}
}