Amigos, hoy vamos a hablar de algo que vuelve loco a cualquiera que haya tenido que hurgar en código PHP ajeno. Abres un sitio web y no hay nada. Una pantalla en blanco. Ni error, ni pista de lo que salió mal.
¿Les suena familiar?
Este es el caso clásico de un error fatal de PHP que simplemente mata el script y desaparece sin despedirse. Hoy aprenderemos a hacer que PHP hable, activar los registros (logs) y encontrar esos errores fatales que se esconden tras la "pantalla blanca de la muerte".
Por qué PHP se calla: un poco de teoría
Para empezar, entendamos cómo maneja PHP los errores en general. No es solo "error -> registro". Hay toda una jerarquía.
En PHP 7+, todo lo que puede salir mal implementa la interfaz Throwable. Tiene dos herederos principales: - Error — errores internos de PHP (fatales, de análisis sintáctico, de tipo) - Exception — excepciones que se pueden capturar con try-catch
Los errores fatales (E_ERROR, E_PARSE, E_CORE_ERROR) son la peor pesadilla de cualquier desarrollador. Matan el script al instante, y los manejadores estándar con set_error_handler() no los capturan . La única forma de interceptar un error fatal es usar register_shutdown_function().
Pero vayamos paso a paso. Primero, necesitamos activar el registro para que los errores se escriban en algún lugar.
Paso 1: Activar el registro mediante php.ini
La forma más correcta de configurar los registros es editar el archivo de configuración de PHP. Su ubicación depende de tu sistema :
| Sistema | Ruta a php.ini |
|---------|----------------|
| Ubuntu/Debian (Apache) | /etc/php/7.x/apache2/php.ini |
| Ubuntu/Debian (CLI) | /etc/php/7.x/cli/php.ini |
| Ubuntu/Debian (PHP-FPM) | /etc/php/7.x/fpm/php.ini |
| CentOS/RHEL | /etc/php.ini o /etc/php.d/ |
| Windows (XAMPP) | C:\xampp\php\php.ini |
| Windows (WAMP) | C:\wamp\bin\php\phpX.X.X\php.ini |
En este archivo, nos interesan las siguientes directivas :
```ini ; Activar la escritura de errores en un archivo de registro (¡obligatorio!) log_errors = On
; Especificar la ruta al archivo de registro error_log = /var/log/php_errors.log
; Desactivar la visualización de errores en pantalla (¡para producción!) display_errors = Off
; Para desarrollo, puedes activar esto, pero desactívalo después display_startup_errors = Off
; Nivel de reporte de errores — todos los errores error_reporting = E_ALL ```
Importante: La interfaz de línea de comandos (CLI) usa su propio php.ini, y los registros pueden escribirse en una ubicación diferente . Si estás probando un script en la consola, verifica por separado.
Después de hacer cambios, necesitas reiniciar el servidor web :
bash
sudo systemctl restart apache2 # para Apache
sudo systemctl restart php7.4-fpm # para PHP-FPM
Qué significan estos ajustes
- log_errors = On — activa la escritura de errores en un archivo. Sin esto, PHP se quedará mudo como una tumba .
- error_log — la ruta al archivo donde se escribirá todo. Es crucial que el usuario del servidor web (normalmente
www-dataoapache) tenga permisos de escritura para este archivo y su directorio . - display_errors = Off — desactiva esto en producción para no exponer detalles a los usuarios .
- error_reporting = E_ALL — registrar todos los tipos de errores. Para producción, puedes limitar esto, pero para depuración es mejor verlo todo.
Paso 2: Alternativa: Activar el registro directamente en el código
Si no tienes acceso a php.ini (por ejemplo, en un hosting compartido), puedes intentar activar el registro directamente en tu script usando la función ini_set().
Inserta esto al principio del archivo problemático:
```php
/dev/null ``` O crea un archivo PHP con `phpinfo();` y busca la sección **error_log**. ## Paso 4: Leer los registros: herramientas y técnicas Una vez que los registros se están escribiendo, necesitas saber cómo verlos y filtrarlos rápidamente. ### tail — Ver los últimos eventos ```bash # Últimas 50 líneas tail -n 50 /var/log/php_errors.log # Seguir en tiempo real (como docker logs -f) tail -f /var/log/php_errors.log ``` ### grep — Buscar errores específicos ```bash # Solo errores fatales grep "Fatal error" /var/log/php_errors.log # Errores de análisis sintáctico (parse errors) grep "Parse error" /var/log/php_errors.log # Ignorar mayúsculas/minúsculas grep -i "warning" /var/log/php_errors.log ``` ### less — Visualización práctica con navegación ```bash less /var/log/php_errors.log ``` Dentro de less, puedes presionar `/` y escribir una palabra para buscar, `n` para el siguiente resultado, `N` para el anterior. ### Combinaciones — Un pipeline poderoso ```bash # Mostrar las últimas 100 líneas y buscar errores tail -n 100 /var/log/php_errors.log | grep -i fatal # Seguir y filtrar en tiempo real tail -f /var/log/php_errors.log | grep --line-buffered "error" # Contar errores por tipo grep -o "PHP [A-Za-z]* error" /var/log/php_errors.log | sort | uniq -c ``` ## Paso 5: Descifrar los errores: qué es cada cosa Una entrada de registro típica se ve así : ``` [2026-03-04 14:35:22 UTC] PHP Fatal error: Uncaught Error: Call to undefined function foo() in /var/www/html/index.php on line 10 ``` Analicémosla: - **Fecha y Hora** — cuándo ocurrió - **PHP Fatal error** — el nivel de error - **Uncaught Error: Call to undefined function foo()** — el mensaje - **/var/www/html/index.php:10** — el archivo y el número de línea Principales niveles de error : | Nivel | Significado | Ejemplo | |-------|-------------|---------| | **E_ERROR** / **Fatal error** | Error fatal, el script muere | Llamar a una función inexistente, memoria insuficiente | | **E_WARNING** / **Warning** | Advertencia, pero el script continúa | `include` de un archivo inexistente | | **E_PARSE** / **Parse error** | Error de sintaxis, el script no se ejecuta | Punto y coma faltante | | **E_NOTICE** / **Notice** | Aviso, generalmente no crítico | Acceder a una variable no definida | | **E_DEPRECATED** | Construcción obsoleta | Usar `mysql_connect()` | ## Paso 6: Capturar errores fatales (la parte interesante) Los errores fatales son aquellos que no pueden ser capturados por el `set_error_handler()` estándar. Matan el script instantáneamente, y el manejador por defecto simplemente no tiene tiempo de ejecutarse . ¡Pero hay una forma! Usa `register_shutdown_function()` — esta función se llama pase lo que pase, incluso en un error fatal . ### Manejador de errores fatales simple ```php getMessage()." | ".$e->getFile().":".$e->getLine()." | $url\n"; file_put_contents($logFile, $msg, FILE_APPEND); }); // Manejador para errores fatales register_shutdown_function(function() use ($logFile) { $error = error_get_last(); if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) { $url = ($_SERVER['HTTP_HOST'] ?? 'CLI') . ($_SERVER['REQUEST_URI'] ?? ''); $msg = "[".date('Y-m-d H:i:s')."] [FATAL] ".$error['message']." | ".$error['file'].":".$error['line']." | $url\n"; file_put_contents($logFile, $msg, FILE_APPEND); } }); ``` Puedes insertar este código al principio de tu archivo principal (por ejemplo, `index.php` o `header.php`), y capturará absolutamente todo . ## Paso 7: Registros en frameworks populares Si usas un framework moderno, el registro ya está configurado, pero las rutas de los registros son diferentes. ### Laravel Los registros se almacenan en `storage/logs/laravel.log`. Por defecto, usa Monolog; el formato puede ser texto o JSON. Para ver errores: ```bash tail -f storage/logs/laravel.log ``` ### Symfony Registros por defecto: `var/log/dev.log` y `var/log/prod.log`. También usa Monolog, altamente configurable. ### WordPress Por defecto, WordPress no escribe registros, pero puedes activarlos añadiendo esto a `wp-config.php`: ```php define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false); ``` Los registros estarán en `/wp-content/debug.log`. ## Paso 8: Problemas comunes y sus soluciones ### Problema: Los registros no se escriben en absoluto Qué verificar: 1. ¿Está `log_errors = On` definitivamente configurado? 2. ¿Hay permisos de escritura para el archivo y su directorio? 3. ¿Editaste el php.ini correcto (verifica con `phpinfo()`)? 4. ¿Reiniciaste el servidor web después de los cambios? ### Problema: Los errores fatales no se capturan Incluso con el registro activado, a veces los errores fatales no se escriben si ocurren muy temprano (por ejemplo, un error de análisis sintáctico en el mismo archivo donde activas el registro). La única solución es una colocación correcta — al principio, antes de cualquier otra cosa . ### Problema: Demasiados registros Si `E_ALL` está activado en producción, los registros crecerán rápidamente. Configura `error_reporting` de manera razonable : ```ini error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE ``` ### Problema: Los registros llenan el disco Configura la rotación de registros con `logrotate`. Una configuración para los registros PHP: ``` /var/log/php_errors.log { daily rotate 30 compress delaycompress missingok notifempty create 644 www-data www-data } ``` ## Paso 9: Ejemplo práctico: Investigar una página en blanco Imaginemos una situación: abres un sitio web y está en blanco. ¿Qué hacer paso a paso? 1. **Verifica los registros del servidor web** (Apache/Nginx) — a menudo contienen una pista 2. **Verifica los registros PHP** — busca entradas de los últimos minutos ```bash tail -n 50 /var/log/php_errors.log | grep -A5 -B5 "$(date +%Y-%m-%d)" ``` 3. **Encuentra el error** : ``` [2026-03-04 15:30:22] PHP Fatal error: Uncaught Error: Class 'DB' not found in /var/www/site/index.php on line 12 ``` 4. **Abre el archivo**, verifica la línea 12 — efectivamente, olvidaste incluir la clase. 5. **Corrige**, prueba — ¡el sitio funciona! ¡Magia! ## Resumen rápido: Chuleta | Acción | Comando / Código | |--------|------------------| | Activar registro en php.ini | `log_errors = On` + `error_log = /ruta/al/archivo` | | Activar en código | `ini_set('log_errors', 'On');` | | Ver últimas líneas | `tail -f /var/log/php_errors.log` | | Buscar errores fatales | `grep "Fatal error" /var/log/php_errors.log` | | Capturar errores fatales | `register_shutdown_function()` + `error_get_last()` | | ¿Dónde están los registros de Laravel? | `storage/logs/laravel.log` | | ¿Dónde están los registros de Symfony? | `var/log/dev.log` y `var/log/prod.log` | ## A modo de conclusión PHP no es tan aterrador como a menudo lo pintan. Sí, la pantalla blanca de la muerte es terrorífica, pero detrás de ella siempre hay un error específico que simplemente no quiere hablar. Aprende a activar los registros, y PHP empezará a hablar. Las reglas principales: - En producción, **siempre** activa `log_errors` y desactiva `display_errors` - Escribe los registros en un archivo dedicado, no en syslog — es más fácil buscar - Usa `register_shutdown_function` para capturar errores fatales - Revisa tus registros regularmente — al menos una vez al día Y recuerda: el código perfecto no escribe errores. Pero si ocurre un error, que al menos deje una nota. ?>