HTTP-Server mit PHP
Links
Zielsetzung
Verständnis für den Ablauf der Kommunikation beim HTTP-Protokoll.
Das HTTP-Protokoll erlaubt es vielen Clients, mit einem Server Verbindung aufzunehmen und Daten auszutauschen.
Ein typischer HTTP-Client ist ein Browser: Er fordert Webseiten vom Webserver an und zeigt diese an.
Wir zeigen hier, wie ein minimaler HTTP-Server mittels PHP programmiert wird.
Das HTTP-Protokoll
Das Hypertext Transfer Protocol (HTTP) ist ein weit verbreitetes Protokoll, das in der Regel zur Übertragung von Daten im World Wide Web (WWW) verwendet wird. Es bildet die Grundlage für den Datenaustausch zwischen Webclients (z.B. Browsern wie Firefox) und Webservern. Das Prinzip des HTTP-Protokolls lässt sich in folgenden Schritten zusammenfassen:
Anforderung (Request)
Ein Client, in der Regel ein Webbrowser, sendet eine HTTP-Anforderung an einen Webserver. Diese Anforderung kann verschiedene Methoden wie GET, POST, PUT oder DELETE verwenden, um den Server über die gewünschte Aktion zu informieren.
Die Anforderung enthält immer eine URL (Universal Resource Locator): das ist die "Webadresse", in der verschieden Informationen zusammengefasst sind:
Beispiel einer URL: https://vokabulabor.hamatoma.de:443/index.php?title=HTTP-Server_mit_PHP&action=edit
https:
Das Schema: https steht für verschlüsseltes HTML, http für unverschlüsseltes. Möglich ist auchfile:
//vokabulabor.hamatoma.de
ist die Domäne. Es gibt eine System namens Domain Name System (DNS), bei der abgefragt werden kann, wo auf der Welt diese Domäne ist und "das Internet" weiß dann, wie die Anfrage dorthin geleitet werden kann.:443
ist der Port. Jede Domäne hat 65534 Ports: 1..65534. Damit kann eine Domäne viele Dienste (auf verschiedenen Ports) anbieten.- Wird kein Port angegeben, so wird beim Schema http der Port 80 genommen, bei https der Port 443.
/index.php
Dieser Pfad sagt dem Webserver, welche Info er bereitstellen soll.?title=HTTP-Server_mit_PHP&action=edit
Das sind die Abfrage (Query) einer Anfrage. Dort werden Zusatzinformationen mitgegeben.
Verbindungsaufbau
Wenn der Client eine Anforderung sendet, baut er eine Verbindung zum Server auf. Dies kann über das TCP/IP-Protokoll erfolgen, wobei normalerweise Port 80 für unverschlüsseltes HTTP und Port 443 für verschlüsseltes HTTPS verwendet wird.
Verarbeitung der Anforderung
Der Webserver empfängt die Anforderung und verarbeitet sie entsprechend. Dies kann das Bereitstellen von Ressourcen wie HTML-Seiten, Bildern, Videos oder anderen Daten beinhalten.
Antwort (Response)
Als Antwort schickt der Webserver Daten: das ist meistens eine HTML-Seite oder eine Datei (z.B. eine CSS-Datei).
Die Antwort enthält immer eine Statuscode:
- 200: OK Die Anfrage wurde korrekt beantwortet
- 301: Die Antwort steht unter einer anderen URL zur Verfügung. Der Browser stellt dann automatisch die Anfrage unter dieser URL.
- 404: Seite unbekannt: Der Server kennt die URL nicht.
- 403: Verboten: Ohne Anmeldung ist die Seite nicht erreichbar
PHP-Programm einer Webanwendung
- Wir legen ein Verzeichnis demowebserver an.
- Wir öffnen diesen Ordner im Visual Studio Code.
- Darin legen wir die Datei demo.php an:
<?php $server = new Server(); if ($_SERVER['REQUEST_URI'] == '/demo.php') { header('Location: http:/demo.php?home'); } elseif ($_SERVER['REQUEST_URI'] === '/demo.php?home') { $server->home(); } elseif ($_SERVER['REQUEST_URI'] === '/demo.php?impressum') { $server->impressum(); } else { header("HTTP/1.0 404 Not Found"); } class Server { public function home(){ $page = file_get_contents('home.html'); echo $page; } public function impressum(){ $page = file_get_contents('impressum.html'); echo $page; } }
Wir brauchen noch eine HTML-Datei home.html:
<!DOCTYPE html> <html lang="en"> <head> <title>Bootstrap 5 Example</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script> </head> <body> <nav class="navbar navbar-expand-sm navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" href="/demo.php?home">Logo</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mynavbar"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="mynavbar"> <ul class="navbar-nav me-auto"> <li class="nav-item"> <a class="nav-link" href="/demo.php?home">Start</a> </li> <li class="nav-item"> <a class="nav-link" href="demo.php?impressum">Impressum</a> </li> </ul> <form class="d-flex"> <button class="btn btn-secondary" type="button">Settings</button> <button class="btn btn-primary" type="button">Logout</button> </form> </div> </div> </nav> <div class="container-fluid p-5 bg-primary text-white text-center"> <h1>Meine erste Bootstrapseite</h1> </div> <div class="container mt-5"> <p>Hier geht es zum <a href="demo.php?login">Login</a></p> </div> </body> </html>
Wir brauchen noch eine HTML-Datei impressum.html:
<!DOCTYPE html> <html lang="en"> <head> <title>Bootstrap 5 Example</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script> </head> <body> <nav class="navbar navbar-expand-sm navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" href="/demo.php?home">Logo</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mynavbar"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="mynavbar"> <ul class="navbar-nav me-auto"> <li class="nav-item"> <a class="nav-link" href="/demo.php?home">Start</a> </li> <li class="nav-item"> <a class="nav-link" href="demo.php?impressum">Impressum</a> </li> </ul> <form class="d-flex"> <button class="btn btn-secondary" type="button">Settings</button> <button class="btn btn-primary" type="button">Logout</button> </form> </div> </div> </nav> <div class="container-fluid p-5 bg-primary text-white text-center"> <h1>Impressum</h1> </div> <div class="container mt-5 text-center"> <p>Verantwortlich ist der Autor.</p> </div> </body> </html>
Anlegen der Testdomäne
Wir wollen im Browser eine "schöne" Adresse haben: demo.test Wichtig: Immer die Endung .test verwenden, dann nimmt der Browser auch http statt https an.
In die Datei /etc/hosts schreiben wir (als root) irgendwo nach der 3. Zeile:
127.0.0.1 demo.test
Einrichten einer NGINX-Anwendung
Wir legen in /etc/nginx/sites-available folgende Datei demo.test an (als root):
DOMAIN=demo.test BASEDIR=/home/ck/tutorial STARTFILE=demo.php cd /etc/nginx/sites-available cat <<EOS >$DOMAIN server { listen 80; server_name $DOMAIN; root $BASEDIR; access_log /var/log/nginx/a.$DOMAIN.log; error_log /var/log/nginx/e.$DOMAIN.log; index $STARTFILE; location / { include fastcgi.conf; fastcgi_intercept_errors on; fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; } } EOS cd ../sites-enabled ln -s ../sites-available/$DOMAIN . systemctl reload nginx
Starten der Webanwendung
PHP bringt einen Webserver mit. Dieser kann in Visual Studio Code benutzt werden:
- Ganz links das Symbol Dreieck ("Start") mit Käferchen (Run-and-Debug) anklicken
- Oben in der Zeile "Run and Debug" ist ein Zahnrad: Einstellungen
- Oben in der Zeile "Run and Debug" in der Combobox "Listen for Xdebug" auswählen und auf den Startpfeil (Dreieck) klicken
- Im Browser in die Adresszeile eintragen: demo.test/demo.php
- Es erscheint unsere Homepage. Seltsamerweise steht in der Adresszeile localhost:8000/demo.php?home
- In der Datei demo.php in die Zeile 2 klicken, und zwar vor der Zeilennummer. Es erscheint ein roter Punkt: Wir haben einen Breakpoint gesetzt.
- Im Browser eintragen:
demo.test/demo.php
, Return - Die 2.te Zeile im Browser wird gelb: Der Debugger hat am Breakpunkt angehalten.
- Wir können jetzt die Variablen anschauen: Rechts "Superglobals" durch Anklicken aufklappen, $_SERVER aufklappen
- Wir sehen hier alle Werte des Arrays $_SERVER. Auch den Eintrag "REQUEST_URI".
- Mit der Taste F10 führen wir genau ein Statement aus und landen in Zeile 3, noch ein F10 geht nach Zeile 4, also zu
header('Location: http:/demo.php?home');
- Diese Anweisung sorgt für eine Weiterleitung auf die Adresse "http:/demo.php?home"
- Wir lassen das Programm mit F5 ("Run") weiterlaufen
- Ohne dass wir im Browser was gemacht haben, stoppt der Debugger wieder in Zeile 2. Wenn wir mit F10 weitergehen, landen wir diesmal in Zeile 6.
- Der Browser hat also automatisch die Adresse http:/demo.php?home' aufgerufen.
- In Zeile 6 landen wir in der Methode home() der Klasse Server.
- Diese liest die Datei home.html und gibt sie einfach aus.
- Der Browser bekommt den Inhalt der Datei home.html und zeigt sie an.
- Wir klicken im Browser in der Titelzeile den Link "Impressum" an.
- Wir landen wieder in Zeile 2.
- Mit F10 weitergehen, wir landen in Zeile 8.
- Dort wird die Datei impressum.html gelesen und ausgegeben.
- Mit F5 läuft das Programm weiter und der Browser zeigt die Impressumseite an.
Verbesserung
Das gezeigte Programm hat noch Potential zur Verbesserung:
- Auf jeder Seite (home, impressum) sind große Teile gemeinsam. Muß zum Beispiel ein Menüpunkt hinzugefügt werden, muss das in allen Seiten wiederholt werden.
- Daher gibt es hier eine bessere Variante: HTTP-Server mit PHP-Verbesserung