Abschnitt 8 · Lektion 2
Eine Datei schreiben
Lesen war die eine Hälfte, Schreiben ist die andere. Und weil du dabei etwas hinterlässt, das den Lauf überdauert, ist es zugleich die erste Stelle im Kurs, an der ein Fehler nicht einfach mit dem Programmende verschwindet.
file_put_contents, und was es mit dem Vorhandenen macht
<?php
file_put_contents("notiz.txt", "Erster Satz.\n");
echo "Nach dem ersten Schreiben:\n";
echo file_get_contents("notiz.txt");
file_put_contents("notiz.txt", "Zweiter Satz.\n");
echo "\nNach dem zweiten Schreiben:\n";
echo file_get_contents("notiz.txt");
echo "\nVom ersten Satz ist nichts uebrig.\n"; file_put_contents() nimmt zwei Dinge: wohin, und was. Gibt es die Datei noch nicht, wird sie
angelegt. Gibt es sie schon, wird ihr Inhalt ersetzt. Ohne Rückfrage, ohne Papierkorb, ohne
Warnung.
Das ist keine Bosheit, sondern die Voreinstellung, die man in neun von zehn Fällen will: eine Zwischendatei neu schreiben, einen Zwischenstand ablegen, gleich in Lektion 8.3 eine JSON-Datei zurückschreiben. Man muss es nur wissen, bevor man es an der falschen Datei ausprobiert.
FILE_APPEND hängt an, statt zu ersetzen
<?php
file_put_contents("notiz.txt", "Erster Satz.\n");
file_put_contents("notiz.txt", "Zweiter Satz.\n", FILE_APPEND);
file_put_contents("notiz.txt", "Dritter Satz.\n", FILE_APPEND);
echo file_get_contents("notiz.txt");
$zeilen = file("notiz.txt", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
echo "\n", count($zeilen), " Zeilen stehen jetzt drin.\n"; Das dritte Argument ist ein Schalter, und der wichtigste davon heißt FILE_APPEND. Damit landet
dein Text hinter dem, was schon dasteht.
Das ist die Form, die ein Protokoll braucht. Jede Zeile kommt dazu, keine geht verloren, und du musst die Datei vorher nicht lesen. Genau das ist die Challenge dieser Lektion.
Der Rückgabewert, den fast niemand ansieht
<?php
$geschrieben = file_put_contents("notiz.txt", "Hallo\n");
echo "Erster Versuch: ";
var_dump($geschrieben);
echo "Zweiter Versuch: ";
$misslungen = file_put_contents("gibtsnicht/notiz.txt", "Hallo\n");
var_dump($misslungen);
echo "\nUnd so faengt man das ab:\n";
if ($misslungen === false) {
echo "Konnte nicht geschrieben werden.\n";
} file_put_contents() gibt die Zahl der geschriebenen Bytes zurück, und im Fehlerfall false. Das
ist genau das Muster aus Lektion 7.4: eine alte Funktion, die auf einen Fehler mit einem Wert
antwortet, den man übersehen kann.
Und übersehen wird er ständig. Im Beispiel scheitert der zweite Aufruf, weil es das Verzeichnis
nicht gibt. PHP schreibt dazu eine Warning auf den Fehlerkanal, liefert false, und das Programm
läuft munter weiter, als sei die Datei geschrieben worden.
Achte beim Prüfen auf ===. Eine leere Datei zu schreiben ist erlaubt und liefert 0, und 0 ist
in einem if falsch. Wer mit if (!$geschrieben) prüft, hält den geglückten Schreibvorgang für
einen Fehlschlag. Die Falsch-Liste aus Lektion 2.5, an einer Stelle, an der sie wehtut.
Rechte und Verzeichnisse
Auf deinem eigenen Rechner klappt Schreiben fast immer. Auf einem Hosting-Paket ist es die häufigste Ursache für „geht nicht”, und die Gründe sind jedes Mal dieselben zwei:
Das Verzeichnis muss es geben. PHP legt keine Ordner nebenbei an. Wer nach daten/log.txt
schreiben will, braucht vorher ein daten. Anlegen geht mit mkdir("daten"), und mit
mkdir("a/b/c", recursive: true) auch mehrstufig.
Der Webserver muss dort schreiben dürfen. Deine Dateien gehören dir, der PHP-Prozess läuft aber unter einem eigenen Benutzer. Deshalb sind auf gemieteten Servern die Verzeichnisse, in die etwas geschrieben wird, meist eigens dafür angelegt und liegen außerhalb dessen, was der Besucher aufrufen kann. Warum das keine Schikane ist, siehst du in Abschnitt 15.
Der vergessene Zeilenumbruch
<?php
foreach (["Milch", "Brot", "Kaffee"] as $ware) {
file_put_contents("liste.txt", $ware, FILE_APPEND);
}
echo "So sieht die Datei aus:\n";
echo file_get_contents("liste.txt"), "\n";
$zeilen = file("liste.txt", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
echo "\nUnd so viele Zeilen zaehlt PHP: ", count($zeilen), "\n"; Der häufigste Anfängerfehler beim Anhängen, und er sieht harmlos aus: Drei Wörter werden angehängt,
und in der Datei steht MilchBrotKaffee. PHP hat alles richtig gemacht, es hat genau das
geschrieben, was dastand.
Ein Zeilenumbruch ist ein Zeichen und entsteht nicht von selbst. Wer Zeilen anhängt, schreibt das
\n mit. Am Ende, nicht am Anfang: sonst fängt die Datei mit einer Leerzeile an.
Im Terminal siehst du das auch ohne PHP: wc -l liste.txt zählt Zeilenumbrüche und sagt 0. Und
weil das Beispiel anhängt, steht nach einem zweiten php index.php der Text zweimal hintereinander
in der Datei. Der Prüfknopf räumt vor jedem Lauf auf, das Terminal nicht.
Löschen
<?php
file_put_contents("temp.txt", "Nur kurz.\n");
echo "Da: ", var_export(file_exists("temp.txt"), true), "\n";
echo "Loeschen sagt: ", var_export(unlink("temp.txt"), true), "\n";
echo "Da: ", var_export(file_exists("temp.txt"), true), "\n";
echo "\nUnd noch einmal loeschen:\n";
echo "Loeschen sagt: ", var_export(@unlink("temp.txt"), true), "\n"; unlink() löscht eine Datei und gibt true oder false zurück. Auf eine Datei, die es nicht gibt,
antwortet es mit false und einer Warning, genau wie das Lesen in Lektion 8.1.
Das @ im letzten Aufruf des Beispiels kennst du aus Lektion 7.1: Es unterdrückt die Meldung, nicht
das Problem. Hier ist es einmal vertretbar, weil das Ergebnis danach wirklich geprüft wird. Die
sauberere Form bleibt trotzdem, vorher mit file_exists() zu fragen.
Zum Mitnehmen
Alles, was deine Programme bisher gerechnet haben, war beim letzten Zeichen der Ausgabe wieder weg. Eine Zeile ändert das, und dieselbe Zeile löscht mit einem falschen Schalter deine Daten.
Jetzt du
Basis Konto, kostenlosZu 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 5 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.