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();
}