Files
philip b239ae3e5f Initial commit: Flutter app + PHP/MySQL backend on Hostinger
Replaces Firebase with a self-hosted PHP/MySQL API served from
winded.prymsolutions.com. Includes full backend (schema, auth, events,
teams, brackets, suggestions, stats, media, file upload) and updated
Flutter repositories and domain models.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 20:13:57 -07:00

35 lines
1.3 KiB
PHP

<?php
// Change JWT_SECRET to a long random string before deploying.
define('JWT_SECRET', 'f0gHGG23#5j9gaGg90asndfa9gtybama89G#');
define('JWT_TTL', 60 * 60 * 24 * 30); // 30 days
class JWT {
public static function encode(array $payload): string {
$header = self::b64e(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
$payload['iat'] = time();
$payload['exp'] = time() + JWT_TTL;
$payload = self::b64e(json_encode($payload));
$sig = self::b64e(hash_hmac('sha256', "$header.$payload", JWT_SECRET, true));
return "$header.$payload.$sig";
}
public static function decode(string $token): ?array {
$parts = explode('.', $token);
if (count($parts) !== 3) return null;
[$header, $payload, $sig] = $parts;
$expected = self::b64e(hash_hmac('sha256', "$header.$payload", JWT_SECRET, true));
if (!hash_equals($expected, $sig)) return null;
$data = json_decode(self::b64d($payload), true);
if (!$data || ($data['exp'] ?? 0) < time()) return null;
return $data;
}
private static function b64e(string $v): string {
return rtrim(strtr(base64_encode($v), '+/', '-_'), '=');
}
private static function b64d(string $v): string {
return base64_decode(strtr($v, '-_', '+/') . str_repeat('=', (4 - strlen($v) % 4) % 4));
}
}