PHP-Basics

aktualisiert am 18.03.2025 - Jetzt neu mit Wissensüberprüfung zu jedem Kapitel.

PHP (Hypertext Preprocessor) ist eine serverseitige Skriptsprache, die für die Webentwicklung konzipiert wurde. Im Gegensatz zu clientseitigen Sprachen wie JavaScript, die im Browser ausgeführt werden, wird PHP-Code auf dem Webserver ausgeführt und generiert HTML, das dann an den Client gesendet wird.

Hinweis

Diese Lernunterlage basiert auf den Kursinhalten und den durchgemachten Übungsbeispielen. Sie deckt die grundlegenden Konzepte von PHP ab.

Hauptmerkmale von PHP

  • Serverseitige Sprache
  • Kann direkt in HTML eingebettet werden
  • Code wird auf dem Server ausgeführt, Ergebnisse werden an den Browser gesendet
  • Dateien haben die Endung .php

Verarbeitungsablauf

PHP-Ablauf

Ausgabestrom in PHP

Bei der Verarbeitung einer PHP-Datei läuft der Prozess folgendermaßen ab:

  • Der PHP-Interpreter durchläuft die Datei von oben nach unten
  • HTML-Code außerhalb von PHP-Tags (<?php ... ?>) wird direkt in den Ausgabestrom geschrieben
  • PHP-Code innerhalb der PHP-Tags wird ausgeführt, und dessen Ausgaben (über echo, print etc.) werden ebenfalls in den Ausgabestrom geschrieben
  • Der Ausgabestrom wird dann an den Browser des Clients gesendet

Beispiel:

<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body>
    <h1>Hallo</h1>               <!-- Direkt in den Ausgabestrom -->
    
    <?php
    $name = "Welt";
    echo "<p>Hallo $name!</p>";  // Wird durch PHP verarbeitet und dann in den Ausgabestrom geschrieben
    ?>
    
    <footer>Fußzeile</footer>     <!-- Wieder direkt in den Ausgabestrom -->
</body>
</html>

Dieser Ablauf ist wichtig zu verstehen, besonders wenn es um die richtige Reihenfolge von Ausgaben und Header-Informationen geht.

Grundlegende PHP-Syntax

PHP-Code wird innerhalb von speziellen Tags geschrieben:

<?php
// Hier steht der PHP-Code
?>

Beispiel aus 12_php_hallowelt.php:

<?php
for($i=0; $i<1000; $i++) {
    echo("<p>Hallo Welt! " . $i . "</p>");
}
?>

Wichtige Syntax-Regeln

  • Anweisungen enden mit einem Semikolon ;
  • Variablen beginnen mit einem $-Zeichen
  • Kommentare werden mit // für einzeilige oder /* */ für mehrzeilige Kommentare gekennzeichnet

PHP-Ausgabemethoden

echo und print_r

PHP bietet verschiedene Methoden, um Inhalte auszugeben:

  1. echo: Gibt Zeichenketten aus
    echo("<p>Hallo Welt!</p>");
  2. print_r: Zeigt den Inhalt von Arrays in lesbarer Form an
    print_r($_POST); // Gibt den Inhalt des POST-Arrays aus

Beispiele aus den Kursdateien:

// Aus 12_php_formulare01.php
print_r($_GET);
print_r($_POST);
print_r($_REQUEST);

Die ta-Funktion (Testausgabe)

In den Beispieldateien wird eine benutzerdefinierte Funktion ta() verwendet, um Arrays übersichtlicher auszugeben. Diese Funktion ist in der Datei common.inc.php definiert:

<?php
function ta(mixed $in):void {
    echo('<pre class="ta">');
    print_r($in);
    echo('</pre>');
}
?>

Diese Funktion formatiert die Ausgabe von print_r in einem vorformatierten HTML-Element mit CSS-Styling. Das zugehörige CSS ist in common.css definiert:

.ta {
    margin:0.5em 0;
    padding:0.5em;
    border:1px solid orange;
    background-color:#ffc;
    font-family:"Courier New", monospace;
    font-size:0.9rem;
    line-height:1.2;
}

Arbeiten mit Formularen in PHP

Formularerfassung

PHP bietet spezielle Arrays, um auf Formulardaten zuzugreifen:

  • $_GET: Enthält Daten, die über die URL gesendet wurden (GET-Methode)
  • $_POST: Enthält Daten, die im HTTP-Request-Body gesendet wurden (POST-Methode)
  • $_REQUEST: Enthält die Daten aus $_GET, $_POST und $_COOKIE

HTML-Formular-Beispiel aus 12_php_formulare01.php:

<!doctype html>
<html lang="de">
    <head>
        <title>PHP: Formulare</title>
        <meta charset="utf-8">
    </head>
    <body>
        <form method="post">
            <label>
                Ihre Emailadresse:
                <input type="email" name="E">
            </label>
            <label>
                Ihr Passwort:
                <input type="password" name="P">
            </label>
            <input type="submit" value="einloggen">
        </form>
    </body>
</html>

Formularverarbeitung

Nach dem Absenden eines Formulars kann PHP die Daten verarbeiten:

if(count($_POST)>0) {
    // Formular wurde abgesendet
    $email_korrekt = "test@test.at";
    $pwd_korrekt = "test123";
    
    if($_POST["E"]==$email_korrekt && $_POST["P"]==$pwd_korrekt) {
        // Korrekte Eingabe
        $msg = '<p class="success">Vielen Dank - Sie werden in Kürze weitergeleitet.</p>';
    }
    else {
        // Falsche Eingabe
        $msg = '<p class="error">Leider waren die eingegebenen Daten nicht korrekt. Bitte versuchen Sie es erneut.</p>';
    }
}

Das CSS für die Erfolgsmeldung und Fehlermeldung ist in common.css definiert:

.success {
    margin:0.5em 0;
    border-left:2px solid green;
    font-style:italic;
    line-height:1.2;
    padding:0.2em 0.5em;
}
.error {
    margin:0.5em 0;
    border-left:2px solid red;
    font-weight:bold;
    line-height:1.2;
    padding:0.2em 0.5em;
}

Formularvalidierung

Die Überprüfung von Formulardaten ist ein wichtiger Bestandteil der Webentwicklung:

PHP-seitige Validierung

// Überprüfung, ob das Formular abgesendet wurde
if(count($_POST)>0) {
    // Formular wurde abgesendet
}

// Überprüfung der Formulardaten
if($_POST["E"]==$email_korrekt && $_POST["P"]==$pwd_korrekt) {
    // Korrekte Eingabe
}

HTML5-Validierung

<input type="email" name="E" required>
<input type="password" name="P" required>
Wichtig

Verlasse dich niemals nur auf client-seitige (HTML5) Validierung. Implementiere immer eine serverseitige Validierung, da client-seitige Validierung leicht umgangen werden kann.

Dateien hochladen mit PHP

PHP ermöglicht es, Dateien vom Client auf den Server hochzuladen. Diese Funktionalität ist essentiell für viele Webanwendungen, z.B. für Profilbilder, Dokumentenuploads oder Medieninhalte.

