chore: восстановление репозитория из снапшота v0.3.1
Прежняя git-история утрачена при переносе проекта на машину владельца (снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной истории. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
commit
1c85091186
184 changed files with 33303 additions and 0 deletions
99
server/lib/auth.php
Normal file
99
server/lib/auth.php
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Сессии и текущий пользователь.
|
||||
* PHP native-сессии, cookie HttpOnly, SameSite=Lax, Secure при HTTPS.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Старт сессии с параметрами cookie по контракту.
|
||||
* Идемпотентно (повторный вызов безопасен).
|
||||
*/
|
||||
function session_start_secure(): void
|
||||
{
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
// Fallback save_path (пустой/несуществующий/недоступный — типично для
|
||||
// ручных сборок и части shared-хостингов): уходим в sys_get_temp_dir().
|
||||
$savePath = (string)ini_get('session.save_path');
|
||||
if (
|
||||
$savePath === ''
|
||||
|| !is_dir($savePath)
|
||||
|| !is_writable($savePath)
|
||||
) {
|
||||
ini_set('session.save_path', sys_get_temp_dir());
|
||||
}
|
||||
$https = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
session_set_cookie_params([
|
||||
'path' => '/',
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax',
|
||||
'secure' => $https,
|
||||
]);
|
||||
session_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Текущий пользователь по сессии или null.
|
||||
*
|
||||
* @return array{id: int, email: string}|null
|
||||
*/
|
||||
function current_user(PDO $pdo): ?array
|
||||
{
|
||||
session_start_secure();
|
||||
$id = $_SESSION['user_id'] ?? null;
|
||||
if (!is_int($id)) {
|
||||
return null;
|
||||
}
|
||||
$stmt = $pdo->prepare('SELECT id, email FROM users WHERE id = ?');
|
||||
$stmt->execute([$id]);
|
||||
$user = $stmt->fetch();
|
||||
if (!is_array($user)) {
|
||||
return null;
|
||||
}
|
||||
return ['id' => (int)$user['id'], 'email' => (string)$user['email']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Текущий пользователь или 401.
|
||||
*
|
||||
* @return array{id: int, email: string}
|
||||
*/
|
||||
function require_user(PDO $pdo): array
|
||||
{
|
||||
$user = current_user($pdo);
|
||||
if ($user === null) {
|
||||
error_out(401, 'unauthorized');
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/** Установить сессию после успешного login (id перегенерируется). */
|
||||
function login_user(int $id): void
|
||||
{
|
||||
session_start_secure();
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['user_id'] = $id;
|
||||
}
|
||||
|
||||
/** Полный выход: очистка $_SESSION, cookie и уничтожение сессии. */
|
||||
function logout_user(): void
|
||||
{
|
||||
session_start_secure();
|
||||
$_SESSION = [];
|
||||
if (ini_get('session.use_cookies')) {
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(session_name(), '', [
|
||||
'expires' => time() - 42000,
|
||||
'path' => $params['path'],
|
||||
'domain' => $params['domain'],
|
||||
'secure' => $params['secure'],
|
||||
'httponly' => $params['httponly'],
|
||||
'samesite' => $params['samesite'] ?? 'Lax',
|
||||
]);
|
||||
}
|
||||
session_destroy();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue