Fehlerbehebung

Nette funktioniert nicht, eine weiße Seite wird angezeigt

  • Versuchen Sie, in der Datei index.php hinter declare(strict_types=1); die Zeile ini_set('display_errors', '1'); error_reporting(E_ALL); einzufügen, um die Anzeige von Fehlern zu erzwingen.
  • Sehen Sie weiterhin eine weiße Seite, liegt vermutlich ein Fehler in der Serverkonfiguration vor, und den Grund finden Sie im Log des Servers. Prüfen Sie zur Sicherheit, ob PHP überhaupt funktioniert, indem Sie versuchen, mit echo 'test'; etwas auszugeben.
  • Sehen Sie den Fehler Server Error: We're sorry! …, machen Sie mit dem nächsten Abschnitt weiter:

Fehler 500 Server Error: We're sorry! …

Diese Fehlerseite zeigt Nette im Produktionsmodus an. Sehen Sie sie auf Ihrem Entwicklungsrechner, wechseln Sie in den Entwicklungsmodus, und Tracy zeigt Ihnen einen ausführlichen Bericht.

Den Grund für den Fehler finden Sie immer im Log im Verzeichnis log/. Enthält die Fehlermeldung jedoch die Formulierung Tracy is unable to log error, stellen Sie zuerst fest, warum sich Fehler nicht protokollieren lassen. Das können Sie 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 sagt Ihnen, warum es nicht protokollieren kann. Die Ursache können unzureichende Rechte zum Schreiben in das Verzeichnis log/ sein.

Einer der häufigsten Gründe für einen Fehler 500 ist ein veralteter Cache. Während Nette den Cache im Entwicklungsmodus klug automatisch aktualisiert, konzentriert es sich im Produktionsmodus auf maximale Leistung, und das Leeren des Caches nach jeder Änderung des Codes liegt in Ihrer Verantwortung. Versuchen Sie, temp/cache zu löschen.

Fehler 404, Routing funktioniert nicht

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

Änderungen in Templates oder in der Konfiguration wirken sich nicht aus

“Ich habe das Template oder die Konfiguration geändert, aber die Website zeigt weiterhin die alte Version.” Dieses Verhalten tritt im Produktionsmodus auf, der aus Leistungsgründen nicht auf Dateiänderungen prüft und den zuvor erzeugten Cache behält.

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

$this->configurator->setDebugMode('your.ip.address');

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

Nette ist klug, und Sie müssen das Caching darin nicht abschalten. Während der Entwicklung aktualisiert es den Cache automatisch, sobald sich etwas am Template oder an der Konfiguration des DI-Containers ändert. Außerdem wird der Entwicklungsmodus per Autodetektion aktiviert, sodass meist nichts konfiguriert werden muss, höchstens die IP-Adresse.

Beim Debuggen des Routers empfehlen wir, den Cache des Browsers abzuschalten, in dem zum Beispiel Weiterleitungen gespeichert sein können: Öffnen Sie die Entwicklerwerkzeuge (Strg+Umschalt+I oder Cmd+Option+I) und aktivieren Sie im Panel Network das Kästchen zum Abschalten des Caches.

Fehler #[\ReturnTypeWillChange] attribute should be used

Dieser Fehler tritt auf, wenn Sie PHP auf Version 8.1 aktualisiert haben, aber eine Version von Nette verwenden, die damit nicht kompatibel ist. Die Lösung ist, Nette mit composer update auf eine neuere Version zu aktualisieren. Nette unterstützt PHP 8.1 seit Version 3.0. Wenn Sie eine ältere Version verwenden (prüfen Sie Ihre composer.json), aktualisieren Sie Nette oder bleiben Sie bei PHP 8.0.

Einstellung der Verzeichnisberechtigungen

Wenn Sie unter macOS oder Linux (oder einem anderen unixbasierten System) entwickeln, müssen Sie Schreibrechte für den Webserver einrichten. Nehmen wir an, Ihre Anwendung liegt im Standardverzeichnis /var/www/html (Fedora, CentOS, RHEL):

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

