öffentlich
Redaktion Druckversion

PHP lernen (4): Manipulation von Dateien

Umgang mit Dateien

PHP findet oft dort Anwendung, wo Daten regelmäßig aktualisiert werden müssen. In der Regel werden Daten in einer Datenbank abgelegt. Wenn aber auf einer Webanwendung nur ein sehr kleiner Teil editierbar sein soll, kann eine Lösung mit einer Textdatei angeraten sein. Außerdem können Sie Log-Daten oder Grundeinstellungen permanent speichern. Inhalte von Formularen können Sie in Textdateien auf dem Server zwischenspeichern und daraus andere Anwendungen steuern. Auch wenn Sie Daten aus einer Datenbank exportieren wollen, können Sie unter Umständen auf Textdateien zurückgreifen.

Der Umgang mit Textdateien ist problematisch. Im Internet können viele Benutzer gleichzeitig auf eine Webseite zugreifen. So könnte es passieren, dass mehrere Benutzer gleichzeitig versuchen, eine Datei zu ändern und sich dabei gegenseitig ins Gehege kommen. Das muss unterbunden werden. Für das Verwalten mehrerer Benutzerzugriffe auf Daten wurden Datenbank Management Systeme (DBMS) wie zum Beispiel MySQL entwickelt. Ein DBMS übernimmt die Steuerung der Zugriffe und ist dabei wesentlich schneller und zuverlässiger als eine manuelle Anwendung es sein könnte. Darum sollten Sie Textdateien nur in kleinen, überschaubaren oder ganz speziellen Bereichen einsetzen, bei denen nur wenige Benutzer die Inhalte der Dateien verändern können.

Als konkretes Beispiel nehmen wir einen Tagestipp, der täglich aktualisiert werden soll. Es gibt nur einen Redakteur, der diesen Tagestipp ändern kann. Die Benutzer lesen diese Datei nur. Eine solche Anwendung wäre akzeptabel.

Zugriffe auf das Dateisystem des Servers stellen immer ein Sicherheitsrisiko dar. Versuchen Sie alles, um diesen Zugriff abzusichern, um zu verhindern, dass auf diese Weise böswilliger Code Ihre Webseite oder noch schlimmer den Webserver manipuliert. Wir werden in den nächsten Seiten darauf zurückkommen.

Tagestipp, eine Textdatei nur auslesen

Im ersten Schritt werden wir eine bereits existierende Datei lesen. Legen Sie zum Testen eine Datei an, die einen Beispieltext enthält, zum Beispiel:

Hallo Welt!

Dies ist der einzige Inhalt der Datei. Speichern Sie diese nun unter dem Namen tagestipp.txt.

Um diese Datei einzubinden, gibt es sehr unterschiedliche Möglichkeiten - je nachdem, was wir mit dem Inhalt der Datei machen wollen. Im Grunde ist es auch möglich, eine reine Textdatei mit include() oder require() einzubinden:

<html>
<head>...</head>
<body>
<div class="tagestipp">
<?php
include('tagestipp.txt');
?>
</div>
</body>
</html>

Dies wäre aber eher eine untypische Anwendung, da wir keinen PHP-Code ausführen, sondern lediglich Inhalt ausgeben wollen. Mit include() oder require() werden üblicherweise Dateien eingebunden, die selbst auch PHP-Code enthalten.

Für eine Textdatei würde man eher readfile() verwenden:

<html>
<head>...</head>
<body>
<div class="tagestipp">
<?php
readfile("tagestipp.txt");
?>
</div>
</body>
</html>

Sie können in der Textdatei übrigens auch HTML-Formate unterbringen. Sie werden ebenfalls angezeigt. Ändern Sie zum Testen den Inhalt Ihrer Datei tagestipp.txt:

Hallo <strong>Welt</strong>! <br>
Schönes Wetter heute -
hoffentlich

Die Funktionen readfile() und include() bzw. require() werden die HTML-Codierungen korrekt anzeigen.

Manuelle Zeilenumbrüche werden übrigens nicht in der Ausgabe angezeigt. Zeilenumbrüche müssen Sie ausdrücklich in HTML <br> gesetzt werden.

Das funktioniert so lange gut, wie Sie nichts am Inhalt der Datei ändern wollen. Wenn Sie allerdings Zeichen manipulieren wollen, bevor die Inhalte ausgegeben werden, zum Beispiel manuelle Zeilenumbrüche durch breaks ersetzen, müssen Sie die Zeichen aus der Datei in eine Variable einlesen. Dazu öffnen Sie die Datei und lesen sie entweder komplett oder zeilenweise in eine Variable ein. Auf diese Variable können Sie z.B. Zeichenkettenfunktionen anwenden und damit ihren Inhalt manipulieren. Beim Öffnen legen Sie fest, ob Sie den Inhalt nur lesen oder auch schreiben wollen.

Dateien öffnen

Das Grundprinzip ist immer das Gleiche: Eine Datei wird geöffnet, ihr Inhalt wird ausgelesen, manipuliert oder Daten werden hineingeschrieben, die Datei wird wieder geschlossen. Wenn die Datei nicht existiert, wird sie angelegt. Dabei spielt der Dateizeiger eine wichtige Rolle. Dieser, eine Art Cursor, wird beim Öffnen einer Datei an die gewünschte Stelle gesetzt, von der aus gelesen oder geschrieben werden soll.

Die wichtigsten Funktionen im Umgang mit Dateien sind fopen(), fgets(), fputs(), fclose(). Der Rückgabewert der Funktion fopen() ist das sogenannte Datei-Handle, mit dem die weiteren Zugriffe auf die Datei gesteuert werden. Die Funktionen werden im Kapitel XL. Funktionen des Dateisystems im Handbuch beschrieben. Betrachten wir zunächst fopen():

resource fopen (string filename, string mode)

Die Datei muss für PHP verfügbar sein, weshalb Sie sicherstellen müssen, dass die Dateirechte diesen Zugriff ermöglichen. Wenn PHP die Datei erzeugt hat, dann hat PHP auch Zugriff auf sie. Tricksen Sie die Privilegien aus, indem Sie in Ihrem Skript die Datei, die Sie später bearbeiten wollen, auch zuerst anlegen. Wir werden das weiter unten sehen.

Je nach Konfiguration des Webservers (safe mode oder open_basedir), können weitere Einschränkungen zutreffen. Solange Sie auf einem Windowssystem arbeiten, werden Sie keine Probleme mit dem Schreiben von Dateien haben.

Der erste Parameter ist der Name der Datei, die geöffnet werden soll. Sie können einen relativen Pfad setzen, einen URI über HTTP oder einen absoluten Pfad im Dateisystem angeben. Wenn Sie Dateien über HTTP öffnen, können Sie natürlich nur Daten lesen, nicht schreiben. Es ist ebenso möglich, Dateien über FTP zu öffnen. Dafür muss eine offene FTP-Verbindung zwischen Ihrem PHP-Skript und dem angegebenen FTP-Server bestehen. Die Pfade sind dann relativ zu dem geöffneten Serverpfad zu setzen.

Im zweiten Parameter bestimmen Sie mit einem festgelegten Attribut, an welche Stelle Sie den Dateizeiger setzen und was Sie mit dem Inhalt der Datei machen wollen. Sie können folgende Attribute setzen:

  • r
    Öffnet die Datei nur zum Lesen (r wie read) und positioniert den Dateizeiger auf den Anfang der Datei.

  • r+
    Öffnet die Datei zum Lesen und Schreiben und setzt den Dateizeiger auf den Anfang der Datei.

  • w
    Öffnet die Datei nur zum Schreiben (w wie write) und setzt den Dateizeiger auf den Anfang der Datei sowie die Länge der Datei auf 0 Byte. Wenn die Datei nicht existiert, wird versucht sie anzulegen.

  • w+
    Öffnet die Datei zum Lesen und Schreiben und setzt den Dateizeiger auf den Anfang der Datei sowie die Länge der Datei auf 0 Byte. Wenn die Datei nicht existiert, wird versucht sie anzulegen.

  • a
    Öffnet die Datei nur zum Schreiben (a wie append = anhängen). Positioniert den Dateizeiger auf das Ende der Datei. Wenn die Datei nicht existiert, wird versucht sie anzulegen.

  • a+
    Öffnet die Datei zum Lesen und Schreiben. Positioniert den Dateizeiger auf das Ende der Datei. Wenn die Datei nicht existiert, wird versucht sie anzulegen.

Zusätzlich kann beim 2. Parameter mode der Buchstabe b hinzugefügt werden, der die Behandlung von Binärdateien erlaubt. Dies ist nur auf Systemen sinnvoll, welche zwischen Binär- und Text-Dateien unterscheiden (z. B. Windows - ist bei Unix sinnlos). Wenn das Feature nicht gebraucht wird, wird es einfach ignoriert. Sie können den Flag b verwenden, um Ihre Skripte portabler zu machen.

Folgende Beispiele sind möglich:

$handle = fopen ("C:/Programme/XAMPP/htdocs/tagestipp.txt", "r");
// auf einem Windowssystem auch: 
$handle = fopen ("C:/Programme/XAMPP/htdocs/tagesbild.gif", "rb");
$handle = fopen ("Workshop/woche3/tagestipp.txt", "wb");
$handle = fopen ("http://www.example.com/tagestipp.txt", "r");
$handle = fopen ("ftp://user:password@example.com/tagestipp.txt", "w");

PHP kann die angegebene Datei nur öffnen, wenn es auch Zugriff auf die Datei hat, siehe oben.

Vergessen Sie nicht, Dateien wieder zu schließen, um sie für andere Prozesse wieder freizugeben und Systemressourcen zu schonen. Gerade bei größeren Zugriffszahlen entwickeln sich nicht sauber geschlossene Dateien schnell zum Problem.

$handle = fopen("tagestipp.txt", "r");
// mach was 
fclose($handle);

Dateinamen und Pfad prüfen

Sollte das Skriptbeispiel nicht funktionieren, überprüfen Sie sorgfältig den Dateinamen der Datei, die Sie zu öffnen versuchen. Befindet sich die Datei im gleichen Verzeichnis wie die Skriptdatei? Um sicherzugehen, dass es sich nicht um einen Tipp- oder Pfadfehler handelt, können Sie mit file_exists() überprüfen, ob die Datei überhaupt an angegebener Stelle existiert:

if (file_exists("tagestipp.txt"))
print 'Datei existiert';

Die Funktion file_exists() funktioniert auch mit relativen oder absoluten Pfadangaben, allerdings nicht mit entfernten Dateien. Die Datei muss im Dateisystem des Servers verfügbar sein.

Was passiert übrigens, wenn das Öffnen der Datei scheitert? Sie erhalten eine PHP-Fehlermeldung, weil der Zeiger für die Datei ungültig ist. Wenn Ihr Skript weiter vorangeschritten ist, werden auch die folgenden Funktionen, die auf diesen Zeiger zugreifen, immer wieder Fehlermeldungen verursachen. Wenn Funktionsaufrufe in einer while-Schleife stehen, gerät der Browser in eine Endlosschleife. Die Escape-Taste rettet den Browser in der Regel vor dem kompletten Absturz. Es ist dennoch angeraten, Endlosschleifen von vorn herein zu vermeiden.

Wir können uns hier der Funktion die() bedienen und das Skript im Fall, dass das Öffnen scheitert, gleich beenden. Beachten Sie den Zeichenfehler im Dateinamen, dipp statt tipp. Das Skript sollte also einen Fehler verursachen und sich selbst beenden:

$handle = fopen('tagesdipp.txt', 'r') 
    OR die('Kann Datei nicht öffnen');

Wollen Sie auch die PHP-Fehlermeldung unterdrücken, ergänzen Sie das @ vor dem Funktionsaufruf:

$handle = @fopen("tagesdipp.txt", "r") 
    OR die('Kann Datei nicht öffnen');

Das Skript wird beim Scheitern sofort beendet, verschwendet keine Performance mehr und verursacht keine weiteren Fehlermeldungen. Die PHP-Fehlermeldung wird gleichzeitig unterdrückt.

Dateien komplett lesen

Mit dem Öffnen der Datei in einem bestimmten Modus ist noch nichts erreicht. Sie haben nur einen "Zipfel", um den Dateizeiger anzufassen. Wenn Sie den gesamten Inhalt einlesen wollen, können Sie die Datei mit fread() auslesen:

string fread ( resource handle, int length)

Die Funktion fread() liest von der Stelle an, an die Sie den Dateizeiger gesetzt haben. Der resource handle ist der Dateizeiger, also unser "Zipfel" $handle. Die Funktion braucht als 2. Parameter die Länge der Zeichen in Bytes. Gelesen wird bis zu dem Ereignis, was als Erstes eintritt:

  • Bis zur angegebenen Länge in Bytes

  • oder bis ans Ende der Datei (End Of File = EOF).

Entfernen Sie aus der Datei tagestipp.txt bitte die HTML-Zeilenumbrüche <br>, damit wir im Folgenden auf die manuellen Zeilenumbrüche eingehen können.

// Datei öffnen
$handle = @fopen("tagestipp.txt", "r") 
    OR die('Kann Datei nicht öffnen');

// Inhalt auslesen und ausgeben
print fread ($handle, 1024);

// Datei schließen
fclose ($handle);

Wenn Sie die gesamte Datei lesen wollen, ohne zu wissen, wie groß sie ist, bestimmen Sie mit filesize() die Dateigröße und geben Sie das als 2. Parameter an:

// Datei öffnen
$handle = @fopen("tagestipp.txt", "r") 
    OR die('Kann Datei nicht öffnen');

// Inhalt auslesen
$inhalt = fread ($handle, filesize ("tagestipp.txt"));

// erst Datei schließen
fclose ($handle); 

// dann Inhalt ausgeben
print $inhalt;

Sie können wie hier gezeigt auch den Rückgabewert von fread() einer Variablen übergeben und erst einmal die Datei schließen.

Die Zeilenumbrüche sind tatsächlich vorhanden, auch wenn sie im Browser nicht zu erkennen sind. Es handelt sich um manuelle Zeilenumbrüche der Art \n, die vom Browser lediglich im Quelltext angezeigt werden. Um die manuelle Zeilenumbrüche \n automatisch in <br> umzuwandeln, wird nl2br() (New Line To Break) benutzt:

print nl2br($inhalt);

Sie können nun beliebige Zeichenkettenfunktionen auf die Variable anwenden, die den Inhalt der Datei gespeichert hat. Vielleicht soll der Firmenname immer in einer bestimmten CSS-Klasse angezeigt werden. Um es dem Redakteur leichter zu machen, automatisieren Sie die Formatierung, indem Sie jedes Auftauchen des Firmennamens mit dem entsprechenden CSS versehen:

$from = 'Firmenname GmbH';
$to = '<span class="firma">Firmenname GmbH</span>';
$inhalt = str_replace ($from, $to, $inhalt);
print nl2br($inhalt);

Was wir hier in vier Schritten gemacht haben, geht auch in nur einem Schritt:

print nl2br( str_replace (
    'Firmenname GmbH', 
    '<span class="firma">Firmenname GmbH</span>', 
    $inhalt));

Im Text der Datei wird jedes einzelne Erscheinen des Firmennamens nun automatisch mit dem span-Container versehen, ohne dass der Redakteur sich darum kümmern muss.

Ab PHP 4.3.0 können Sie auch file_get_contents() verwenden, um den Inhalt einer Datei als String zurückzugeben.

print file_get_contents('tagestipp.txt');

Textdatei zeilenweise lesen

Eine Textdatei kann ein kleiner Ersatz für eine Datenbank sein. Stellen Sie sich eine kleine Adressdatendatei vor. Sie kennen vielleicht das Format csv von MS Excel her als Trennzeichen getrenntes Dateiformat. Sie können als Trennzeichen jedes beliebige Zeichen festlegen. Wählen Sie ein Zeichen, dass gewiss nicht in Ihren Daten enthalten ist, bei Adressdaten zum Beispiel '#'. Excel verwendet in der Standardeinstellung ein Semikolon ';'. Wenn Sie tabellarische Daten unter dem Format csv speichern und Sie die Datei anschließend in einem Editor öffnen, sieht die Datei in etwa so aus:

König#Manuela#Bergstraße 17#12345#Bergen
Meier#Maria#Seestraße 23d#12333#Seehausen
Müller#Anton#Talstraße 2#23453#Hirschtal

Sie erkennen, dass Sie so auch eine Schnittstelle für den Datenaustausch zu Excel programmieren können oder zu anderen Programmen, die mit diesem Format umgehen können.

Um diese Daten verarbeiten zu können, müssen Sie zeilenweise auf die Inhalte zugreifen können. Um auf die Zeilen zugreifen zu können, wird die Funktion fgets() benutzt:

string fgets ( resource handle [, int length])

Die Funktion fgets() liest von der Stelle an, an die Sie den Dateizeiger gesetzt haben, eine Zeile aus. Der resource handle ist der Dateizeiger, also unser "Zipfel" $handle. Sie können im 2. Parameter die Länge der Zeichen in Bytes bestimmen, die ausgelesen werden soll. Ist er nicht angegeben, wird er auf 1 K bzw. 1024 Bytes gesetzt. Gelesen wird bis zu dem Ereignis, das als Erstes eintritt:

  • Entweder bis zum Zeilenumbruch, der mit im Rückgabewert enthalten ist!

  • Oder bis ans Ende der Datei (End Of File = EOF).

  • Oder bis zur angegebenen Länge in Bytes.

Ausschlaggebend ist das zuerst auftretende Ereignis. Wenn das Ende der Datei erreicht ist, kann nichts weiter ausgelesen werden. Wenn die Zeile länger ist als die im Funktionsaufruf enthaltene Länge in Bytes, wird nur die definierte Datenmenge ausgelesen.

Ändern Sie nun den Inhalt Ihrer Datei tagestipp.txt. Wir brauchen mehrere Zeilen Text, zum Beispiel:

1. Zeile
2. Zeile
3. Zeile
4. Zeile

In die eigentliche Skriptdatei schreiben Sie folgenden Code:

// Datei öffnen:
$handle = @fopen("tagestipp.txt", "r") 
    OR die('Kann Datei nicht öffnen');

// eine Zeile lesen:
$inhalt = fgets($handle);

// erst Datei schließen:
fclose($handle);

// dann Inhalt ausgeben:
print nl2br($inhalt);

Dieses Beispiel liest nur die erste Zeile der Textdatei aus! Zum Verständnis: fgets() liest im Normalfall eine Zeile aus. Der Zeilenumbruch am Ende dieser Zeile ist mit in der Zeile enthalten. Der Dateizeiger steht also nun am Ende dieser Zeile hinter dem Zeilenumbruch, also am Anfang der neuen Zeile. So ist es möglich, im nächsten Schritt die zweite Zeile auszulesen.

Um jede Zeile auszulesen, bedienen wir uns einer while-Schleife. Als Abbruchbedingung wird geprüft, ob das Ende der Datei erreicht ist. Dies prüft die Funktion feof(). Sie gibt true, also wahr, zurück, wenn das Dateiende erreicht ist. Vor dem Funktionsaufruf steht ein Ausrufezeichen, das den Wahrheitswert negiert. Der Ausdruck wird also insgesamt false, wenn das Dateiende erreicht ist. Im Klartext könnte man formulieren: Solange nicht das Ende der Datei erreicht ist, wird sie zeilenweise ausgegeben.

$handle = @fopen("tagestipp.txt", "r") 
    OR die('Kann Datei nicht öffnen');

while (!feof($handle)) {
    $inhalt = fgets($handle);
    print nl2br($inhalt);
}

fclose($handle);

Dieses Beispiel gibt den Inhalt Zeile für Zeile an den Browser aus.

Übrigens: Soll auch mit fgets() der gesamte Inhalt der Datei in einer Variablen gespeichert werden, hängen Sie jede neue Zeile an die Variable durch den Operator .= an:

$handle = @fopen("tagestipp.txt", "r") OR die('Kann Datei nicht öffnen');
while (!feof($handle)) {
$inhalt .= fgets($handle);
}
fclose($handle);

print nl2br($inhalt);

Wenn Sie auf einen Datensatz mit einer Adresse zugreifen wollen, wie wir ihn oben gesehen haben, bedienen Sie sich der Funktion explode(), die anhand eines Trennzeichens eine Zeichenkette in Elemente eines Arrays aufspaltet. Kopieren Sie nun die Liste mit den Adressdaten in eine neue Datei, die Sie unter dem Namen adressen.txt speichern. Ihre Skriptdatei öffnet die Datei und liest zeilenweise die Daten aus:

$handle = @fopen("adressen.txt", "r") 
    OR die('Kann Datei nicht öffnen');

while (!feof($handle)) {
   $inhalt = fgets($handle);
   $arrInhalt[] = explode('#', $inhalt);
}

fclose($handle);

print '<pre>';
print_r($arrInhalt);
print '</pre>';

Achten Sie in der fünften Zeile darauf, dass Sie ein Array $arrInhalt[] initiieren. Sonst würde bei jedem Schleifendurchlauf der Wert des vorherigen Durchlaufs ersetzt und es bliebe nur die letzte Zeile der ausgelesenen Textdatei in der Variablen gespeichert. Das Beispiel speichert die Datensätze aus der Textdatei in einem zweidimensionalen Array. Ein Datensatz ist jeweils ein Array mit den Adressdaten einer Person wiederum in einem Array. Geben Sie sich das Array nach der Schleife mit print_r() aus, um zu erkennen, wie das Array aufgebaut ist. Sie werden etwas in dieser Art sehen:

Array
(
    [0] => Array
        (
            [0] => König
            [1] => Manuela
            [2] => Bergstraße. 17
            [3] => 12345 Bergen

        )

    [1] => Array
        (
            [0] => Meier
            [1] => Maria
            [2] => Seestraße 23d
            [3] => 12333 Seehausen

        )

    [2] => Array
        (
            [0] => Müller
            [1] => Anton
            [2] => Talstraße 2
            [3] => 23453 Hirschtal
        )

)

Dieses Array können wir in einer Schleife als Tabelle ausgeben. Wie die Datensätze erzeugt werden, besprechen wir später.

In diesem Zusammenhang sei auch auf die Funktion file() verwiesen, die eine Datei komplett in ein Array einliest. Dabei ist jede Zeile ein Element des Arrays, die Zeilennummern werden als Schlüssel gespeichert. Der Zeilenumbruch am Zeilenende bleibt erhalten.

Dateien schreiben

Bisher haben wir die Textdateien im Editor geschrieben, um sie anschließend durch ein Skript auszulesen. Wenn unser Redakteur an seinem Tagestipp sitzt, will er natürlich nicht mit einem Editor arbeiten und die Datei vor allem nicht anschließend erst auf den FTP-Server übertragen müssen. Besser stellen wir ihm ein Browser basiertes Tool zur Verfügung, in das er seine Daten eintragen kann.

Zum Schreiben von Daten benutzen Sie fwrite(). Wir öffnen die Textdatei, schreiben Daten hinein und schließen die Datei wieder:

$handle = @fopen("tagestipp.txt", "w") 
    OR die('Kann Datei nicht öffnen');

$write = fwrite($handle, "Hallo Welt!");

fclose($handle);

Beachten Sie, dass sich der Modus im zweiten Parameter von fopen() geändert hat. Dort steht nicht mehr wie bisher "r" für read, sondern "w" für write. Wir benutzen "w" und nicht "a", weil wir die vorhandenen Daten überschreiben wollen. Der Dateizeiger wird auf den Anfang der Datei gesetzt. Während "w" alle bereits vorhandenen Daten löscht, hängt "a" die zu schreibenden Daten hinten an das Dateiende an. Wenn Sie zum Beispiel einen Zähler brauchen, der von der Laufzeit Ihres PHP-Skripts unabhängig sein muss, deshalb in einer Textdatei hinterlegt ist und bei bestimmten Aktionen erhöht wird, soll der Dateiinhalt jedes Mal überschrieben werden (Attribut "w"). Wenn aber E-Mail-Adressen in eine Datei geschrieben und dort permanent gespeichert werden sollen, müssen die neuen Einträge jeweils hinten an das Dateiende angehängt werden (Attribut "a").

