Résolution de problèmes

Nette ne fonctionne pas, une page blanche s'affiche

  • Essayez de placer ini_set('display_errors', '1'); error_reporting(E_ALL); après declare(strict_types=1); dans le fichier index.php pour forcer l'affichage des erreurs.
  • Si vous voyez toujours un écran blanc, il y a probablement une erreur dans la configuration du serveur et vous en trouverez la raison dans le journal du serveur. Pour en être sûr, vérifiez que PHP fonctionne tout court en essayant d'afficher quelque chose avec echo 'test';.
  • Si vous voyez l'erreur Server Error: We're sorry! …, continuez avec la section suivante :

Erreur 500 Server Error: We're sorry! …

Cette page d'erreur est affichée par Nette en mode production. Si vous la voyez sur votre machine de développement, passez en mode développement et Tracy affichera un rapport détaillé.

Vous trouverez toujours la raison de l'erreur dans le journal du répertoire log/. Si le message d'erreur contient cependant la phrase Tracy is unable to log error, déterminez d'abord pourquoi les erreurs ne peuvent pas être journalisées. Vous pouvez le faire, par exemple, en passant temporairement en mode développement et en laissant Tracy journaliser quelque chose après son démarrage :

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

Tracy vous dira pourquoi elle ne peut pas journaliser. La cause peut être des permissions insuffisantes pour écrire dans le répertoire log/.

L'une des causes les plus fréquentes d'une erreur 500 est un cache périmé. Alors que Nette met intelligemment le cache à jour automatiquement en mode développement, en mode production il vise les performances maximales et c'est à vous de vider le cache après chaque modification du code. Essayez de supprimer temp/cache.

Erreur 404, le routage ne fonctionne pas

Lorsque toutes les pages (sauf la page d'accueil) renvoient une erreur 404, cela ressemble à un problème de configuration du serveur pour les URL élégantes.

Les changements dans les templates ou la configuration ne sont pas pris en compte

“J'ai modifié le template ou la configuration, mais le site affiche toujours l'ancienne version.” Ce comportement survient en mode production, qui, pour des raisons de performance, ne vérifie pas les changements de fichiers et conserve le cache généré précédemment.

Pour éviter de vider manuellement le cache sur le serveur de production après chaque modification, activez le mode développement pour votre adresse IP dans le fichier Bootstrap.php :

$this->configurator->setDebugMode('votre.adresse.ip');

Comment désactiver le cache pendant le développement ?

Nette est malin et vous n'avez pas besoin d'y désactiver la mise en cache. Pendant le développement, il met automatiquement le cache à jour dès qu'un template ou la configuration du conteneur DI change. De plus, le mode développement est activé par détection automatique, il n'y a donc généralement rien à configurer, ou seulement l'adresse IP.

Lors du débogage du routeur, nous recommandons de désactiver le cache du navigateur, où peuvent par exemple être stockées les redirections : ouvrez les outils de développement (Ctrl+Shift+I ou Cmd+Option+I) et, dans le panneau Réseau, cochez la case désactivant le cache.

Erreur #[\ReturnTypeWillChange] attribute should be used

Cette erreur survient si vous avez mis PHP à niveau vers la version 8.1 mais utilisez une version de Nette qui n'est pas compatible avec elle. La solution est de mettre Nette à jour vers une version plus récente avec composer update. Nette prend en charge PHP 8.1 depuis la version 3.0. Si vous utilisez une version plus ancienne (vérifiez votre composer.json), mettez Nette à niveau ou restez sur PHP 8.0.

Régler les permissions des répertoires

Si vous développez sur macOS ou Linux (ou tout autre système fondé sur Unix), vous devez configurer les droits d'écriture pour le serveur web. En supposant que votre application se trouve dans le répertoire par défaut /var/www/html (Fedora, CentOS, RHEL) :

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

Sur certains systèmes Linux (Fedora, CentOS, …), SELinux peut être activé par défaut. Vous devrez peut-être mettre à jour les politiques SELinux ou attribuer aux chemins des répertoires temp et log le bon contexte de sécurité SELinux. Les répertoires temp et log devraient recevoir le contexte httpd_sys_rw_content_t ; pour le reste de l'application – surtout le dossier app – le contexte httpd_sys_content_t suffira. Exécutez sur le serveur en tant que root :

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

Il faut ensuite activer le booléen SELinux httpd_can_network_connect_db pour permettre à Nette de se connecter à la base de données par le réseau. Il est désactivé par défaut. La commande setsebool peut servir à cette tâche et, si l'option -P est indiquée, ce réglage persistera après les redémarrages :

setsebool -P httpd_can_network_connect_db on

Comment changer ou supprimer le répertoire www de l'URL ?

Le répertoire www/ utilisé dans les projets d'exemple de Nette représente le répertoire public, ou document-root, du projet. C'est le seul répertoire dont le contenu est accessible au navigateur. Il contient le fichier index.php, le point d'entrée qui lance l'application web Nette.

Pour faire tourner l'application sur un hébergement, vous devez configurer correctement le document-root. Vous avez deux possibilités :

  1. Définir le document-root sur ce répertoire dans la configuration de l'hébergement.
  2. Si l'hébergement dispose d'un dossier préparé (par exemple public_html), renommer www/ avec ce nom.

N'essayez jamais de sécuriser votre application en vous appuyant seulement sur .htaccess ou sur des règles de routeur pour empêcher l'accès aux autres dossiers.

Si l'hébergement ne permet pas de définir le document-root sur un sous-répertoire (autrement dit de créer des répertoires un niveau au-dessus du répertoire public), cherchez un autre prestataire. Sinon, vous vous exposeriez à un risque de sécurité important. Ce serait comme habiter un appartement dont la porte d'entrée ne peut pas se fermer et reste toujours grande ouverte.

Comment configurer un serveur pour des URL élégantes ?

Apache : vous devez activer et configurer les règles mod_rewrite dans le fichier .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 vous rencontrez des problèmes, assurez-vous que :

Si vous installez l'application dans un sous-dossier, vous devrez peut-être décommenter la ligne du réglage RewriteBase et l'ajuster au bon dossier.

nginx : la redirection doit être configurée à l'aide de la directive try_files à l'intérieur du bloc location / de la configuration du serveur.

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args EST IMPORTANT !
}

