162 lines
6.9 KiB
PHP
162 lines
6.9 KiB
PHP
<?php
|
|
/**
|
|
* config.php — Configuración principal del sistema
|
|
* Carga variables desde .env y proporciona constantes globales
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
// ── Carga del archivo .env ────────────────────────────────────────────────────
|
|
function loadEnv(string $path): void {
|
|
if (!file_exists($path)) return;
|
|
$lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
|
foreach ($lines as $line) {
|
|
$line = trim($line);
|
|
if (str_starts_with($line, '#') || !str_contains($line, '=')) continue;
|
|
[$key, $value] = explode('=', $line, 2);
|
|
$key = trim($key);
|
|
$value = trim($value, " \t\n\r\"'");
|
|
if (!array_key_exists($key, $_SERVER) && !array_key_exists($key, $_ENV)) {
|
|
putenv("$key=$value");
|
|
$_ENV[$key] = $value;
|
|
$_SERVER[$key] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
$envFile = dirname(__DIR__) . '/.env';
|
|
if (!file_exists($envFile)) {
|
|
$envFile = dirname(__DIR__) . '/.env.example';
|
|
}
|
|
loadEnv($envFile);
|
|
|
|
// ── Helper para leer .env ─────────────────────────────────────────────────────
|
|
function env(string $key, mixed $default = null): mixed {
|
|
return $_ENV[$key] ?? getenv($key) ?: $default;
|
|
}
|
|
|
|
// ── Constantes de aplicación ──────────────────────────────────────────────────
|
|
define('APP_NAME', env('APP_NAME', 'Sistema de Gestión'));
|
|
define('APP_URL', env('APP_URL', 'http://localhost/ProyectoGestion'));
|
|
define('APP_ENV', env('APP_ENV', 'production'));
|
|
define('APP_DEBUG', env('APP_DEBUG', false));
|
|
define('APP_TIMEZONE', env('APP_TIMEZONE', 'America/Caracas'));
|
|
define('APP_SECRET', env('APP_SECRET_KEY', 'change_me_in_env'));
|
|
|
|
define('BASE_PATH', dirname(__DIR__));
|
|
define('UPLOAD_PATH', BASE_PATH . '/' . env('UPLOAD_PATH', 'uploads/'));
|
|
define('EXPORT_PATH', BASE_PATH . '/exports/');
|
|
define('LOG_PATH', BASE_PATH . '/logs/');
|
|
|
|
define('SESSION_TIMEOUT', (int)env('SESSION_TIMEOUT', 3600));
|
|
define('SESSION_NAME', env('SESSION_NAME', 'gestion_doc_session'));
|
|
define('CSRF_TOKEN_NAME', env('CSRF_TOKEN_NAME', '_csrf_token'));
|
|
|
|
define('UPLOAD_MAX_SIZE', (int)env('UPLOAD_MAX_SIZE', 10485760));
|
|
define('UPLOAD_ALLOWED_TYPES', explode(',', env('UPLOAD_ALLOWED_TYPES', 'pdf,doc,docx,jpg,jpeg,png')));
|
|
|
|
define('INSTITUCION_NOMBRE', env('INSTITUCION_NOMBRE', 'Institución'));
|
|
define('INSTITUCION_CARGO', env('INSTITUCION_CARGO_FIRMA', 'Director(a)'));
|
|
define('LOGO_PATH', BASE_PATH . '/' . env('LOGO_PATH', 'assets/img/logo.png'));
|
|
|
|
// ── Zona horaria ──────────────────────────────────────────────────────────────
|
|
date_default_timezone_set(APP_TIMEZONE);
|
|
|
|
// ── Manejo de errores ─────────────────────────────────────────────────────────
|
|
if (APP_DEBUG === 'true' || APP_DEBUG === true) {
|
|
ini_set('display_errors', '1');
|
|
error_reporting(E_ALL);
|
|
} else {
|
|
ini_set('display_errors', '0');
|
|
error_reporting(0);
|
|
}
|
|
|
|
// ── Conexión a la base de datos (PDO) ────────────────────────────────────────
|
|
function getDB(): PDO {
|
|
static $pdo = null;
|
|
if ($pdo === null) {
|
|
$dsn = sprintf('mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4',
|
|
env('DB_HOST', 'localhost'),
|
|
env('DB_PORT', '3306'),
|
|
env('DB_NAME', 'gestion_documentos')
|
|
);
|
|
$options = [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
|
|
];
|
|
try {
|
|
$pdo = new PDO($dsn, env('DB_USER', 'root'), env('DB_PASS', ''), $options);
|
|
} catch (PDOException $e) {
|
|
if (APP_DEBUG) {
|
|
die('Error de conexión: ' . $e->getMessage());
|
|
} else {
|
|
die('Error de conexión a la base de datos. Contacte al administrador.');
|
|
}
|
|
}
|
|
}
|
|
return $pdo;
|
|
}
|
|
|
|
// ── Inicialización de sesión ──────────────────────────────────────────────────
|
|
function iniciarSesion(): void {
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_name(SESSION_NAME);
|
|
session_set_cookie_params([
|
|
'lifetime' => 0,
|
|
'path' => '/',
|
|
'secure' => isset($_SERVER['HTTPS']),
|
|
'httponly' => true,
|
|
'samesite' => 'Strict',
|
|
]);
|
|
session_start();
|
|
}
|
|
// Regenerar ID de sesión periódicamente
|
|
if (!isset($_SESSION['_last_regen'])) {
|
|
session_regenerate_id(true);
|
|
$_SESSION['_last_regen'] = time();
|
|
} elseif (time() - $_SESSION['_last_regen'] > 300) {
|
|
session_regenerate_id(true);
|
|
$_SESSION['_last_regen'] = time();
|
|
}
|
|
}
|
|
|
|
// ── CSRF ──────────────────────────────────────────────────────────────────────
|
|
function csrfToken(): string {
|
|
iniciarSesion();
|
|
if (empty($_SESSION[CSRF_TOKEN_NAME])) {
|
|
$_SESSION[CSRF_TOKEN_NAME] = bin2hex(random_bytes(32));
|
|
}
|
|
return $_SESSION[CSRF_TOKEN_NAME];
|
|
}
|
|
|
|
function csrfField(): string {
|
|
return '<input type="hidden" name="' . CSRF_TOKEN_NAME . '" value="' . htmlspecialchars(csrfToken()) . '">';
|
|
}
|
|
|
|
function verificarCsrf(): void {
|
|
$token = $_POST[CSRF_TOKEN_NAME] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
|
|
if (!hash_equals($_SESSION[CSRF_TOKEN_NAME] ?? '', $token)) {
|
|
http_response_code(403);
|
|
die(json_encode(['error' => 'Token CSRF inválido.']));
|
|
}
|
|
}
|
|
|
|
// ── Sanitización ──────────────────────────────────────────────────────────────
|
|
function clean(mixed $value): string {
|
|
return htmlspecialchars(trim((string)$value), ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
function redirect(string $url): never {
|
|
header("Location: $url");
|
|
exit();
|
|
}
|
|
|
|
function jsonResponse(mixed $data, int $code = 200): never {
|
|
http_response_code($code);
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
|
exit();
|
|
}
|