135 lines
4.3 KiB
PHP
135 lines
4.3 KiB
PHP
<?php
|
|
/**
|
|
* core/Helpers.php
|
|
* Funciones de utilidad globales del ERP.
|
|
* Consolida helpers duplicados de api/lab/_helpers.php y config/config.php.
|
|
*
|
|
* REQUIERE: config/config.php ya cargado (para APP_ROOT si se usa).
|
|
*/
|
|
|
|
// ─── Seguridad / Output ─────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Escapa una cadena para salida HTML segura.
|
|
*/
|
|
if (!function_exists('esc')) {
|
|
function esc(?string $value): string
|
|
{
|
|
return htmlspecialchars($value ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
|
}
|
|
}
|
|
|
|
// ─── Respuestas JSON ────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Envía respuesta JSON de éxito y termina la ejecución.
|
|
*
|
|
* @param array $payload Datos adicionales a fusionar en la respuesta.
|
|
* @param string $message Mensaje descriptivo opcional.
|
|
*/
|
|
if (!function_exists('jsonOk')) {
|
|
function jsonOk(array $payload = [], string $message = ''): void
|
|
{
|
|
if (ob_get_level() > 0) {
|
|
ob_clean();
|
|
}
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
$resp = ['ok' => true, 'success' => true];
|
|
if ($message !== '') {
|
|
$resp['message'] = $message;
|
|
}
|
|
echo json_encode(array_merge($resp, $payload), JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Envía respuesta JSON de error con código HTTP y termina la ejecución.
|
|
*
|
|
* @param string $message Descripción del error.
|
|
* @param int $code Código HTTP (400, 401, 403, 404, 500…).
|
|
*/
|
|
if (!function_exists('jsonError')) {
|
|
function jsonError(string $message, int $code = 400): void
|
|
{
|
|
if (ob_get_level() > 0) {
|
|
ob_clean();
|
|
}
|
|
http_response_code($code);
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
echo json_encode(
|
|
['ok' => false, 'success' => false, 'error' => $message, 'code' => $code],
|
|
JSON_UNESCAPED_UNICODE
|
|
);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// ─── Request ────────────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Detiene la ejecución con 405 JSON si el método HTTP no coincide.
|
|
*
|
|
* @param string $method Método esperado: 'GET', 'POST', etc.
|
|
*/
|
|
if (!function_exists('requireMethod')) {
|
|
function requireMethod(string $method): void
|
|
{
|
|
if ($_SERVER['REQUEST_METHOD'] !== strtoupper($method)) {
|
|
jsonError('Método no permitido', 405);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lee y decodifica el body JSON del request actual.
|
|
* Se cachea en la misma petición.
|
|
*
|
|
* @return array Datos decodificados o array vacío si el body no es JSON válido.
|
|
*/
|
|
if (!function_exists('inputJson')) {
|
|
function inputJson(): array
|
|
{
|
|
static $parsed = null;
|
|
if ($parsed === null) {
|
|
$raw = file_get_contents('php://input');
|
|
$parsed = json_decode($raw ?: '{}', true) ?? [];
|
|
}
|
|
return $parsed;
|
|
}
|
|
}
|
|
|
|
// ─── Texto / Formato ────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Convierte bytes a representación legible (KB, MB, GB).
|
|
*/
|
|
if (!function_exists('formatBytes')) {
|
|
function formatBytes(int $bytes, int $precision = 2): string
|
|
{
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
$bytes = max($bytes, 0);
|
|
$pow = $bytes > 0 ? floor(log($bytes) / log(1024)) : 0;
|
|
$pow = min($pow, count($units) - 1);
|
|
return round($bytes / (1024 ** $pow), $precision) . ' ' . $units[$pow];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Formatea una fecha a formato legible en español.
|
|
*
|
|
* @param string|null $date Fecha en cualquier formato reconocible por strtotime.
|
|
* @param bool $time Si true incluye la hora.
|
|
*/
|
|
if (!function_exists('formatDate')) {
|
|
function formatDate(?string $date, bool $time = false): string
|
|
{
|
|
if (!$date) {
|
|
return '—';
|
|
}
|
|
$ts = strtotime($date);
|
|
$format = $time ? 'd/m/Y H:i' : 'd/m/Y';
|
|
return $ts ? date($format, $ts) : esc($date);
|
|
}
|
|
}
|