Risoluzione dei problemi

Nette non funziona, viene mostrata una pagina bianca

  • Provate a mettere ini_set('display_errors', '1'); error_reporting(E_ALL); dopo declare(strict_types=1); nel file index.php per forzare la visualizzazione degli errori.
  • Se vedete ancora una schermata bianca, probabilmente c'è un errore nella configurazione del server e il motivo lo troverete nel log del server. Per sicurezza verificate che PHP funzioni affatto, provando a stampare qualcosa con echo 'test';.
  • Se vedete l'errore Server Error: We're sorry! …, proseguite con la sezione successiva:

Errore 500 Server Error: We're sorry! …

Questa pagina di errore viene mostrata da Nette in modalità produzione. Se la vedete sulla vostra macchina di sviluppo, passate alla modalità di sviluppo e Tracy vi mostrerà un report dettagliato.

Il motivo dell'errore lo trovate sempre nel log nella directory log/. Se però nel messaggio di errore compare la frase Tracy is unable to log error, scoprite prima perché gli errori non si possono registrare. Potete farlo per esempio passando temporaneamente alla modalità di sviluppo e lasciando che Tracy registri qualcosa dopo il suo avvio:

// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // il vostro indirizzo IP
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');

Tracy vi dirà perché non può registrare. La causa possono essere i permessi insufficienti per scrivere nella directory log/.

Uno dei motivi più frequenti dell'errore 500 è una cache obsoleta. Mentre in modalità di sviluppo Nette aggiorna la cache automaticamente e in modo intelligente, in modalità produzione punta alle massime prestazioni e la cancellazione della cache dopo ogni modifica del codice è compito vostro. Provate a cancellare temp/cache.

Errore 404, il routing non funziona

Quando tutte le pagine (tranne la homepage) restituiscono l'errore 404, sembra un problema di configurazione del server per gli URL leggibili.

Le modifiche ai template o alla configurazione non si vedono

“Ho modificato il template o la configurazione, ma il sito mostra ancora la vecchia versione.” Questo comportamento si verifica in modalità produzione, che per motivi di prestazioni non controlla le modifiche ai file e mantiene la cache generata in precedenza.

Per non dover cancellare a mano la cache sul server di produzione dopo ogni modifica, attivate la modalità di sviluppo per il vostro indirizzo IP nel file Bootstrap.php:

$this->configurator->setDebugMode('vostro.indirizzo.ip');

Come disattivare la cache durante lo sviluppo?

Nette è intelligente e non serve disattivarci la cache. Durante lo sviluppo aggiorna automaticamente la cache ogni volta che cambia il template o la configurazione del container DI. La modalità di sviluppo si attiva inoltre per rilevamento automatico, quindi di solito non serve configurare nulla, oppure solo l'indirizzo IP.

Quando fate il debug del router, consigliamo di disattivare la cache del browser, in cui possono per esempio essere salvati i redirect: aprite i Developer Tools (Ctrl+Shift+I oppure Cmd+Option+I) e nel pannello Network spuntate la casella per disattivare la cache.

Errore #[\ReturnTypeWillChange] attribute should be used

Questo errore compare se avete aggiornato PHP alla versione 8.1 ma usate una versione di Nette che non è compatibile con essa. La soluzione è aggiornare Nette a una versione più recente con composer update. Nette supporta PHP 8.1 dalla versione 3.0. Se usate una versione più vecchia (controllate il vostro composer.json), aggiornate Nette oppure restate con PHP 8.0.

Impostazione dei permessi delle directory

Se sviluppate su macOS o Linux (o su un altro sistema basato su Unix), dovete impostare i permessi di scrittura per il server web. Supponendo che la vostra applicazione si trovi nella directory predefinita /var/www/html (Fedora, CentOS, RHEL):

cd /var/www/html/MIO_PROGETTO
chmod -R a+rw temp log