Le bloc location ne doit apparaître qu'une seule fois par chemin du système de fichiers au sein du bloc server. Si vous avez déjà un bloc location / dans votre configuration, ajoutez la directive try_files dans le bloc existant.

Tester si .htaccess fonctionne

La façon la plus simple de tester si Apache utilise ou ignore votre fichier .htaccess est de le casser intentionnellement. Placez la ligne Test au début du fichier. Si vous rafraîchissez alors la page dans votre navigateur, vous devriez voir une Internal Server Error.

Si vous voyez cette erreur, c'est en fait une bonne nouvelle ! Cela signifie qu'Apache analyse le fichier .htaccess et rencontre l'erreur que nous y avons mise. Supprimez la ligne Test.

Si vous ne voyez pas d'Internal Server Error, votre configuration Apache ignore le fichier .htaccess. En général, Apache l'ignore parce que la directive de configuration AllowOverride All manque.

Si vous hébergez vous-même, c'est facile à corriger. Ouvrez votre httpd.conf ou apache.conf dans un éditeur de texte, trouvez la section <Directory> concernée et ajoutez ou modifiez cette directive :

<Directory "/var/www/htdocs"> # chemin de votre document root
    AllowOverride All
    ...

Si votre site est hébergé ailleurs, regardez dans votre panneau de contrôle si vous pouvez y activer .htaccess. Sinon, contactez votre hébergeur pour qu'il le fasse pour vous.

Tester si mod_rewrite est activé

Si vous avez vérifié que .htaccess fonctionne, vous pouvez vérifier que l'extension mod_rewrite est activée. Placez la ligne RewriteEngine On au début du fichier .htaccess et rafraîchissez la page dans votre navigateur. Si vous voyez une Internal Server Error, cela signifie que mod_rewrite n'est pas activé. Il existe plusieurs façons de l'activer. Voyez Stack Overflow pour les différentes manières d'y parvenir selon les configurations.