Grundlagen des Dateiuploads

Um Dateien hochladen zu können, muss das HTML-Formular spezielle Attribute haben:

<form method="post" enctype="multipart/form-data">
                <input type="file" name="dokument">
                <input type="submit" value="hochladen">
            </form>
Wichtig

Das Attribut enctype="multipart/form-data" ist für Dateiuploads zwingend erforderlich!

Prozess des Dateiuploads

Beim Hochladen einer Datei passiert Folgendes:

  1. Der Client sendet die Formulardaten und die hochzuladende Datei an den Server
  2. Der Server speichert die Datei zunächst in einem temporären Verzeichnis unter einem automatisch generierten Namen
  3. PHP stellt die Informationen über die hochgeladene Datei im superglobalen Array $_FILES bereit
  4. Der PHP-Code muss die temporäre Datei an den gewünschten Zielort verschieben
  5. Nach Abschluss des Requests wird die temporäre Datei automatisch gelöscht, falls sie nicht verschoben wurde
Sicherheitshinweis

Das temporäre Speichern und Umbenennen dient der Sicherheit. Würden hochgeladene Dateien direkt im Webserver-Verzeichnis unter ihrem Originalnamen gespeichert, könnten Angreifer PHP-Dateien oder andere ausführbare Skripte hochladen und ausführen.

Das $_FILES-Array

Das $_FILES-Array enthält alle Informationen zu den hochgeladenen Dateien:

$_FILES["feldname"]["tmp_name"] // Temporärer Pfad und Name der Datei
            $_FILES["feldname"]["name"]     // Originaler Dateiname auf dem Client
            $_FILES["feldname"]["full_path"] // Vollständiger Pfad (browserabhängig)
            $_FILES["feldname"]["error"]    // Fehlercode (0 = kein Fehler)
            $_FILES["feldname"]["type"]     // MIME-Typ der Datei
            $_FILES["feldname"]["size"]     // Größe der Datei in Bytes

Einfacher Dateiupload

Ein grundlegendes Beispiel für einen Dateiupload aus 14_php_upload.php:

<?php
            require("includes/config.inc.php");
            require("includes/common.inc.php");
            
            ta($_FILES);
            $msg = "";
            if(count($_FILES)>0) {
                $f = $_FILES["myUpload"]; //Hilfsvariable
                if($f["error"]==0) {
                    $ok = move_uploaded_file($f["tmp_name"],"./uploads/" . $f["name"]);
                    if($ok) {
                        $msg = '<p class="success">Vielen Dank - Die Datei ' . $f["name"] . ' wurde erfolgreich hochgeladen.</>';
                    }
                    else {
                        $msg = '<p class="error">Leider konnte die Datei ' . $f["name"] . ' nicht gespeichert werden. Bitte versuchen Sie es erneut.</p>';
                    }
                }
                else {
                    $msg = '<p class="error">Leider ist beim Upload etwas schiefgegangen. Bitte versuchen Sie es erneut.</p>';
                }
            }
            ?>
            <!doctype html>
            <html lang="de">
                <head>
                    <title>Upload</title>
                    <meta charset="utf-8">
                    <link rel="stylesheet" href="css/common.css">
                </head>
                <body>
                    <?php echo($msg); ?>
                    <form method="post" enctype="multipart/form-data">
                        <label>
                            Bitte wählen Sie eine Datei aus:
                            <input type="file" name="myUpload">
                        </label>
                        <input type="submit" value="hochladen">
                    </form>
                </body>
            </html>
  1. Das Formular hat das erforderliche enctype="multipart/form-data" Attribut
  2. Überprüfung, ob das $_FILES-Array Einträge enthält
  3. Erstellen einer Hilfsvariablen $f für bessere Lesbarkeit
  4. Überprüfung, ob bei dem Upload ein Fehler aufgetreten ist (error==0)
  5. Verwendung von move_uploaded_file(), um die Datei aus dem temporären Verzeichnis in den gewünschten Zielordner zu verschieben
  6. Erstellen einer Erfolgsmeldung oder Fehlermeldung je nach Ergebnis

Filterung nach Dateityp

Aus Sicherheitsgründen ist es wichtig, nur bestimmte Dateitypen zuzulassen. Beispiel aus 14_php_upload02.php:

if(count($_FILES)>0) {
                $f = $_FILES["myUpload"];
                if($f["error"]==0) {
                    if(
                        $f["type"]=="image/webp" ||
                        $f["type"]=="image/jpeg" ||
                        $f["type"]=="image/gif" ||
                        $f["type"]=="image/png" ||
                        $f["type"]=="image/avif" ||
                        $f["type"]=="image/svg+xml"
                    ) {
                        $ok = move_uploaded_file($f["tmp_name"],"./uploads/" . $f["name"]);
                        // Weitere Verarbeitung...
                    }
                    else {
                        $msg = '<p class="error">Das ist leider keine Bilddatei: ' . $f["name"] . '</p>';
                    }
                }
            }

Whitelist-Ansatz mit Arrays

Eine elegantere Methode zur Filterung von Dateitypen verwendet ein Array als Whitelist. Beispiel aus 14_php_upload02a.php:

$whitelist = ["image/webp","image/jpeg","image/gif","image/png","image/avif","image/svg+xml"];
            
            if(count($_FILES)>0) {
                $f = $_FILES["myUpload"];
                if($f["error"]==0) {
                    if(in_array($f["type"],$whitelist)) {
                        $ok = move_uploaded_file($f["tmp_name"],"./uploads/" . $f["name"]);
                        // Weitere Verarbeitung...
                    }
                    else {
                        $msg = '<p class="error">Das ist leider keine Bilddatei: ' . $f["name"] . '</p>';
                    }
                }
            }
Tipp

Die Whitelist kann auch als Konstante definiert werden, um Modifikationen zu verhindern:

define("WHITELIST",[
                "image/webp",
                "image/jpeg",
                "image/gif",
                "image/png",
                "image/avif",
                "image/svg+xml"
            ]);

Mehrere Dateien hochladen

Um mehrere Dateien hochzuladen, wird das multiple-Attribut beim Eingabefeld verwendet und der Name des Feldes mit eckigen Klammern versehen. Beispiel aus 14_php_upload03.php:

<input type="file" name="myUpload[]" multiple>

Die Verarbeitung mehrerer Dateien erfordert eine Schleife:

$f = $_FILES["myUpload"];
            for($i=0; $i<count($f["name"]); $i++) {
                if($f["error"][$i]==0) {
                    $ok = move_uploaded_file($f["tmp_name"][$i],"./uploads/" . $f["name"][$i]);
                    // Weitere Verarbeitung...
                }
            }

Komplexeres Beispiel: Bewerbungsformular

Ein umfassenderes Beispiel für Dateiuploads ist das Bewerbungsformular aus 14_php_upload05_bewerbungsformular.php:

DEFINE("WHITELIST_BEWERBUNG", [
                "Bilder" => [
                    "image/webp",
                    "image/jpeg",
                    "image/gif",
                    "image/png",
                    "image/avif"
                ],
                "Dokumente" => [
                    "application/msword",
                    "application/vnd.oasis.opendocument.text",
                    "application/pdf",
                    "image/jpeg"
                ]
            ]);
            
            // Verarbeitung des Profilbilds
            $f = $_FILES["Profilbild"];
            if($f["error"]==0) {
                if(in_array($f["type"],WHITELIST_BEWERBUNG["Bilder"])) {
                    $ok = move_uploaded_file($f["tmp_name"],"./uploads/profilbilder/" . $f["name"]);
                    if($ok) {
                        $msg.= '<p class="success">Danke, das Profilbild wurde gespeichert.</p>';
                    }
                    else {
                        $msg.= '<p class="error">Sorry, beim Upload des Profilbildes ist ein Fehler aufgetreten.</p>';
                    }
                }
                else {
                    $msg.= '<p class="error">Dein Profilbild ist keine Bilddatei. Zurück zum Anfang.</p>';
                }
            }
            
            // Verarbeitung der Dokumente
            $f = $_FILES["Dokumente"];
            for($i=0; $i<count($f["name"]); $i++) {
                if($f["error"][$i]==0) {
                    if(in_array($f["type"][$i],WHITELIST_BEWERBUNG["Dokumente"])) {
                        $ok = move_uploaded_file($f["tmp_name"][$i],"./uploads/dokumente/" . $f["name"][$i]);
                        if($ok) {
                            $msg.= '<p class="success">Danke, das Dokument ' . $f["name"][$i] . ' wurde gespeichert.</p>';
                        }
                        else {
                            $msg.= '<p class="error">Sorry, beim Upload des Dokuments ' . $f["name"][$i] . ' ist ein Fehler aufgetreten.</p>';
                        }
                    }
                    else {
                        $msg.= '<p class="error">Die Datei ' . $f["name"][$i] . ' ist kein erlaubtes Dokument. Zurück zum Anfang.</p>';
                    }
                }
            }
<form method="post" enctype="multipart/form-data">
                <fieldset>
                    <legend>Persönliche Daten</legend>
                    <label>
                        Vorname:
                        <input type="text" name="VN" required>
                    </label>
                    <label>
                        Nachname:
                        <input type="text" name="NN" required>
                    </label>
                    <label>
                        Emailadresse:
                        <input type="email" name="E" required>
                    </label>
                </fieldset>
                <fieldset>
                    <legend>Dokumente</legend>
                    <label>
                        Bitte laden Sie ein Profilbild hoch:
                        <input type="file" name="Profilbild" required>
                    </label>
                    <label>
                        Bitte laden Sie sämtliche relevanten Dokumente (Zeugnisse, Empfehlungsschreiben, etc.) hoch:
                        <input type="file" name="Dokumente[]" multiple>
                    </label>
                </fieldset>
                <input type="submit" value="abschicken">
            </form>
Hinweis

In diesem Beispiel werden verschiedene Dateitypen für verschiedene Zwecke akzeptiert: Bilder für das Profilbild und Dokumente (PDF, Word, etc.) für die Bewerbungsunterlagen. Die Dateien werden in unterschiedlichen Verzeichnissen gespeichert.

Sicherheitsaspekte beim Dateiupload

Sicherheitsrisiken

Dateiuploads stellen ein erhebliches Sicherheitsrisiko dar, wenn sie nicht richtig implementiert werden. Potenziell könnten Angreifer schädliche Dateien hochladen und ausführen.

Beste Praktiken für sichere Dateiuploads:

  • Immer eine Whitelist von erlaubten Dateitypen verwenden
  • Die Dateigröße begrenzen
  • Hochgeladene Dateien in einem separaten Verzeichnis außerhalb des Webroot speichern, wenn möglich
  • Die Originalnamen der Dateien ändern, um Konflikte und Sicherheitsprobleme zu vermeiden
  • Die Dateierweiterung überprüfen (nicht nur den MIME-Typ)
  • Virenscans für hochgeladene Dateien implementieren, wenn möglich
// Größenbegrenzung (beispielsweise 5 MB)
            if($f["size"] > 5 * 1024 * 1024) {
                $msg = '<p class="error">Die Datei ist zu groß. Maximale Dateigröße: 5 MB</p>';
                return;
            }
            
            // Generierung eines eindeutigen Dateinamens
            $neuerDateiname = time() . '_' . mt_rand(1000, 9999) . '_' . $f["name"];
            
            // Überprüfung der Dateierweiterung
            $erlaubteEndungen = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
            $endung = strtolower(pathinfo($f["name"], PATHINFO_EXTENSION));
            if(!in_array($endung, $erlaubteEndungen)) {
                $msg = '<p class="error">Diese Dateierweiterung ist nicht erlaubt.</p>';
                return;
            }

Arbeiten mit Sessions

Sessions ermöglichen die Speicherung von Benutzerdaten über mehrere Seitenaufrufe hinweg. Im Gegensatz zum zustandslosen HTTP-Protokoll, bei dem der Server normalerweise keine Informationen zwischen Anfragen des Clients speichert, bieten Sessions einen Mechanismus zur Benutzeridentifikation und Datenspeicherung.

Wichtig

Eine Session ist nicht gleichbedeutend mit einem Login! Sessions sind eine Technik, um den Benutzer wiederzuerkennen, während ein Login ein Anwendungskonzept ist, das Sessions nutzen kann.

Konzept der Sessions

  • Client-Server-Kommunikation basiert auf Request-Response
  • Nach jeder Kommunikation ist die Verbindung abgeschlossen
  • Der Server merkt sich normalerweise keine Informationen zwischen den Anfragen
  • Sessions bieten einen Mechanismus, um dieses Problem zu lösen und Daten zwischen Seitenaufrufen zu speichern

Ablauf einer Session

  1. Client sendet einen Request an den Server (z.B. mit Formulardaten)
  2. Server erstellt eine eindeutige Session-ID und legt einen Eintrag auf dem Server ab
  3. Im Session-Eintrag können Variablen gespeichert werden (im superglobalen Array $_SESSION)
  4. Server sendet die Session-ID und den Timeout-Wert als Cookie an den Client
  5. Client speichert diese Informationen in einem Session-Cookie
  6. Bei jeder weiteren Anfrage sendet der Client das Cookie mit, und der Server kann die Session wiedererkennen

Sessions starten

session_start(); // Startet eine Session oder setzt eine bestehende fort
Wichtig

Der Aufruf von session_start() muss vor jeder HTML-Ausgabe erfolgen, da er HTTP-Header sendet.

Session-Variablen

Daten können in der $_SESSION-Superglobalen gespeichert werden:

$_SESSION["eingeloggt"] = true;

Beispiel aus 13_php_login.php:

session_start();
            $_SESSION["eingeloggt"] = true;

Session Timeout

Sessions haben eine begrenzte Lebensdauer, die durch den Timeout bestimmt wird:

  • Der Standard-Timeout beträgt 24 Minuten (kann in der php.ini konfiguriert werden)
  • Der Timeout wird zurückgesetzt, wenn innerhalb dieser Zeit neue Anfragen gestellt werden
  • Nach Ablauf des Timeouts wird die Session automatisch beendet
Tipp

Um die Session-Timeout-Zeit zu ändern, kann man in der php.ini die session.gc_maxlifetime Einstellung anpassen oder im PHP-Code ini_set('session.gc_maxlifetime', 3600); verwenden, um sie beispielsweise auf eine Stunde (3600 Sekunden) zu setzen.

Session-Sicherheit

Die Überprüfung des Login-Status:

if(!(isset($_SESSION["eingeloggt"]) && $_SESSION["eingeloggt"]===true)) {
                header("Location: 13_php_login.php");
            }
Wichtig

Verwende immer den strikten Vergleichsoperator (===) bei der Überprüfung von Session-Variablen, um Typumwandlungsprobleme zu vermeiden.

In einer typischen Anwendung mit geschützten Seiten muss jede geschützte Seite überprüfen, ob der Benutzer eingeloggt ist. Dies geschieht durch Verifikation der Session-Variablen am Anfang jeder Seite.

Sessions beenden

Sessions können auf verschiedene Arten beendet werden:

  • Automatisch nach Ablauf des Timeouts
  • Durch Schließen des Browserfensters (Client-seitiges Cookie wird gelöscht)
  • Explizit durch einen Logout-Prozess

Beispiel eines Logout-Prozesses aus 13_php_geschuetzt.php:

if(count($_POST)>0) {
                if(isset($_POST["btnLogout"])) {
                    // Löscht alle Session-Variablen
                    $_SESSION = [];
                    
                    // Löscht das Session-Cookie
                    if(ini_get("session.use_cookies")) {
                        $cookieparams = session_get_cookie_params();
                        setcookie(session_name(),"",time()-86400,$cookieparams["path"],$cookieparams["domain"],$cookieparams["secure"],$cookieparams["httponly"]);
                    }
                    
                    // Zerstört die Session
                    session_destroy();
                }
            }

Der obige Code führt folgende Schritte aus:

  1. Löscht alle in der Session gespeicherten Variablen
  2. Löscht das Session-Cookie, indem es mit einem Ablaufdatum in der Vergangenheit (24 Stunden zurück) neu gesetzt wird
  3. Zerstört die Server-seitige Session vollständig

Praxisbeispiel: Login-System mit Sessions

Ein typisches Login-System mit Sessions besteht aus drei Hauptkomponenten:

Login-Seite (login.php)

<?php
            require("includes/config.inc.php");
            require("includes/common.inc.php");
                                    
            $msg = "";
                                    
            if(count($_POST)>0) {
                $email_korrekt = "test@test.at";
                $pwd_korrekt = "test123";
                                        
                if($_POST["E"]==$email_korrekt && $_POST["P"]==$pwd_korrekt) {
                    session_start();
                    $_SESSION["eingeloggt"] = true;
                                            
                    header("Location: geschuetzt.php");
                }
                else {
                    $msg = '<p class="error">Leider waren die eingegebenen Daten nicht korrekt.</p>';
                }
            }
            ?>
            <!doctype html>
            <html lang="de">
                <head>
                    <title>Login</title>
                    <meta charset="utf-8">
                </head>
                <body>
                    <?php echo($msg); ?>
                    <form method="post">
                        <label>
                            Email:
                            <input type="email" name="E" required>
                        </label>
                        <label>
                            Passwort:
                            <input type="password" name="P" required>
                        </label>
                        <input type="submit" value="Einloggen">
                    </form>
                </body>
            </html>

Seitenschutz (geschuetzt.php)

<?php
            session_start();
            if(!(isset($_SESSION["eingeloggt"]) && $_SESSION["eingeloggt"]===true)) {
                header("Location: login.php");
                exit; // Wichtig: Beendet die Skriptausführung
            }
            ?>
            <!doctype html>
            <html lang="de">
                <head>
                    <title>Geschützte Seite</title>
                    <meta charset="utf-8">
                </head>
                <body>
                    <h1>Willkommen im geschützten Bereich!</h1>
                    <p>Diese Seite ist nur für eingeloggte Benutzer sichtbar.</p>
                    
                    <form method="post">
                        <input type="submit" name="btnLogout" value="Ausloggen">
                    </form>
                </body>
            </html>

Logout-Verarbeitung (am Anfang von geschuetzt.php)

<?php
            session_start();
            
            // Prüfen, ob Logout-Button geklickt wurde
            if(isset($_POST["btnLogout"])) {
                // Löscht alle Session-Variablen
                $_SESSION = [];
                
                // Löscht das Session-Cookie
                if(ini_get("session.use_cookies")) {
                    $cookieparams = session_get_cookie_params();
                    setcookie(session_name(),"",time()-86400,$cookieparams["path"],$cookieparams["domain"],$cookieparams["secure"],$cookieparams["httponly"]);
                }
                
                // Zerstört die Session
                session_destroy();
                
                // Umleitung zur Login-Seite
                header("Location: login.php");
                exit;
            }
            
            // Prüfen, ob Benutzer eingeloggt ist
            if(!(isset($_SESSION["eingeloggt"]) && $_SESSION["eingeloggt"]===true)) {
                header("Location: login.php");
                exit;
            }
            ?>

Sicherheitsrisiken bei Sessions

Sicherheitsrisiko

Session-Hijacking ist ein häufiger Angriff, bei dem ein Angreifer versucht, die Session-ID eines Benutzers zu stehlen, um sich als dieser auszugeben.

Sicherheitsmaßnahmen für Sessions:

  • Verwende HTTPS, um die Übertragung der Session-ID zu verschlüsseln
  • Setze das httponly-Flag für Session-Cookies, um Zugriff über JavaScript zu verhindern
  • Verwende das secure-Flag, damit Cookies nur über HTTPS gesendet werden
  • Implementiere ein Session-Timeout
  • Regeneriere die Session-ID nach dem Login mit session_regenerate_id(true)
  • Binde die IP-Adresse oder andere Client-Informationen in die Session ein
// Sicherer Login-Prozess
            if(validiert_login()) {
                session_start();
                
                // Alte Session-ID verwerfen und neue generieren
                session_regenerate_id(true);
                
                // Session-Variablen setzen
                $_SESSION["eingeloggt"] = true;
                $_SESSION["benutzer_id"] = $benutzer_id;
                $_SESSION["ip_adresse"] = $_SERVER["REMOTE_ADDR"];
                $_SESSION["user_agent"] = $_SERVER["HTTP_USER_AGENT"];
                $_SESSION["letzter_zugriff"] = time();
            }

PHP Include und Require

PHP ermöglicht das Einbinden externer Dateien:

include

Bindet eine Datei ein, erzeugt eine Warnung, wenn die Datei nicht gefunden wird

include("includes/common.inc.php");

require

Bindet eine Datei ein, erzeugt einen Fehler, wenn die Datei nicht gefunden wird

require("includes/config.inc.php");

Typisches Beispiel für die Verwendung von require in den Kursdateien:

require("includes/config.inc.php");
require("includes/common.inc.php");

Inhalt der Datei config.inc.php:

<?php
error_reporting(E_ALL);
ini_set("display_errors",1);
?>
Tipp

Verwende require für kritische Dateien, die für die Funktionalität deiner Anwendung notwendig sind, und include für optionale Dateien.

Exkurs: Include und Require

Neben include und require gibt es auch die Varianten include_once und require_once.

include_once

Bindet eine Datei ein, stellt jedoch sicher, dass sie nur einmal eingebunden wird.

include_once("includes/functions.inc.php");

require_once

Bindet eine Datei ein, stellt sicher, dass sie nur einmal eingebunden wird und erzeugt einen Fehler, wenn die Datei nicht gefunden wird.

require_once("includes/config.inc.php");

Typische Projektstruktur

Eine gängige Struktur für PHP-Projekte könnte so aussehen:

project/
            ├── index.php                 # Startseite
            ├── includes/                 # Wiederverwendbare PHP-Dateien
            │   ├── config.inc.php        # Konfigurationsdatei
            │   ├── common.inc.php        # Gemeinsame Funktionen
            │   └── db.inc.php            # Datenbankfunktionen
            ├── css/                      # CSS-Dateien
            ├── js/                       # JavaScript-Dateien
            ├── images/                   # Bilder
            └── pages/                    # Einzelne Seitenmodule
                ├── kontakt.php
                ├── login.php
                └── profil.php
Wichtig

Verwende include_once oder require_once, wenn du Funktionsdefinitionen oder Klassen einbindest, um doppelte Definitionen zu vermeiden.

PHP-Funktionen

Funktionen in PHP werden wie folgt definiert:

function ta(mixed $in):void {
    echo('<pre class="ta">');
    print_r($in);
    echo('</pre>');
}
  • mixed: Der Parameter kann verschiedene Datentypen haben
  • :void: Die Funktion gibt nichts zurück (Rückgabetyp ist void)
Funktionsparameter

Ab PHP 8.0 können Typen für Parameter und Rückgabewerte deklariert werden, was die Codequalität verbessert und Fehler reduziert.

Beispiel einer Funktion mit Parametern und Rückgabewert

function addiere(int $a, int $b): int {
    return $a + $b;
}

$summe = addiere(5, 3); // Ergebnis: 8

Erweiterte PHP-Funktionskonzepte

Exkurs: Funktionen in PHP

Funktionen sind wiederverwendbare Codeblöcke, die bestimmte Aufgaben ausführen. Sie verbessern die Lesbarkeit und Wartbarkeit des Codes.

Optionale Parameter und Standardwerte

In PHP können Funktionen optionale Parameter mit Standardwerten haben:

function begruessung($name, $sprache = "Deutsch") {
    if($sprache == "Deutsch") {
        return "Hallo, " . $name . "!";
    } else if($sprache == "Englisch") {
        return "Hello, " . $name . "!";
    }
}

// Aufruf mit nur einem Parameter (Standardwert wird verwendet)
echo begruessung("Max");  // Ausgabe: Hallo, Max!

// Aufruf mit beiden Parametern
echo begruessung("Max", "Englisch");  // Ausgabe: Hello, Max!

Rückgabewerte und Typisierung

Funktionen können verschiedene Datentypen zurückgeben:

// Funktion mit Rückgabetyp (ab PHP 7)
function addiere(float $a, float $b): float {
    return $a + $b;
}

// Funktion mit unterschiedlichen möglichen Rückgabetypen (ab PHP 8)
function getData(string $id): string|array|null {
    // Implementation
}

Anonyme Funktionen/Closures

Anonyme Funktionen (auch Closures genannt) haben keinen Namen und können in Variablen gespeichert werden:

// Anonyme Funktion in einer Variable speichern
$multiplikator = function($x, $y) {
    return $x * $y;
};

// Anonyme Funktion aufrufen
echo $multiplikator(5, 3);  // Ausgabe: 15

CSS-Integration mit PHP

Einbindung von CSS in PHP-Dateien

<link rel="stylesheet" href="css/common.css">

In den Kursdateien werden verschiedene CSS-Dateien verwendet, wie common.css, basic.css und formatierung.css.

Dynamische CSS-Generierung

CSS kann auch dynamisch mit PHP generiert werden. Beispiel der Datei gemeinsam.php:

<?php
header("Content-type: text/css");
$r = "";
$a = ["./basic.css","./formatierung.css"];
for($i=0; $i<count($a); $i++) {
    $r.= file_get_contents($a[$i]);
}
echo($r);
?>

Diese PHP-Datei liest den Inhalt mehrerer CSS-Dateien ein und kombiniert sie zu einer einzigen CSS-Ausgabe. So werden die folgenden CSS-Dateien eingebunden:

basic.css:

* {
    margin:0;
    padding:0;
    box-sizing:border-box;
    position:relative;
}

formatierung.css:

body {
    background-color:#eee;
    color:#333;
    font-family:Arial, Verdana, sans-serif;
    font-size:1em;
    line-height:1.5;
}

h1 {
    font-size:4rem;
    font-family:"Times New Roman", serif;
}

Die dynamische CSS-Datei wird dann so eingebunden:

<link rel="stylesheet" href="gemeinsam.php">
Tipp

Dynamisch generiertes CSS ist nützlich für Theme-Anpassungen oder um mehrere CSS-Dateien zu kombinieren und so die Anzahl der HTTP-Anfragen zu reduzieren.

Best Practices

Trennung von HTML und PHP-Code

Für bessere Lesbarkeit und Wartbarkeit sollten HTML und PHP-Code getrennt werden.

Schlechte Praxis

<?php
if(count($_POST)>0) {
    echo "<p>Formular wurde abgesendet</p>";
    if($_POST["E"]=="test@test.at") {
        echo "<p>Korrekte E-Mail</p>";
    } else {
        echo "<p>Falsche E-Mail</p>";
    }
}
?>
<form method="post">
    <input type="email" name="E">
    <input type="submit">
</form>

Gute Praxis

<?php
$msg = "";
if(count($_POST)>0) {
    if($_POST["E"]=="test@test.at") {
        $msg = "<p class='success'>Korrekte E-Mail</p>";
    } else {
        $msg = "<p class='error'>Falsche E-Mail</p>";
    }
}
?>
<!doctype html>
<html lang="de">
    <head>
        <title>Formular</title>
        <meta charset="utf-8">
    </head>
    <body>
        <?php echo($msg); ?>
        <form method="post">
            <input type="email" name="E">
            <input type="submit">
        </form>
    </body>
</html>

Verwendung von Hilfsvariablen für Meldungen

$msg = "";
// ... Code zur Formularverarbeitung
echo($msg); // Ausgabe der Meldung im HTML

Strukturierung von Code mit include/require

Wiederverwendbarer Code sollte in separate Dateien ausgelagert werden, wie in den Kursdateien gezeigt:

  • config.inc.php: Enthält Konfigurationseinstellungen (z.B. Fehlerberichterstattung)
  • common.inc.php: Enthält gemeinsam genutzte Funktionen wie ta()
// Hauptdatei
                        php");
                        require("includes/common.inc.php");
                        
                        // Jetzt können die Konfigurationen und Funktionen verwendet werden
                        ?>
Tipp

Die Auslagerung von wiederverwendbarem Code in separate Dateien verbessert die Wartbarkeit und reduziert Duplizierungen.

Fehlerbehandlung in PHP

Die richtige Konfiguration der Fehlerberichterstattung ist wichtig für die Entwicklung und den produktiven Einsatz. In der Datei config.inc.php wird die Fehlerberichterstattung aktiviert:

<?php
                        error_reporting(E_ALL);
                        ini_set("display_errors",1);
                        ?>
  • error_reporting(E_ALL): Aktiviert die Berichterstattung für alle Fehlertypen
  • ini_set("display_errors",1): Zeigt Fehlermeldungen im Browser an
Wichtig

Im Produktivbetrieb sollte display_errors deaktiviert sein, um sensible Informationen zu schützen. Stattdessen sollten Fehler in Log-Dateien geschrieben werden.

Erweiterte Fehlerbehandlung

PHP-Fehlertypen
  • Notice: Nicht kritische Fehler, z.B. Zugriff auf undefinierte Variablen
  • Warning: Wichtige Fehler, die die Ausführung nicht unterbrechen
  • Fatal Error: Kritische Fehler, die die Ausführung abbrechen
  • Parse Error: Syntaxfehler im PHP-Code

Konfiguration der Fehlerberichterstattung

In der php.ini-Datei können verschiedene Fehlereinstellungen vorgenommen werden:

; Fehlerberichterstattung
            error_reporting = E_ALL
            
            ; Fehler anzeigen
            display_errors = On
            
            ; Fehler in Protokolldatei speichern
            log_errors = On
            
            ; Pfad zur Fehlerprotokolldatei
            error_log = /path/to/error.log

Finden der php.ini in XAMPP

In XAMPP findest du die php.ini-Datei typischerweise unter:

  • Windows: C:\xampp\php\php.ini
  • macOS: /Applications/XAMPP/xamppfiles/etc/php.ini
  • Linux: /opt/lampp/etc/php.ini
Wichtig

Auf vielen Servern hast du keinen direkten Zugriff auf die php.ini. In diesem Fall kannst du die ini_set()-Funktion verwenden, um Einstellungen im Skript vorzunehmen.

// Fehlerberichterstattung aktivieren
            ini_set('display_errors', 1);
            ini_set('display_startup_errors', 1);
            error_reporting(E_ALL);

try/catch zur Fehlerbehandlung

Für eine systematische Fehlerbehandlung kann der try/catch-Mechanismus verwendet werden:

try {
                // Code, der möglicherweise einen Fehler verursacht
                $ergebnis = 10 / 0; // Division durch Null erzeugt einen Fehler
            } catch (Exception $e) {
                // Fehlerbehandlung
                echo "Fehler aufgetreten: " . $e->getMessage();
            } finally {
                // Dieser Code wird immer ausgeführt, unabhängig davon, ob ein Fehler aufgetreten ist
                echo "Verarbeitung abgeschlossen.";
            }

PHP-Sicherheitsgrundlagen

Schutz vor unerwünschtem Zugriff

Beispiel zum Schutz einer Seite mittels Session:

<?php
                        session_start();
                        if(!(isset($_SESSION["eingeloggt"]) && $_SESSION["eingeloggt"]===true)) {
                            header("Location: 13_php_login.php");
                        }
                        ?>

Weiterleitung mit header()

Die header()-Funktion leitet den Benutzer auf eine andere Seite weiter:

header("Location: 13_php_geschuetzt.php");
Wichtig

Vor header() darf keine Ausgabe erfolgen! Der Aufruf muss vor jeglicher HTML- oder Echo-Ausgabe stattfinden.

Beispiel für einen Loginprozess:

<?php
                        require("includes/config.inc.php");
                        require("includes/common.inc.php");
                        
                        $msg = "";
                        
                        if(count($_POST)>0) {
                            $email_korrekt = "test@test.at";
                            $pwd_korrekt = "test123";
                            
                            if($_POST["E"]==$email_korrekt && $_POST["P"]==$pwd_korrekt) {
                                session_start();
                                $_SESSION["eingeloggt"] = true;
                                
                                header("Location: 13_php_geschuetzt.php");
                            }
                            else {
                                $msg = '<p class="error">Leider waren die eingegebenen Daten nicht korrekt.</p>';
                            }
                        }
                        ?>

Sichere Formulare

  1. Serverseitige Validierung: Immer Formulardaten auf dem Server überprüfen
  2. Clientseitige Validierung: Mit HTML5-Attributen wie required und Typ email
  3. Passwortschutz: Verwendung des password-Typs für Passwortfelder
<form method="post">
                            <label>
                                Emailadresse:
                                <input type="email" name="E" required>
                            </label>
                            <label>
                                Passwort:
                                <input type="password" name="P" required>
                            </label>
                            <input type="submit" value="login">
                        </form>
Sicherheitsrisiko

In einer echten Anwendung sollten Passwörter niemals im Klartext gespeichert werden, sondern immer gehasht (z.B. mit password_hash()).

Dateisystem in PHP

PHP bietet verschiedene Funktionen, um mit dem Dateisystem zu interagieren. Dies umfasst das Erstellen, Auslesen und Verwalten von Verzeichnissen und Dateien.

Hinweis

Der Zugriff auf das Dateisystem ist ein wichtiger Bestandteil vieler Webanwendungen, zum Beispiel beim Speichern von hochgeladenen Dateien oder beim Organisieren von Inhalten.

Verzeichnisse anlegen

Mit der Funktion mkdir() können neue Verzeichnisse erstellt werden:

mkdir($verzeichnispfad, $berechtigungen, $rekursiv);

Beispiel aus 15_php_mkdir.php:

<?php
            require("includes/config.inc.php");
            require("includes/common.inc.php");
            
            $msg = "";
            $vz = "./a/b/c/d";
            if(!file_exists($vz)) {
                $ok = mkdir($vz,0755,true);
                if($ok) {
                    $msg = '<p class="success">Das Wunschverzeichnis wurde erfolgreich angelegt.</p>';
                }
                else {
                    $msg = '<p class="error">Das Wunschverzeichnis konnte leider nicht erfolgreich angelegt werden.</p>';
                }
            }
            else {
                $msg = '<p class="error">Dieses Verzeichnis existiert bereits.</p>';
            }
            ?>
Wichtig

Bei der Verwendung von mkdir() mit Benutzereingaben ist Vorsicht geboten. Das dritte Argument true ermöglicht das rekursive Erstellen von Verzeichnissen, was ein Sicherheitsrisiko darstellen kann.

Beispiel für sicherere Verzeichniserstellung aus 15_php_mkdir01a.php:

<?php
            if(count($_POST)>0) {
                $vz = trim($_POST["VZNeu"]);
                if(!file_exists($vz)) {
                    $ok = mkdir($vz,0755); //beim Arbeiten mit Userdaten ist eine Rekursion nicht zu empfehlen
                    if($ok) {
                        $msg = '<p class="success">Das Wunschverzeichnis wurde erfolgreich angelegt.</p>';
                    }
                    else {
                        $msg = '<p class="error">Das Wunschverzeichnis konnte leider nicht erfolgreich angelegt werden.</p>';
                    }
                }
                else {
                    $msg = '<p class="error">Dieses Verzeichnis existiert bereits.</p>';
                }
            }
            ?>

Die Verzeichnisse für Upload-Dateien können auch programmatisch angelegt werden, wie im Beispiel aus 15_php_upload05_bewerbungsformular.php zu sehen:

// ---- Verzeichnisse anlegen: ----
            $user_root = "./uploads/" . $_POST["E"] . "/";
            $ok = false;
            if(!file_exists($user_root)) {
                $ok = mkdir($user_root,0755);
                if($ok) {
                    $ok = mkdir($user_root."profilbild",0755);
                    if($ok) {
                        $ok = mkdir($user_root."dokumente",0755);
                    }
                }
            }
            // --------------------------------

Verzeichnisse auslesen

Mit der Funktion scandir() kann der Inhalt eines Verzeichnisses ausgelesen werden:

$inhalt = scandir($verzeichnispfad);

Beispiel aus 15_php_scandir.php:

<?php
            $inhalt = scandir("./"); //liest den Inhalt des gegebenen Verzeichnisses ein und speichert die Namen der dortig vorkommenden Dateien, Verzeichnisse und Verknüpfungen in ein Array
            //ta($inhalt);
            
            echo('<ul>');
            foreach($inhalt as $d) {
                switch(true) {
                    case is_dir("./" . $d):
                        echo('<li class="dir">' . $d . '</li>');
                        break;
                        
                    case is_file("./" . $d):
                        echo('<li class="file">' . $d . '</li>');
                        break;
                        
                    case is_link("./" . $d):
                        echo('<li class="link">' . $d . '</li>');
                        break;
                }
            }
            echo('</ul>');
            ?>
Hinweis

Die Funktion scandir() gibt auch die Einträge "." (aktuelles Verzeichnis) und ".." (übergeordnetes Verzeichnis) zurück. Diese sollten in der Regel aus der Anzeige gefiltert werden.

Verbessertes Beispiel aus 15_php_scandir01a.php mit Filterung von "." und "..":

$vz = "./";
            $inhalt = scandir($vz);
            
            echo('<ul>');
            foreach($inhalt as $d) {
                if($d!="." && $d!="..") {
                    switch(true) {
                        case is_dir($vz . $d):
                            $cls = "dir";
                            break;
                            
                        case is_file($vz . $d):
                            $cls = "file";
                            break;
                            
                        case is_link($vz . $d):
                            $cls = "link";
                            break;
                    }
                    
                    echo('<li class="' . $cls . '">' . $d . '</li>');
                }
            }
            echo('</ul>');

Rekursives Auslesen von Verzeichnissen

Was ist Rekursion?

Rekursion ist ein Konzept in der Programmierung, bei dem eine Funktion sich selbst aufruft. Dies ist besonders nützlich, wenn ein Problem in kleinere, identische Teilprobleme zerlegt werden kann. Bei Verzeichnisstrukturen ist Rekursion ideal, da jedes Unterverzeichnis nach dem gleichen Prinzip ausgelesen werden kann wie das übergeordnete Verzeichnis.

Grundprinzip der Rekursion

Bei der rekursiven Verarbeitung von Verzeichnisstrukturen wird folgendes Schema angewendet:

  1. Auslesen des aktuellen Verzeichnisses
  2. Für jedes Element prüfen, ob es sich um ein Verzeichnis handelt
  3. Falls ja: Die Funktion ruft sich selbst mit dem Pfad des Unterverzeichnisses auf
  4. Falls nein: Das Element wird verarbeitet (z.B. angezeigt)

Beispiel aus 15_php_scandir01b.php:

function leseVZ(string $vz):void {
                    $inhalt = scandir($vz); // Schritt 1: Verzeichnisinhalt auslesen
                    
                    echo('<ul>');
                    foreach($inhalt as $d) {
                        if($d!="." && $d!="..") { // Aktuelle und übergeordnete Verzeichnisse ignorieren
                            if(is_dir($vz.$d)) { // Schritt 2: Prüfen, ob Element ein Verzeichnis ist
                                echo('<li class="dir">' . $d);
                                
                                // Schritt 3: Rekursiver Aufruf für Unterverzeichnisse
                                // ---- Rekursion: ----
                                // Eine Funktion, die SICH SELBST mit GEÄNDERTEN Übergabe-Informationen 
                                // ("tatsächliche Parameter"; andere Verzeichnispfade) aufruft
                                leseVZ($vz.$d."/");
                                // --------------------
                
                                echo('</li>');
                            }
                            else {
                                // Schritt 4: Verarbeitung von Nicht-Verzeichnissen
                                if(is_file($vz.$d)) {
                                    echo('<li class="file">' . $d . '</li>');
                                }
                                else {
                                    echo('<li class="link">' . $d . '</li>');
                                }
                            }
                        }
                    }
                    echo('</ul>');
                }

Visuelles Beispiel des rekursiven Ablaufs

Angenommen, wir haben folgende Verzeichnisstruktur:

root/
                ├── datei1.txt
                ├── verzeichnis1/
                │   ├── datei2.txt
                │   └── unterverzeichnis/
                │       └── datei3.txt
                └── verzeichnis2/
                    └── datei4.txt

Der rekursive Ablauf wäre dann:

  1. Aufruf von leseVZ("root/")
  2. Anzeige von datei1.txt als Datei
  3. Für verzeichnis1:
    1. Anzeige von verzeichnis1 als Verzeichnis
    2. Rekursiver Aufruf: leseVZ("root/verzeichnis1/")
      1. Anzeige von datei2.txt als Datei
      2. Für unterverzeichnis:
        1. Anzeige von unterverzeichnis als Verzeichnis
        2. Rekursiver Aufruf: leseVZ("root/verzeichnis1/unterverzeichnis/")
          1. Anzeige von datei3.txt als Datei
          2. Rückkehr zum aufrufenden Kontext
        3. Rückkehr zum aufrufenden Kontext
      3. Rückkehr zum aufrufenden Kontext
  4. Für verzeichnis2:
    1. Anzeige von verzeichnis2 als Verzeichnis
    2. Rekursiver Aufruf: leseVZ("root/verzeichnis2/")
      1. Anzeige von datei4.txt als Datei
      2. Rückkehr zum aufrufenden Kontext