Su alcuni sistemi Linux (Fedora, CentOS, …) SELinux può essere attivo per impostazione predefinita. Può essere necessario aggiornare le policy di SELinux oppure impostare per i percorsi delle directory temp e log il corretto contesto di sicurezza SELinux. Le directory temp e log andrebbero impostate con il contesto httpd_sys_rw_content_t; per il resto dell'applicazione, soprattutto per la cartella app, basterà il contesto httpd_sys_content_t. Eseguite sul server come root:

semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MIO_PROGETTO/log(/.*)?'
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MIO_PROGETTO/temp(/.*)?'
restorecon -Rv /var/www/html/MIO_PROGETTO/

Va inoltre attivato il booleano SELinux httpd_can_network_connect_db, che permette a Nette di connettersi al database in rete. Per impostazione predefinita è disattivato. Per questo compito si può usare il comando setsebool e, se si indica l'opzione -P, l'impostazione resta valida anche dopo il riavvio:

setsebool -P httpd_can_network_connect_db on

Come cambiare o rimuovere la directory www dall'URL?

La directory www/ usata nei progetti di esempio di Nette rappresenta la directory pubblica, il document-root del progetto. È l'unica directory il cui contenuto è accessibile dal browser. Contiene il file index.php, il punto di ingresso che avvia l'applicazione web Nette.

Per far girare l'applicazione su un hosting, dovete configurare correttamente il document-root. Avete due possibilità:

  1. Impostare nella configurazione dell'hosting il document-root su questa directory.
  2. Se l'hosting ha una cartella già pronta (per esempio public_html), rinominate www/ con questo nome.

Non provate mai a mettere in sicurezza la vostra applicazione usando solo .htaccess o le regole del router per impedire l'accesso alle altre cartelle.

Se l'hosting non permette di impostare il document-root su una sottodirectory (cioè di creare directory un livello sopra la directory pubblica), cercatevi un altro provider. Altrimenti correreste un notevole rischio di sicurezza. Sarebbe come vivere in un appartamento la cui porta d'ingresso non si può chiudere ed è sempre spalancata.

Come configurare il server per gli URL leggibili?

Apache: dovete attivare e configurare le regole di mod_rewrite nel file .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]

Se incontrate problemi, assicuratevi che:

Se installate l'applicazione in una sottocartella, può essere necessario decommentare la riga con l'impostazione RewriteBase e impostarla sulla cartella corretta.

nginx: il reindirizzamento va configurato con la direttiva try_files dentro il blocco location / nella configurazione del server.

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args È IMPORTANTE!
}

Il blocco location deve comparire una sola volta per ogni percorso del filesystem dentro il blocco server. Se nella vostra configurazione avete già un blocco location /, aggiungete la direttiva try_files nel blocco esistente.

Verificare che .htaccess funzioni

Il modo più semplice di verificare se Apache usa o ignora il vostro file .htaccess è romperlo di proposito. Mettete all'inizio del file la riga Test. Se ora aggiornate la pagina nel browser, dovreste vedere un Internal Server Error.

Se vedete questo errore, è in realtà una buona cosa! Significa che Apache analizza il file .htaccess e incontra l'errore che ci abbiamo messo. Rimuovete la riga Test.

Se non vedete l'Internal Server Error, la vostra configurazione di Apache ignora il file .htaccess. Di solito Apache lo ignora perché manca la direttiva di configurazione AllowOverride All.

Se lo ospitate voi stessi, si risolve facilmente. Aprite il vostro httpd.conf oppure apache.conf in un editor di testo, trovate la sezione <Directory> pertinente e aggiungete o modificate questa direttiva:

<Directory "/var/www/htdocs"> # percorso del vostro document root
    AllowOverride All
    ...

Se il vostro sito è ospitato altrove, controllate nel pannello di controllo se potete attivare lì .htaccess. Se non è possibile, contattate il vostro provider di hosting perché lo faccia per voi.

Verificare che mod_rewrite sia attivo

Se avete verificato che .htaccess funziona, potete verificare che l'estensione mod_rewrite sia attiva. Mettete all'inizio del file .htaccess la riga RewriteEngine On e aggiornate la pagina nel browser. Se vedete un Internal Server Error, significa che mod_rewrite non è attivo. Ci sono vari modi per attivarlo. Guardate su Stack Overflow i vari modi in cui si può fare nelle diverse configurazioni.

Nette genera i link con lo stesso protocollo della pagina corrente. Su una pagina https://foo genera quindi link che iniziano con https: e viceversa. Se state dietro a un reverse proxy che rimuove HTTPS (per esempio in Docker), dovete impostare il proxy nella configurazione perché il rilevamento del protocollo funzioni correttamente.

Se usate Nginx come proxy, dovete avere il reindirizzamento impostato per esempio così:

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-applicazione:80;  # IP o hostname del server/container su cui gira l'applicazione
}

Nella configurazione dovete inoltre indicare l'IP del proxy ed eventualmente l'intervallo di IP della vostra rete locale in cui fate girare l'infrastruttura:

http:
	proxy: IP-proxy/intervallo-IP

Uso dei caratteri { } in JavaScript

I caratteri { e } si usano per scrivere i tag di Latte. Tutto ciò che segue il carattere { (tranne lo spazio e le virgolette) è considerato un tag. Se dovete stampare direttamente il carattere { (spesso in JavaScript), potete mettere uno spazio (o un altro carattere di spaziatura) subito dopo {. Questo impedisce che venga interpretato come tag.

Se è necessario stampare questi caratteri in una situazione in cui il testo verrebbe interpretato come tag, potete usare i tag speciali per stampare questi caratteri: {l} per { e {r} per }.

{is a tag}
{ is not a tag }
{l}is not a tag{r}

Errore Cannot modify header information - headers already sent

Questo errore si verifica quando l'applicazione prova a inviare un header HTTP (un cookie, un redirect o l'avvio di una sessione) in un momento in cui al browser è già stato inviato qualche output. Gli header devono sempre precedere il corpo della risposta.

Le cause possibili sono due: o l'output esce troppo presto, oppure l'header viene inviato troppo tardi.

L'output esce di solito troppo presto a causa di uno spazio sperduto o di una riga vuota prima di <?php, dopo la chiusura ?>, oppure a causa di un BOM che l'editor ha inserito all'inizio del file e non mostra. Perciò non terminate mai i file PHP con ?>. Per scoprire quale punto ha stampato per primo, usate Tracy\OutputDebugger.

L'header viene inviato troppo tardi tipicamente quando si lavora con la sessione. Nette avvia la sessione automaticamente alla prima lettura o scrittura e, se questo avviene solo durante il rendering del template, l'output è già in viaggio. Lavorate perciò con la sessione al più tardi nel metodo beforeRender(), nei componenti anche nei metodi handle<Signal>().

Non provate a risolvere il problema impostando autoStart: true. Questo avvia la sessione per ogni visitatore, robot compresi, e crea inutilmente un'enorme quantità di file sul disco. Il valore predefinito smart avvia la sessione solo quando serve davvero.

Avviso Presenter::getContext() is deprecated

Nette è stato di gran lunga il primo framework PHP a passare alla dependency injection e a guidare i programmatori a usarla in modo coerente, a partire proprio dai presenter. Se un presenter ha bisogno di una dipendenza, se la fa passare. Al contrario, passare l'intero container DI a una classe e lasciare che estragga da sé le dipendenze è considerato un antipattern (noto come service locator). Questo approccio si usava in Nette 0.x prima dell'avvento della dependency injection e il metodo Presenter::getContext(), da tempo contrassegnato come deprecato, è un residuo di quell'epoca.

Se state portando avanti un'applicazione Nette molto vecchia, potreste scoprire che usa ancora questo metodo. Dalla versione 3.1 di nette/application incontrerete l'avviso Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection e dalla versione 4.0 un errore che dice che il metodo non esiste.

La soluzione pulita è naturalmente rifattorizzare l'applicazione perché passi le dipendenze con la dependency injection. Come soluzione di ripiego potete aggiungere al vostro presenter di base un vostro metodo getContext() per aggirare il messaggio:

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;
	}
}
versione: 4.x