Die Funktion fwrite() braucht mindestens zwei Parameter.

int fwrite ( resource handle, string string [, int length])

Der erste Parameter ist wieder unser Dateizeiger, also der Rückgabewert von fopen(), den wir in $handle gespeichert haben. Der zweite Parameter enthält die Zeichenkette, die in die Datei hineingeschrieben werden soll. Als optionalen dritten Parameter können Sie die Länge der Zeichen in Bytes angeben, die in die Datei geschrieben werden sollen. So können Sie die Größe der Textdatei begrenzen. Es werden nur so viele Zeichen geschrieben, wie die Größe im dritten Parameter erlaubt. Ist der dritte Parameter nicht angegeben, wird die komplette Zeichenkette in die Datei geschrieben. Rückgabewert ist die Anzahl der geschriebenen Bytes. Wenn das Schreiben misslingt, wird der Rückgabewert false sein.

Für unser Tagestipp-Tool brauchen wir ein Formular mit einem mehrzeiligen Texteingabefeld und einen Submit-Button. Das Formular senden Sie im Action-Attribut an ein neues Skript, dass die Daten speichert. Hier nennen wir diese Datei php1_w4_loes_03b.php. Als Wert soll in dem mehrzeiligen Textfeld der Inhalt ausgegeben werden, der in der Tagestipp-Datei bereits vorhanden ist. Öffnen Sie also zuerst die Datei, speichern ihren Inhalt in einer Variablen und geben Sie diese Variable in dem Formular aus. Speichern Sie die Datei mit dem Formular z.B. unter dem Namen php1_w4_loes_03a.php.

<?
$dateiname = 'tagestipp.txt';

// Datei öffnen
$handle = @fopen($dateiname, "r") 
    OR die('Kann Datei nicht öffnen');

// Inhalt auslesen
$inhalt = fread ($handle, filesize ($dateiname));

// erst Datei schließen
fclose ($handle); 
?>

<form action="php1_w4_loes_03b.php" method="post">
<textarea name="tagestipp"><?=$inhalt;?></textarea><br>
<input type="Submit" name="send" value="speichern">
</form>

Im Skript php1_w4_loes_03b.php wird keinerlei Ausgabe erzeugt. Das Skript verarbeitet lediglich die Formulardaten. Entfernen Sie zunächst mögliche HTML- oder PHP-Tags, konvertieren Sie Sonderzeichen und Anführungszeichen und entfernen Sie die Backslashs. Dann werden die Daten in die Textdatei hineingeschrieben. Geben Sie eigene Fehlermeldungen aus.

<?
$dateiname = 'tagestipp.txt';

if ($_POST["send"])
{
   // erst Daten sichern:
   $tagestipp = htmlentities( 
                stripslashes( 
                strip_tags($_POST["tagestipp"])), ENT_QUOTES);
   
   // dann Daten in Datei schreiben:
   $handle = @fopen($dateiname, "w") 
             OR die('Kann Datei nicht öffnen');

   if (fwrite($handle, $tagestipp))
   {
      print 'Tagestipp wurde aktualisiert';
   }
   else
   {
      print 'Tagestipp konnte nicht aktualisiert werden';
   }

   fclose($handle);
}

?>

Wenn Sie direkt kontrollieren wollen, was in der Textdatei steht, können Sie alternativ das Formularskript wieder einbinden.

Hier arbeiten wir nicht mit fwrite() OR die(), weil wir nicht nur eine Fehler-, sondern auch eine Erfolgsmeldung ausgeben wollen. Der Redakteur weiß sonst nicht, ob das Speichern gelungen ist.

Das Tagestippbeispiel haben wir nun fertig gestellt. Wie eine Ausgabe des Tagestipps auf der Webseite aussieht, die eventuell noch Firmennamen oder bestimmte Kodierungen enthält, haben wir bereits besprochen.

Datensätze in Textdateien ablegen

Als Letztes schauen wir uns noch kurz an, wie man einen Datensatz in einer Textdatei ablegen kann. Im Grunde ist das Prinzip ja klar. Wir nehmen ein Formular mit Textfeldern für die einzelnen Adressdaten. Diese Formulardaten nimmt unser Skript entgegen, entfernt wieder Tags etc. und schreibt sie in unsere Adressdatei. Für die Funktion fopen() benutzen wir nun das Attribut "a", damit die neuen Daten unten angehängt werden. Wichtig ist, dass jeder Datensatz mit einem Zeilenumbruch \n oder \n\r endet. Damit wird eine Zeile abgeschlossen. Zwischen den einzelnen Formularfeldern wird das Rautezeichen als Trennzeichen eingefügt. Wie oben bereits erwähnt, legen Sie dieses Trennzeichen selbst fest.

