First git commit

This commit is contained in:
root
2026-09-08 18:21:10 +01:00
commit 66911dc450
65 changed files with 7012 additions and 0 deletions

117
public_html/lib/auth.php Normal file
View File

@ -0,0 +1,117 @@
<?php
// Sessions, auth, CSRF. Included by every page via bootstrap.php.
function session_boot(): void {
if (session_status() === PHP_SESSION_ACTIVE) return;
// WAP gateways often strip cookies -> accept the sid from the query string.
ini_set('session.use_only_cookies', '0');
ini_set('session.use_trans_sid', '0');
session_name('WAPSID');
if (!empty($_REQUEST['WAPSID']) && preg_match('/^[A-Za-z0-9,\-]{8,64}$/', $_REQUEST['WAPSID'])) {
session_id($_REQUEST['WAPSID']);
}
session_start();
}
function csrf_token(): string {
if (empty($_SESSION['csrf'])) $_SESSION['csrf'] = bin2hex(random_bytes(16));
return $_SESSION['csrf'];
}
function csrf_ok(): bool {
$t = $_POST['csrf'] ?? $_GET['csrf'] ?? '';
return $t !== '' && !empty($_SESSION['csrf']) && hash_equals($_SESSION['csrf'], $t);
}
function require_csrf(): void {
if (!csrf_ok()) bail('Error', 'Session expired or bad token. Please try again.');
}
function current_user(): ?array {
static $cache = null;
static $done = false;
if ($done) return $cache;
$done = true;
if (empty($_SESSION['uid'])) return $cache = null;
$s = db()->prepare("SELECT * FROM users WHERE id=?");
$s->execute([$_SESSION['uid']]);
$u = $s->fetch();
if (!$u || $u['is_banned']) { $_SESSION['uid'] = null; return $cache = null; }
// throttle last_seen writes to once a minute
if (time() - (int)$u['last_seen'] > 60) {
db()->prepare("UPDATE users SET last_seen=? WHERE id=?")->execute([time(), $u['id']]);
}
return $cache = $u;
}
function require_login(): array {
$u = current_user();
if (!$u) {
page_start('Login needed', ['back' => '/index.php']);
p_para('You must log in to use this feature.');
p_links([['/login.php', 'Login'], ['/signup.php', 'Sign up'], ['/index.php', 'Home']]);
page_end();
exit;
}
return $u;
}
function require_admin(): array {
$u = require_login();
if (!$u['is_admin']) bail('Denied', 'Admin only.');
return $u;
}
function user_login(string $name, string $pass): ?array {
$s = db()->prepare("SELECT * FROM users WHERE username=?");
$s->execute([$name]);
$u = $s->fetch();
if (!$u || !password_verify($pass, $u['pass_hash'])) return null;
if ($u['is_banned']) return null;
$_SESSION['uid'] = (int)$u['id'];
return $u;
}
function user_create(string $name, string $pass, int $admin = 0): int {
$s = db()->prepare("INSERT INTO users (username,pass_hash,is_admin,created_at)
VALUES (?,?,?,?)");
$s->execute([$name, password_hash($pass, PASSWORD_DEFAULT), $admin, time()]);
return (int)db()->lastInsertId();
}
function username_taken(string $n): bool {
$s = db()->prepare("SELECT 1 FROM users WHERE username=?");
$s->execute([$n]);
return (bool)$s->fetchColumn();
}
function valid_username(string $n): bool {
return (bool)preg_match('/^[A-Za-z0-9_]{3,16}$/', $n);
}
function user_by_id(int $id): ?array {
$s = db()->prepare("SELECT * FROM users WHERE id=?");
$s->execute([$id]);
return $s->fetch() ?: null;
}
function user_by_name(string $n): ?array {
$s = db()->prepare("SELECT * FROM users WHERE username=?");
$s->execute([$n]);
return $s->fetch() ?: null;
}
function unread_count(int $uid): int {
$s = db()->prepare("SELECT COUNT(*) FROM messages WHERE to_id=? AND is_read=0");
$s->execute([$uid]);
return (int)$s->fetchColumn();
}
function ago(int $ts): string {
$d = max(0, time() - $ts);
if ($d < 60) return $d . 's';
if ($d < 3600) return floor($d / 60) . 'm';
if ($d < 86400) return floor($d / 3600) . 'h';
if ($d < 2592000) return floor($d / 86400) . 'd';
return date('d/m/y', $ts);
}