Le mostraré la configuración lista para producción para Alojamiento PHP Error Handlingdesde los valores predeterminados de php.ini y las estrategias de registro hasta los manejadores personalizados para obtener respuestas limpias. Así es como mantengo errores de producción desde la interfaz de usuario, proteger la información confidencial y aumentar la estabilidad del servidor en funcionamiento.
Puntos centrales
- php.ini desconectar: DEV muestra todo, PROD registra discretamente.
- Nivel de error filtro fino: Centrarse en los auténticos defectos de producción.
- Gestor personalizado utilizar: Interceptar errores, reaccionar limpiamente.
- Registro estructura: Contexto, rotación, alertas.
- Alrededores claramente separadas: banderas DEBUG y valores por defecto seguros.
Breve explicación de la configuración de errores PHP lista para producción
Dejo que todos los mensajes aparezcan en el desarrollo porque yo Código de calidad asegurar pronto. En los servidores en vivo, apago estrictamente la pantalla, pero registro todo para poder Diagnóstico posible en cualquier momento. Así se mantienen limpias las interfaces de usuario, mientras que los registros dicen la verdad. Los textos de error visibles ponen en peligro la confidencialidad y pueden interrumpir cadenas de funciones; yo lo evito con una separación clara. Este patrón aumenta la estabilidad del servidor y mantiene previsibles los tiempos de respuesta.
php.ini: valores predeterminados seguros para el tráfico en directo
Para entornos de desarrollo activo display_errors y establecer notificación_de_errores En producción, desactivo sistemáticamente los anuncios, pero mantengo informes y registros exhaustivos. Esta combinación protege a los usuarios y mantiene intacta mi visión del comportamiento del sistema. Defino los valores de forma centralizada en php.ini y en fragmentos ini adicionales de versiones. Esto me da despliegues reproducibles y minimiza las sorpresas en la operación en vivo.
La siguiente tabla muestra una comparación de las configuraciones típicas DEV y PROD para más Transparencia y claro Directrices:
| Configuración | Desarrollo | Producción | Nota |
|---|---|---|---|
| display_errors | En | Fuera de | Evitar estrictamente la visualización en modo directo |
| mostrar_errores_de_arranque | En | Fuera de | Hacer que el error de inicio sólo sea visible en DEV |
| notificación_de_errores | E_ALL o -1 | E_ALL (filtro opcional) | -1 cubre todos los niveles, incluidos los futuros |
| log_errores | En | En | Los registros son una fuente obligatoria de análisis |
| error_log | Archivo/Ruta | Archivo/Ruta | Ruta segura con rotación y derechos |
Así que he puesto “display off, report on” en PROD y tengo error_log escribir todo en los archivos. También establezco permisos de archivo duros porque los archivos de registro a menudo contienen contextos sensibles. Si utiliza hosts virtuales o contenedores, separe limpiamente las rutas para cada aplicación. Esto simplifica las correlaciones posteriores y acelera los análisis de causa raíz. Esto mantiene la interfaz de usuario amigable, mientras obtengo trazas completas en segundo plano.
Ajuste del nivel de notificación de errores sin inundación de registros
Por defecto utilizo en PROD E_ALL y opcionalmente filtrar ruidos de fondo como avisos si no tienen valor. Un patrón utilizado con frecuencia es E_ALL & ~E_NOTICE & ~E_WARNING & ~E_DEPRECATED. De este modo se evita el ruido, pero se sigue centrando la atención en las notificaciones reales. errores de producción. Antes de hacer cambios, compruebo los efectos sobre el rendimiento y la latencia, porque muchos registros cuestan IO. Si quieres entender los efectos por nivel, puedes encontrar información de fondo en Nivel de error y rendimiento.
Mantengo el principio de “primero arreglar limpiamente, luego filtrar”, ya que la supresión sólo pospone los problemas. En las fases de migración, registro visiblemente DEPRECATED para reconocer desde el principio las futuras interrupciones. También marco por separado las clases de errores críticos para que las alarmas se disparen de forma fiable. Esto beneficia a las rutas de análisis y me ahorra tiempo en la resolución de problemas. El resultado es menos ruido y más datos utilizables. Señales.
Manejador personalizado: intercepta limpiamente excepciones, errores y cierres
Instalo mis propios manejadores con set_error_handler(), set_exception_handler() y register_shutdown_function(). Así es como capturo los errores clásicos, las excepciones uncaught y los errores fatales. Proporciono a los usuarios una página 500 neutral, y el contexto completo acaba en el registro. Esto protege los detalles sensibles y mantiene alta la estabilidad del servidor. Al mismo tiempo, conservo el control sobre el formato, los campos y los canales de salida.
<?php
class ErrorHandler {
public static function register() {
set_error_handler([__CLASS__, 'handleError']);
set_exception_handler([__CLASS__, 'handleException']);
register_shutdown_function([__CLASS__, 'handleShutdown']);
}
public static function handleError($errno, $errstr, $errfile, $errline) {
error_log("ERROR: [$errno] $errstr in $errfile on line $errline");
if ($errno === E_ERROR) {
http_response_code(500);
echo "Ein interner Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.";
}
return true;
}
public static function handleException($exception) {
error_log("EXCEPTION: " . $exception->getMessage());
http_response_code(500);
echo "Ein interner Fehler ist aufgetreten.";
}
public static function handleShutdown() {
$error = error_get_last();
if ($error !== null) {
error_log("FATAL: " . $error['message']);
http_response_code(500);
}
}
}
ErrorHandler::register(); En la vida cotidiana, añado campos como el ID de solicitud, el ID de usuario y el hash de sesión para Correlación para hacerlo más fácil. Para las API, proporciono una estructura de error genérica en PROD, como JSON con código e ID de ticket. Esto permite que el soporte comience inmediatamente, mientras que la información interna permanece oculta. También encapsulo IO alrededor de loggers para que un sistema de archivos defectuoso no desencadene más errores. Esta evitación en cascada contribuye directamente a reducir el MTTR.
Registro estructurado: contexto, rotación, alertas
Una buena explotación forestal empieza por Contexto: marca de tiempo, tipo, archivo, línea y referencia de la solicitud. A esto le sigue la disciplina: política de rotación, permisos y retención. Separo los registros de la aplicación y los del servidor web para mantener una visión general rápida. Activo clases críticas como E_ERROR en canales de alarma, como el correo o el chat. Según blog.nevercodealone.de, un registro de errores claro reduce el tiempo de depuración hasta en un 70 %: una poderosa palanca para las operaciones.
<?php
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
if (!(error_reporting() & $errno)) return false;
$type = match($errno) {
E_ERROR => 'ERROR',
E_WARNING => 'WARNING',
E_NOTICE => 'NOTICE',
default => 'UNKNOWN'
};
$message = sprintf(
"[%s] %s: %s in %s on line %d | req=%s user=%s",
date('Y-m-d H:i:s'), $type, $errstr, $errfile, $errline,
$_SERVER['HTTP_X_REQUEST_ID'] ?? '-', $_SESSION['uid'] ?? '-'
);
error_log($message, 3, '/var/log/app/custom_error.log');
if ($errno === E_ERROR) {
// Alert versenden
}
return true;
}); Compruebo el tamaño del registro diaria o automáticamente para Memoria para proteger los discos. La rotación con reglas basadas en el tamaño o el tiempo evita los discos llenos. Además, opcionalmente escribo en formato JSON para que los analizadores sintácticos puedan extraer métricas. Un inicio estructurado ayuda en la evaluación; la guía de Analizar registros útiles para la reflexión. Esto me permite reconocer más rápidamente los valores atípicos y minimizar los vuelos a ciegas.
Separación coherente entre DEV, STAGE y PROD
Mantengo cada entorno con su propio Indicador DEBUG y overrides ini dedicados. Los valores de configuración terminan en variables Env, no en el código. El servidor web muestra cabeceras de caché en PROD, mientras que DEV está generosamente desactivado. Para STAGE, reflejo la configuración de PROD pero habilito métricas adicionales. Esta disciplina evita sorpresas y aumenta la previsibilidad de los despliegues.
Los nombres de los archivos de registro difieren según el entorno, por lo que puedo Imágenes de errores no se mezclan. CI/CD fija las banderas antes del despliegue para que no se cuele ningún error humano. Añado comprobaciones de salud para puntos finales clave, de modo que los tiempos de inactividad se detecten pronto. Las banderas de características ayudan a proteger temporalmente las rutas de riesgo. De este modo, mantengo la previsibilidad de los lanzamientos y reduzco los riesgos de reversión.
Depuración en tiempo de ejecución: Cuando necesito comprobar rápidamente
A veces necesito un Insight en una instancia de prueba, por ejemplo inmediatamente después de un hotfix. Entonces configuro temporalmente ini_set(‚display_errors‘, 1) y error_reporting(E_ALL) - pero nunca en producción real. Registro todos los cambios, los borro después y no hago ningún commit. Una breve ronda de pruebas con peticiones específicas suele ser suficiente. Después de eso, vuelvo inmediatamente a los registros silenciosos y a las páginas de error neutrales.
Para que los análisis sean reproducibles, encapsulo los indicadores de depuración detrás de botones de función que a tiempo límite. De este modo, evito los estados permanentes y reduzco el riesgo. Si necesito profundizar más, recurro a Xdebug en un entorno DEV aislado. Medir en lugar de adivinar sigue siendo el principio rector. Sólo así puedo reconocer los cuellos de botella reales y no los placebos.
Configurar WordPress y frameworks de forma segura
Con WordPress configuro en PROD WP_DEBUG a false y redirigir los errores a los logs. En DEV, uso WP_DEBUG_LOG y WP_DEBUG_DISPLAY específicamente para el desarrollo de características. Desactivo los editores de plugins en PROD para que no se produzcan cambios de código en vivo. Cron control a través de cronjobs sistema reduce los valores atípicos y suaviza Picos de carga. Para más detalles, la guía compacta del Modo de depuración de WordPress.
Frameworks como Symfony o Laravel proporcionan banderas ENV dedicadas y páginas de error, que yo coherente uso. Utilizo registradores centralizados como Monolog con una estructura de canales. Para las respuestas HTTP en PROD, emito textos de error genéricos y me remito internamente a las correlaciones. De este modo, las interfaces permanecen neutrales, pero los registros siguen siendo productivos. Esta combinación contribuye notablemente a la estabilidad del servidor.
Aspectos de seguridad: Lo que nunca debe acabar en el registro
Filtro constantemente SecretosContraseñas, tokens, fragmentos de tarjetas de crédito y datos personales. El enmascaramiento tiene lugar lo antes posible, por ejemplo a nivel de servicio antes del registrador. En el caso de los mensajes de error, compruebo si el contenido contiene rutas de archivos, SQL o IP internas. Blindo o anonimizo todo lo que aumente la superficie de ataque. De este modo, los registros siguen siendo útiles sin poner en peligro la protección o la seguridad de los datos.
Configuro los permisos de los archivos de forma restrictiva y los procesos sólo escriben en los archivos compartidos. Caminos. También activo la rotación de registros con compresión para que los datos antiguos no queden a la vista. Mantengo un runbook preparado para los incidentes: Dónde encuentro qué rastros, a qué equipos aviso primero. Esta preparación ahorra minutos preciosos en situaciones agitadas. Al final, lo que cuenta es el tiempo hasta la recuperación.
Control y alarma sin fallos
Defino valores umbral que sensible al contexto son: Los avisos individuales no activan una alarma, pero sí los picos repentinos. Las ventanas de tiempo, los límites de velocidad y la deduplicación evitan la fatiga de los buscapersonas. Notifico inmediatamente las clases críticas como E_ERROR, E_PARSE y los tiempos de espera recurrentes. Para los valores atípicos recurrentes, planifico tickets en lugar de medidas ad hoc. De este modo, el equipo mantiene su capacidad de actuación y los problemas reales no pasan desapercibidos.
La visualización me ayuda a reconocer patrones ReconocerCiclos diarios, picos de despliegue, oleadas de bots. Las correlaciones entre los tiempos de despliegue y las tasas de error revelan las causas. Almaceno los libros de ejecución directamente en textos de alarma para que el personal de guardia pueda actuar de inmediato. También controlo dependencias como bases de datos y colas. Un flujo de errores sin contexto rara vez aporta soluciones.
Lista de comprobación de la implantación: Despliegue con pocos errores
Antes de cada lanzamiento, compruebo Configuración, logs, permisos y memoria libre. A continuación, realizo una prueba de humo con los puntos finales más importantes. Las banderas de características y las versiones canarias reducen los riesgos en caso de cambios importantes. Registro los tiempos de despliegue para facilitar las correlaciones posteriores. También planifico rutas de retorno en caso de que un hotfix vaya mal.
Para las actualizaciones de mayor envergadura, desplazo la carga de escritura durante un breve periodo de tiempo y realizo Disponibilidad-las sondas son más estrictas. Esto incluye una comprobación de la capacidad de escritura del registro y de las conexiones a la base de datos. También compruebo si 500 páginas aparecen correctamente y sin información interna. Estos puntos aparentemente pequeños evitan grandes sorpresas. Esto hace que los rollouts sean más tranquilos y comprensibles.
FPM y servidor web: protección específica SAPI
Además de php.ini guardo el archivo Piscinas FPM duro. En todo el grupo, establezco display_errors en Off a través de php_admin_flag y de este modo aplico los valores predeterminados productivos incluso con anulaciones de aplicación defectuosas. Uso slowlog y request_terminate_timeout para identificar y limitar cuelgues antes de que bloqueen a los trabajadores. También registro las salidas de los trabajadores para registrar casos extremos raros.
[www]
php_admin_flag[mostrar_errores] = Desactivado
php_admin_value[error_reporting] = E_ALL
php_admin_value[log_errors] = Activado
php_admin_value[memory_limit] = 256M
catch_workers_output = yes
request_terminate_timeout = 30s
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 5s A nivel de servidor web (nginx/Apache) activo fastcgi_intercept_errors o ProxyErrorOverride. Esto permite al servidor web entregar 50x páginas estáticas si PHP falla. Caché ninguno 5xx, pero manejo los errores 4xx con TTLs cortos. El servidor web genera una cabecera X-Request-ID y la pasa a PHP para que pueda corregir cada ruta.
# nginx
error_page 500 502 503 504 /50x.html;
location = /50x.html { root /usr/share/nginx/html; internal; }
fastcgi_intercept_errors on;
add_header X-Request-Id $request_id siempre;
# Apache (extracto)
DocumentoError 500 /50x.html
ProxyErrorOverride On En PROD también desactivo html_errores y exponer_php. De este modo se evitan los textos incorrectos con formato HTML y las filtraciones a través de las versiones de PHP. Con ignorar_errores_repetidos y log_errors_max_len Mantengo a raya las tormentas de registros sin tragarme las señales reales. Ejecuto Opcache estrictamente cerca de la producción, pero me aseguro de que los mensajes de error no queden ocultos por una revalidación agresiva.
Respuestas de error normalizadas para API y frontales
Normalizo el esquema de respuesta: Los usuarios ven genérico Los textos, los sistemas reciben códigos estructurados. Los errores 4xx indican problemas del cliente (validación, autenticación), los errores 5xx indican problemas del servidor. Una correspondencia coherente entre las excepciones y el estado HTTP evita malentendidos y facilita el seguimiento.
[
'code' => $code,
'message' => $publicMessage,
'request_id' => $_SERVER['HTTP_X_REQUEST_ID'] ?? '-',
'timestamp' => date('c'),
] + $meta
];
header('Content-Type: application/json');
echo json_encode($payload);
}
try {
// ...
} catch (ValidationException $e) {
respondError(422, 'VALIDATION_FAILED', 'Entrada incompleta o inválida');
} catch (NotFoundException $e) {
respondError(404, 'NOT_FOUND', 'Recurso no encontrado');
} catch (Throwable $e) {
error_log('UNHANDLED: '.$e->getMessage());
respondError(500, 'INTERNAL_ERROR', 'Se ha producido un error interno');
} Para las interfaces de usuario, mantengo una página limpia de 500 que no muestra ninguna información interna. Si localizo texto incorrecto, sólo lo hago para Público Mensajes: los detalles internos permanecen en los registros. Esto aumenta la calidad de la asistencia y reduce las consultas.
Recogida centralizada de registros, muestras y contenedores
En las configuraciones modernas, reenvío los registros de forma centralizada a Syslog o Journald. En contenedores, prefiero escribir en stdout/stderr y dejar la rotación y el envío a la plataforma. Evito los registros basados en archivos en contenedores a menos que un sidecar los rote de forma fiable. Utilizo el muestreo de forma controlada: En el caso de masas de avisos similares, registro muestras aleatorias representativas y continúo guardándolas. cada clase crítica en su totalidad.
Enriquezco las líneas de registro con el hash del despliegue, el host, el ID del pod/contenedor y el entorno. Si el envío central falla, almaceno localmente y vuelvo al registro mínimo si es necesario para no bloquear la petición. Los problemas de red no deben ser Cascadas de errores en la ruta crítica: la estabilidad prima sobre la exhaustividad.
Gestión robusta de CLI, cronjobs y procesos de trabajo
Los scripts CLI siguen sus propias reglas: Necesitas Códigos de salida, escriben a STDERR y nunca deben fallar silenciosamente. Separo sus registros de las peticiones web y proporciono estrategias de retroceso/reintento para errores transitorios. Para trabajos largos, establezco deliberadamente límites de memoria y registro estados intermedios para poder reconocer cuelgues o fugas.
<?php
if (PHP_SAPI === 'cli') {
set_error_handler(function($errno, $errstr, $errfile, $errline) {
$msg = sprintf("CLI [%s] %s in %s:%d\n", $errno, $errstr, $errfile, $errline);
fwrite(STDERR, $msg);
return true;
});
register_shutdown_function(function() {
$e = error_get_last();
if ($e) fwrite(STDERR, "CLI FATAL: {$e['message']}\n");
});
}
try {
// Job-Logik
exit(0);
} catch (Throwable $e) {
fwrite(STDERR, "CLI EXCEPTION: ".$e->getMessage()."\n");
// 2 = temporär, 1 = dauerhaft, 3 = Konfig-Fehler (Beispiel)
exit(2);
} Encapsulo las tareas cron con archivos de bloqueo o bloqueos distribuidos para que los arranques en paralelo no provoquen picos de carga y salvas de errores. Planifico las ventanas de reintento para que no coincidan con picos de tráfico. Lo mismo se aplica aquí: rico en contexto Los registros superan cualquier rastro de pila de stub.
Profundizar en la protección, el almacenamiento y el enmascaramiento de datos
Más allá de “no registrar”, implemento Normas de enmascaramientoSustituyo los tokens y las contraseñas por marcadores de posición, almaceno las IP acortadas y seudonimizo los identificadores personales (hash con sal). Para cada entorno, defino Retención-y eliminar automáticamente las existencias antiguas. Las rutas de exportación (por ejemplo, paquetes de soporte) también están codificadas y se puede acceder a ellas en función de las funciones.
Compruebo las excepciones de contenido sensible (SQL con valores claros, nombres de host internos). Instruyo a los equipos para que reconozcan las excepciones útiles, pero neutro para formular textos de error. La protección de datos empieza en el código: el registrador es sólo la última instancia, no el primer filtro.
Versiones, obsoletos y ventanas de migración
Para las actualizaciones de PHP describo una ventana de migración: En ETAPA evalúo E_DEPRECATED Las registro visiblemente en PROD, pero sin alertas. Distingo entre las depreciaciones de mi código base y las de paquetes de terceros, y planifico las correcciones de forma iterativa. Un caso de prueba específico garantiza que las depreciaciones no contaminan la interfaz de usuario y acaban exclusivamente en los registros.
También tengo un Matriz de compatibilidad listo para las ampliaciones. Si los componentes divergen temporalmente, reduzco el volumen de registro de forma selectiva sin desactivar las clases críticas. El objetivo es siempre arreglar las cosas limpiamente, no ocultarlas.
SLO, presupuestos de errores y control fino de alarmas
No sólo mido las cifras absolutas que faltan, sino que también defino Tasa de error SLO por punto final. Derivo la frecuencia de despliegue y el modo de vigilancia del presupuesto de errores: si el presupuesto es ajustado, aumento la precaución, activo el muestreo de forma más estricta y doy prioridad al trabajo de calidad. Deduzco las alarmas en función del tiempo y las agrupo según la causa (misma traza de pila, mismo endpoint) para que On-Call siga siendo capaz de actuar.
Páginas de error del servidor web, fallos de FPM y trampas de caché
Si FPM baja o entrega 502/504, el estático 50x como alternativa fiable. Esta página no contiene información de construcción ni enlaces internos, sino instrucciones claras para usuarios y contactos de soporte. Me aseguro de que las CDN y los proxies inversos no almacenen en caché 5xx y respeten las cabeceras Retry-After. Para las ventanas de mantenimiento, envío 503 con Retry-After, no 500, y mantengo las páginas de mantenimiento fuera de PHP.
Para las peticiones con aceptación JSON, ofrezco opcionalmente una respuesta de error JSON mínima del servidor web para 5xx para que los clientes no se encuentren con nada. Al mismo tiempo, evito que el servidor web revele rutas o módulos internos: la seguridad también prima sobre la comodidad cuando se trata de fallback.
Resumen práctico
Separo sistemáticamente DEV y PROD, desactivo los anuncios en Live y registro completa. Los manejadores personalizados me permiten controlar la reacción y el contexto. Un nivel de error claro, filtros sensatos y una rotación limpia reducen el ruido. Los filtros de seguridad protegen los secretos, mientras que las alarmas sólo se disparan en caso de problemas reales. De este modo, la interfaz es silenciosa, los registros hablan claro y la estabilidad del servidor aumenta notablemente.
Si sigues esta configuración, te alejas del extinción de incendios hacia el funcionamiento predictivo. Los despliegues se vuelven calculables, las interrupciones más cortas y los análisis repetibles. Precisamente por eso merece la pena invertir en una configuración limpia. Pongo en práctica estos principios en cada proyecto y duermo más tranquilo. La producción no necesita magia, sino reglas claras y una aplicación disciplinada.