Vorsicht bei Rekursion

Rekursion kann zu Speicherüberläufen führen, wenn die Verschachtelungstiefe zu groß wird. Bei sehr tiefen Verzeichnisstrukturen sollte entweder die Rekursionstiefe begrenzt oder ein iterativer Ansatz gewählt werden. PHP hat standardmäßig einen Limit für die Rekursionstiefe (meistens 100-1000 Aufrufe), der in der php.ini mit xdebug.max_nesting_level konfiguriert werden kann.

Wichtige Aspekte bei rekursiven Funktionen

  • Basisfall (Abbruchbedingung): Jede Rekursion braucht einen Basisfall, bei dem die Rekursion endet. In unserem Beispiel ist der Basisfall erreicht, wenn ein Verzeichnis keine Unterverzeichnisse mehr enthält.
  • Stapelspeicher (Stack): Bei jedem rekursiven Aufruf wird der aktuelle Zustand auf den Stapelspeicher gelegt. Erst wenn der rekursive Aufruf beendet ist, wird der vorherige Zustand wiederhergestellt.
  • Rekursionstiefe: Die Anzahl der verschachtelten Aufrufe wird als Rekursionstiefe bezeichnet. Je tiefer die Verzeichnisstruktur, desto höher die Rekursionstiefe.

Verbessertes Beispiel mit Fehlerbehandlung und Benutzereingabe aus 15_php_scandir02.php:

function leseVZ(string $vz):void {
                    // Sicherheitsüberprüfung: Prüft, ob der Pfad existiert
                    if(file_exists($vz)) { //prüft, ob ein Pfad existiert (nicht: ob eine Datei existiert --> falsche Interpretation des Befehlsnamens)
                        $inhalt = scandir($vz);
                        
                        echo('<ul>');
                        foreach($inhalt as $d) {
                            if($d!="." && $d!="..") {
                                if(is_dir($vz.$d)) {
                                    echo('<li class="dir">' . $d);
                                    
                                    // Rekursiver Aufruf für jedes Unterverzeichnis
                                    leseVZ($vz.$d."/");
                
                                    echo('</li>');
                                }
                                else {
                                    if(is_file($vz.$d)) {
                                        echo('<li class="file">' . $d . '</li>');
                                    }
                                    else {
                                        echo('<li class="link">' . $d . '</li>');
                                    }
                                }
                            }
                        }
                        echo('</ul>');
                    }
                }
                
                // Verwendung der rekursiven Funktion mit Benutzereingabe
                if(count($_POST)>0) {
                    $_POST["VZPfad"] = trim($_POST["VZPfad"]); //entfernt führende/abschließende Leerzeichen von einem String
                    if(strlen($_POST["VZPfad"])>0) {
                        leseVZ($_POST["VZPfad"]);
                    }
                }
Anwendungsfälle für Rekursion

Rekursion ist besonders nützlich bei:

  • Traversieren von hierarchischen Datenstrukturen (wie Verzeichnisstrukturen)
  • Generieren von Menüstrukturen aus Verzeichnissen
  • Erstellung von Sitemaps
  • Synchronisation von Verzeichnisstrukturen
  • Backup-Prozessen, die komplette Verzeichnisbäume sichern müssen
Sicherheitshinweis

Bei der Verwendung von Benutzereingaben für Pfade ist Vorsicht geboten. Unbeschränkter Zugriff auf das Dateisystem kann ein Sicherheitsrisiko darstellen. Es sollte immer validiert werden, dass der Benutzer nur auf erlaubte Verzeichnisse zugreifen kann. Mögliche Sicherheitsmaßnahmen sind:

  • Einschränkung auf bestimmte Basisverzeichnisse
  • Verhinderung des Zugriffs auf kritische Systembereiche
  • Überprüfung auf ".." im Pfad, um ein Verlassen des erlaubten Verzeichnisbereichs zu verhindern

Wichtige Dateisystem-Funktionen

PHP bietet verschiedene Funktionen zur Arbeit mit dem Dateisystem:

  • file_exists($pfad): Prüft, ob ein Pfad (Datei oder Verzeichnis) existiert
  • is_dir($pfad): Prüft, ob es sich um ein Verzeichnis handelt
  • is_file($pfad): Prüft, ob es sich um eine Datei handelt
  • is_link($pfad): Prüft, ob es sich um einen symbolischen Link handelt
  • filesize($datei): Ermittelt die Größe einer Datei in Bytes
  • filetype($pfad): Ermittelt den Typ eines Pfads
  • mkdir($pfad, $berechtigungen, $rekursiv): Erstellt ein Verzeichnis
  • rmdir($pfad): Löscht ein leeres Verzeichnis
  • scandir($pfad): Liest den Inhalt eines Verzeichnisses aus
  • unlink($pfad): Löscht eine Datei
  • rename($alter_pfad, $neuer_pfad): Benennt eine Datei oder ein Verzeichnis um oder verschiebt sie
  • copy($quelle, $ziel): Kopiert eine Datei
Praxisbeispiel: Upload-Verzeichnisse

Ein praktisches Beispiel für die Kombination von Dateiupload und Verzeichniserstellung ist das Anlegen von benutzerspezifischen Upload-Verzeichnissen, wie im folgenden Code zu sehen:

// Verzeichnisstruktur für einen neuen Benutzer anlegen
            $user_email = "benutzer@example.com";
            $user_dir = "./uploads/" . $user_email . "/";
            
            if(!file_exists($user_dir)) {
                mkdir($user_dir, 0755);
                mkdir($user_dir . "bilder", 0755);
                mkdir($user_dir . "dokumente", 0755);
            }

Der Unterschied zwischen Pfad und Dateiname:

  • Dateiname: Nur der Name der Datei, z.B. datei.txt
  • Pfad: Vollständiger Weg zur Datei, z.B. /verzeichnis/unterverzeichnis/datei.txt
Pfadangaben in PHP

Bei Pfadangaben in PHP ist zu beachten:

  • Relative Pfade beginnen mit ./ (aktuelles Verzeichnis) oder ../ (übergeordnetes Verzeichnis)
  • Absolute Pfade beginnen mit einem Schrägstrich / oder einem Laufwerksbuchstaben (unter Windows)
  • Bei der Verkettung von Pfaden muss auf die Schrägstriche geachtet werden: $pfad . "/" . $datei

Zusammenfassung

Diese Lernunterlage deckt die Grundlagen von PHP ab, mit besonderem Fokus auf:

  • PHP-Syntax und Ausgabemethoden
  • Formularverarbeitung und -validierung
  • Sessions für Benutzerverwaltung
  • Code-Organisation mit include/require
  • CSS-Integration und dynamische CSS-Generierung
  • Fehlerbehandlung und -berichterstattung
  • Sicherheitsgrundlagen

Durch die Kombination von theoretischen Konzepten und praktischen Beispielen aus den Kursdateien sollte ein umfassendes Verständnis der PHP-Grundlagen erreicht werden.

EN