Dateisystem mit PHP
Mit PHP kann auf das Dateisystem eines Webservers direkt zugegrffen werden. Dateien können erstellt und gelöscht werden, in Dateien kann geschrieben und gelesen werden.
Zusätzlich kann PHP auch auf die Verzeichnisse des Dateisystems zugreifen.
Für die Arbeit mit Dateien und Verzeichnissen braucht man ausreichend Informationen über die vorliegenden Pfadstrukturen, einzelne Verzeichnisse und Dateien.
PHP stellt Ihnen eine Reihe nützlicher Funktionen zur Verfügung, eine Liste der Datei- Verzeichnisfunktionen finden sie hier:
php.net/Verzeichnisfunktionen
php.net/Dateisystemfunktionen
Für Beispiele dieser Seite brauchen sie eine php-Datei z.B. index.php und eine Textdatei myText.txt.
Pfadangaben
Die meisten Funktionen erwarten eine Pfadangabe als Argument. Diese muss sich in der Regel auf eine existierende Datei beziehen.
Den beiden Funktionen basename() und dirname() genügt ein String, der einen Pfad bezeichnet, ob Datei und Verzeichnis existieren, ist dabei nicht relevant.
Im folgenden Beispiel liefert basename myText.txt als Wert,
dirname liefert C:/adiprinz/php
<?php
echo basename("C:/adiprinz/php/myText.txt");
echo dirname("C:/adiprinz/php/myText.txt");
?>
Die folgenden Funktionen erwarten jedoch, dass der im Argument angegebene Pfad existiert.
<?php
$file = file_exists("C:/adiprinz/php/myText.txt");
$size = filesize("C:/adiprinz/php/myText.txt");
$type = filetype("C:/adiprinz/php/myText.txt");
$isDir = is_dir("C:/adiprinz/php");
$isFile = is_file("C:/adiprinz/php/myText.txt");
?>
Die Funktionen eignen sich hervorragend für den Einsatz in if-Anweisungen.
<?php
if (is_dir("C:/adiprinz/php")) {
echo "Verzeichnis ist vorhanden!";
}
?>
Die Pfadangaben dürfen keinen abschließenden Slash enthalten,
z. B. C:/adiprinz/php/. Dies würde zu einer Fehlermeldung führen!
Relative und absolute Pfadangaben
Ein relativer Pfad ist relativ zum aktuellen Arbeitsverzeichnis des Benutzers oder der Anwendung.
Um innerhalb dieses Arbeitsverzeichnisses zu agieren, müssen die vollständigen Pfade nicht mehr angegeben werden.
Ein absoluter Pfad zeigt unverwechselbar auf genau eine Stelle in einem Dateisystem, unabhängig von dem Arbeitsverzeichnis.
Verzeichnisse
Für die Verwaltung des Verzeichnissystems und dessen Manipulation stellt Ihnen PHP ebenfalls eine Reihe von Funktionen zur Verfügung.
Die Funktionen mkdir() legt ein neues Verzeichnis an, die Funktion rmdir() dagegen löscht Verzeichnisse.
Auch diese beiden Funktionen beziehen sich, wenn keine vollständigen Pfade übergeben werden, auf das aktuelle Verzeichnis.
<?php
echo getcwd();
mkdir("myPHP",0700);
rmdir("myPHP");
?>
Beide Funktionen liefern bei fehlerfreier Ausführung den Wert true, andernfalls wird eine Fehlermeldung ausgegeben.
mkdir()
Die mkdir-Funktion kann bis zu vier Parameter aufnehmen. Die Syntax lautet:
mkdir(Pfad, Mode, Recursive)
Der erste Parameter ist das zu erstellende Verzeichnis. Bei meinen Tests hat eine verschachtelte Ordnerstruktur nur mit Recursive(true) funktioniert.
Der zweite Parameter Mode bestimmt die Berechtigung und der dritte Parameter Recursive für verschachtelte Ordnerstrukturen.
<?php
$recursiv = 'Ordner1/Ordner2/Ordner3';
if (!mkdir($recursiv ,0777, true)) {
die('Erstellung der Verzeichnisse schlug fehl...');
}
?>
Berechtigung
Sowohl die Funktion chmod() als auch das zweite Argument der Funktion mkdir() ermöglichen die Vergabe von Berechtigungen für Dateien und Verzeichnisse. Diese Zahl setzt sich aus vier Stellen zusammen.
- Die erste Stelle ist die Null, Berechtigungen werden im Oktal-Zahlenformat geschrieben
- Die zweite Stelle stellt die Benutzerberechtigungen des Dateieigentümers dar
- Die dritte Stelle steht für die Gruppenberechtigung und bestimmt, was Benutzer der Gruppe, der die Datei angehört, mit ihr machen können.
- Die vierte Stelle steht für die globalen Berechtigungen und bestimmt, was alle Benutzer mit der Datei machen dürfen.
Der höchste Werte für die zweite, dritte und vierte Stelle ist sieben (7). Eine Berechtigung von 0777 ergibt somit volle Berechtigung für
lesen, schreiben und ausführen der Datei bzw. Verzeichnisse.
Mehr Informationen über Berechtigungen finden sie hier:
php.net
Verarbeitung von Dateien
In diesem Abschnitt befassen wir uns mit der Verarbeitung von Dateien. Sie lernen Funktionen kennen, die es Ihnen ermöglichen, Dateien zu
- erzeugen
- öffnen
- schreiben,
- lesen
- kopieren und
- umzubenennen
Einsatz von file() und readfile()
Mit dem Einsatz der Funktionen file() und readfile() kann PHP recht einfach auf den kompletten Inhalt einer Datei zuzugreifen.
Die Funktion readfile() sendet den Inhalt direkt an den Browser und file() schreibt den Inhalt in ein Array.
Die folgende Anweisung reicht aus, um die Datei myText.txt im Browser anzuzeigen:
<?php
readfile("myText.txt");
?>
Die Funktion gibt im Erfolgsfall den Dateiinhalt aus. Sollte es nicht funktionieren, liefert sie den Wert false.
Wenn auf eine Pfadangabe verzichtet wird, muss sich die Datei im selben Verzeichnis befinden wie das Skript,
das die Anweisung enthält. Die Funktion eignet sich hervorragend zur Einbindung von HTML-Dateien.
Mit der Funktion file() kommen Sie ebenfalls an den Inhalt einer Datei. Der Inhalt wird als Array zurückgegeben.
<?php
$datei = file("myText.txt");
foreach($datei as $zeile) {
echo "$zeile <br>";
}
?>
$file() gibt die Datei in einem Array zurück. Jedes Element des Arrays entspricht einer Zeile in der Datei, ohne dass das Zeilenende entfernt wird. Im Fehlerfall gibt file() FALSE zurück.
Lesen und schreiben von Dateien
Um eine Datei zu öffnen, benötigt PHP die Funktion fopen(). Diese erwartet zwei Argumente:
- Name der Datei
- Dateiattribut
Die Funktion liefert als Rückgabewert einen Verweis (Handle) auf die Datei. Diesen Verweis benötigen sie für Lese- und Schreiboperationen, beispielsweise in Verbindung mit fread().
<?php
$datei = fopen("myText.txt","r");
echo fread($datei,1000);
fclose($datei);
?>
Dasselbe Beispiel nochmal, aber mit einer Fehlerbehandlung. Fehlermeldung wird unterdrückt und die eigene angezeigt.
<?php
@$datei = fopen("myText.txt", "r") or die("Kann myText.txt nicht öffnen!");
echo fread($datei, 1000);
fclose($datei);
?>
fread() liest eine bestimmte Anzahl von Bytes aus einer Datei, im Beispiel 1.000 Bytes.
Das Dateiattribut, welches sich im zweiten Argument der fopen()-Funktion befindet, ist "r" und stellt die Datei lediglich zum Lesen zur Verfügung.
Modi von fopen()
In der folgenden Tabelle habe ich Ihnen die zur Verfügung stehenden Modi aufgelistet:
Sie sollten vor allem auf die Angaben »w« und »w+« achten. Damit sind Sie in der Lage, Dateien zu löschen oder zu erzeugen. Die Angabe a (append) sollten Sie verwenden, wenn Sie an eine bereits bestehende Datei weitere Daten anhängen wollen.
Die folgende Tabelle soll Ihnen die Entscheidung für den einen oder anderen Modus beim Verarbeiten von Dateien erleichtern:
Dateien von einem entfernten Server
Mit fopen() können auch Dateien von einem entfernten Server geöffnet werden wenn der Zugang mit http oder ftp erlaubt ist.
<?php
$datei = fopen("http://www.adiprinz.at/myText.txt","r");
?>
Um mithilfe von fopen() Dateien zu öffnen, die einen Benutzernamen und ein Passwort voraussetzen, platzieren Sie die Authentifizierungsinformationen wie folgt in die URL:
<?php
$datei = fopen("ftp://benutzername:passwort@ftp.adiprinz.at/php/myText.txt","r");
$datei = fopen("benutzername:passwort@http://www.adiprinz.at/myText.txt","r");
?>
Die Dateien werden mithilfe des URL-fopen-Wrapper übertragen. In der Standardkonfiguration ist dieser freigegeben, lässt sich jedoch durch die Option allow_url_fopen in Ihrer php.ini sperren.
Einsatz von fgets()
Neben dem bereits vorgestellten fread() stellt PHP zum Auslesen einer Datei auch noch fgets() zur Verfügung. Die beiden unterscheiden sich in einem wesentlichen Punkt: fread() liest immer so viele Zeichen, wie im zweiten Argument angegeben werden, fgets() liest nur bis zum nächsten Zeilenumbruch, auch wenn im zweiten Argument ein größerer Wert angegeben wurde.
fread() ignoriert beim Auslesen einer Datei die enthaltenen Zeilenumbrüche.
<?php
$datei = fopen("myText.txt","r");
echo fread($datei,1000);
fclose($datei);
?>
Das Beispiel oben liest den gesamten Inhalt von myText.txt, das Beispiel unten liest die erste Zeile von myText.txt.
<?php
$datei = fopen("myText.txt","r");
echo fgets($datei,1000);
fclose($datei);
?>
Bei jedem Aufruf von fgets() oder auch fread() wird der interne Dateizeiger an das Ende des eingelesenen Abschnitts gesetzt.
Bei fgets() ist das in der Regel eine Zeile. Sollte jedoch eine Zeile länger sein als im zweiten Argument angegeben, wird lediglich ein Teil der Zeile eingelesen.
Das heißt, dass fgets() bei jedem Aufruf eine Zeile weiter geht.
Zum Auslesen aller Zeilen mit der Funktion fgets() bietet sich eine Schleife an, um nacheinander sämtliche Zeilen auszugeben.
<?php
$datei = fopen("myText.txt","r");
$zeile = true;
while ($zeile) {
$zeile = fgets($datei, 1000);
echo "$zeile <br>";
}
fclose($datei);
?>
Da fgets() ein Leerzeichen zurückgibt und dieses von der while-Schleife als false interpretiert wird, endet die Schleife automatisch, wenn in der Datei keine weiteren Zeilen vorkommen.
Die Funktion fgets() kann auch behilflich sein, eine Datei zu analysieren, wie beispielsweise die Anzahl der Zeilen zu ermitteln.
<?php
$zeilen = 0;
if ($datei = fopen("myText.txt","r")) {
while (!feof($datei)) {
if (fgets($datei, 1048576)) {
$zeilen++;
}}}
echo $zeilen;
fclose($datei);
?>
Der Wert für das zweite Argument in fgets() wurde bewusst so hoch gesetzt, um möglichst sämtliche Zeichen pro Zeile zu erfassen.
Sonderfall Datensätze
Eine Datei, welche datensatzähnliche Strukturen wie Trennzeichen aufweist, kann ebenfalls analysiert werden. Dafür muss im Text ein Zeichen oder String vorhanden
sein, der als Trenner taugt. Im folgenden Beispiel ist es folgender String: -*-
<?php
$dsatz = 0;
$dsatz_trenner = '-*-';
if ($datei = fopen('myText.txt','r')) {
while (!feof($datei)) {
$z = rtrim(fgets($datei, 1048576));
if ($z == $dsatz_trenner) {
$dsatz++;
}}}
echo $dsatz;
fclose($datei);
?>
Bearbeiten einzelner Wörter einer Datei
Um mithilfe der Funktion fgets() einzelne Wörter bearbeiten bzw. erfassen zu können, müssen zusätzlich reguläre Ausdrücke z.B. mit der Funktion preg_split() verwendet werden.
<?php
$datei = fopen('myText.txt','r');
while (! feof($datei)) {
if ($z = fgets($datei,1048576)) {
// Zeile nach Wörtern durchsuchen
$worte = preg_split('/\s+/',$z,-1, PREG_SPLIT_NO_EMPTY);
// Alle Wörter einer Zeile bearbeiten
foreach ($worte as $wort) {
echo "$wort <br>";
}}}
fclose($datei);
?>
Der Code verwendet das Metazeichen \s der Regular Expression Engine. Hiermit werden Leerzeichen (Whitespaces) jeglicher Art verarbeitet, wie Leerzeichen, Tabulatoren, Zeilenvorschübe, Wagenrückläufe und Seitenvorschübe.
Erzeugen und Schreiben von Dateien
Eine neue Datei anzulegen bzw. eine bestehende Datei zu öffnen und darin zu schreiben ist mithilfe der Funktionen fopen() und fwrite() recht einfach.
<?php
$datei = fopen("myText.txt","w");
echo fwrite($datei, "Hallo Welt",100);
fclose($datei);
?>
Die fwrite()-Funktion gibt die Anzahl der Zeichen zurück, welche in die neue Datei myText.txt geschrieben wurden. Das letzte Argument von fwrite() ist übrigens optional:
Sollte die Anzahl der Zeichen aus der Zeichenfolge den Wert überschreiten, wird die Zeichenfolge auf den festgelegten Wert gekürzt. Zusätzlich ist zu beachten, dass fwrite() den internen Dateizeiger weitersetzt. Dieser steht nach der Ausführung hinter dem letzten geschriebenen Zeichen. Sollten Sie fwrite() erneut aufrufen, wird die neue Zeichenfolge an den vorhandenen Text angefügt.
In eine vorhandene Datei schreiben
Beim Schreiben in eine vorhandene Datei kommt es vor allem darauf an, mit welcher Zugriffsmethode die Datei geöffnet wird. Hierbei sind folgende Situationen zu unterscheiden:
-
Sie wollen weitere Daten an die Datei anfügen. In diesem Fall wählen Sie den Wert a (bzw. a+). Die Datei wird dann so geöffnet, dass ein schreibender
Zugriff nur am Ende der Datei erfolgen kann
-
Sie wollen an einer beliebigen Stelle Daten in die Datei schreiben. Die an dieser Stelle befindlichen Daten werden dann jedoch überschrieben. In diesem Fall öffnen Sie die Datei mit der Einstellung r+. Der Dateizeiger steht dann am Anfang der Datei. Um an einer beliebigen Stelle zu schreiben, muss der Dateizeiger mit der Funktion fseek() positioniert werden
-
Sie wollen eine bestehende Datei ganz neu schreiben, also keine bestehenden Daten übernehmen. In diesem Fall wählen Sie den Zugriffsmodus w (bzw. w+).
Im Grunde wird die Datei hierdurch gelöscht und mit dem gleichen Namen neu erzeugt
Die interessanteste Methode dürfte die zweite Variante sein. Hierbei handelt es sich um einen Zugriff auf eine bereits bestehende Datei,
jedoch an einer beliebigen Stelle und nicht am Anfang oder am Ende der Datei. Hierfür benötigen Sie Funktionen, mit denen Sie die Position
des Dateizeigers abfragen und setzen können. Diese habe ich in der folgenden Tabelle für Sie zusammengefasst:
Im folgenden Beispiel öffnet $datei die Datei myText.txt im Lese- und Schreibmodus, der Zeiger wird an die oberste Position gestellt (r+).
$zeiger1 liefert die aktuelle Zeigerposition (0). fwrite schreibt den Text "Hallo Welt!", vorhandener Text wird dabei überschrieben.
$zeiger2 liefert die neu aktuelle Zeigerposition (11).
<?php
$datei = fopen("myText.txt","r+");
$zeiger1 = ftell($datei);
echo $zeiger1 . "<br>"; // 0
fwrite($datei, "Hallo Welt!");
$zeiger2 = ftell($datei);
echo $zeiger2; // 11
fclose($datei);
?>
fopen öffnet die Datei myText.txt im Lesemodus. fgets findet Bytes -1 der ersten Zeile (falls vorhanden).
ftell setzt den Zeiger fgets-1.
Die Funktion fseek()
Die Funktion fseek() benötigt einen offset (Versatzwert), um den Dateizeiger ausgehend von einer festgelegten Position neu zu positionieren. Auf welche Startposition sich der Versatz bezieht, bestimmen Sie im letzten Argument. Dieses Argument ist optional. Wenn Sie darauf verzichten, zählt der Versatzwert vom Anfang der Datei. Die Startposition lässt sich mithilfe einer der folgenden Konstanten bestimmen:
-
SEEK_SET – Als Startposition wird der Dateianfang angenommen. Der Versatzwert steht dann auch für die absolute Position. Diese Konstante
entspricht dem Standardwert und muss daher nicht unbedingt angegeben werden
- SEEK_CUR – Als Startposition wird die aktuelle Position angenommen. Der Versatzwert bezieht sich dann auf diese Position
-
SEEK_END – Als Startposition wird das Dateiende angenommen. Das bedeutet, dass der Dateizeiger auch nach dem eigentlichen Ende der Datei positioniert
werden kann. Diese Eigenschaft macht es möglich, eine strukturierte Datei mit
Datensätzen fester Länge zu erzeugen. Die Datei muss hierzu nicht mit SEEK_END geöffnet werden
Die aktuelle Position kann mit der Funktion ftell() ausgelesen werden. Das folgende Beispiel kombiniert beide Funktionen und stellt die relative Positionierung mit SEEK_CUR dar.
<?php
$datei = fopen("myText.txt","r+");
fseek($datei, 50);
echo ftell($datei) . "<br>";
fseek($datei, 15, SEEK_CUR);
echo ftell($datei) . "<br>";
fwrite($datei, "Hallo Welt!");
echo ftell($datei) . "<br>";
fclose($datei);
?>
Die Datei wurde mit dem Zugriffsmode r+ geöffnet. Der Dateizeiger lässt sich dann auch für das Schreiben frei positionieren.
Wenn hingegen den Modus a (bzw. a+) verwendet wird,, werden sämtliche Daten an das Ende der Datei angefügt, unabhängig davon, wo gerade der Dateizeiger steht.
Die Positionierung mit fseek() kann dann lediglich für das Auslesen benutzt werden.
Kopieren, Umbenennen und Löschen von Dateien
Zusätzlich zu den bisherigen Funktionen stehen noch die Funktionen copy(), rename() und unlink() zur Verfügung, mit deren Hilfe Dateien kopiert, umbenannt und gelöscht werden.
Kopieren
<?php
if (@copy("myText.txt", "daten.txt")) {
echo "Kopiert";
} else {
echo "Fehler!";
}
?>
Umbenennen - Verschieben
<?php
if (@rename("daten.txt", "datenumbenannt.txt")) {
echo "Umbenannt";
} else {
echo "Fehler!";
}
?>
Löschen
<?php
if (@unlink("datenumbenannt.txt")) {
echo "Gelöscht";
} else {
echo "Fehler!";
}
?>
Weitere Einsatzgebiete
Funktionen wie file() oder file_get_contents() sorgen dafür, dass der Inhalt einer Datei eingelesen wird.
Einsatz von serialize() und unserialize()
Eine Variable (z.B. ein Array) kann mithilfe von serialize() in ein speicherbares Format übertragen werden.
Beim Auslesen werden diese Daten wieder deserialisiert.
Die serialize()-Funktion gibt eine Zeichenfolge zurück, die eine einem Byte-Stream entsprechende Wiedergabe von einer Variablen enthält und beliebig abgespeichert werden kann. Diese Funktion dient der Speicherung oder Übergabe von PHP-Werten, ohne dass diese ihren Wert oder ihre Struktur verlieren.
<?php
$personen = array(
"Adi", "Gabi", "Harald");
$daten = serialize($personen);
echo $daten;
// liefert a:3:{i:0;s:3:"Adi";i:1;s:4:"Gabi";i:2;s:6:"Harald";}
?>
Eine solche Zeichenfolge kann mithilfe der Funktion unserialize(), wieder in eine gültige Variable umgewandelt werden.
<?php
$daten = 'a:3:{i:0;s:3:"Adi";i:1;s:4:"Gabi";i:2;s:6:"Harald";}';
$personen = unserialize($daten);
echo "<pre>";
print_r ($personen);
echo "</pre>";
/* liefert:
Array
(
[0] => Adi
[1] => Gabi
[2] => Harald
)
*/
?>
Verriegelung von Dateien
Jeder Schreibvorgang innerhalb einer Webanwendung birgt das Risiko, dass Daten überschrieben werden.
Ein Verriegelungsverfahren davor schützt, dass Inhalte einer Datei nicht ungewollt verändert werden können.
Eine Datei wird hierbei durch einen Lock geschützt. Dieses Verfahren sperrt eine Datei, sodass ein ungewollter Zugriff ausgeschlossen werden kann.
Die Funktion für die Verriegelung heißt flock().
Diese Funktion erwartet neben dem Datei-Handler als zweites Argument einen Integerwert für die durchzuführende Verriegelungsoperation. Dabei stehen folgende Verriegelungs-Konstanten zur Verfügung:
Um eine Datei zu sperren, benötigt die Funktion einen Datei-Handler, den Sie mit fopen() erhalten. Als Operation können Sie entweder einen verteilten oder einen exklusiven Zugriff erlauben oder eine Verriegelung wieder aufheben. Die Option LOCK_NB legt fest, wie reagiert werden soll, wenn eine Datei gesperrt vorgefunden wird. Um dies anzugeben, notieren Sie nach der Operation einen senkrechten Strich und danach die Konstante. Sie sollten diese nur dann einsetzen, wenn Sie Zugriffe während der Verriegelung durch flock() zulassen wollen.
Der Einsatz einer Verriegelung macht jedoch nur dann Sinn, wenn alle Programme die gleiche Art und Weise der Verriegelung nutzen. Eine Verriegelung von Dateien wird im Übrigen lediglich empfohlen. Solange Sie kein flock() verwenden, um den Verriegelungsstatus einer Datei festzulegen, können Sie auf diese bequem Lese-/Schreibzugriffe ausführen.
<?php
$datei = fopen("myText.txt","w+");
// exclusive lock
if (flock($datei,LOCK_EX))
{
fwrite($datei,"Hallo Welt!");
// release lock
flock($datei,LOCK_UN);
} else {
echo "Error locking file!";
}
fclose($datei);
?>
Auslesen von CSV-Dateien
Abschließend wird noch die Funktion fgetcsv() vorgestellt. Vorab jedoch noch eine kurze Einführung in die Struktur von CSV-Dateien (comma separated values). Hierbei handelt es sich um Textdateien, deren Einträge in Zeilen und Spalten (Felder) unterteilt sind. Die Zeilen werden durch Zeilenumbrüche gekennzeichnet und die Felder durch Kommata oder andere Trennzeichen. Für das Auslesen solcher Dateien können Sie die Funktion fgetcsv() einsetzen. Die Funktion erwartet eine Textdatei, die beispielsweise wie folgt strukturiert ist:
1, erster Mitarbeiter, Adi, Prinz
2, zweiter Mitarbeiter, Gabi, Prinz
Jeder Aufruf von fgetcsv() liefert die jeweils nächste Zeile. Die Funktion benötigt mindestens zwei Argumente:
- Dateihandle
- Maximale Anzahl der auszulesenden Zeichen
<?php
$datei = fopen("myText.txt", "r");
$daten = fgetcsv($datei, 1000);
while ($daten) {
echo implode(" – ", $daten) . "<br>";
$daten = fgetcsv($datei, 1000);
}
/* liefert:
1 – erster Mitarbeiter – Adi – Prinz
2 – zweiter Mitarbeiter – Gabi – Prinz
*/
?>