Tom: Textfile sicher sperren bei gleichzeitigem Zugriff?

Beitrag lesen

Hello,

Ich lese die Daten aus einem Textfile ein, mutiere eine oder mehrere Zeilen und schreibe die mutierten Daten wieder zurück. In letzter Zeit ist zweimal das Problem aufgetreten, dass die Daten plötzlich nur noch unvollständig im Textfile vorhanden waren. Meine Vermutung: Wenn zwei oder mehr User gleichzeitig darauf zugreifen, kommt da was in Unordung.

Ja, da mal Dir mal ein Bild, was Du denn da tust...
(Phasenzeitdiagramm)

Mein heutiges Script sieht so aus:

$statistics =  file("$filename");

Hier wurde die Datei ohne Rücksicht auf Sperren eingelesen. Das bedeutet, dass während dieses Lesevorganges ggf. jemand anders die Datei beschreiben hat.

....
 (Hier Daten in Array mutieren/aufbereiten)

$statfile = fopen ("$filename","w+");

Hier wurde die Datei einfach zum Schreiben geöffnet und damit zerstört, unabhängig davon, ob gerade jemand anders liest.

flock($statfile, LOCK_EX);

Hier wurde versucht, in die Locktabelle einen Lock einzutragen und solange zu warten (da LOCK_NB nicht addiert wurde) bis der Lock durchgeführt werden konnte.

for($b=0;$b<=$usermenge-1;$b++)
   {
   fputs ($statfile,"$fragenstat[$b]$nl");
   }

Hier wird nun die Datei geschrieben.

flock($statfile,LOCK_UN);

...und unnötigerweise wieder freigegeben,

fclose($statfile);

denn die Freigabe erfolgt automatisch beim fclose().
Wenn es also nicht einen besonderen Grund dafür gibt, Dateihandles länger zu behalten, dann kann man sich das entsperren sparen.

Die Dateisperre findet mit der Funktion flock() in PHP und auch in C nur "advisory" statt, also absolut parallel zum fopen(), fread(), fwrite()... Die bekommen nichts von der Sperre mit. Die Sicherheit muss Deine Applikation leisten.

Wenn man also dieselbe Datei sperren will, die man lesen und beschreiben will, dann kann man nur non destructive open benutzen. Entweder legt man also vorher alle Dateien an, die man benutzen will und öffnet sie mit fopen(...,"r+") oder man benutzt fopen(...,"a+) und rewind() oder fseek().

Da man die Datei nicht löscht, bevor sie nei geschreiben wird, empfihlt es sich, den ggf. überstehenden Rest nach dem Neuschreiben mit ftruncate() wieder abzuschneiden.

Also öffen mit fopen(...,"a+");
Sperren mit flock($fh, LOCK_EX);
Zurückspulen mit fseek($fh,0,SEEK_SET);
Lesen mit fread();

Stream -> Satzarray
Bearbeitungen einfügen, anhängen etc...
Satzarray -> Stream

$len = strlen($stream);

zurückspulen mit fseek(), da der Dateizaieger vom Lesen noch am Ende steht.
Schreiben mit fwrite($fh,$data,$len)
Trimmen mit ftruncate($fh, $len);
Und schnell wieder schließen und damit freigeben mit fclose($fh);

Wenn man nun diese Dateien auch gleichzeitig durch das Programm anlegen und löschen lässt, kann jeder der Befehle "auf die Schnauze fallen", obwohl die Datei gesperrt war. Es ist nämlich leider möglich, eine gesperrte Datei zu löschen.

Es sollte also tunlichst keine andere Applikation auf die Dateien (schreibend, löschend) zugreifen, als dafür vorgesehen ist.

Liebe Grüße aus http://www.braunschweig.de

Tom

--
Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen