Sync current dev state
This commit is contained in:
393
f_core/f_functions/functions.api.php
Normal file
393
f_core/f_functions/functions.api.php
Normal file
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
/**
|
||||
* API Response Helper Functions
|
||||
* Provides standardized API responses across EasyStream
|
||||
*/
|
||||
|
||||
if (!defined('_ISVALID')) {
|
||||
die('Direct access is not allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send success response
|
||||
* Standardized success response format for all API endpoints
|
||||
*
|
||||
* @param mixed $data Data to return (can be array, object, string, etc.)
|
||||
* @param int $statusCode HTTP status code (default: 200)
|
||||
* @param array $meta Optional metadata (pagination, etc.)
|
||||
* @return void (exits after sending response)
|
||||
*/
|
||||
function sendApiSuccess($data = null, $statusCode = 200, $meta = null) {
|
||||
http_response_code($statusCode);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$response = [
|
||||
'success' => true,
|
||||
'data' => $data,
|
||||
'error' => null
|
||||
];
|
||||
|
||||
// Add metadata if provided (pagination, etc.)
|
||||
if ($meta !== null) {
|
||||
$response['meta'] = $meta;
|
||||
}
|
||||
|
||||
// Add timestamp
|
||||
$response['timestamp'] = date('Y-m-d H:i:s');
|
||||
|
||||
echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error response
|
||||
* Standardized error response format for all API endpoints
|
||||
*
|
||||
* @param string $message Error message
|
||||
* @param int $statusCode HTTP status code (default: 400)
|
||||
* @param array $details Additional error details (validation errors, etc.)
|
||||
* @return void (exits after sending response)
|
||||
*/
|
||||
function sendApiError($message, $statusCode = 400, $details = null) {
|
||||
http_response_code($statusCode);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$response = [
|
||||
'success' => false,
|
||||
'data' => null,
|
||||
'error' => $message
|
||||
];
|
||||
|
||||
// Add error details if provided
|
||||
if ($details !== null) {
|
||||
$response['details'] = $details;
|
||||
}
|
||||
|
||||
// Add timestamp
|
||||
$response['timestamp'] = date('Y-m-d H:i:s');
|
||||
|
||||
// Log error for debugging
|
||||
VLogger::log('error', 'API Error: ' . $message, [
|
||||
'status_code' => $statusCode,
|
||||
'details' => $details,
|
||||
'endpoint' => $_SERVER['REQUEST_URI'] ?? 'unknown',
|
||||
'method' => $_SERVER['REQUEST_METHOD'] ?? 'unknown'
|
||||
]);
|
||||
|
||||
echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate API request method
|
||||
* Ensures only allowed HTTP methods are used
|
||||
*
|
||||
* @param string|array $allowedMethods Single method or array of allowed methods
|
||||
* @throws Exception if method not allowed (sends 405 response)
|
||||
* @return void
|
||||
*/
|
||||
function validateApiMethod($allowedMethods) {
|
||||
$allowedMethods = (array) $allowedMethods;
|
||||
$currentMethod = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
if (!in_array($currentMethod, $allowedMethods)) {
|
||||
sendApiError(
|
||||
'Method not allowed. Allowed methods: ' . implode(', ', $allowedMethods),
|
||||
405,
|
||||
['allowed_methods' => $allowedMethods, 'current_method' => $currentMethod]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON input from request body
|
||||
* Handles both JSON and form-encoded data
|
||||
*
|
||||
* @param bool $assoc Return as associative array (default: true)
|
||||
* @return array|object Decoded JSON data
|
||||
* @throws Exception if JSON is invalid
|
||||
*/
|
||||
function getJsonInput($assoc = true) {
|
||||
$input = file_get_contents('php://input');
|
||||
|
||||
if (empty($input)) {
|
||||
return $assoc ? [] : (object) [];
|
||||
}
|
||||
|
||||
$data = json_decode($input, $assoc);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
sendApiError(
|
||||
'Invalid JSON input: ' . json_last_error_msg(),
|
||||
400,
|
||||
['json_error' => json_last_error_msg()]
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate required fields in request data
|
||||
* Checks if all required fields are present and not empty
|
||||
*
|
||||
* @param array $data Request data
|
||||
* @param array $requiredFields Array of required field names
|
||||
* @return void (sends error response if validation fails)
|
||||
*/
|
||||
function validateRequiredFields($data, $requiredFields) {
|
||||
$missingFields = [];
|
||||
|
||||
foreach ($requiredFields as $field) {
|
||||
if (!isset($data[$field]) || (is_string($data[$field]) && trim($data[$field]) === '')) {
|
||||
$missingFields[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($missingFields)) {
|
||||
sendApiError(
|
||||
'Missing required fields',
|
||||
400,
|
||||
['missing_fields' => $missingFields, 'required_fields' => $requiredFields]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pagination parameters from request
|
||||
* Standardized pagination handling
|
||||
*
|
||||
* @param int $defaultLimit Default items per page (default: 20)
|
||||
* @param int $maxLimit Maximum items per page (default: 100)
|
||||
* @return array ['page', 'limit', 'offset']
|
||||
*/
|
||||
function getPaginationParams($defaultLimit = 20, $maxLimit = 100) {
|
||||
$page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
|
||||
$limit = isset($_GET['limit']) ? min($maxLimit, max(1, (int) $_GET['limit'])) : $defaultLimit;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
return [
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
'offset' => $offset
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pagination metadata
|
||||
* Returns standardized pagination info for responses
|
||||
*
|
||||
* @param int $page Current page
|
||||
* @param int $limit Items per page
|
||||
* @param int $total Total items
|
||||
* @return array Pagination metadata
|
||||
*/
|
||||
function createPaginationMeta($page, $limit, $total) {
|
||||
return [
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
'total' => $total,
|
||||
'pages' => ceil($total / $limit),
|
||||
'has_more' => $page < ceil($total / $limit)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Require authentication for API endpoint
|
||||
* Checks if user is authenticated via JWT or session
|
||||
*
|
||||
* @return int User ID
|
||||
* @throws Exception if not authenticated (sends 401 response)
|
||||
*/
|
||||
function requireAuth() {
|
||||
$userId = null;
|
||||
|
||||
// Try JWT authentication first
|
||||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? null;
|
||||
|
||||
if ($authHeader && preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
|
||||
$token = $matches[1];
|
||||
$tokenData = VAuth::verifyToken($token);
|
||||
|
||||
if ($tokenData && isset($tokenData['user_id'])) {
|
||||
$userId = $tokenData['user_id'];
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to session authentication
|
||||
if (!$userId) {
|
||||
$userId = getCurrentUserId();
|
||||
}
|
||||
|
||||
if (!$userId) {
|
||||
sendApiError('Authentication required', 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check user permission for API endpoint
|
||||
* Requires authentication and checks RBAC permission
|
||||
*
|
||||
* @param string $permission Permission to check (e.g., 'videos.delete')
|
||||
* @return int User ID if authorized
|
||||
* @throws Exception if not authorized (sends 403 response)
|
||||
*/
|
||||
function requirePermission($permission) {
|
||||
$userId = requireAuth();
|
||||
|
||||
if (!VAuth::hasPermission($permission)) {
|
||||
sendApiError(
|
||||
'Permission denied',
|
||||
403,
|
||||
['required_permission' => $permission, 'user_id' => $userId]
|
||||
);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rate limit API requests
|
||||
* Simple in-memory rate limiting (consider Redis for production)
|
||||
*
|
||||
* @param string $key Rate limit key (e.g., 'api:' . $userId)
|
||||
* @param int $maxRequests Maximum requests allowed
|
||||
* @param int $timeWindow Time window in seconds
|
||||
* @return void (sends 429 response if limit exceeded)
|
||||
*/
|
||||
function rateLimitApiRequest($key, $maxRequests = 60, $timeWindow = 60) {
|
||||
// Use APCu if available, otherwise session
|
||||
if (function_exists('apcu_fetch')) {
|
||||
$requests = apcu_fetch($key, $success);
|
||||
|
||||
if (!$success) {
|
||||
$requests = ['count' => 0, 'start' => time()];
|
||||
}
|
||||
|
||||
// Reset if time window expired
|
||||
if (time() - $requests['start'] > $timeWindow) {
|
||||
$requests = ['count' => 0, 'start' => time()];
|
||||
}
|
||||
|
||||
$requests['count']++;
|
||||
|
||||
if ($requests['count'] > $maxRequests) {
|
||||
$retryAfter = $timeWindow - (time() - $requests['start']);
|
||||
|
||||
header('Retry-After: ' . $retryAfter);
|
||||
header('X-RateLimit-Limit: ' . $maxRequests);
|
||||
header('X-RateLimit-Remaining: 0');
|
||||
header('X-RateLimit-Reset: ' . ($requests['start'] + $timeWindow));
|
||||
|
||||
sendApiError(
|
||||
'Rate limit exceeded',
|
||||
429,
|
||||
[
|
||||
'max_requests' => $maxRequests,
|
||||
'time_window' => $timeWindow,
|
||||
'retry_after' => $retryAfter
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
apcu_store($key, $requests, $timeWindow);
|
||||
|
||||
// Add rate limit headers
|
||||
header('X-RateLimit-Limit: ' . $maxRequests);
|
||||
header('X-RateLimit-Remaining: ' . ($maxRequests - $requests['count']));
|
||||
header('X-RateLimit-Reset: ' . ($requests['start'] + $timeWindow));
|
||||
|
||||
} else {
|
||||
// Fallback: Use session storage (not ideal for distributed systems)
|
||||
if (!isset($_SESSION['rate_limit'])) {
|
||||
$_SESSION['rate_limit'] = [];
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['rate_limit'][$key])) {
|
||||
$_SESSION['rate_limit'][$key] = ['count' => 0, 'start' => time()];
|
||||
}
|
||||
|
||||
$requests = $_SESSION['rate_limit'][$key];
|
||||
|
||||
// Reset if time window expired
|
||||
if (time() - $requests['start'] > $timeWindow) {
|
||||
$_SESSION['rate_limit'][$key] = ['count' => 0, 'start' => time()];
|
||||
$requests = $_SESSION['rate_limit'][$key];
|
||||
}
|
||||
|
||||
$requests['count']++;
|
||||
$_SESSION['rate_limit'][$key] = $requests;
|
||||
|
||||
if ($requests['count'] > $maxRequests) {
|
||||
$retryAfter = $timeWindow - (time() - $requests['start']);
|
||||
|
||||
header('Retry-After: ' . $retryAfter);
|
||||
|
||||
sendApiError(
|
||||
'Rate limit exceeded',
|
||||
429,
|
||||
[
|
||||
'max_requests' => $maxRequests,
|
||||
'time_window' => $timeWindow,
|
||||
'retry_after' => $retryAfter
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize API input
|
||||
* Wrapper around VSecurity::sanitize with logging
|
||||
*
|
||||
* @param mixed $input Input to sanitize
|
||||
* @param string $type Type of sanitization (string, email, url, int, etc.)
|
||||
* @return mixed Sanitized input
|
||||
*/
|
||||
function sanitizeApiInput($input, $type = 'string') {
|
||||
if ($input === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'int':
|
||||
return (int) $input;
|
||||
|
||||
case 'float':
|
||||
return (float) $input;
|
||||
|
||||
case 'bool':
|
||||
return (bool) $input;
|
||||
|
||||
case 'email':
|
||||
return filter_var($input, FILTER_SANITIZE_EMAIL);
|
||||
|
||||
case 'url':
|
||||
return filter_var($input, FILTER_SANITIZE_URL);
|
||||
|
||||
case 'string':
|
||||
default:
|
||||
return VSecurity::sanitize($input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log API request for debugging/analytics
|
||||
*
|
||||
* @param string $endpoint Endpoint name
|
||||
* @param array $data Additional data to log
|
||||
* @return void
|
||||
*/
|
||||
function logApiRequest($endpoint, $data = []) {
|
||||
VLogger::log('info', 'API Request', array_merge([
|
||||
'endpoint' => $endpoint,
|
||||
'method' => $_SERVER['REQUEST_METHOD'] ?? 'unknown',
|
||||
'user_id' => getCurrentUserId(),
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
|
||||
'user_agent' => substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 200)
|
||||
], $data));
|
||||
}
|
||||
278
f_core/f_functions/functions.session.php
Normal file
278
f_core/f_functions/functions.session.php
Normal file
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
/**
|
||||
* Session Helper Functions
|
||||
* Provides standardized session access across EasyStream
|
||||
*
|
||||
* This file resolves conflicts between different session variable names
|
||||
* used throughout the application.
|
||||
*/
|
||||
|
||||
if (!defined('_ISVALID')) {
|
||||
die('Direct access is not allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user ID from session
|
||||
* Handles legacy session variable names for backward compatibility
|
||||
*
|
||||
* @return int User ID or 0 if not logged in
|
||||
*/
|
||||
function getCurrentUserId() {
|
||||
// Check modern standard (preferred)
|
||||
if (isset($_SESSION['USER_ID']) && $_SESSION['USER_ID'] > 0) {
|
||||
return (int) $_SESSION['USER_ID'];
|
||||
}
|
||||
|
||||
// Check legacy variant 1 (migrate to new standard)
|
||||
if (isset($_SESSION['usr_id']) && $_SESSION['usr_id'] > 0) {
|
||||
$_SESSION['USER_ID'] = (int) $_SESSION['usr_id'];
|
||||
unset($_SESSION['usr_id']);
|
||||
VLogger::log('info', 'Migrated session variable usr_id to USER_ID', [
|
||||
'user_id' => $_SESSION['USER_ID']
|
||||
]);
|
||||
return (int) $_SESSION['USER_ID'];
|
||||
}
|
||||
|
||||
// Check legacy variant 2 (migrate to new standard)
|
||||
if (isset($_SESSION['user_id']) && $_SESSION['user_id'] > 0) {
|
||||
$_SESSION['USER_ID'] = (int) $_SESSION['user_id'];
|
||||
unset($_SESSION['user_id']);
|
||||
VLogger::log('info', 'Migrated session variable user_id to USER_ID', [
|
||||
'user_id' => $_SESSION['USER_ID']
|
||||
]);
|
||||
return (int) $_SESSION['USER_ID'];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current user ID in session
|
||||
* Automatically cleans up legacy session variables
|
||||
*
|
||||
* @param int $userId User ID to set
|
||||
* @return void
|
||||
*/
|
||||
function setCurrentUserId($userId) {
|
||||
$_SESSION['USER_ID'] = (int) $userId;
|
||||
|
||||
// Clean up legacy session variables to prevent conflicts
|
||||
unset($_SESSION['usr_id']);
|
||||
unset($_SESSION['user_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is logged in
|
||||
*
|
||||
* @return bool True if user is authenticated, false otherwise
|
||||
*/
|
||||
function isUserLoggedIn() {
|
||||
return getCurrentUserId() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current username from session
|
||||
*
|
||||
* @return string|null Username or null if not set
|
||||
*/
|
||||
function getCurrentUsername() {
|
||||
return $_SESSION['USER_NAME'] ?? $_SESSION['usr_user'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user email from session
|
||||
*
|
||||
* @return string|null Email or null if not set
|
||||
*/
|
||||
function getCurrentUserEmail() {
|
||||
return $_SESSION['USER_EMAIL'] ?? $_SESSION['usr_email'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user key (unique identifier)
|
||||
*
|
||||
* @return string|null User key or null if not set
|
||||
*/
|
||||
function getCurrentUserKey() {
|
||||
return $_SESSION['USER_KEY'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear user session completely
|
||||
* Removes all user-related session variables
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function clearUserSession() {
|
||||
// Standard variables
|
||||
unset($_SESSION['USER_ID']);
|
||||
unset($_SESSION['USER_NAME']);
|
||||
unset($_SESSION['USER_EMAIL']);
|
||||
unset($_SESSION['USER_KEY']);
|
||||
|
||||
// Legacy variables
|
||||
unset($_SESSION['usr_id']);
|
||||
unset($_SESSION['user_id']);
|
||||
unset($_SESSION['usr_user']);
|
||||
unset($_SESSION['usr_email']);
|
||||
|
||||
// Additional user data
|
||||
unset($_SESSION['usr_verified']);
|
||||
unset($_SESSION['usr_partner']);
|
||||
unset($_SESSION['usr_avatar']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate all session variables to new standard
|
||||
* Useful for one-time migration during login
|
||||
*
|
||||
* @param array $userData User data from database
|
||||
* @return void
|
||||
*/
|
||||
function migrateSessionVariables($userData) {
|
||||
// Set standard variables
|
||||
if (isset($userData['usr_id'])) {
|
||||
setCurrentUserId($userData['usr_id']);
|
||||
}
|
||||
|
||||
if (isset($userData['usr_user'])) {
|
||||
$_SESSION['USER_NAME'] = $userData['usr_user'];
|
||||
}
|
||||
|
||||
if (isset($userData['usr_email'])) {
|
||||
$_SESSION['USER_EMAIL'] = $userData['usr_email'];
|
||||
}
|
||||
|
||||
if (isset($userData['usr_key'])) {
|
||||
$_SESSION['USER_KEY'] = $userData['usr_key'];
|
||||
}
|
||||
|
||||
// Store additional user data if needed
|
||||
if (isset($userData['usr_verified'])) {
|
||||
$_SESSION['usr_verified'] = (bool) $userData['usr_verified'];
|
||||
}
|
||||
|
||||
if (isset($userData['usr_partner'])) {
|
||||
$_SESSION['usr_partner'] = (bool) $userData['usr_partner'];
|
||||
}
|
||||
|
||||
if (isset($userData['usr_avatar'])) {
|
||||
$_SESSION['usr_avatar'] = $userData['usr_avatar'];
|
||||
}
|
||||
|
||||
VLogger::log('info', 'Session variables migrated to new standard', [
|
||||
'user_id' => getCurrentUserId()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all current user session data
|
||||
*
|
||||
* @return array User session data
|
||||
*/
|
||||
function getCurrentUserSessionData() {
|
||||
return [
|
||||
'user_id' => getCurrentUserId(),
|
||||
'username' => getCurrentUsername(),
|
||||
'email' => getCurrentUserEmail(),
|
||||
'user_key' => getCurrentUserKey(),
|
||||
'verified' => $_SESSION['usr_verified'] ?? false,
|
||||
'partner' => $_SESSION['usr_partner'] ?? false,
|
||||
'avatar' => $_SESSION['usr_avatar'] ?? null,
|
||||
'is_logged_in' => isUserLoggedIn()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate session and check for hijacking attempts
|
||||
*
|
||||
* @return bool True if session is valid, false if suspicious
|
||||
*/
|
||||
function validateUserSession() {
|
||||
if (!isUserLoggedIn()) {
|
||||
return true; // No session to validate
|
||||
}
|
||||
|
||||
// Check if user agent changed (possible hijacking)
|
||||
$currentUserAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
|
||||
$sessionUserAgent = $_SESSION['USER_AGENT'] ?? '';
|
||||
|
||||
if (!empty($sessionUserAgent) && $sessionUserAgent !== $currentUserAgent) {
|
||||
VLogger::log('warning', 'Session user agent mismatch - possible hijacking', [
|
||||
'user_id' => getCurrentUserId(),
|
||||
'session_ua' => substr($sessionUserAgent, 0, 100),
|
||||
'current_ua' => substr($currentUserAgent, 0, 100)
|
||||
]);
|
||||
|
||||
clearUserSession();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if IP changed (optional strict check)
|
||||
if (defined('SESSION_IP_CHECK') && SESSION_IP_CHECK === true) {
|
||||
$currentIp = $_SERVER['REMOTE_ADDR'] ?? '';
|
||||
$sessionIp = $_SESSION['USER_IP'] ?? '';
|
||||
|
||||
if (!empty($sessionIp) && $sessionIp !== $currentIp) {
|
||||
VLogger::log('warning', 'Session IP mismatch - possible hijacking', [
|
||||
'user_id' => getCurrentUserId(),
|
||||
'session_ip' => $sessionIp,
|
||||
'current_ip' => $currentIp
|
||||
]);
|
||||
|
||||
clearUserSession();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize session security variables
|
||||
* Call this after successful login
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function initializeSessionSecurity() {
|
||||
$_SESSION['USER_AGENT'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
|
||||
$_SESSION['USER_IP'] = $_SERVER['REMOTE_ADDR'] ?? '';
|
||||
$_SESSION['SESSION_START_TIME'] = time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if session has expired
|
||||
*
|
||||
* @param int $timeout Timeout in seconds (default: 1 hour)
|
||||
* @return bool True if expired, false otherwise
|
||||
*/
|
||||
function isSessionExpired($timeout = 3600) {
|
||||
if (!isset($_SESSION['SESSION_START_TIME'])) {
|
||||
return false; // No timestamp, can't determine
|
||||
}
|
||||
|
||||
$elapsed = time() - $_SESSION['SESSION_START_TIME'];
|
||||
|
||||
if ($elapsed > $timeout) {
|
||||
VLogger::log('info', 'Session expired', [
|
||||
'user_id' => getCurrentUserId(),
|
||||
'elapsed_seconds' => $elapsed
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh session timestamp
|
||||
* Call periodically to extend session
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function refreshSession() {
|
||||
if (isUserLoggedIn()) {
|
||||
$_SESSION['SESSION_START_TIME'] = time();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user