Solución de problemas
- Nette no funciona, se muestra una página en blanco
- Error 500 Server Error: We're sorry! …
- Error 404, el enrutamiento no funciona
- Los cambios en las plantillas o en la configuración no se reflejan
- ¿Cómo desactivar la caché durante el desarrollo?
- Error #[\ReturnTypeWillChange] attribute should be used
- Establecer los permisos de los directorios
- ¿Cómo cambiar o quitar el directorio www de la URL?
- ¿Cómo configurar el servidor para URL bonitas?
- Compruebe si .htaccess funciona
- Compruebe si mod_rewrite está habilitado
- Los enlaces se generan sin https:
- Uso de los caracteres { } en JavaScript
- Error Cannot modify header information - headers already sent
- Aviso Presenter::getContext() is deprecated
Nette no funciona, se muestra una página en blanco
- Pruebe a poner
ini_set('display_errors', '1'); error_reporting(E_ALL);detrás dedeclare(strict_types=1);en el archivoindex.phppara forzar la visualización de los errores. - Si sigue viendo una pantalla en blanco, probablemente haya un error en la configuración del servidor y encontrará el motivo
en el log del servidor. Para asegurarse, compruebe si PHP funciona siquiera intentando imprimir algo con
echo 'test';. - Si ve el error Server Error: We're sorry! …, continúe con la sección siguiente:
Error 500 Server Error: We're sorry! …
Esta página de error la muestra Nette en modo de producción. Si la ve en su máquina de desarrollo, cambie al modo de desarrollador y Tracy le mostrará un informe detallado.
El motivo del error lo encontrará siempre en el log del directorio log/. Pero si en el mensaje de error aparece
la frase Tracy is unable to log error, averigüe primero por qué no se pueden registrar los errores. Puede hacerlo,
por ejemplo, cambiando temporalmente
al modo de desarrollador y dejando que Tracy registre cualquier cosa tras arrancar:
// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // su dirección IP
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');
Tracy le dirá por qué no puede registrar. La causa pueden ser permisos insuficientes para escribir en el directorio
log/.
Uno de los motivos más habituales del error 500 es una caché desactualizada. Mientras que en modo de desarrollo Nette
actualiza la caché automáticamente y de forma inteligente, en modo de producción se centra en el máximo rendimiento y borrar
la caché tras cada modificación del código es responsabilidad suya. Pruebe a borrar temp/cache.
Error 404, el enrutamiento no funciona
Cuando todas las páginas (salvo la de inicio) devuelven un error 404, parece un problema de configuración del servidor para las URL bonitas.
Los cambios en las plantillas o en la configuración no se reflejan
“He modificado la plantilla o la configuración, pero la web sigue mostrando la versión antigua.” Este comportamiento se da en modo de producción, que, por motivos de rendimiento, no comprueba los cambios en los archivos y mantiene la caché generada anteriormente.
Para no tener que borrar la caché a mano en el servidor de producción tras cada modificación, habilite el modo de desarrollo
para su dirección IP en el archivo Bootstrap.php:
$this->configurator->setDebugMode('su.direccion.ip');
¿Cómo desactivar la caché durante el desarrollo?
Nette es inteligente y no necesita desactivar la caché en él. Durante el desarrollo actualiza automáticamente la caché siempre que hay un cambio en la plantilla o en la configuración del contenedor DI. Además, el modo de desarrollo se activa por autodetección, así que normalmente no hace falta configurar nada, o solo la dirección IP.
Al depurar el router recomendamos desactivar la caché del navegador, donde pueden quedar guardadas, por ejemplo, las redirecciones: abra las herramientas para desarrolladores (Ctrl+Shift+I o Cmd+Option+I) y en el panel Network marque la casilla para desactivar la caché.
Error
#[\ReturnTypeWillChange] attribute should be used
Este error aparece si ha actualizado PHP a la versión 8.1 pero usa una versión de Nette que no es compatible con ella. La
solución es actualizar Nette a una versión más reciente con composer update. Nette soporta PHP 8.1 desde la
versión 3.0. Si usa una versión anterior (compruebe su composer.json), actualice Nette o quédese con PHP 8.0.
Establecer los permisos de los directorios
Si desarrolla en macOS o Linux (o en cualquier otro sistema basado en Unix), tendrá que configurar los permisos de escritura
para el servidor web. Suponiendo que su aplicación esté en el directorio predeterminado /var/www/html (Fedora,
CentOS, RHEL):
cd /var/www/html/MI_PROYECTO
chmod -R a+rw temp log
En algunos sistemas Linux (Fedora, CentOS, …) puede que SELinux esté habilitado de forma predeterminada. Puede que tenga que
actualizar las políticas de SELinux o establecer las rutas de los directorios temp y log con el
contexto de seguridad de SELinux correcto. A los directorios temp y log hay que asignarles el contexto
httpd_sys_rw_content_t; para el resto de la aplicación, sobre todo la carpeta app, bastará con el
contexto httpd_sys_content_t. Ejecute en el servidor como root:
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MI_PROYECTO/log(/.*)?'
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MI_PROYECTO/temp(/.*)?'
restorecon -Rv /var/www/html/MI_PROYECTO/
Además hay que habilitar el booleano de SELinux httpd_can_network_connect_db para permitir que Nette se conecte a
la base de datos por la red. De forma predeterminada está deshabilitado. Para ello se puede usar el comando
setsebool, y si se indica la opción -P, este ajuste será persistente tras los reinicios:
setsebool -P httpd_can_network_connect_db on
¿Cómo cambiar o quitar el directorio www de
la URL?
El directorio www/ que se usa en los proyectos de ejemplo de Nette representa el directorio público,
o document-root, del proyecto. Es el único directorio cuyo contenido es accesible desde el navegador. Contiene el archivo
index.php, el punto de entrada que arranca la aplicación web de Nette.
Para ejecutar la aplicación en un hosting hay que configurar correctamente el document-root. Tiene dos opciones:
- Establecer en la configuración del hosting el document-root a este directorio.
- Si el hosting tiene una carpeta ya preparada (p. ej.
public_html), renombrewww/con ese nombre.
Nunca intente asegurar su aplicación usando solo .htaccess o reglas del router para impedir el
acceso a otras carpetas.
Si el hosting no permite establecer el document-root a un subdirectorio (es decir, crear directorios un nivel por encima del directorio público), busque otro proveedor. En caso contrario se expondría a un riesgo de seguridad considerable. Sería como vivir en un piso cuya puerta de entrada no se puede cerrar y está siempre abierta de par en par.
¿Cómo configurar el servidor para URL bonitas?
Apache: hay que habilitar y configurar las reglas de mod_rewrite en el archivo .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz)$ index.php [L]
Si se topa con problemas, asegúrese de que:
- el archivo
.htaccessestá en el directorio document-root (es decir, junto al archivoindex.php) - Apache procesa los archivos
.htaccess - mod_rewrite está habilitado
Si instala la aplicación en una subcarpeta, puede que tenga que descomentar la línea del ajuste RewriteBase y
ponerle la carpeta correcta.
nginx: hay que configurar la redirección con la directiva try_files dentro del bloque
location / de la configuración del servidor.
location / {
try_files $uri $uri/ /index.php$is_args$args; # ¡$is_args$args ES IMPORTANTE!
}
El bloque location debe aparecer solo una vez para cada ruta del sistema de archivos dentro del bloque
server. Si ya tiene un bloque location / en su configuración, añada la directiva
try_files al bloque existente.
Compruebe si .htaccess funciona
La forma más sencilla de comprobar si Apache usa o ignora su archivo .htaccess es romperlo a propósito. Ponga
la línea Test al principio del archivo. Ahora, al refrescar la página en el navegador, debería ver un Internal
Server Error.
Si ve ese error, ¡eso está bien! Significa que Apache analiza el archivo .htaccess y se topa con el error que
hemos puesto ahí. Elimine la línea Test.
Si no ve el Internal Server Error, su configuración de Apache ignora el archivo .htaccess. Normalmente
Apache lo ignora porque falta la directiva de configuración AllowOverride All.
Si lo aloja usted mismo, es fácil de arreglar. Abra su httpd.conf o apache.conf en un editor de
texto, localice la sección <Directory> correspondiente y añada o cambie esta directiva:
<Directory "/var/www/htdocs"> # ruta a su document root
AllowOverride All
...
Si su sitio está alojado en otro sitio, mire en su panel de control si puede habilitar ahí .htaccess. Si no,
pida a su proveedor de hosting que lo haga por usted.
Compruebe si mod_rewrite está habilitado
Si ha verificado que .htaccess funciona, puede verificar que la
extensión mod_rewrite está habilitada. Ponga la línea RewriteEngine On al principio del archivo
.htaccess y refresque la página en el navegador. Si ve un Internal Server Error, significa que mod_rewrite
no está habilitado. Hay varias formas de habilitarlo. Vea en Stack Overflow las distintas maneras de hacerlo en cada
configuración.
Los enlaces se generan sin https:
Nette genera los enlaces con el mismo protocolo que usa la página actual. Así, en una página https://foo genera
enlaces que empiezan por https:, y al revés. Si está detrás de un proxy inverso que elimina HTTPS (por ejemplo, en
Docker), tiene que configurar el proxy en la
configuración para que la detección del protocolo funcione correctamente.
Si usa Nginx como proxy, tiene que tener la redirección configurada, por ejemplo, así:
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_pass http://IP-aplicacion:80; # IP o hostname del servidor/contenedor donde corre la aplicación
}
Además hay que indicar en la configuración la IP del proxy y, opcionalmente, el rango de IP de su red local donde ejecuta la infraestructura:
http:
proxy: IP-proxy/rango-IP
Uso de los caracteres { } en JavaScript
Los caracteres { y } se usan para escribir las etiquetas de Latte. Todo lo que sigue al carácter
{ (salvo un espacio y unas comillas) se considera una etiqueta. Si necesita imprimir directamente el carácter
{ (a menudo en JavaScript), puede poner un espacio (u otro carácter en blanco) justo detrás de {. Eso
evita que se interprete como una etiqueta.
Si hay que imprimir estos caracteres en una situación en la que el texto se interpretaría como una etiqueta, puede usar
etiquetas especiales para imprimirlos: {l} para { y {r} para }.
{is a tag}
{ is not a tag }
{l}is not a tag{r}
Error
Cannot modify header information - headers already sent
Este error aparece cuando la aplicación intenta enviar una cabecera HTTP (una cookie, una redirección o el inicio de la sesión) en un momento en el que ya se ha enviado alguna salida al navegador. Las cabeceras tienen que preceder siempre al cuerpo de la respuesta.
Hay dos causas posibles: o la salida se escapa demasiado pronto, o la cabecera se envía demasiado tarde.
La salida suele escaparse demasiado pronto por un espacio o una línea en blanco perdidos delante de <?php,
detrás del ?> de cierre, o por un BOM que el editor insertó al principio del archivo y no muestra. Por eso
nunca termine los archivos PHP con ?>. Para averiguar qué sitio imprimió primero, use Tracy\OutputDebugger.
La cabecera se envía demasiado tarde normalmente al trabajar con la sesión. Nette arranca la sesión automáticamente la
primera vez que lee de ella o escribe en ella, y si eso ocurre solo mientras se renderiza la plantilla, la salida ya va de
camino. Por eso, trabaje con la sesión como muy tarde en el método beforeRender(), y en los componentes también en
los métodos handle<Signal>().
No intente resolver el problema estableciendo autoStart:
true. Eso arranca la sesión para cada visitante, incluidos los robots, y crea innecesariamente una enorme cantidad de
archivos en el disco. El valor predeterminado smart arranca la sesión solo cuando de verdad hace falta.
Aviso Presenter::getContext() is deprecated
Nette fue con diferencia el primer framework de PHP que pasó a la dependency injection y guió a los programadores para usarla
de forma consistente, empezando por los propios presenters. Si un presenter necesita una dependencia, la pide. Por el contrario, pasar todo el contenedor
DI a una clase y que esta saque las dependencias directamente se considera un antipatrón (conocido como patrón service locator).
Este enfoque se usaba en Nette 0.x, antes de la llegada de la dependency injection, y el método
Presenter::getContext(), marcado desde hace mucho como obsoleto, es un resto de aquella época.
Si está portando una aplicación de Nette muy antigua, puede que descubra que todavía usa este método. Desde la versión
3.1 de nette/application se encontrará con el aviso
Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, y desde la versión 4.0 con un
error que dice que el método no existe.
La solución limpia es, por supuesto, refactorizar la aplicación para pasar las dependencias mediante dependency injection.
Como solución provisional puede añadir a su presenter base su propio método getContext() para esquivar el
mensaje:
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
private Nette\DI\Container $context;
public function injectContext(Nette\DI\Container $context): void
{
$this->context = $context;
}
public function getContext(): Nette\DI\Container
{
return $this->context;
}
}