HTTP-Server mit PHP

Aus Vokabulabor
Zur Navigation springen Zur Suche springen

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 auch file:
  • //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