cr: datei beim auslesen sperren?

hallo an dem schönen sonntag mittag,

ich habe eine frage zu dateien.

wenn ich mittels fopen eine txt datei öffne und diese nur auslese (z.b. über ein abfrageformular auf einer internetseite) und dies mehrere personen tun können (auch evtl. gleichzeitig oder kurz nacheinander), sollte man dann die datei beim aufrufen jedesmal sperren?

und wie ist es, wenn man in die datei schreibt?

danke für eure hilfe!

cr

  1. hi,

    wenn ich mittels fopen eine txt datei öffne und diese nur auslese (z.b. über ein abfrageformular auf einer internetseite) und dies mehrere personen tun können (auch evtl. gleichzeitig oder kurz nacheinander), sollte man dann die datei beim aufrufen jedesmal sperren?

    Alleiniges Lesen ist "harmlos", und erfordert m.E. keinen Sperrmechanimus.

    und wie ist es, wenn man in die datei schreibt?

    Dann könnte ein solcher aber auch für's Lesen angebracht sein. Sonst liest vielleicht jemand etwas gerade erst "halb fertig" geschriebenes aus.

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
    1. hi,

      danke für die antwort.

      welche werte soll ich dann flock geben? lesen und schreiben
      ich kenne mich nicht aus und will nichts falsch machen mit dem befehl flock.

      danke

      1. hi,

        welche werte soll ich dann flock geben? lesen und schreiben

        LOCK_SH zu den Zeitpunkten, wo du nur liest,
        LOCK_EX zu den Zeitpunkten, wo du schreiben willst.

        gruß,
        wahsaga

        --
        /voodoo.css:
        #GeorgeWBush { position:absolute; bottom:-6ft; }
        1. ah ok, danke!

        2. Hello,

          welche werte soll ich dann flock geben? lesen und schreiben

          LOCK_SH zu den Zeitpunkten, wo du nur liest,

          und niemals vorhast, zu schreiben.

          LOCK_EX zu den Zeitpunkten, wo du schreiben willst.

          oder erstmal liest, um eventuell noch zu schreiben

          Harzliche Grüße vom Berg
          http://www.annerschbarrich.de

          Tom

          --
          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
          Nur selber lernen macht schlau

      2. Hallo,

        welche werte soll ich dann flock geben? lesen und schreiben
        ich kenne mich nicht aus und will nichts falsch machen mit dem befehl flock.

        Locking von Dateien ist eine sehr trickreiche Sache. Die Funktion flock() bietet 3 mögliche Operationen an:

        * LOCK_SH: Ein shared lock auf die Datei anlegen. Es können beliebig viele
                    Prozesse ein shared lock auf eine Datei anlegen - ein shared
                    lock verhindert *lediglich*, dass ein exclusive lock auf eine
                    Datei angelegt wird. Ferner kann man kein shared lock anlegen,
                    falls die Datei gerade mit einem exclusive lock gelockt ist
                    (wenn etwas nicht geht, wartet flock() immer, bis die Sperre
                    wieder frei ist)
         * LOCK_EX: Ein exclusive lock auf die Datei anlegen. Es kann nur ein
                    exclusive lock auf eine Datei angelegt werden.
         * LOCK_UN: Alle Locks des *aktuelllen* Prozesses entfernen. Im Prinzip
                    unnötig, wenn Du die Datei direkt nach dem Lesen/Schreiben
                    wieder schließen willst.

        Wie wäre also die Vorgehensweise für das Locking von Dateien?

        * Lesende Prozesse öffnen die Datei mit fopen im 'r'-Modus und versuchen
           dann mit LOCK_SH die Datei zu sperren. Sobald flock erfolgreich war,
           können sie sich sicher sein, dass kein anderer Prozess die Datei
           verändert. Da bei fclose() auch alle Locks entfernt werden, ist es
           *nicht* notwendig, die Sperre zu entfernen, wenn man fclose () verwendet.
         * Schreibende Prozesss öffnen die Datei (dazu später mehr) und versuchen
           dann mit LOCK_EX die Datei zu sperren. Sobald flock erfolgreich war,
           können sie sich sicher sein, dass die Datei *nur* für sie geöffent ist
           und kein anderer Prozess dazwischenfunkt. LOCK_EX sollte man nur so kurz
           wie möglich verwenden, denn solange sind andere Prozesse gesperrt.

        Dabei gibt es jedoch noch einige *sehr* wichtige Punkt zu beachten:

        * flock() funktioniert nicht auf FAT-Dateisystemen, nicht unter Windows
           95/98/ME (unter NT4/2000/XP/2003/Vista schon) und nicht über die meisten
           Netzwerkdateisysteme.
         * Insbesondere unter Windows, wenn PHP als ISAP-Filter betrieben wird,
           aber unter Umständen auch unter anderen Betriebsystemen, wenn PHP als
           Multithread-Webservermodul verwendet wird, kann es sein, dass flock()
           nutzlos ist, denn flock() ist in manchen Betriebsystemen nur auf
           Prozess-, nicht aber auf Thread-Ebene implementiert. Wenn PHP als CGI
           oder als Webservermodul eines Singlethread-Webservers läuft, dann
           besteht das Problem nicht.
         * flock() ist eine *freiwillige* Angelegenheit. Ich kann alles mit der
           Datei anstellen, auch wenn sie von einem anderen Prozess per LOCK_EX
           gesperrt ist. D.h. alle Programme, die auf die Datei zugreifen, *müssen*
           Locking korrekt implementieren, damit es zu keinen Fehlern kommt, d.h.
           sie *müssen* sich an die Konvention halten.

        Und als _allerwichtigsten_ Punkt kommt noch das Öffnen von Dateien zum Schreiben (!) hinzu. Betrachten wir nun folgenden Beispielcode, der eine Datei zum *Lesen* öffnet:

        $fp = fopen("datei", "r");  
        if (flock($fp, LOCK_SH)) {  
           // irgendwas aus $fp auslesen  
        } else {  
           echo "Fehler beim Anfordern der Sperre!";  
        }  
        fclose($fp);
        

        Der Code ist so korrekt, d.h. wenn sich alle lesenden Prozesse an das obige Schema halten, dann funktioniert's korrekt. Betrachten wir jedoch mal folgenden Beispielcode, der eine Datei zum Schreiben öffnet.

        $fp = fopen("datei", "w");  
        if (flock($fp, LOCK_EX)) {  
           // irgendwas in $fp schreiben  
        } else {  
           echo "Fehler beim Anfordern der Sperre!";  
        }  
        fclose($fp);
        

        Sieht doch ganz OK aus, oder? FALSCH!

        Das Problem an dem obigen Code ist, dass der Code Änderung an der Datei vornimmt, *bevor* das Lock angefordert wurde. Warum das? Da ist doch ne if-Bedingung? Die Antwort: Beim fopen () mit dem "w"-Flag wird der komplette Inhalt der Datei gelöscht (d.h. wenn Du nur fclose (fopen ("datei", "w")); machst, dann löscht Du den kompletten Inhalt der Datei "datei" - oder legst eine Datei mit diesem Namen an).

        Oftmals wird hierfür eine Lösung über eine separate Lockfile vorgeschlagen. Obwohl das durchaus funktioniert, ist das nicht die einfachste:

        Es gibt zwei sich sehr ähnliche Lösungsmöglichkeiten für das Problem:

        1. Die Datei als 'r+' öffnen (statt als 'w') - dann wird die Datei zum Lesen geöffent mit zusätzlicher Möglichkeit, in der Datei zu schreiben - die Datei wird allerdings *nicht* beim Öffnen gelöscht. Nach dem Erlangen der Sperre wird die Datei per ftruncate() gelöscht und dann kann normal darin geschrieben werden:

        $fp = fopen("datei", "r+");  
        if (flock($fp, LOCK_EX)) {  
           // Kompletten Dateiinhalt löschen  
           ftruncate ($fp, 0);  
           // irgendwas in $fp schreiben  
        } else {  
           echo "Fehler beim Anfordern der Sperre!";  
        }  
        fclose($fp);
        

        Dieses Verfahren hat einen gravierenden Nachteil: Wenn die Datei nicht existiert, schlägt das Öffnen der Datei fehl. Man kann dem aber abhelfen, indem man mit der touch()-Funktion vorher dafür sorgt, dass die Datei existiert, d.h. *vor* dem fopen() noch ein

        touch ($datei);

        Das sorgt dafür, dass die Datei definitiv existiert, bevor man sie öffnet, allerdings fasst touch() den Inhalt der Datei nicht an.

        2. Die alternative Lösung ist, die Datei zum Anhängen zu öffnen ('a' statt 'r+') und dann wieder ftruncate() anzuwenden:

        $fp = fopen("datei", "a");  
        if (flock($fp, LOCK_EX)) {  
           // Kompletten Dateiinhalt löschen  
           ftruncate ($fp, 0);  
           // irgendwas in $fp schreiben  
        } else {  
           echo "Fehler beim Anfordern der Sperre!";  
        }  
        fclose($fp);
        

        Diese Lösung hat den Vorteil, dass fopen() beim Öffnen über 'a' die Datei im Zweifel auch anlegt. *Allerdings* hat dieses Verfahren den Nachteil, dass man weder im 'a'- noch im 'a+'-Modus in der Datei mittels fseek() die Position verändern kann. Ok, im 'a+'-Modus geht's, um irgendwo aus der Datei etwas zu *lesen* - allerdings wird in beiden 'a'-Modi alles, was geschrieben wird, *immer* an die Datei angehöngt, *nicht* an die aktuelle Position geschrieben - nur das ftruncate() sorgt dafür, es überhaupt wieder am Anfang der Datei losgeht (wenn die Datei leer ist, dann heißt "anhängen" einfach "ab dem Anfang schreiben"). Wenn Du also *nur* linear Schreiben willst und fseek() gar nicht zum Verändern der SCHREIB-Position verwenden willst, dann ist die 'a'-Lösung genauso gut wie die 'r+'-Lösung - wenn Du allerdings mittels fseek() die SCHREIB-Position verändern willst, dann ist die 'a'-Lösung keine Option und Du musst die 'r+'-Lösung verwenden.

        Viele Grüße,
        Christian

        --
        "I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone." - Bjarne Stroustrup
  2. Hello cr,

    wenn ich mittels fopen eine txt datei öffne und diese nur auslese (z.b. über ein abfrageformular auf einer internetseite) und dies mehrere personen tun können (auch evtl. gleichzeitig oder kurz nacheinander), sollte man dann die datei beim aufrufen jedesmal sperren?

    und wie ist es, wenn man in die datei schreibt?

    Die Antwort ist abhängig von der Wahl des Sperrmechanismus.
    Die üblichen Linunx-Systeme nutzen per default das "Advisory Locking". Das liegt formal neben dem Dateisystem als eigenes Informationssystem für die Applikationen, sollte genutzt werden, aber kann umgangen werden. Man kann aber auch das "Mandatory Locking" benutzen, lässt sich auch bei Linux einschalten...

    I.d.R. benutzen andere Filesysteme (Windows FAT32, NTFS, NOVELL DS, ...) Mandatory Locking.

    Wenn eine Datei mit Mandatory Locking schreib-lese-gesperrt ist, kann keine andere Applikation darauf zugreifen, solange diese Sperre besteht, egal, ob sie selber daran gedacht hat, oder nicht.

    Beim Mandatory Locking kann jede Applikation lesen und schreiben, auch wenn Sperren bestehen.
    Linux geht hier ohnehin von einem anderen Ansatz aus:
    Alle Dateien, die zum Lesen UND Schreiben erreichbar sind, sind geminsames Gut und daher auch gemeinschaftlich pfleglich zu behandeln. Wenn ein User eine Datei nbicht beschreiben darf, dann nimmt man ihm das w-Recht im Dateisystem.

    Da PHP(Modul) und der Apache hier im Normalfall aber alle Anfragen über HTTP ein und demselben User zuordnen, muss man auf Applikationsebene agieren. Ich würde daher den Rat geben, alle Dateien, die über HTTP geöffnet werden sollen, immer dem Mandatory-Zyklus zu unterwerfen. JEDE Applikation, die Zugriff nehmen darf, MUSS sich daran halten, sonst hat es keinen  Zweck.

    Mach Die also von Anfang an zur Gewohnheit, die Sperren zu setzen, abzufragen und zu beachten. Das erspart Dir später Kummer, wenn das System wächst.

    Harzliche Grüße vom Berg
    http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau

    1. Hello,

      sollte natürlich heißen:

      Beim Advisory Locking kann jede Applikation lesen und schreiben, auch wenn Sperren bestehen.

      Linux geht hier ohnehin von einem anderen Ansatz aus:
      Alle Dateien, die zum Lesen UND Schreiben erreichbar sind, sind geminsames Gut und daher auch gemeinschaftlich pfleglich zu behandeln. Wenn ein User eine Datei nbicht beschreiben darf, dann nimmt man ihm das w-Recht im Dateisystem.

      Harzliche Grüße vom Berg
      http://www.annerschbarrich.de

      Tom

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau