mitmario.dev

Mehrere Seiten

PHP Sandbox 4 Min Lesezeit 3 BeispieleLektion 5 von 7

Bis hierhin hattest du eine Seite. Jetzt sollen es mehrere werden, und dafür gibt es genau zwei Wege. Beide funktionieren, beide kommen im echten Leben vor, und der Unterschied zwischen ihnen ist größer, als er zuerst aussieht.

Weg eins: eine Datei je Seite

Zwei Dateien nebeneinander
<?php

echo "<!doctype html>\n";
echo "<html lang=\"de\"><head><meta charset=\"utf-8\"><title>Hofladen</title></head>\n";
echo "<body>\n";
echo "<nav><a href=\"/\">Start</a> | <a href=\"/impressum.php\">Impressum</a></nav>\n";
echo "<h1>Startseite</h1>\n";
echo "<p>Diese Seite liegt in index.php.</p>\n";
echo "</body></html>\n";

Der einfachste Weg ist auch der älteste. Du legst impressum.php neben index.php, und schon beantwortet der Server /impressum.php. Kein Code dazwischen, keine Verzweigung, nichts einzurichten.

So arbeitet klassisches Hosting bis heute. Du lädst Dateien in einen Ordner, und jede Datei ist eine Adresse. Für eine überschaubare Seite ist das vollkommen in Ordnung, und wer behauptet, das sei falsch, hat noch nie eine Vereinsseite gebaut.

Zwei Nachteile hat der Weg trotzdem, und beide siehst du im Beispiel. Erstens steht die Adressendung .php in jeder Adresse. Zweitens, und das wiegt schwerer: Die Navigationsleiste steht jetzt zweimal da. Bei zwei Dateien fällt das nicht auf. Bei acht schon, und spätestens wenn ein Menüpunkt dazukommt, änderst du sieben Dateien und vergisst die achte. Genau dagegen hilft Lektion 10.6.

Weg zwei: eine Datei entscheidet selbst

Eine Datei, die den Pfad liest
<?php

$pfad = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);

$titel = match ($pfad) {
    "/" => "Startseite",
    "/impressum" => "Impressum",
    "/preise" => "Preise",
    default => "Unbekannt",
};

?>
<!doctype html>
<html lang="de">
<head><meta charset="utf-8"><title><?= $titel ?></title></head>
<body>
    <nav>
        <a href="/">Start</a> |
        <a href="/impressum">Impressum</a> |
        <a href="/preise">Preise</a> |
        <a href="/unfug">Unfug</a>
    </nav>
    <h1><?= $titel ?></h1>
    <p>Angefragter Pfad: <?= htmlspecialchars($pfad) ?></p>
    <p>Alle vier Adressen landen in derselben Datei.</p>
</body>
</html>

Der zweite Weg macht sich zunutze, was du in Lektion 10.2 gesehen hast: Ein Pfad ohne passende Datei landet auf der index.php, und der echte Pfad steht trotzdem in $_SERVER["REQUEST_URI"].

Damit kann eine einzige Datei jede Adresse beantworten. Sie liest den Pfad, entscheidet, was gemeint ist, und baut die passende Seite. Klick dich im Browser durch die vier Links: Die Adresse in der Adresszeile ändert sich jedes Mal, die Datei dahinter bleibt dieselbe. Mit Zurück und Vor in der Browser-Leiste gehst du den Weg noch einmal ab, wie in jedem Browser, und im Reiter Netzwerk steht nach jedem Klick die Anfrage dazu. Alle vier tragen eine 200, auch /unfug: Das Beispiel setzt für den unbekannten Pfad nur einen anderen Titel, noch keinen Statuscode. Das holt die Aufgabe nach.

Für die Verzweigung nimmt das Beispiel match aus Lektion 4.2. Das ist die Form, die am besten liest, solange es um feste Pfade geht. Sobald ein Pfad einen Platzhalter hat, etwa eine Artikelnummer wie in /notiz/12, reicht sie nicht mehr; dann braucht es einen Vergleich mit einem Muster, und das ist der Weg, den Abschnitt 16 geht.