$dateiname = 'adressen.txt';

if ($_POST["send"])
{
   // erst Daten sichern!
   $name    = Text_sichern($_POST["name"]); 
   $vorname = Text_sichern($_POST["vorname"]);
   // usw.

   // Datensatz erzeugen:
   $adresse = $name . "#". 
              $vorname . "#". 
              $strasse . "#". 
              $plz . "#". 
              $ort . "#". 
              $tel . "#". 
              $email . "\n";
   
   // dann Daten in Datei schreiben:
   $handle = @fopen($dateiname, "a") 
       OR die('Kann Datei nicht &ouml;ffnen');

   if ($write = fwrite($handle, $adresse))
   {
      print 'Adresse wurde hinzugef&uuml;gt';
   }
   else
   {
      print 'Adresse konnte nicht hinzugef&uuml;gt werden';
   }
   
   fclose($handle);
}
?>

Bei jedem Abschicken des Formulars wird in der Textdatei eine neue Zeile angelegt, die wiederum alle Formulardaten enthält. Damit entspricht eine Zeile der Textdatei einem Datensatz. Beim Auslesen trennen Sie wie oben besprochen die Zeile einfach mithilfe der Funktion explode() am Trennzeichen und haben dann ein Array zur Verfügung, dessen einzelne Elemente jeweils die Adressdaten einer Person enthalten.

Bitte beachten Sie, dass dies eine kleine oder Notfallvariante für eine Datenbank ist. Textdateien in dieser Form sind geeignet, Schnittstellen zwischen unterschiedlichen Anwendungen zu generieren, um Daten zu transferieren. Für eine Adressverwaltung wären sie aber völlig ungeeignet. Sie müssen Benutzerzugriffe steuern, die Veränderung eines einzelnen Datensatzes wäre speicherintensiv und unkomfortabel, da Sie die gesamte Textdatei neu schreiben müssten.

Dateien verschieben

Um sinnvoll mit Dateien arbeiten zu können, sind Funktionen, die ein Dateimanager bietet, notwendig. Die Dateien an sich können mit copy() kopiert, mit rename() umbenannt und mit unlink() gelöscht werden.

Zum Verschieben einer Datei wird diese zuerst an den gewünschten Ort kopiert und dann, wenn das Kopieren erfolgreich war, die Ursprungsdatei gelöscht. Diese Vorgehensweise stellt sicher, dass Dateien nicht verloren gehen, falls beim Verschieben etwas schief läuft.

$cop = copy("datei.txt", "backups/datei.txt.bak"); 
if ($cop) unlink("datei.txt");

Die Datei wird nur gelöscht, wenn der Kopiervorgang erfolgreich war. Die Funktion copy() gibt wahr zurück, wenn erfolgreich kopiert wurde. Der Rückgabewert wird in $cop gespeichert und als Bedingung vor dem Löschen der Ursprungsdatei abgefragt. Ist er true, wird die Ursprungsdatei gelöscht.

Die Funktion rename() benennt Dateien um. Sie können relative und absolute Pfadangaben machen. Mit rename() können Sie Dateien auch direkt verschieben. Wenn der Dateiname gleich bleibt, aber Quell- und Zielpfad nicht übereinstimmen, wird die Datei ohne Sicherungskopie in das angegebene Verzeichnis geschoben. Der Rückgabewert der Funktion enthält die Information darüber, ob das Umbenennen bzw. Verschieben erfolgreich ausgeführt werden konnte.

$quelle = "datei.txt";
$ziel = "adressen.txt";

if (!@rename ($quelle, $ziel)) {
   print "Die Umbenennung von $quelle zu $ziel";
   print " ist gescheitert.";
}
else {
   print $quelle . " wurde erfolgreich in " . $ziel . " umbenannt.";
}

Die if-Bedingung in diesem Beispiel enthält die gesamte Funktion rename(), deren Negation (!) und die Unterdrückung der Fehlermeldung des Parsers (@): Wenn die Umbenennung nicht geklappt hat, gehe in die if-Bedingung, sonst in die else-Bedingung, gebe aber nie eine PHP-Fehlermeldung aus.

Das folgende Beispiel wird die Datei verschieben, sofern die Verzeichnisse existieren und PHP Schreibrechte dort hat:

$quelle = "datei.txt";
$ziel = "backups/datei.txt.bak";

if (!@rename ($quelle, $ziel)) {
   print "Die Umbenennung von $quelle zu $ziel";
   print " ist gescheitert.";
}
else {
   print $quelle . " wurde erfolgreich in ";
   print $ziel . " umbenannt.";
}

Verzeichnisse

Als Letztes beschäftigen wir uns kurz mit Verzeichnisfunktionen. Um sich innerhalb des Dateisystems frei bewegen zu können, sind Verzeichnisfunktionen notwendig, mit denen Verzeichnisse geöffnet, gelesen, angelegt oder leere Verzeichnisse gelöscht werden können.