Auf manchen Linux-Systemen (Fedora, CentOS, …) ist SELinux möglicherweise standardmäßig aktiviert. Unter Umständen müssen Sie die SELinux-Richtlinien aktualisieren oder für die Pfade der Verzeichnisse temp und log den richtigen SELinux-Sicherheitskontext setzen. Für die Verzeichnisse temp und log sollte der Kontext httpd_sys_rw_content_t gesetzt werden; für den Rest der Anwendung – vor allem den Ordner app – genügt der Kontext httpd_sys_content_t. Führen Sie auf dem Server als root 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, damit Nette sich über das Netzwerk mit der Datenbank verbinden darf. Standardmäßig ist er deaktiviert. Dafür lässt sich der Befehl setsebool verwenden, und wenn die Option -P angegeben wird, bleibt diese Einstellung über Neustarts hinweg erhalten:

setsebool -P httpd_can_network_connect_db on

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

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

Um die Anwendung bei einem Hoster zu betreiben, müssen Sie den Document-Root korrekt einrichten. Sie haben zwei Möglichkeiten:

  1. Setzen Sie den Document-Root in der Konfiguration des Hostings auf dieses Verzeichnis.
  2. Hat das Hosting einen vorbereiteten Ordner (z. B. public_html), benennen Sie www/ in diesen Namen um.

Versuchen Sie niemals, Ihre Anwendung nur mit .htaccess oder Regeln des Routers abzusichern, um den Zugriff auf andere Ordner zu verhindern.

Erlaubt der Hoster nicht, den Document-Root auf ein Unterverzeichnis zu setzen (also Verzeichnisse eine Ebene über dem öffentlichen Verzeichnis anzulegen), suchen Sie sich einen anderen Anbieter. Sonst gingen Sie ein erhebliches Sicherheitsrisiko ein. Das wäre, als würden Sie in einer Wohnung leben, deren Wohnungstür sich nicht schließen lässt und immer weit offen steht.

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

Apache: Sie müssen die mod_rewrite-Regeln in der Datei .htaccess aktivieren und konfigurieren:

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:

Richten Sie die Anwendung in einem Unterordner ein, müssen Sie eventuell die Zeile für die Einstellung RewriteBase einkommentieren und auf den richtigen Ordner setzen.

nginx: Die Weiterleitung muss über die Direktive try_files innerhalb des Blocks location / in der Serverkonfiguration eingerichtet werden.

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

Der Block location darf innerhalb des Blocks server für jeden Dateisystempfad nur einmal vorkommen. Wenn Sie in Ihrer Konfiguration bereits einen Block location / haben, ergänzen Sie die Direktive try_files im bestehenden Block.

Überprüfung, ob .htaccess funktioniert

Am einfachsten prüfen Sie, ob Apache Ihre Datei .htaccess verwendet oder ignoriert, indem Sie sie absichtlich kaputt machen. Setzen Sie an den Anfang der Datei die Zeile Test. Wenn Sie die Seite nun im Browser neu laden, sollten Sie einen Internal Server Error sehen.

Wenn Sie diesen Fehler sehen, ist das eigentlich gut! Es bedeutet, dass Apache die Datei .htaccess verarbeitet und auf den Fehler stößt, den wir dort hineingeschrieben haben. Entfernen Sie die Zeile Test.

Sehen Sie keinen Internal Server Error, ignoriert Ihre Apache-Einrichtung die Datei .htaccess. Meist ignoriert Apache sie, weil die Konfigurationsdirektive AllowOverride All fehlt.

Wenn Sie selbst hosten, lässt sich das leicht beheben. Öffnen Sie Ihre httpd.conf oder apache.conf in einem Texteditor, suchen Sie den passenden Abschnitt <Directory> und ergänzen bzw. ändern Sie diese Direktive:

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

Wird Ihre Site anderswo gehostet, sehen Sie in Ihrem Control Panel nach, ob Sie .htaccess dort aktivieren können. Wenn nicht, wenden Sie sich an Ihren Hoster, damit er es für Sie tut.

Überprüfung, ob mod_rewrite aktiviert ist

Wenn Sie geprüft haben, dass .htaccess funktioniert, können Sie prüfen, ob die Extension mod_rewrite aktiviert ist. Setzen Sie an den Anfang der Datei .htaccess die Zeile RewriteEngine On und laden Sie die Seite im Browser neu. Sehen Sie einen Internal Server Error, bedeutet das, dass mod_rewrite nicht aktiviert ist. Es gibt mehrere Wege, es zu aktivieren. Auf Stack Overflow finden Sie verschiedene Wege, wie das bei unterschiedlichen Einrichtungen geht.

Nette erzeugt Links mit demselben Protokoll, das die aktuelle Seite verwendet. Auf einer Seite https://foo erzeugt es also Links, die mit https: beginnen, und umgekehrt. Wenn Sie hinter einem Reverse Proxy stehen, der HTTPS abstreift (zum Beispiel in Docker), müssen Sie in der Konfiguration einen Proxy einrichten, damit die Erkennung des Protokolls richtig funktioniert.

Wenn Sie Nginx als Proxy verwenden, muss die Weiterleitung zum Beispiel so eingerichtet 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-aplikace:80;  # IP oder Hostname des Servers/Containers, auf dem die Anwendung läuft
}

Weiterhin müssen Sie in der Konfiguration die IP des Proxys und optional den IP-Bereich Ihres lokalen Netzwerks angeben, in dem Sie die Infrastruktur betreiben:

http:
	proxy: IP-proxy/IP-range

Verwendung der Zeichen { } in JavaScript

Die Zeichen { und } dienen zum Schreiben von Latte-Tags. Alles, was auf das Zeichen { folgt (außer einem Leerzeichen und einem Anführungszeichen), gilt als Tag. Wenn Sie das Zeichen { direkt ausgeben müssen (häufig in JavaScript), können Sie direkt hinter { ein Leerzeichen (oder ein anderes Whitespace-Zeichen) setzen. Damit wird es nicht als Tag interpretiert.

Müssen diese Zeichen in einer Situation ausgegeben werden, in der der Text als Tag interpretiert würde, können Sie spezielle Tags zur Ausgabe dieser Zeichen verwenden – {l} für { und {r} für }.

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

Fehler Cannot modify header information - headers already sent

Dieser Fehler tritt auf, wenn die Anwendung versucht, einen HTTP-Header zu senden (ein Cookie, eine Weiterleitung oder den Start einer Session), obwohl bereits eine Ausgabe an den Browser gegangen ist. Header müssen immer vor dem Body der Response kommen.

Es gibt zwei mögliche Ursachen: Entweder geht die Ausgabe zu früh raus, oder der Header wird zu spät gesendet.

Die Ausgabe geht meist wegen eines versehentlichen Leerzeichens oder einer Leerzeile vor <?php, nach dem schließenden ?> oder wegen eines BOM zu früh raus, das der Editor am Anfang der Datei eingefügt hat und nicht anzeigt. Beenden Sie PHP-Dateien deshalb niemals mit ?>. Um herauszufinden, welche Stelle zuerst etwas ausgegeben hat, verwenden Sie Tracy\OutputDebugger.

Der Header wird typischerweise bei der Arbeit mit der Session zu spät gesendet. Nette startet die Session automatisch beim ersten Lesen oder Schreiben, und wenn das erst beim Rendern des Templates passiert, ist die Ausgabe bereits unterwegs. Arbeiten Sie mit der Session deshalb spätestens in der Methode beforeRender(), in Komponenten auch in den Methoden handle<Signal>().

Versuchen Sie nicht, das Problem mit autoStart: true zu lösen. Das startet die Session für jeden Besucher, auch für Robots, und legt unnötig eine riesige Zahl von Dateien auf der Festplatte an. Der Standardwert smart startet die Session nur dann, wenn sie wirklich gebraucht wird.

Meldung Presenter::getContext() is deprecated

Nette war bei Weitem das erste PHP-Framework, das auf Dependency Injection umgestiegen ist und Programmierer angeleitet hat, sie konsequent zu verwenden, gleich beginnend bei den Presentern. Braucht ein Presenter eine Abhängigkeit, fordert er sie an. Umgekehrt gilt es als Antipattern, einer Klasse den gesamten DI-Container zu übergeben und sich die Abhängigkeiten direkt daraus zu holen (bekannt als Service-Locator-Pattern). Dieser Ansatz wurde in Nette 0.x vor dem Aufkommen von Dependency Injection verwendet, und die seit Langem als veraltet markierte Methode Presenter::getContext() ist ein Überbleibsel jener Zeit.

Wenn Sie eine sehr alte Nette-Anwendung portieren, kann es sein, dass sie diese Methode noch verwendet. Seit nette/application in Version 3.1 begegnet Ihnen die Warnung Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, und seit Version 4.0 ein Fehler, dass die Methode nicht existiert.

Die saubere Lösung ist natürlich, die Anwendung so umzubauen, dass die Abhängigkeiten per Dependency Injection übergeben werden. Als Behelfslösung können Sie in Ihrem Basis-Presenter eine eigene Methode getContext() ergänzen, um die Meldung zu 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.x