fopen('data.txt', 'r') öffnet eine Datei und liefert ein Handle, eine Stream-Ressource, die die anderen Dateifunktionen als erstes Argument nehmen. Du liest mit fgets() (eine Zeile) oder fread() (eine Anzahl Bytes), schreibst mit fwrite() und schließt mit fclose(). Das zweite Argument ist der Modus: 'r' zum Lesen, 'w' zum Schreiben, 'a' zum Anhängen.
Ausgabe:
Got: apple
Got: banana
Got: cherry
fopen() liefert false, wenn es die Datei nicht öffnen kann (sie existiert im Modus r nicht, ein Ordner fehlt, keine Berechtigung), und PHP gibt eine Warnung aus wie:
Warning: fopen(missing.txt): Failed to open stream: No such file or directory in /home/index.php on line 2
Prüfe also auf false, bevor du das Handle verwendest. Um eine ganze kleine Datei mit einem Aufruf zu lesen oder zu schreiben, sind file_get_contents() und file_put_contents() kürzer; fopen() ist für Dateien, die du stückweise liest oder offen hältst.
fopen-Modi
| Modus | Lesen | Schreiben | Wenn die Datei existiert | Wenn nicht | Beginnt am |
|---|---|---|---|---|---|
r | ja | nein | öffnet sie | scheitert | Anfang |
r+ | ja | ja | öffnet sie, behält den Inhalt | scheitert | Anfang |
w | nein | ja | leert sie | legt sie an | Anfang |
w+ | ja | ja | leert sie | legt sie an | Anfang |
a | nein | ja | behält den Inhalt | legt sie an | Ende, jedes Schreiben hängt an |
a+ | ja | ja | behält den Inhalt | legt sie an | Ende, jedes Schreiben hängt an |
x | nein | ja | scheitert | legt sie an | Anfang |
x+ | ja | ja | scheitert | legt sie an | Anfang |
c | nein | ja | behält den Inhalt | legt sie an | Anfang |
c+ | ja | ja | behält den Inhalt | legt sie an | Anfang |
Zwei Zeilen überraschen. r+ überschreibt die vorhandenen Bytes an Ort und Stelle, ohne einzufügen, und a+ schreibt immer ans Ende, auch nachdem du den Zeiger mit fseek() bewegt hast (das Verschieben wirkt nur aufs Lesen):
Ausgabe:
Xbc
Xbc
Xbc
end
Unter Windows siehst du vielleicht 'rb' oder 'wb': Das Flag b bedeutet binär und verhindert, dass Windows Zeilenenden übersetzt. Unter Linux und macOS bewirkt es nichts, es hinzuzufügen ist also harmlos und portabel.
Eine Datei mit fgets() Zeile für Zeile lesen
fgets() liefert die nächste Zeile einschließlich ihres \n und am Dateiende false. Weil immer nur eine Zeile im Speicher liegt, kommt diese Schleife mit einer Logdatei jeder Größe zurecht, und du kannst mit break früh aufhören:
Ausgabe:
2 errors in 5 lines
line 2: database timeout
line 4: disk full
Vergleiche mit !== auf false, nicht mit einem einfachen while ($line = fgets($fh)): Eine Zeile, die nur "0" ohne Zeilenumbruch enthält (die letzte Zeile einer Datei kann so eine sein), ist falsy und würde die Schleife zu früh beenden.
Mit fwrite() schreiben und anhängen
fwrite() schreibt einen String an der aktuellen Position und liefert die Anzahl der geschriebenen Bytes oder false bei einem Fehler. fputs() ist dieselbe Funktion unter anderem Namen. Öffne mit 'a', um ans Ende einer Datei anzuhängen, ohne anzurühren, was dort steht:
Ausgabe:
wrote 12 bytes
wrote 13 bytes
wrote 15 bytes
visit /home
visit /about
visit /contact
visit /home
PHP_EOL ist das Zeilenende des Systems, auf dem PHP läuft (\n unter Linux und macOS, \r\n unter Windows). Für Dateien, die andere Programme lesen, wählst du eines ausdrücklich, meist "\n".
CSV-Dateien mit fgetcsv() und fputcsv() lesen und schreiben
fputcsv() schreibt ein Array als eine CSV-Zeile und setzt Felder mit Kommas, Anführungszeichen oder Zeilenumbrüchen in Anführungszeichen. fgetcsv() liest eine Zeile als Array zurück. Übergib Trennzeichen, Einschlusszeichen und ein leeres Escape-Zeichen ausdrücklich: Das ergibt Standard-CSV, und PHP 8.4 gibt einen Deprecation-Hinweis aus, wenn das Escape-Argument fehlt.
Ausgabe:
name,city,note
Ada,London,"likes ""math"", a lot"
Linus,Helsinki,kernel
Ada lives in London: likes "math", a lot
Linus lives in Helsinki: kernel
Zeilen mit explode(',', $line) aufzuteilen, scheitert, sobald ein Feld ein Komma enthält; fgetcsv() erledigt die Anführungszeichen für dich. Für eine Datei mit Semikolon als Trennzeichen (in Europa üblich bei Excel-Exporten) übergibst du ';' als Trennzeichen.
Mit fseek(), ftell() und rewind() in einer Datei bewegen
Eine geöffnete Datei hat eine Position. Lese- und Schreibvorgänge beginnen dort und schieben sie weiter. ftell() sagt dir, wo sie steht, fseek() verschiebt sie zu einem Byte-Offset, und rewind() geht zurück an den Anfang. Mit w+ kannst du eine Datei schreiben und über dasselbe Handle zurücklesen:
Ausgabe:
11
world
hello world
Eine Datei mit flock() sperren
Zwei Anfragen, die gleichzeitig einen Zähler lesen, eins addieren und zurückschreiben, können beide 41 lesen und beide 42 schreiben. flock() mit LOCK_EX lässt die zweite warten, bis die erste die Sperre freigibt. Der Modus c+ ist hier der richtige: Er legt die Datei bei Bedarf an und leert sie, anders als w+, nicht, bevor du die Sperre hältst.
Ausgabe:
Visitor number 1
Visitor number 2
Visitor number 3
Sperren sind nur beratend: Sie halten nur anderen Code auf, der ebenfalls flock() aufruft. Um eine Zeile anzuhängen, macht file_put_contents($path, $line, FILE_APPEND | LOCK_EX) dasselbe in einem Aufruf.
Typischer Fehler: while (!feof($fh))
Viele alte Tutorials laufen mit feof() in einer Schleife. Es liefert erst true, nachdem ein Lesevorgang schon auf das Ende gestoßen ist, also läuft die Schleife einmal öfter, als es Zeilen gibt, und das letzte fgets() liefert false:
Ausgabe:
string(2) "a
"
string(2) "b
"
string(2) "c
"
bool(false)
4 rounds for 3 lines
Dieses zusätzliche false wird zu einer leeren Zeile in einem Bericht oder einem leeren Element in einem Array. Steuere die Schleife über den Lesevorgang selbst, while (($line = fgets($fh)) !== false), wie es jedes andere Beispiel auf dieser Seite tut.
Häufig gestellte Fragen
Welche fopen-Modi gibt es in PHP?
r liest, w schreibt, nachdem die Datei geleert wurde, a schreibt ans Ende, x legt eine neue Datei an und scheitert, wenn sie existiert, und c schreibt, ohne sie zu leeren. Ein angehängtes + (r+, w+, a+, x+, c+) erlaubt Lesen und Schreiben. Jeder Modus außer r und r+ legt die Datei an, wenn sie fehlt.
Was ist der Unterschied zwischen w und a bei fopen?
w leert die Datei, sobald sie geöffnet wird, und schreibt ab dem Anfang. a behält den Inhalt, und jedes fwrite() geht ans Ende der Datei, auch nach fseek(), und das macht ihn zum Modus für Logdateien.
Wie lese ich in PHP eine CSV-Datei?
Öffne sie mit fopen($path, 'r') und rufe fgetcsv() in einer Schleife auf: while (($row = fgetcsv($fh, null, ',', '"', '')) !== false) { ... }. Jeder Aufruf liefert eine Zeile als Array von Feldern, wobei Anführungszeichen und eingebettete Kommas für dich behandelt werden.
Muss ich in PHP fclose aufrufen?
PHP schließt jede offene Datei, wenn das Skript endet, also funktioniert ein kurzes Skript auch ohne. Rufe fclose() trotzdem auf, sobald du fertig bist: Es schreibt gepufferte Daten weg, gibt mit flock() gesetzte Sperren frei und verhindert, dass einem lang laufenden Skript die Datei-Handles ausgehen.