Werbung einblenden Werbung ausblenden


Home / Tutorials / PHP Handbuch / Der erste PHP Skript

Flatfile - Datenbanken
Eine Flatfile-Datenbank auslesen
In eine Datei schreiben
Datei öffnen zum Anfügen von Daten
Ändern und Löschen von Daten in einer Flatfile-Datenbank


Flatfile - Datenbanken

Flatfile-Datenbanken sind die einfachste Möglichkeit, Daten zu speichern. Sie bestehen aus nichts anderem als strukturiertem Text.
Eine Flatfile-Datenbank sieht zum Beispiel so aus:

Name:Andrés Ehmann:::Beruf:Diplom Volkswirt, Magister Artium:::Telefon:030/47301386
Name:Ernst Müller:::Beruf:Diplom Kaufmann:::Telefon:040/4564567
Name:Werner Maier:::Beruf:Diplom Physiker:::Telefon:089/3454443

Der Inhalt ist selbsterklärend. Um das nachfolgende Beispiel nachzuvollziehen, sollten diese drei Zeilen unter dem Namen flatfile.txt in dem Ordner abgespeichert werden, in dem sich auch, das gleich folgende Programm befindet, dass die Daten ausliest. Diese Flatfile-Datenbank kann dann mit diesem kleinen Skript ausgelesen werden.

Eine Flatfile-Datenbank auslesen

<?
$flatfile=file("flatfile.txt");
foreach ($flatfile as $zeile)
{

$einzelne_Elemente_jeder_Zeile=split(":::",$zeile);

foreach ($einzelne_Elemente_jeder_Zeile as $einzelteile)
{
print "$einzelteile <br>";
}
print "-----------------------------------------------------<br>";
}
?>

Als Ergebnis erhält man dann, so denn die Datei flatfile.txt tatsächlich eingerichtet wurde

Name:Andrés Ehmann
Beruf:Diplom Volkswirt, Magister Artium
Telefon:030/47301386
-----------------------------------------------------
Name:Ernst Müller
Beruf:Diplom Kaufmann
Telefon:040/4564567
-----------------------------------------------------
Name:Werner Maier
Beruf:Diplom Physiker
Telefon:089/3454443
-----------------------------------------------------

Der Befehl split, als Alternative zu explode oder einer regular expression, wurde bereits unter Funktionen zum Bearbeiten von Zeichenketten beschrieben. Interessant ist eigentlich nur noch diese Zeile.
$flatfile=file("flatfile.txt");

Die Funktion file hat folgende Wirkung. Sie schnappt sich die komplette Datei, die ihr als Parameter übergeben wird und speichert sie in einen Array, in diesem Falle also in $flatfile. Hierbei wird jede Zeile der Datei ein Element des Arrays.

Wir erhalten also folgendes:


$flatfile[0] => ist dann: Name:Andrés Ehmann:::Beruf:Diplom Volkswirt, Magister Artium:::Telefon:030/47301386
$flatfile[1] => ist dann: Name:Ernst Müller:::Beruf:Diplom Kaufmann:::Telefon:040/4564567
$flatfile[2] => ist dann: Name:Werner Maier:::Beruf:Diplom Physiker:::Telefon:089/3454443

Hat man die Datei, lässt sie sich wie ein Array auslesen, zur foreach-Schleife siehe Schleifen. Eine alternative Möglichkeit einen Flatfile auszulesen, sähe so aus.

<?
$datei_handle = fopen("flatfile.txt", "r");
$flatfile = fread($datei_handle, filesize("flatfile.txt"));
fclose ($datei_handle);
$inhalt_in_Zeilen=explode("\n",$flatfile);
foreach($inhalt_in_Zeilen as $wert)
{
$einzelteile=preg_split("/:::/",$wert);
foreach ($einzelteile as $einzelner_wert)
{
print "$einzelner_wert <br>";
}
}
?>

Das Ergebnis ist mit dem oben Abgebildeten völlig identisch. Wie unschwer zu erkennen, ist aber die zuletzt dargestellte Methode umständlicher. Betrachten wir die ersten vier Zeilen genauer.
(1) $datei_handle = fopen("flatfile.txt", "r");
(2) $flatfile = fread($datei_handle, filesize("flatfile.txt"));
(3) fclose ($datei_handle);
(4) $inhalt_in_Zeilen=explode("\n",$flatfile);

(1) Mit der Funktion fopen öffnen wir eine Datei und zwar zum Lesen (r wie read). Diese geöffnete Datei weisen wir einem file-handle zu. Alle Operationen, wie lesen, schreiben oder änfügen (siehe unten) gehen auf den file-handle und nicht direkt auf die Datei auf die der file-handle zeigt. (2) Mit fread lesen wir die Datei aus. Die Funktion fread hat zwei Parameter, den oben generierten file-handle, und die Anzahl an Bytes, die ausgelesen werden sollen. Wir wollen die gesamte Datei auslesen, wissen aber nicht, wie lang diese eigentlich ist. Das ermitteln wir mit der Funktion filesize. (3) Da wir den Inhalt der Datei nun in der Skalarvariablen $flatfile haben, können wir die Verbindung zu file-handle auch wieder schliessen. (4) Wir splitten am newline Zeichen \n. Das newline Zeichen entseht, wenn wir die Return-Taste drücken, was wir bei der Eingabe der Zeilen getan haben, sonst stünden sie nich so brav untereinander. Wir erhalten übergeben dann jedes Element dem Array $inhalt_der_Zeilen. Der Array ist dann identisch wie oben und lässt sich somit auch identisch auswerten. Explode, split, preg_split sind in diesem Zusammenhang austauschbar. Die Verwendung aller drei Funktionen hat lediglich didaktische Gründe.
Es ist somit klar, dass man die Funktion file verwenden sollte, wenn man lediglich einen Flatfile auslesen will. Die Funktion fread sollte man verwenden, wenn man lediglich Teile einer Datei auslesen will, oder eine Datei, die als Binary vorliegt, wie etwa ein Bild.
Will man ein Bild auslesen, funktioniert das nicht

<?
$bild=file("kirsche.jpg");
foreach ($bild as $schrott)
{
print $schrott;
}
?>

Sehr wohl aber das:

<?
$datei_handle = fopen("kirsche.jpg", "rb");
$bild = fread($datei_handle, filesize("kirsche.jpg"));
fclose ($datei_handle);
print $bild;
?>

Die Funktion file erlaubt das Umstellen in den binary mode nicht. Nur im binary mode werden Dateien 1 zu 1 übertragen, völlig unabhängig davon, ob das Betriebssystem damit was anfangen kann oder nicht. Im Ascii Mode, wird versucht, die Datei systemadäquat zu interpretieren, was bei Bilder dann zum Absturz führt. Bei der Verwendung der Funktion fopen kann man angeben, ob sie im binary-Mode, rb, oder im Ascii-Mode geöffnet werden soll. Das Bild das in diesem Beispiel verwendet wurde, kann hier via copy and paste in den passenden Ordner gelegt werden.
Das Ergebnis der Funktion split (explode oder preg_split) einer Liste übergeben:

Der Vollständigkeitshalber sei noch gesagt, dass man das Ergebnis der Funktionen split (explode, preg_split) auch einer Liste übergeben kann.

<?
$flatfile=file("flatfile.txt");

foreach ($flatfile as $zeile)
{

list ($name, $beruf,$telefon)=explode(":::",$zeile);
print "$name <br>";
print "$beruf <br>";
print "$telefon <br>";

print "-----------------------------------------------------<br>";
}
?>

Der exotische Fall: Man kennt die genaue Länge der Teilbereiche einer Zeile
Kennt man die Anzahl an Bytes, die jede Informationseinheit einer Zeile ausmacht, dann kann man auch mit fgets eine Datei auslesen.
Andres Ehmann Dipl. Volkwirt 03047301386 -
Hans Maier Dipl. Ing. Elektr. 040456456666 -
Werner Müller Baufachverkäufer 0894457868 -

Der Block mit dem Namen, mit der Berufsbezeichnung und mit der Telefonnummer haben jeweis 20 Zeichen. Es wurde mit Leerzeichen aufgefüllt. Das folgende Beispiel setzt voraus, dass der Flatfile oben unter dem Namen test.txt in dem Ordner abgespeichert wird, wo sich auch der PHP Skript befindet, der ihn ausliest. (Man kann ihn natürlich auch sonstwo abspeichern, aber dann muss der physikalische Pfad, relativ oder absolut, angegeben werden.) Die Zeilen wurde, durch Auffüllen mit Leerzeichen so geschrieben, dass der Name aus Leerzeichen besteht und genau 13 Bytes (was dann wiederum 13 Zeichen sind, da jedes Zeichen ein Byte ist) lang ist. In solch einem Fall, kann man eine Flatfile-Datenbank auch mit fgets auslesen.

<?
$datei_handle=fopen("test.txt",r);
while(!feof($datei_handle))
{
$name=fgets($datei_handle,20);
print $name;
print "<font color=red> Position des Zeigers ".ftell($datei_handle)."</font>";
print "<br>";
}
fclose($datei_handle);
?>

Das Ergebnis sieht dann so aus:

Andres Ehmann Position des Zeigers 19
Dipl. Volkwirt Position des Zeigers 38
03047301386 Position des Zeigers 57
- Position des Zeigers 70
Hans Maier Position des Zeigers 89
Dipl. Ing. Elektr. Position des Zeigers 108
040456456666 Position des Zeigers 127
- Position des Zeigers 136
Werner Müller Position des Zeigers 155
Baufachverkäufer Position des Zeigers 174
0894457868 Position des Zeigers 193
- Position des Zeigers 198

Was ist passiert ? Wir haben einen file-handle auf die Datei test.txt generiert. Diesen file-handle haben wir mit einer while-Schleife ausgelesen. Die while-Schleife ist solange gelaufen, wie die Funktion feof nicht den Wert true zurück gegeben hat (bis zum Ende gibt sie immer false zurück, aber das haben wir mit dem ! negiert). Wir haben dann jeweils in 20 Bytes Schritten die Zeichenkette ausgelesen und den Rückgabewert in der Variablen $name gespeichert. Anschliessend haben wir uns die aktuelle Position des Zeigers ausdrucken lassen. Er ist 19 weil wir ja bei 0 gestartet sind und 20 Zeichen weitergelaufen sind. Dann haben wir uns den nächsten Informationsblock, die Berufsbezeichnung, ausdrucken lassen. Wieder wird bei 0 gestartet und weitergezählt, sodass wir bei 38 landen. So lesen wir die komplette Zeile aus. Am Schluss bleibt ein Block übrig, der weniger als 20 Zeichen hat. Der Zeiger bricht aber auf jeden Fall bei dem newline Zeichen ab, was das Ende der Zeile markiert. Wir erhalten also noch einen Restblock von 3 Bytes (70 - 57). In der nächsten Zeile beginnt das Spiel von vorne. Für die meisten praktischen Anwendungen, gibt es zu diesem Verfahren, wie oben beschrieben, zahlreiche, wesentlich einfacherer Alternativen.
HTML und PHP Tags entfernen mit getss:
Etwas ähnliches wie getss leistet auch die Funktion strip_tap, siehe Funktionen zum Bearbeiten von Zeichenketten Um das unten stehende Skript laufen zu lassen, muss eine Datei htmlwech.htm mit unten stehendem Inhalt in dem Ordner eingerichtet werden, in dem sich auch der PHP Skript befindet.
<html><head><title>test</title></head><body>hallo <img src=kirsche.jpg></body></html>

Will man jetzt alle HTML Tags entfernen, kann man das mit diesem Skript tun.

<?
$html_seite=fopen("htmlwech.htm",r);
while(!feof($html_seite))
{
$gereinigt=fgetss($html_seite,filesize("htmlwech.htm"));
print $gereinigt;
}
fclose($html_seite);
?>

Das Ergebniss ist dann ein simples testhallo, da ja alle HTML Tags eliminiert wurden. Die Funktion fgetss bietet noch optional, ähnlich wie strip_tag, die Möglichkeit an bestimmte HTML Tags stehen zu lassen. In diesem konkreten Fall würde es sich zum Beispiel anbieten, den img Tag stehen zu lassen. Das sieht dann so aus.

<?
$html_seite=fopen("htmlwech.htm",r);
while(!feof($html_seite))
{
$gereinigt=fgetss($html_seite,filesize("htmlwech.htm"),'<img>');
print $gereinigt;
}
fclose($html_seite);
?>

Das Ergebnis als HTML Quelltext sieht dann so aus

testhallo <img src=kirsche.jpg>

Wie unschwer zu erkennen, wurde der img Tag nicht eliminiert.
CSV (comma separates files) auslesen
Oben wurde als delimiter, also als Zeichen, dass innerhalb einer Zeile einen Informationsblock vom anderen trennt, dreimal der Doppelpunkt gewählt (:::). Obwohl es eigentlich ziemlich egal ist, gibt es zahlreiche Anwendungen, die das Komma als delimiter wählen. Bei den meisten Internetanwendungen, die Eingaben des Users speichern, ist das Komma eher ungeeignet, weil der User dieses Zeichen selber eingeben kann. Wie dem auch sei, die Funktion fgetcsv liest, ähnlich wie die Funktion fgets, eine Datei aus, spaltet aber jede Zeile noch an einem delimiter und übergibt die Werte in einen Array. Obwohl also jeder x-beliebige Werst als delimiter übergeben werden kann, heisst die funktion fgetcsv. Um das Beispiel laufen zu lassen, muss man folgende Datei in dem Ordner, in dem auch der PHP Skript liegt unter dem Namen csv.txt abspeichern.
Andres Ehmann, Diplom Volkswirt/Magister der romanischen Philologie, 030-47301386
Heiner Geissler, Rechtsanwalt, 067-345633333
Helmut Kohl, Historiker, 089-3453454444

Auslesen könnte man die Datei mit folgendem Skript.

<?
$file_handle=fopen("csv.txt",r);
while(!feof($file_handle))
{
$einzelteile=fgetcsv($file_handle,filesize("csv.txt"));

foreach($einzelteile as $block)
{
print "$block <br>";
}
}
fclose($file_handle);
?>

Wie deutlich zu sehen, haben wir nicht angegeben, an welchem Zeichen, jede Zeile aufgehackt werden soll. Das müssen wir auch nicht unbedingt, denn der Default-Wert ist das Komma. Man kann aber auch an einem anderen Zeichen aufspalten, wie das folgende Beispiel zeigt. Um den Skript laufen zu lassen, muss man vorher eine Datei sonstiges.txt mit folgendem Inhalt abspeichern.
Andres Ehmann^Diplom Volkswirt/Magister der romanischen Philologie^030-47301386
Heiner Geissler^Rechtsanwalt^067-345633333
Helmut Kohl^Historiker^089-3453454444

Diese Datei könnte man mit diesem Skript auslesen.

<?
$file_handle=fopen("sonstiges.txt",r);
while(!feof($file_handle))
{
$einzelteile=fgetcsv($file_handle,filesize("sonstiges.txt"),"^");

foreach($einzelteile as $block)
{
print "$block<br>";
}
}
?>

Anzumerken ist, dass die Funktion fgetcsv mit einer Kombination von Zeichen als delimiter, z.B. ^^^ oder &&& nicht klarzukommen scheint. Alternativ hätte man den Skript oben auch so schreiben können.

<?
$file_handle=fopen("sonstiges.txt",r);
while( $einzelteile=fgetcsv($file_handle,filesize("sonstiges.txt"),"^"))
{
foreach($einzelteile as $block)
{
print "$block<br>";
}
}
?>

Man kann sich darüber wundern, dass so etwas funktioniert, aber die Begründung ist einfach. Jeder von 0 oder undef verschiedene Wert ist true. Also solange die fgetcsv Funktion irgendwas zurückgibt, was sie bis zum Ende ja tut, ist das für die while-Schleife true.

In eine Datei schreiben

Lesen ist ja ganz nett, aber bevor irgend jemand was lesen kann, muss irgend jemand was geschrieben haben. Daten einlesen ist einfacher als Daten rausholen. Es funktionniert mit diesem Skript.

<?
$string="
Im Windesweben,
war deine Frage nur Träumerei,
nur Lächeln war, was du gegeben,
in dunkler Nacht, ein Glanz entfacht,
nun ist es Herbst,
nun muss ich wohl um dein Aug und Haar,
alle Tage in Sehnen leben";
$datei_handle=fopen("stefan_george.txt",w);
fwrite ($datei_handle,$string);
fclose($datei_handle);
print "Wie sagte schon Mozart ? Das Weib ist das schönste Ding auf der Welt,".
"Sonate in F Dur für Geigen";
?>

Der Skript führt dazu, dass im gleichen Ordner, in dem der PHP Skript liegt, eine Datei mit dem Namen stefan_george.txt eingerichtet wird, die auch tatsächlich ein Gedicht dieses Dichters enthält. Wie es funktionniert, ist schnell erklärt. Wir öffnen die Datei zum schreiben, man achte auf das w wie write. Anschliessend beschreiben wir die Datei mit der Funktion fwrite. Schreiben, also write ist hier folgendermaßen zu verstehen. Ist die Datein noch nicht da, wird sie eingerichtet. Hat die Datei schon Inhalte, werden diese von den neuen Inhalten überschrieben. Das heisst, die alten Inhalte sind dann weg. Das heisst im Klartext, für Gästebücher ist die Option w wie write ausgesprochen schlecht, weil so ein Gästebuch immer nur einen Beitrag hätte.

