Welche Funktionen für Speichern/Auslesen in Text-Datei ?
Gustav Gans
- php
Moin!
Soweit ich weiß, kann man Daten bzw. sowas wie Datensätze ja auch ohne einer MYSQL-Datenbank speichern, auslesen, ändern oder löschen, in dem man statt einer Datenbank eine txt-Datei verwendet.
Könnt Ihr mir bitte sagen, mit welchen php-Funktionen ich mich da beschäftigen muß, damit ich oben Beschriebenes verwirklichen kann?!
Oder viellcht kennt wer einen Link zu einer Seite, die sich mit dem Thema beschäftigt.
Danke im Voraus!
Gustav Gans
Hi Gustav,
Könnt Ihr mir bitte sagen, mit welchen php-Funktionen ich mich da beschäftigen muß, damit ich oben Beschriebenes verwirklichen kann?!
dich dürfte das gesamte Kapitel Filesystem Functions interessieren. Außerdem kann der Artikel Sperren von Dateien von Christian Seiler sicher nicht schaden.
Gruß,
Andreas.
Hi Andreas!
dich dürfte das gesamte Kapitel Filesystem Functions interessieren. Außerdem kann der Artikel Sperren von Dateien von Christian Seiler sicher nicht schaden.
Vielen Dank fürs schnelle Antworten! Und welche dieser 78 Funktionen sind jetzt die elementaren zum Schreiben von Daten und zum Auslesen von Daten in/aus einer txt-Datei, also jene 2 Funktionen, mit denen ich anfangen möchte? :-)
Gustav Gans
Hi Gustav,
Und welche dieser 78 Funktionen
hehe - hast du nachgezählt? ;-)
sind jetzt die elementaren zum Schreiben von Daten und zum Auslesen von Daten in/aus einer txt-Datei, also jene 2 Funktionen, mit denen ich anfangen möchte? :-)
Am einfachsten sind sicherlich file_get_contents() und file_put_contents(), die jeweils einen kompletten String aus der Datei auslesen bzw. in die Datei schreiben und sich um das Öffnen, ggf. Sperren und Schließen der Datei selbst kümmern.
Gruß,
Andreas.
Hello,
Am einfachsten sind sicherlich file_get_contents() und file_put_contents(), die jeweils einen kompletten String aus der Datei auslesen bzw. in die Datei schreiben und sich um das Öffnen, ggf. Sperren und Schließen der Datei selbst kümmern.
Die kümmern sich keinesfalls um das _erforderliche_ Sperren der Dateien!
Da es namensbasierte Funktionen sind, können sie kein Handle weitergeben.
Sperren werden aber an die Handles gebunden
Die hier erforderliche Sperre kann also nicht vom Lesevorgang an den Schreibvorgang weitergereicht werden. Um daten zu verändern, muss aber ein gebundener Vorgang (atomarisiert) aus Lesen und Schreiben mit einer gemeinsamen exclusiven Sperre belegt werden.
Ich empfehle Dir daher auch nochmal den Artikel von Christian. :-))
http://aktuell.de.selfhtml.org/artikel/programmiertechnik/dateisperren/index.htm
Außerdem weiß ich nicht, ob die aktuelle Version von file_get_contents()
http://de2.php.net/manual/en/function.file-get-contents.php
sich überhaupt um Sperren kümmert.
Vielleicht habe ich nachher mal Zeit, nachzuschauen.
Ein harzliches Glückauf
Tom vom Berg
Hello,
Vielleicht habe ich nachher mal Zeit, nachzuschauen.
ab Zeile 549 in php-5.2.5\ext\standard\file.c
stream = php_stream_open_wrapper_ex(filename, "rb",
(use_include_path ? USE_PATH : 0) | ENFORCE_SAFE_MODE | REPORT_ERRORS,
NULL, context);
if (!stream) {
RETURN_FALSE;
}
if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", offset);
php_stream_close(stream);
RETURN_FALSE;
}
Wenn nun php_stream_open_wrapper_ex() die Datei exclusiv öffnet (worauf der name schließen lässt), dann haben wir zum LESEN tatsächlich eine exclusive Sperre, was hier aber unsinnig wäre, weil die ja nicht weitergereicht werden kann.
Das muss man aber erst nachverfolgen, dazu habe ich jetzt keine Zeit mehr :-(
Tschüss bis später.
Ein harzliches Glückauf
Tom vom Berg
echo $begrüßung;
Soweit ich weiß, kann man Daten bzw. sowas wie Datensätze ja auch ohne einer MYSQL-Datenbank speichern, auslesen, ändern oder löschen, in dem man statt einer Datenbank eine txt-Datei verwendet.
Könnt Ihr mir bitte sagen, mit welchen php-Funktionen ich mich da beschäftigen muß, damit ich oben Beschriebenes verwirklichen kann?!
Du möchtest Text-Dateien als Datenbankersatz verwenden? Das kann man nur bis zu recht geringen Größen guten Gewissens empfehlen. Bedenke, dass sämtliche Komfortmerkmale einer Datenbank damit nicht zur Verfügung stehen oder teilweise nur umständlich zu realisieren sind. Dateien im Allgemeinen sind nur eine Aneinanderreihung von Bytes. Man kann beispielsweise nicht einfach etwas dazwischenschieben. Wollte man so etwas machen, gilt es zunächst die Position zu errechnen, dann den Rest bis zum Ende auszulesen, das Einzufügende zu schreiben und den Rest hinten anzufügen.
Bei Textdateien verwendet man oftmals ein Zeichen als Trennzeichen, z.B. den Zeilenumbruch. Willst du nun den dritten Datensatz haben, musst du zeichenweise die Datei lesen, bis zum zweiten Zeilenumbruch. Ab dort bis zum nächsten Zeilenumbruch steht dein Datensatz. Das ganze kann man beim kompletten Einlesen der Datei auch mittels Stringfunktionen erledigen. Doch du siehst sicher schon an den Beispielen, dass dieses Handling je nach Aufgabenstellung recht umfangreich werden kann. Es gilt hier Aufwand und Nutzen gegeneinander anzuwägen.
Eine für dich einfache Möglichkeit wäre, wenn du deine Daten in einer Struktur verwaltest (Array oder Objekt), und dieses komplett serialisiert in eine Datei schreibst. Nach dem Einlesen und Deserialisieren hast du dann wieder eine Struktur. Den Aufwand, die Struktur textdateifähig zu machen und sie wiederherzustellen erledigt dann PHP für dich.
Als Kompromiss zwischen "einfach" und "Komfort" kann man SQLite sehen. Das stellt einen SQL-datenbanktypischen Zugriff auf eine irgendwo abgelegte Datei zur Verfügung, ohne dass ein DBMS ständig bereitstehen muss.
echo "$verabschiedung $name";
Hi Dedlfix!
Danke für die lange Ausführung!
Du möchtest Text-Dateien als Datenbankersatz verwenden? Das kann man nur bis zu recht geringen Größen guten Gewissens empfehlen.
Ich möchte versuchsweise eine Seite erstellen, die nur 3 mal abgerufen werden kann/darf.
Ich hab mir das so vorgestellt, daß ich eine Variable $aufrufe mit 0 vorbelege und in einer txt-datei speichere. Beim Aufruf der Seite überprüft php, ob Die Variable schon den Wert 3 hat. Wenn ja, dann kommt eine alternative Ausgabe, wenn nein, dann wird die Seite ausgegeben und der Wert der Variable um 1 erhöht sowie neu gespeichert/überschrieben.
Ich denke, dafür ist die Variante mit der txt-Datei OK, oder?
Mit Grüßen aus Entenhausen
Gustav Gans
echo $begrüßung;
Ich hab mir das so vorgestellt, daß ich eine Variable $aufrufe mit 0 vorbelege und in einer txt-datei speichere. Beim Aufruf der Seite überprüft php, ob Die Variable schon den Wert 3 hat. Wenn ja, dann kommt eine alternative Ausgabe, wenn nein, dann wird die Seite ausgegeben und der Wert der Variable um 1 erhöht sowie neu gespeichert/überschrieben.
Ich denke, dafür ist die Variante mit der txt-Datei OK, oder?
Ja, das sieht angemessen aus. Für den Fall schließe ich mich der Empfehlung von Andreas an.
echo "$verabschiedung $name";
Hi dedlfix!
Jetzt habe ich mich daran gemacht, etwas herumzuexperimentieren, habe aber ein kleines Problem.
Mit folgendem Code erreiche ich genau das, was ich will, nämlich daß eine Zahl in einer txt-Datei mit jedem Aufruf einer Testseite um 1 größer wird:
<?php
$handle=fopen("testfile.txt","r");
$inhalt=fgets($handle);
$inhaltneu=$inhalt+1;
fclose($handle);
echo"<p>In der Datei steht: ".$inhalt."</p>\n";
echo"<p>Der NEUE Inhalt wäre: ".$inhaltneu."</p>\n";
$handle=fopen("testfile.txt","w");
fputs($handle,$inhaltneu);
fclose($handle);
?>
Wenn ich mir die txt-Datei nach mehreren Seitenaufrufen öffne, steht auch wirklich nur eine Zahl drin, nämlich die aktuelle. Das heißt, mit oben geschriebenen Code erreiche ich genau das, was ich will, nämlich das der alte Inhalt überschrieben wird mit dem neuen.
Dann habe ich mir gedacht, ich könnte den Code schlanker machen und nur ein mal das txt-File öffnen und schließen. Im php-Buch steht bei der fopen-Funktion, daß sowohl w+, a+ als auch r+ zum Lesen UND Schreiben berechtigt. Das würde dann so aussehen:
<?php
$handle=fopen("testfile.txt","w+");
$inhalt=fgets($handle);
$inhaltneu=$inhalt+1;
fputs($handle,$inhaltneu);
fclose($handle);
echo"<p>In der Datei steht: ".$inhalt."</p>\n";
echo"<p>Der NEUE Inhalt wäre: ".$inhaltneu."</p>\n";
?>
Das bewirkt aber, daß ich bei JEDEM Aufruf der Seite stehen habe:
In der Datei steht:
Der NEUE Inhalt wäre: 1
Und auch nach mehrmaligen Aufruf ist immer noch eine 1 in der txt-Datei.
Wenn ich eine 13 in die txt-datei schreibe und die Seite aufrufe, steht anschließend auch wieder eine 1 drin und die AUsgabe bleibt wieder immer die selbe.
Mit einem r+ oder a+ ändern sich die Zahlen völlig chaotisch.
Wo ist mein Denk-/Programmierfehler???
Gustav Gans
echo $begrüßung;
Mit folgendem Code erreiche ich genau das, was ich will, nämlich daß eine Zahl in einer txt-Datei mit jedem Aufruf einer Testseite um 1 größer wird:
<?php
$handle=fopen("testfile.txt","r");
$inhalt=fgets($handle);
$inhaltneu=$inhalt+1;
fclose($handle);
echo"<p>In der Datei steht: ".$inhalt."</p>\n";
echo"<p>Der NEUE Inhalt wäre: ".$inhaltneu."</p>\n";
$handle=fopen("testfile.txt","w");
fputs($handle,$inhaltneu);
fclose($handle);
?>
Du solltest dir unbedingt den Artikel über das [Sperren von Dateien](http://aktuell.de.selfhtml.org/artikel/programmiertechnik/dateisperren/index.htm) zu Herzen nehmen. In deinem Labor bist du der einzige, der die Seite aufruft. Stellst du sie online, können weitere Zugriffe erfolgen, während du noch mitten in der Bearbeitung bist. Das muss verhindert werden, wenn du keine falschen Ergebnisse haben möchtest.
> Wenn ich mir die txt-Datei nach mehreren Seitenaufrufen öffne, steht auch wirklich nur eine Zahl drin, nämlich die aktuelle. Das heißt, mit oben geschriebenen Code erreiche ich genau das, was ich will, nämlich das der alte Inhalt überschrieben wird mit dem neuen.
Nein, es gibt beim Nichtbeachten der parallelen Zugriffe Ausnahmen: A liest den Wert x aus der Datei aus. Nun kommt B und liest ebenfalls den aktuellen Wert x aus. Jetzt kommt A wieder an die Reihe, erhöht auf x+1 und schreibt die Datei. Anschließend macht B das genauso. Am Ende hast du x+1 und nicht x+2 in der Datei stehen.
Anderes Szenario: A ist bereits dabei, die Datei zum Schreiben zu öffnen. Dabei wird im Modus w der Inhalt gelöscht. Nun kommt B und will selbigen lesen, doch es ist nichts da, was beim folgenden Rechnen mit diesem Wert 0 entspricht. A schreibt sein x+1 hinein, nun öffnet B zum Schreiben und schreibt eine 1 hinein, denn 0+1=1.
> Dann habe ich mir gedacht, ich könnte den Code schlanker machen und nur ein mal das txt-File öffnen und schließen. Im php-Buch steht bei der [fopen-Funktion](http://de.php.net/manual/de/function.fopen.php), daß sowohl w+, a+ als auch r+ zum Lesen UND Schreiben berechtigt.
Ja, da steht aber auch, was die drei Modi voneinander unterscheidet.
Wie ich ja bereits in meiner ersten Antwort ausführte, ist eine Datei eine Aneinanderreihung von Bytes. Es gibt außerdem einen Dateizeiger, der die Position angibt, an der die nächste Aktion erfolgt, sei es nun Lesen oder Schreiben. Wenn der Dateizeiger am Ende der Datei steht, kann ein Lesezugriff nichts mehr lesen. Ein Schreibzugriff hingegen hängt das zu Schreibende hinten an. Steht er am Anfang, ohne dass der Inhalt gelöscht wurde, liest ein Lesezugriff den Wert aus. Ein anschließender Schreibzugriff hängt hinten an, wenn der Zeiger nicht wieder nach vorn positioniert wurde. Wurde er das, wird der alte Wert überschrieben, was aber alten Rest übrig lässt, wenn der neue Wert kürzer war als der alte.
echo "$verabschiedung $name";
Hi dedlfix!
Du solltest dir unbedingt den Artikel über das Sperren von Dateien zu Herzen nehmen. In deinem Labor bist du der einzige, der die Seite aufruft. Stellst du sie online, können weitere Zugriffe erfolgen, während du noch mitten in der Bearbeitung bist. Das muss verhindert werden, wenn du keine falschen Ergebnisse haben möchtest.
Das glaub ich nicht, es kennt ja keiner die URL, unter der die Seite aufzurufen ist momentan. :-)
Nein, es gibt beim Nichtbeachten der parallelen Zugriffe Ausnahmen: A liest den Wert x aus der Datei aus. Nun kommt B und liest ebenfalls den aktuellen Wert x aus. Jetzt kommt A wieder an die Reihe, erhöht auf x+1 und schreibt die Datei. Anschließend macht B das genauso. Am Ende hast du x+1 und nicht x+2 in der Datei stehen.
Heißt das jetzt, daß der funktionierende Code kein optimaler ist und ich noch was ändern muß, damit das von Dir beschriebene mögliche Parallellverhalten verhindert wird? Oder ist das was, womit ich leben muß, wenn ich das ganze ohne einer DB und nur mit einer txt-Datei löse?
Mit freundlichen Grüßen
Gustav Gans
echo $begrüßung;
Heißt das jetzt, daß der funktionierende Code kein optimaler ist und ich noch was ändern muß, damit das von Dir beschriebene mögliche Parallellverhalten verhindert wird? Oder ist das was, womit ich leben muß, wenn ich das ganze ohne einer DB und nur mit einer txt-Datei löse?
Erstens ja, zweitens nein. Im schon mehrfach angesprochene Artikel über das Sperren von Dateien ist der übliche Weg beschrieben, diese Problematik nicht zum Problem werden zu lassen.
echo "$verabschiedung $name";
Hi,
Im schon mehrfach angesprochene Artikel über das Sperren von Dateien ist der übliche Weg beschrieben, diese Problematik nicht zum Problem werden zu lassen.
Zu diesem Artikel habe ich eine Frage, ich verstehe etwas nicht ganz, zB:
<?php
touch ('counter.txt');
$fp = fopen ('counter.txt', 'r+');
if (!is_resource ($fp)) {
die ('Konnte die Datei nicht öffnen!');
}
if (!flock ($fp, LOCK_EX)) {
die ('Sperren der Datei fehlgeschlagen!');
}
ftruncate ($fp, 0);
fwrite ($fp, '0');
fclose ($fp);
echo "Zähler wurde zurückgesetzt.";
?>
Bei der zweiten if-Abfrage wird gefragt: Wennn die Sperre _nicht_ möglich ist/wenn nicht gesperrt ist, dann...
Aber es gibt keinen _direkten_ Sperrbefehl. Also so in der Art wie flock ($fp, LOCK_EX));
Wenn ich abfrage, ob $a==1, dann heißt das ja auch nicht automatisch, daß $a=1 gesetzt wird.
Frage: Wieso gibt es in all dem Beispielen des verlinkten Artikels immer nur if-Abfragen mit !flock und nirgends eine direkte flock-Anweisung?
MfG
Gustav Gans
echo $begrüßung;
if (!flock ($fp, LOCK_EX)) {
die ('Sperren der Datei fehlgeschlagen!');
}
Bei der zweiten if-Abfrage wird gefragt: Wennn die Sperre _nicht_ möglich ist/wenn nicht gesperrt ist, dann...
Aber es gibt keinen _direkten_ Sperrbefehl. Also so in der Art wieflock ($fp, LOCK_EX));
Es ist unerheblich, ob eine Funktion allein stehend oder in einem (komplexen) Ausdruck aufgerufen wird. Aufruf ist Aufruf. Sie arbeitet keineswegs anders, wenn man sie in einem anderen Kontext aufruft.
Wenn ich abfrage, ob $a==1, dann heißt das ja auch nicht automatisch, daß $a=1 gesetzt wird.
Das ist richtig. Es ist jedoch nicht unüblich, eine Zuweisung innerhalb eines Bedingungsausdrucks zu notieren
while ($row = fetch(...))
oder auch
if ($row = fetch(...))
wenn man nur ein Ergebnis erwartet. Bei beiden Beispiele sei anzunehmen, dass fetch() im Erfolgsfall ein von false unterschiedliches Ergebnis liefert, ansonsten ein false. Die Zuweisung ergibt also ein false oder was anderes. Das Ergebnis einer Zuweisung ist immer der Wert ihrer Zuweisung, hier also false oder das andere, nicht jedoch ob die Zuweisung erfolgreich war.
Frage: Wieso gibt es in all dem Beispielen des verlinkten Artikels immer nur if-Abfragen mit !flock und nirgends eine direkte flock-Anweisung?
Es ist überfüssig umständlich, zuerst das Funktionsergebnis einer Variablen zuzuweisen und selbige anschließend nur ein einziges Mal auszuwerten. Da kann man auch gleich das Funktionsergebnis direkt auswerten.
echo "$verabschiedung $name";
Hi dedlfix,
sorry, ich verstehe es einfach nicht. :-(
if (!flock ($fp, LOCK_EX)) {
die ('Sperren der Datei fehlgeschlagen!');
}
Bei der zweiten if-Abfrage wird gefragt: Wennn die Sperre _nicht_ möglich ist/wenn nicht gesperrt ist, dann...
Aber es gibt keinen _direkten_ Sperrbefehl. Also so in der Art wieflock ($fp, LOCK_EX));
Es ist unerheblich, ob eine Funktion allein stehend oder in einem (komplexen) Ausdruck aufgerufen wird. Aufruf ist Aufruf. Sie arbeitet keineswegs anders, wenn man sie in einem anderen Kontext aufruft.
Hier wird gefragt, ob gesperrt ist oder nicht. Unabhängig vom Ergebnis wird nicht explizit angeordnet, zu sperren. Nochmal:
Wenn ich abfrage, ob $a==1, dann heißt das ja auch nicht automatisch, daß $a=1 gesetzt wird.
Ich verstehe einfach nicht, wieso hier etwas gemacht wird, wenn es nicht per Befehl im Code steht. Und das tut es doch eindeutig nicht, es wird einfach nur nachgefragt.
Das ist richtig. Es ist jedoch nicht unüblich, eine Zuweisung innerhalb eines Bedingungsausdrucks zu notieren
while ($row = fetch(...))
oder auch
if ($row = fetch(...))
wenn man nur ein Ergebnis erwartet. Bei beiden Beispiele sei anzunehmen, dass fetch() im Erfolgsfall ein von false unterschiedliches Ergebnis liefert, ansonsten ein false. Die Zuweisung ergibt also ein false oder was anderes. Das Ergebnis einer Zuweisung ist immer der Wert ihrer Zuweisung, hier also false oder das andere, nicht jedoch ob die Zuweisung erfolgreich war.
Ich hab Deine Erklärung jetzt mehrmals gelesen, ich verstehe es noch immer nicht. :-(
Frage: Wieso gibt es in all dem Beispielen des verlinkten Artikels immer nur if-Abfragen mit !flock und nirgends eine direkte flock-Anweisung?
Es ist überfüssig umständlich, zuerst das Funktionsergebnis einer Variablen zuzuweisen und selbige anschließend nur ein einziges Mal auszuwerten. Da kann man auch gleich das Funktionsergebnis direkt auswerten.
Nochmal, wo wird da was zugewiesen? Es wird doch nur was gefragt? (Was mich wieder zu meinem $a==1-Beispiel bringt.)
*seufz*
Gustav Gans
Hallo,
Hier wird gefragt, ob gesperrt ist oder nicht. Unabhängig vom Ergebnis wird nicht explizit angeordnet, zu sperren.
Doch.
Nochmal:
Wenn ich abfrage, ob $a==1, dann heißt das ja auch nicht automatisch, daß $a=1 gesetzt wird.
Natürlich nicht. Aber wenn Du abfragst, ob if (bla() == 1) ist, dann wird die Funktion bla() aufgerufen und das Ergebnis der Funktion dann mit 1 verglichen. Und in meinem Artikel wird halt das Ergebnis mit false verglichen (das macht das !).
Ich verstehe einfach nicht, wieso hier etwas gemacht wird, wenn es nicht per Befehl im Code steht. Und das tut es doch eindeutig nicht, es wird einfach nur nachgefragt.
Im Prinzip ist
if (bla () == 1)
eine Kurzschreibweise für:
$resultat = bla ();
if ($resultat == 1)
PHP ersetzt das automatisch durch das Ergebnis der Funktion bla (). Das ist genauso, wenn Du das Ergebnis einer Funktion als Aufrufparameter einer weiteren Funtkion verwendest vergleiche z.B.
printf ("%s\n", bla ());
mit
$resultat = bla ();
printf ("%s\n", $resultat);
In beiden Fällen wird die Funktion bla () ausgeführt und das Ergebnis dann als Parameter für die Funktion printf () verwendet. Im zweiten Fall hast Du jedoch eine zusätzliche Variable, die Du im ersten Fall nicht hast (weil PHP das Ergebnis implizit verwendet).
Das ist übrigens nicht nur in PHP der Fall, sondern in so gut wie jeder imperativen Programmiersprache (es gibt Ausnahmen).
In meinem Artikel wird nun die Funktion flock() aufgerufen. Die sperrt die Datei und gibt dann zurück, ob das Sperren erfolgreich durchgeführt werden konnte. D.h. die Tatsache, dass dort flock (...) steht heißt, dass beim Auswerten der Funktion schon gesperrt wird.
Viele Grüße,
Christian
Hi Christian,
danke für die Erklärung, ich werde mir das mal in Ruhe zu Gemüte ziehn jetzt, bis ich es verstanden habe. Danke für die Hilfe!
Liebe Grüße
Gustav Gans
Hello,
sorry, ich verstehe es einfach nicht. :-(
if (!flock ($fp, LOCK_EX)) {
die ('Sperren der Datei fehlgeschlagen!');
}
macht nichts, das kann jedem passieren :-)
$lock_ok = flock ($fp, LOCK_EX);
if (!$lock_ok ($fp, LOCK_EX))
{
die ('Sperren der Datei fehlgeschlagen!');
}
Ich habe es Dir mal umgeschrieben.
Im Prinzip sind beide Codestücke gleich. Einziger Unterschied ist nur, dass das Ergebnis der Lock-Funktion im ersten Codebeispiel nicht zwischengespeichert wird, sondern sofort weiterverwendet wird für den Vergleich. Wenn der Vergleich endet, ist das Ergebnis nicht mehr vorhanden.
Außerdem muss man zum Verständnis dieses Codestückchens wissen, dass flock() in der obigen Anwendungsart intern eine Schleife aufmacht (Warteschleife), die solange automatisch versucht, die _vorhandene_ Ressource $fp zu sperren, bis sie Erfolg hatte. Der Programmfluss ist also an dieser Stelle bis zum erfolgreichen Lock unterbrochen.
Es geht nur dann weiter, wenn ein Fehler auftrat. Wenn z.B. die Ressource nicht vorhanden ist, die gesperrt werden soll (ein ungültiges Handle übergeben wurde), dann bricht flock() den Lockversuch mit 'false' ab. Genau dieser Fall wird hier mit if() abgefragt.
Wenn man nicht will, dass das Programm an dieser Stelle wartet, muss man flock() im sogenannten "NON-BLOCKING-MODE" aufrufen. Dann führt es nur eine begrenzte Anzahl von Lockversuchen durch (z.B. 5 Versuche im Abstand von 5ms) und bricht ab, wenn kein Lock möglich war.
Allerdings funktioniert es gerade mal nicht in
PHP-Version: 5.2.0-8+etch10
Ich wollte ein Beispiel bereitstellen, aber das flock() wartet immer. Es kann nicht in den Non-Blocking-Mode geschaltet werden. Muss ich also erst herausfinden, woran es liegt.
<?php ### flock.php ###
error_reporting(E_ALL);
echo "PHP-Version: ".phpversion()."<br>";
$filename = 'dummy.txt';
if (!file_exists($filename))
{
touch($filename);
}
$fh = fopen($filename,'rb'); ## absichtlich ungültiges File-Handle produzieren.
$err = false;
$ok = flock($fh, (LOCK_EX + LOCK_NB); # , $err); # Zum Testen, was wouldblock macht...
echo "Ergebnis des Lockversuches auf <b>$filename</b> ist ".(($ok)?'TRUE':'FALSE')."<br>";
echo "Error ist: $err (".(($err)?'TRUE':'FALSE').")<br>";
flush(); ## obige Ausgaben an den Browser schicken.
sleep(15); ## warten, um bei einem zweiten Aufruf des Scriptes das Lock zu verweigern.
echo "<br>fertig<br>";
?>
Ein harzliches Glückauf
Tom vom Berg
Hello,
Allerdings funktioniert es gerade mal nicht in
PHP-Version: 5.2.0-8+etch10
Ich wollte ein Beispiel bereitstellen, aber das flock() wartet immer. Es kann nicht in den Non-Blocking-Mode geschaltet werden. Muss ich also erst herausfinden, woran es liegt.
hierzu auch der Thread http://forum.de.selfhtml.org/archiv/2008/4/t169108/#m1104421 von "Herzlicher".
Da hatte ich damals nicht extra getestet. Der Thread ist auch ohne befriedigende Antwort geblieben.
Ein harzliches Glückauf
Tom vom Berg
Hello,
PHP-Version: 5.2.0-8+etch10
Ich wollte ein Beispiel bereitstellen, aber das flock() wartet immer. Es kann nicht in den Non-Blocking-Mode geschaltet werden. Muss ich also erst herausfinden, woran es liegt.hierzu auch der Thread http://forum.de.selfhtml.org/archiv/2008/4/t169108/#m1104421 von "Herzlicher".
Der Bug scheint schon aus dem Jahr 2006 zu stammen: http://bugs.php.net/bug.php?id=39138
Ich habe ein Update auf PHP-Version: 5.2.0-8+etch11 durchgeführt.
Eine neuere ist bei Debain fertig nicht zu bekommen.
Bevor ich nun PHP selber baue, wüsste ich gerne, ob der Fehler beseitigt wurde.
Ein harzliches Glückauf
Tom vom Berg
Hallo Tom,
Dein Beispiel funktioniert, auch wenn Du eher | statt + verwenden solltest.
Vielleicht verwechselst Du einfach nur die Tatsache, dass Du immer ein sleep(15) in Deinem Code hast damit, dass flock() immer wartet.
Ich habe Dir mal Dein Beispiel etwas angepasst, damit es sleep() nur noch ausführt, wenn das Sperren erfolgreich war:
<?php
if (php_sapi_name () == 'cli') {
define ('NL', "\n");
} else {
define ('NL', "<br />\n");
}
error_reporting (E_ALL);
echo "PHP-Version: " . phpversion () . NL;
$filename = 'dummy.txt';
if (!file_exists ($filename)) {
touch ($filename);
}
$fh = fopen ($filename, 'rb');
$wb = false;
$ok = flock ($fh, LOCK_EX | LOCK_NB, $wb);
echo "Ergebnis des Lockversuchs auf $filename ist " . ($ok ? 'true' : 'false') . NL;
echo "Wouldblock: " . ($wb ? 'true' : 'false') . NL;
if ($ok) {
flush ();
sleep (15);
}
echo NL . 'fertig' . NL;
?>
Viele Grüße,
Christian
Hello Christian,
Dein Beispiel funktioniert, auch wenn Du eher | statt + verwenden solltest.
bei mir leider nicht :-(
Muss wohl an der PHP-Version liegen, aus der die Debain-Leute ihre erzeugt haben.
Vielleicht verwechselst Du einfach nur die Tatsache, dass Du immer ein sleep(15) in Deinem Code hast damit, dass flock() immer wartet.
Ich denke nicht. Dann müsste doch das als zweites aufgerufene Script ein "FALSE" für $ok zurückgeben.
Ich habe Dir mal Dein Beispiel etwas angepasst, damit es sleep() nur noch ausführt, wenn das Sperren erfolgreich war:
Das mit dem NL für cli oder Browser-Ausgabe merke ich mir doch gleich mal :-)
Nur eine kleine Änderung, die mMn die Konformität mit HTML wieder herstellen sollte.
[code lang=php]<?php
if (php_sapi_name () == 'cli') {
define ('NL', "\n");
} else {
define ('NL', "<br />\r\n");
}
[...]
$ok = flock ($fh, LOCK_EX | LOCK_NB, $wb);
das hatte ich vorhin schon angepasst.
Es funktioniert trotzdem nicht mehr und ich finde auch eine ganze Menge Meldungen über Google, wenn ich nach dem LOCK_NB suche, dass Andere das gleiche Problem festgestellt haben.
Das Problem ist: für eine Applikation benötige ich dringend ein funktionierendes flock(). Ich habe es auch erst durch diesen Thread her gemerkt, dass es nicht mehr funktioniert und frage mich jetzt, woran es liegen kann.
Das Script liegt unter http://selfhtml.bitworks.de/artikel_locking/flock_nb.php?showscript
Ohne den Parameter 'showscript' wird es ausgeführt.
Ich bekomme aber in beiden Fällen die folgende Antwort:
Locking Test: 2008-05-29 19:38:45
PHP-Version: 5.2.0-8+etch11
Ergebnis des Lockversuchs auf dummy.txt ist true
Wouldblock: false
fertig
Ein harzliches Glückauf
Tom vom Berg
Hallo Tom,
Das Script liegt unter http://selfhtml.bitworks.de/artikel_locking/flock_nb.php?showscript
Tatsache, Bug. Der aber zumindest in aktuellen PHP-Versionen nicht mehr auftritt.
Update halt mal. ;-)
Viele Grüße,
Christian
Hello,
Das Script liegt unter http://selfhtml.bitworks.de/artikel_locking/flock_nb.php?showscript
Tatsache, Bug. Der aber zumindest in aktuellen PHP-Versionen nicht mehr auftritt.
Update halt mal. ;-)
Das werde ich müssen und zwar im Eilzugtempo, da mein Anwender, der dringend diese Funktionalität benötigt, mir spätestens am 05. Juni auf den Füßen stehen wird. Ich habe es (vielleicht) gerade noch rechtzeitig gemerkt.
Nur was tun? Da werde ich wohl selber kompilieren müssen.
Ich habe bisher alles als apt-get-Module installiert und es hat bisher auch immer den Zweck erfüllt.
Das letzte Update von Debian habe ich gerade vorhin gefahren von PHP-Version: 5.2.0-8+etch10 auf PHP-Version: 5.2.0-8+etch11. Es hat sich leider nichts geändert.
Ich nehme an, dass die Debian-Entwickler leider eine buggy PHP-Version als Grundlage verwenden.
Nun benötige ich
Apache 2.2
PHP als Modul mit
- gdlib
- freetype
- dio
- dbase
usw.
Da krieg ich doch gleich schon wieder Panik!
Ein harzliches Glückauf
Tom vom Berg
Hi Tom,
danke auch Dir für die Erklärung, ich werde mir das mal in Ruhe zu Gemüte ziehn jetzt, bis ich es verstanden habe. Danke für die Hilfe!
Liebe Grüße
Gustav Gans
Hello,
Heißt das jetzt, daß der funktionierende Code kein optimaler ist und ich noch was ändern muß, damit das von Dir beschriebene mögliche Parallellverhalten verhindert wird?
Sowie Dein für ein Netzwerk bestimmtes Programm den Laborbetrieb verlässt, muss es für den konkurrierenden Betrieb Vorsorge getroffen haben, sondt können die ungewöhnlichsten Dinge passieren.
Ein harzliches Glückauf
Tom vom Berg
Hallo.
Dateien im Allgemeinen sind nur eine Aneinanderreihung von Bytes.
Datenbanken im Speziellen ebenfalls.
MfG, at