Fehlerbehebung

Nette funktioniert nicht, eine weiße Seite wird angezeigt

  • Versuchen Sie, in die Datei index.php direkt nach declare(strict_types=1); ini_set('display_errors', '1'); error_reporting(E_ALL); einzufügen, damit erzwingen Sie die Anzeige von Fehlern.
  • Wenn Sie immer noch einen weißen Bildschirm sehen, liegt wahrscheinlich ein Fehler in der Serverkonfiguration vor und Sie finden den Grund im Server-Log. Überprüfen Sie zur Sicherheit auch, ob PHP überhaupt funktioniert, indem Sie versuchen, etwas mit echo 'test'; auszugeben.
  • Wenn Sie den Fehler Server Error: We're sorry! … sehen, fahren Sie mit dem nächsten Abschnitt fort:

Fehler 500 Server Error: We're sorry! …

Diese Fehlerseite zeigt Nette im Produktionsmodus an. Wenn sie auf Ihrem Entwicklungsrechner angezeigt wird, wechseln Sie in den Entwicklungsmodus und Tracy wird Ihnen mit einer detaillierten Meldung angezeigt.

Den Grund für den Fehler finden Sie immer im Log im Verzeichnis log/. Wenn jedoch in der Fehlermeldung der Satz Tracy is unable to log error erscheint, finden Sie zuerst heraus, warum Fehler nicht protokolliert werden können. Sie können dies zum Beispiel tun, indem Sie vorübergehend in den Entwicklungsmodus wechseln und Tracy nach dem Start irgendetwas protokollieren lassen:

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

Tracy wird Ihnen mitteilen, warum sie nicht protokollieren kann. Die Ursache können wahrscheinlich unzureichende Berechtigungen für das Schreiben in das Verzeichnis log/ sein.

Einer der häufigsten Gründe für einen 500-Fehler ist ein veralteter Cache. Während Nette im Entwicklungsmodus den Cache intelligent automatisch aktualisiert, konzentriert es sich im Produktionsmodus auf die Maximierung der Leistung, und das Löschen des Caches nach jeder Codeänderung liegt bei Ihnen. Versuchen Sie, temp/cache zu löschen.

Fehler 404, Routing funktioniert nicht

Wenn alle Seiten (außer der Homepage) einen 404-Fehler zurückgeben, sieht es nach einem Problem mit der Serverkonfiguration für schöne URLs (Pretty URLs) aus.

Änderungen in Templates oder Konfiguration werden nicht angezeigt

“Ich habe das Template oder die Konfiguration geändert, aber die Website zeigt immer noch die alte Version an.” Dieses Verhalten tritt im Produktionsmodus auf, der aus Leistungsgründen keine Änderungen in Dateien überprüft und einen einmal generierten Cache beibehält.

Damit Sie nicht auf dem Produktionsserver nach jeder Änderung den Cache manuell löschen müssen, aktivieren Sie den Entwicklungsmodus für Ihre IP-Adresse in der Datei Bootstrap.php:

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

Wie schaltet man den Cache während der Entwicklung aus?

Nette ist intelligent, und Sie müssen das Caching darin nicht deaktivieren. Während der Entwicklung aktualisiert es nämlich den Cache automatisch bei jeder Änderung des Templates oder der DI-Container-Konfiguration. Der Entwicklungsmodus wird außerdem durch Autodetektion aktiviert, daher ist es normalerweise nicht notwendig, etwas zu konfigurieren, oder nur die IP-Adresse.

Beim Debuggen des Routers empfehlen wir, den Browser-Cache zu deaktivieren, in dem beispielsweise Weiterleitungen gespeichert sein können: öffnen Sie die Developer Tools (Strg+Shift+I oder Cmd+Option+I) und aktivieren Sie im Panel Network (Netzwerk) die Deaktivierung des Caches.

Fehler #[\ReturnTypeWillChange] attribute should be used

Dieser Fehler tritt auf, wenn Sie PHP auf Version 8.1 aktualisiert haben, aber eine Nette-Version verwenden, die nicht damit kompatibel ist. Die Lösung besteht also darin, Nette auf eine neuere Version mit composer update zu aktualisieren. Nette unterstützt PHP 8.1 ab Version 3.0. Wenn Sie eine ältere Version verwenden (Sie finden es heraus, indem Sie in composer.json nachsehen), führen Sie ein Upgrade von Nette durch oder bleiben Sie bei PHP 8.0.

Einstellung der Verzeichnisberechtigungen

Wenn Sie auf macOS oder Linux entwickeln (oder auf einem anderen Unix-basierten System), müssen Sie Schreibberechtigungen für den Webserver festlegen. Angenommen, Ihre Anwendung befindet sich im Standardverzeichnis /var/www/html (Fedora, CentOS, RHEL).

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

Auf einigen Linux-Systemen (Fedora, CentOS, …) ist SELinux standardmäßig aktiviert. Sie müssen die SELinux-Policies entsprechend anpassen und den korrekten SELinux-Sicherheitskontext für die Ordner temp und log festlegen. Für temp und log setzen wir den Kontexttyp httpd_sys_rw_content_t, für den Rest der Anwendung (und insbesondere für den Ordner app) wird httpd_sys_content_t ausreichen. Führen Sie auf dem Server aus:

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

Weiterhin muss der SELinux-Boolean httpd_can_network_connect_db aktiviert werden, der standardmäßig deaktiviert ist und der Nette erlaubt, sich über das Netzwerk mit der Datenbank zu verbinden. Wir verwenden dazu den Befehl setsebool und mit der Option -P machen wir die Änderung dauerhaft, d.h. nach einem Server-Neustart erwartet uns keine böse Überraschung:

setsebool -P httpd_can_network_connect_db on

Wie ändert oder entfernt man das Verzeichnis www aus der URL?

Das Verzeichnis www/, das in den Beispielprojekten in Nette verwendet wird, stellt das sogenannte öffentliche Verzeichnis oder das Document-Root des Projekts dar. Es ist das einzige Verzeichnis, dessen Inhalt für den Browser zugänglich ist. Und es enthält die Datei index.php, den Einstiegspunkt, der die in Nette geschriebene Webanwendung startet.

Um die Anwendung auf einem Hosting zum Laufen zu bringen, muss das Document-Root korrekt konfiguriert sein. Sie haben zwei Möglichkeiten:

  1. Stellen Sie in der Hosting-Konfiguration das Document-Root auf dieses Verzeichnis ein.
  2. Wenn das Hosting einen vorbereiteten Ordner hat (z.B. public_html), benennen Sie www/ in diesen Namen um.

Versuchen Sie niemals, die Sicherheit nur mit .htaccess oder dem Router zu lösen, die den Zugriff auf andere Ordner verhindern würden.

Wenn das Hosting es nicht erlaubt, das Document-Root auf ein Unterverzeichnis zu setzen (d.h. Verzeichnisse eine Ebene über dem öffentlichen Verzeichnis zu erstellen), suchen Sie nach einem anderen. Sie würden sonst ein erhebliches Sicherheitsrisiko eingehen. Es wäre, als würde man in einer Wohnung leben, in der die Eingangstür nicht geschlossen werden kann und immer offen steht.

Wie konfiguriert man den Server für schöne URLs (Pretty URLs)?

Apache: Es ist notwendig, die mod_rewrite-Regeln in der Datei .htaccess zu aktivieren und einzustellen:

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]

Wenn Sie auf Probleme stoßen, stellen Sie sicher, dass:

Wenn Sie die Anwendung in einem Unterordner einrichten, müssen Sie möglicherweise die Zeile für die Einstellung RewriteBase auskommentieren und sie auf den richtigen Ordner setzen.

nginx: Es ist notwendig, die Weiterleitung mit der Direktive try_files innerhalb des location / Blocks in der Serverkonfiguration einzustellen.

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args IST WICHTIG!
}

Der location-Block für jeden Dateisystempfad darf im server-Block nur einmal vorkommen. Wenn Sie bereits location / in der Konfiguration haben, fügen Sie die Direktive try_files hinzu.

Überprüfung, ob .htaccess funktioniert

Der einfachste Weg zu testen, ob Apache Ihre Datei .htaccess verwendet oder ignoriert, ist, sie absichtlich zu beschädigen. Fügen Sie am Anfang der Datei die Zeile Test ein und nun, wenn Sie die Seite im Browser aktualisieren, sollten Sie Internal Server Error sehen.

Wenn Ihnen dieser Fehler angezeigt wird, ist das eigentlich gut! Es bedeutet, dass Apache die Datei .htaccess analysiert und auf den Fehler stößt, den wir dort eingefügt haben. Entfernen Sie die Zeile Test.

Wenn kein Internal Server Error angezeigt wird, ignoriert Ihre Apache-Einstellung die Datei .htaccess. Im Allgemeinen ignoriert Apache sie aufgrund der fehlenden Konfigurationsdirektive AllowOverride All.