Les liens sont générés sans https:

Nette génère les liens avec le même protocole que celui de la page courante. Sur une page https://foo, il génère donc des liens commençant par https:, et inversement. Si vous êtes derrière un reverse proxy qui supprime le HTTPS (par exemple dans Docker), vous devez configurer un proxy dans la configuration pour que la détection du protocole fonctionne correctement.

Si vous utilisez Nginx comme proxy, vous devez avoir une redirection configurée, par exemple ainsi :

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-application:80;  # IP ou nom d'hôte du serveur/conteneur où tourne l'application
}

Vous devez en outre indiquer dans la configuration l'IP du proxy et, éventuellement, la plage d'IP de votre réseau local où vous faites tourner l'infrastructure :

http:
	proxy: IP-proxy/plage-IP

Utilisation des caractères { } en JavaScript

Les caractères { et } servent à écrire les balises Latte. Tout ce qui suit le caractère { (à l'exception de l'espace et du guillemet) est considéré comme une balise. Si vous avez besoin d'afficher directement le caractère { (souvent en JavaScript), vous pouvez placer une espace (ou un autre caractère blanc) juste après {. Cela empêche qu'il soit interprété comme une balise.

S'il faut afficher ces caractères dans une situation où le texte serait interprété comme une balise, vous pouvez utiliser des balises spéciales pour les afficher : {l} pour { et {r} pour }.

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

Erreur Cannot modify header information - headers already sent

Cette erreur survient lorsque l'application essaie d'envoyer un en-tête HTTP (un cookie, une redirection ou le démarrage d'une session) à un moment où une sortie a déjà été envoyée au navigateur. Les en-têtes doivent toujours précéder le corps de la réponse.

Il y a deux causes possibles : soit la sortie part trop tôt, soit l'en-tête est envoyé trop tard.

La sortie part généralement trop tôt à cause d'une espace ou d'une ligne vide égarée avant <?php, après le ?> fermant, ou à cause d'un BOM que l'éditeur a inséré au début du fichier sans l'afficher. Ne terminez donc jamais les fichiers PHP par ?>. Pour découvrir quel endroit a affiché quelque chose en premier, utilisez Tracy\OutputDebugger.

L'en-tête est typiquement envoyé trop tard lors du travail avec une session. Nette démarre la session automatiquement à la première lecture ou écriture et, si cela n'arrive que pendant le rendu du template, la sortie est déjà en route. Travaillez donc avec la session au plus tard dans la méthode beforeRender(), dans les composants aussi dans les méthodes handle<Signal>().

N'essayez pas de résoudre le problème en définissant autoStart: true. Cela démarre la session pour chaque visiteur, robots compris, et crée inutilement une quantité énorme de fichiers sur le disque. La valeur par défaut smart ne démarre la session que lorsqu'elle est vraiment nécessaire.

Avertissement Presenter::getContext() is deprecated

Nette a été de loin le premier framework PHP à passer à l'injection de dépendances et à guider les programmeurs pour qu'ils l'utilisent systématiquement, en commençant par les presenters. Si un presenter a besoin d'une dépendance, il la demande. À l'inverse, passer tout le conteneur DI à une classe pour qu'elle en tire directement ses dépendances est considéré comme un anti-pattern (connu sous le nom de service locator). Cette approche était utilisée dans Nette 0.x, avant l'arrivée de l'injection de dépendances, et la méthode Presenter::getContext(), marquée obsolète depuis longtemps, est un vestige de cette époque.

Si vous portez une très vieille application Nette, vous découvrirez peut-être qu'elle utilise encore cette méthode. Depuis la version 3.1 de nette/application, vous rencontrerez l'avertissement Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection et, depuis la version 4.0, une erreur indiquant que la méthode n'existe pas.

La solution propre est bien sûr de refactoriser l'application pour passer les dépendances par injection de dépendances. Comme solution de contournement, vous pouvez ajouter votre propre méthode getContext() à votre presenter de base pour contourner le message :

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