Ein ganzes Verzeichnis nach einer bestimmten Datei zu durchsuchen, ohne die möglichen Dateinamen zu kennen, ermöglicht folgendes Beispiel:

$ordner = 'c:/windows';
$verz_handle = opendir($ordner);
while ($file = readdir ($verz_handle)) 
{
   print $file . "<br>";
   if ($file == "Gesucht.txt") 
   {
      print "Datei \"Gesucht.txt\" gefunden.";
      rename($file, "gefunden.txt");
   }
}
closedir($verz_handle);

Mit opendir() wird ein Verzeichnis oder Ordner geöffnet. Rückgabewert ist wie bei den Dateien ein Handle, mit dem das Verzeichnis angefasst werden kann. Die Funktion readdir() liest das Verzeichnis aus und gibt die Dateinamen zurück. Die while-Schleife liest also so lange Dateinamen aus dem Verzeichnis wie Dateien vorhanden sind. Dabei werden auch mögliche Unterordner als Name zurückgegeben.

Die Kurzschreibweise für die while-Schleife ist etwas gewöhnungsbedürftig. Auch hier hilft wieder die Übersetzung in eine normale Sprache: Solange der Ausdruck $file = readdir ($verz_handle) wahr ist, gebe $file aus. Wenn in dem Verzeichnis nichts mehr auszulesen ist, ist auch der Ausdruck falsch, da der Rückgabewert der Funktion readdir() false ist, und die while-Schleife bricht ab.

Die eingeschachtelte if-Schleife sucht nach einer bestimmten Datei innerhalb des Verzeichnisses, nämlich der Textdatei Gesucht.txt. Wird diese gefunden, wird eine entsprechende Meldung an den Bildschirm ausgegeben und die Datei in gefunden.txt umbenannt. Auch hier darf wieder nicht vergessen werden, das Verzeichnis mit closedir() zu schließen.

Das Beispiel funktioniert nur, wenn die Dateien im Dateisystem des Webservers dem PHP-Skript zur Verfügung stehen. Sie können es nicht auf entfernte Dateien anwenden.

Wichtig ist, dass auch das aktuelle Verzeichnis als Punkt '.' und das übergeordnete Verzeichnis als Punkt Punkt '..' in dieser Liste vorhanden sind. Schauen Sie sich die Ausgabe des oben beschriebenen Skriptstücks einfach an und wählen Sie dabei für $ordner ein Verzeichnis, das auch Unterordner enthält. Eine Ausgabe sieht dann wie folgt aus:

.
..
SYSTEM
COMMAND
WIN.INI
INF
TELEPHON.INI
HWINFO.EXE
NETDET.INI
PIDGEN.DLL
SMARTDRV.EXE
SYSTEM32
HIMEM.SYS
RAMDRIVE.SYS

Sie sehen, dass Verzeichnisse und Dateien durcheinander stehen. Es ist nun Aufgabe des Skripts, die Verzeichnisse '.' und '..' auszusortieren und jeden ausgelesenen Namen darauf zu überprüfen, ob es sich um eine Datei oder einen Unterordner handelt, je nachdem, welche Aufgabe das Programm erfüllen soll. Die Funktionen is_dir(), die prüft, ob es sich um ein Verzeichnis handelt, und is_file(), die prüft, ob die übergebene Zeichenkette eine reguläre Datei ist, werden Ihnen dabei nützlich sein.

PHP kennt etliche Funktionen zur Manipulation von Dateien und Verzeichnissen, die wir hier nicht besprochen haben. Sie können z.B. ganze Verzeichnisse mit mkdir() erzeugen. Alle Arbeiten, die ein Dateimanager erledigt, können Sie mit PHP steuern. Anwendungen im Dateisystem können beliebig komplex werden. Sie haben hier nur einen kleinen Einblick in die Möglichkeiten von PHP im Umgang mit Dateien kennen gelernt.

Als Mitglied können Sie diesen Beitrag weiterlesen!

Werden Sie Mitglied und testen Sie akademie.de 14 Tage lang kostenlos!

In den ersten 14 Tagen haben Sie Zugriff auf alle Inhalte auf akademie.de, außer Downloads. Sie können in dieser Zeit ohne Angabe von Gründen stornieren. Eine E-Mail an service@akademie.de genügt. Nur wenn Sie Mitglied bleiben, wird der Mitgliedsbeitrag nach Ende der 14tägigen Stornofrist abgebucht.

Ich bin bereits Mitglied
Jetzt Mitglied werden und akademie.de 14 Tage kostenlos testen
Ich entscheide mich für folgende Zahlungsweise:
14 Tage Stornorecht:
Ich kann meine Mitgliedschaft in den ersten 14 Tagen jederzeit formlos stornieren, z.B. per E-Mail an service@akademie.de.

Inhalt

Downloads zu diesem Beitrag

Newsletter abonnieren