Wenn Sie es selbst hosten, lässt sich das leicht beheben. Öffnen Sie die Datei httpd.conf oder apache.conf in einem Texteditor, suchen Sie den entsprechenden <Directory>-Abschnitt und fügen/ändern Sie diese Direktive:

<Directory "/var/www/htdocs"> # Pfad zu Ihrem Document Root
    AllowOverride All
    ...

Wenn Ihre Website woanders gehostet wird, schauen Sie im Control Panel nach, ob Sie dort die Datei .htaccess aktivieren können. Wenn nicht, wenden Sie sich an Ihren Hosting-Anbieter, damit er das für Sie erledigt.

Überprüfung, ob mod_rewrite aktiviert ist

Wenn Sie überprüft haben, dass .htaccess funktioniert, können Sie überprüfen, ob die Erweiterung mod_rewrite aktiviert ist. Fügen Sie am Anfang der Datei .htaccess die Zeile RewriteEngine On ein und aktualisieren Sie die Seite im Browser. Wenn Internal Server Error angezeigt wird, bedeutet das, dass mod_rewrite nicht aktiviert ist. Es gibt mehrere Möglichkeiten, es zu aktivieren. Verschiedene Möglichkeiten, wie dies in verschiedenen Setups durchgeführt werden kann, finden Sie auf Stack Overflow.

Nette generiert Links mit demselben Protokoll wie die Seite selbst. Also generiert es auf der Seite https://foo Links, die mit https: beginnen und umgekehrt. Wenn Sie sich hinter einem Reverse-Proxy-Server befinden, der HTTPS entfernt (zum Beispiel in Docker), dann müssen Sie in der Konfiguration den Proxy einstellen, damit die Protokollerkennung korrekt funktioniert.

Wenn Sie Nginx als Proxy verwenden, muss die Weiterleitung z.B. so eingestellt sein:

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-der-Anwendung:80;  # IP oder Hostname des Servers/Containers, auf dem die Anwendung läuft
}

Weiterhin muss in der Konfiguration die IP des Proxys und gegebenenfalls der IP-Bereich Ihres lokalen Netzwerks angegeben werden, wo Sie die Infrastruktur betreiben:

http:
	proxy: IP-proxy/IP-range

Verwendung von Zeichen { } in JavaScript

Die Zeichen { und } werden für die Notation von Latte-Tags verwendet. Als Tag wird alles betrachtet, was auf das Zeichen { folgt, mit Ausnahme eines Leerzeichens und eines Anführungszeichens. Wenn Sie also direkt das Zeichen { ausgeben müssen (oft zum Beispiel in JavaScript), können Sie nach dem Zeichen { ein Leerzeichen (oder ein anderes Leerzeichen) setzen. Dadurch vermeiden Sie die Interpretation als Tag.

Wenn es notwendig ist, diese Zeichen in einer Situation auszugeben, in der der Text als Tag verstanden würde, können Sie spezielle Tags zur Ausgabe dieser Zeichen verwenden – {l} für { und {r} für }.

{ist ein Tag}
{ ist kein Tag }
{l}ist kein Tag{r}

Meldung Presenter::getContext() is deprecated

Nette ist bei weitem das erste PHP-Framework, das auf Dependency Injection umgestiegen ist und Programmierer zu dessen konsequenter Nutzung angeleitet hat, schon bei den Presentern selbst. Wenn ein Presenter eine Abhängigkeit benötigt, fordert er sie an. Umgekehrt gilt der Weg, bei dem wir der Klasse den gesamten DI-Container übergeben und sie sich daraus direkt Abhängigkeiten holt, als Antipattern (wird Service Locator genannt). Diese Methode wurde in Nette 0.x noch vor dem Aufkommen von Dependency Injection verwendet und ihr Überbleibsel ist die Methode Presenter::getContext(), die vor langer Zeit als deprecated markiert wurde.

Wenn Sie eine sehr alte Anwendung für Nette portieren, kann es vorkommen, dass sie diese Methode immer noch verwendet. Ab nette/application Version 3.1 werden Sie auf die Warnung Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection stoßen, ab Version 4.0 auf den Fehler, dass die Methode nicht existiert.

Die saubere Lösung besteht natürlich darin, die Anwendung umzugestalten, sodass sie Abhängigkeiten mittels Dependency Injection übergibt. Als Workaround können Sie Ihrem Basis-Presenter eine eigene getContext()-Methode hinzufügen und die Meldung so umgehen:

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.0