Прежняя git-история утрачена при переносе проекта на машину владельца (снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной истории. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
99 lines
2.8 KiB
PHP
99 lines
2.8 KiB
PHP
<?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();
|
||
}
|