Datei öffnen zum Anfügen von Daten

Damit wir in unserer Datenbank einen umfassenden Überblick über die Lyrik Stefan Georges erhalten, fügen wir jetzt zu dem ersten Gedicht noch ein weiteres hinzu.

<?
$string="
Sage mir auf welchem Pfade,
heute sie vorüberschreite,
dass ich aus der reichsten Lade,
zarte Seidenweben hole,
Rosen pflücke und Violen,
dass ich meine Wange reiche,
Schemmel unter ihrer Sohle";
$datei_handle=fopen("stefan_george.txt",a);
fwrite($datei_handle,$string);
fclose($datei_handle);
print "Es ist vollbracht";
?>

Nachdem beide Skripte ausgeführt wurden, sieht die Datei stefan_george.txt so aus.

Im Windesweben, war deine Frage nur Träumerei,
nur Lächeln war, was du gegeben,
in dunkler Nacht, ein Glanz entfacht,
nun ist es Herbst,
nun muss ich wohl um dein Aug und Haar,
alle Tage in Sehnen leben
Sage mir auf welchem Pfade,
heute sie vorüberschreite,
dass ich aus der reichsten Lade,
zarte Seidenweben hole,
Rosen pflücke und Violen,
dass ich meine Wange reiche,
Schemmel unter ihrer Sohle

Ändern und Löschen von Daten in einer Flatfile-Datenbank

Für kleine Datenmengen, etwa 1000 Zeilen ist eine Flatfile-Datenbank ausreichend. Zumindest dann, wenn keine komplexen Suchalgorithmen, simultanes Löschen/Ändern von Datensätzen etc. benötigt werden. Meistens will man aber zumindest die Möglichkeit haben, einzelne Datensätze zu ändern oder zu löschen, beispielsweise bei Gästebüchern, wenn einzelne Beiträge "daneben" sind. Das Problem ist, dass man einzelne Datensätze nicht löschen kann. Man kann nur den kompletten Flatfile auslesen, die Zeile, die man verändern oder löschen will bearbeiten und anschliessend den gesamten Flatfile zurückschreiben. Bedingung hierfür ist, dass jeder Datensatz eindeutig charakterisiert ist, also so etwas ähnliches wie einen "primary key" hat, also einen Spaltenwert, der ihn eindeutig identifiziert. Nehmen wir an, wir haben einen Flatfile dieser Art.

Andres Ehmann, Diplom Volkswirt, Berlin, Hallandstrasse 2,1
Heiner Müller, Dichter, Berlin, Brechtgasse 23,2
Ottilie Wagenbrecht, Dipl.Kauffrau, Hamburg,Goldgasse 12,3
Felipe Gonzale, Licenciado en letras, Madrid, Avenida de las Americas 55,4

Und nehmen wir an, dieser Flatfile ist unter dem Namen adressen.txt in dem Ordner abgespeichert, in dem auch der PHP-Skript liegt. Wie deutlich zu sehen, hat jeder Datensatz am Schluss eine Nummer, die ihn eindeutig identifiziert. Eine solche Nummer könnten wir ohne weiteres bei einer online Anwendung für jeden Datensatz kreieren. Wir hätten dann die Möglichkeit, die Zeile mit der Nummer 3 mit folgendem Skript zu ändern. Für ein komplexeres Beispiel siehe Telefondatenbank.

<?
$zu_aendernder_array=file("adressen.txt");
$geaenderter=array();
foreach($zu_aendernder_array as $zeile)
{
list ($name,$Beruf,$stadt,$strasse,$ident)=explode(",",$zeile);
chop($ident);
if ($ident != 3)
{
array_push($geaenderter,"$name,$Beruf,$stadt,$strasse,$ident");
}
}

$datei_handle=fopen("adressen.txt",w);
$fertisch=implode("",$geaenderter);
fwrite($datei_handle,$fertisch);
fclose($datei_handle);
print "Datensatz Nr. 3 wurde gelöscht";
?>

vorhergehendes Kapitel