Warum der Anhang wegmuss

In REQUEST_URI steht der Pfad samt allem hinter dem Fragezeichen. Ein Aufruf von /preise?sortierung=name gibt dir also nicht /preise, sondern die ganze Zeichenkette, und ein Vergleich mit "/preise" schlägt fehl.

parse_url($adresse, PHP_URL_PATH) schneidet den Anhang ab und gibt dir nur den Pfad. Die Funktion kann noch mehr, sie zerlegt eine vollständige Adresse auch in Protokoll, Servername und Port, aber in diesem Kurs brauchst du nur diesen einen Teil. Der Anhang selbst ist nicht verloren: Er steht weiterhin in $_GET, so wie in Lektion 10.3.

Was noch alles in $_SERVER steht

Was der Server dir hinlegt
<?php

$felder = ["REQUEST_URI", "SCRIPT_NAME", "PHP_SELF", "QUERY_STRING", "REQUEST_METHOD"];

echo "<!doctype html>\n";
echo "<html lang=\"de\"><head><meta charset=\"utf-8\"><title>Was ankommt</title></head>\n";
echo "<body>\n";
echo "<h1>Was der Server dir hinlegt</h1>\n";
echo "<ul>\n";

foreach ($felder as $feld) {
    $wert = $_SERVER[$feld] ?? "";
    echo "  <li>$feld = \"" . htmlspecialchars($wert) . "\"</li>\n";
}

echo "</ul>\n";
echo "<p><a href=\"/\">/</a> | <a href=\"/notiz/12\">/notiz/12</a> | ";
echo "<a href=\"/suche?ware=Kaffee\">/suche?ware=Kaffee</a></p>\n";
echo "</body></html>\n";

$_SERVER ist wie $_GET ein Array, das PHP für dich füllt, nur kommt es nicht vom Besucher, sondern vom Server. Fünf Einträge daraus wirst du wiedersehen.

REQUEST_URI ist der angefragte Pfad samt Anhang, also der wichtigste für dich. REQUEST_METHOD sagt GET oder POST und trägt ab Lektion 11.1 jedes Formular. QUERY_STRING ist der Anhang allein, unzerlegt. SCRIPT_NAME ist die Datei, die den Job wirklich macht, hier also immer /index.php.

Und PHP_SELF ist der Eintrag, bei dem man aufpassen muss. Klick im Browser auf /notiz/12, dann steht dort /index.php/notiz/12: die Datei plus alles, was dahinter noch am Pfad hing. Der Wert kommt also aus der Adresse und damit vom Besucher. Ihn ungeprüft in eine Seite zu schreiben ist eine der klassischen Lücken, und Abschnitt 15 zeigt sie. Merk dir für heute: $_SERVER ist nicht durchweg vertrauenswürdig, nur weil es vom Server kommt.

Welchen Weg nimmt dieser Kurs

Beide, und zwar der Reihe nach. Die Challenge dieser Lektion baut drei Seiten aus einer Datei, weil das der Weg ist, auf dem alles Weitere steht. In Abschnitt 16 bekommt dieselbe Idee einen Namen, nämlich Front Controller, und eine Struktur, mit der auch dreißig Seiten übersichtlich bleiben.

Was du dafür nicht brauchst, ist eine Einstellung am Server. Auf einem echten Hosting-Paket schreibt man dafür ein paar Zeilen in eine Datei namens .htaccess, damit alle Adressen bei der index.php ankommen. Der Server in diesem Kurs macht das von sich aus.

Zum Mitnehmen

Eine Seite reicht selten. Für mehrere gibt es zwei Wege, und beide sind richtig: eine Datei je Seite, so wie es klassisches Hosting seit dreißig Jahren macht, oder eine Datei, die den Pfad liest und selbst entscheidet. Der zweite ist der Anfang von allem, was heute Framework heißt.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.