OLZU: Frage zu flock()

Hallo zusammen.

Auf einer Website hab ich einen Download-Counter (für mp3-Dateien) mit PHP realisiert.
Das ist ein ganz einfaches Script, das eine Text-Datei öffnet, den Zählerstand
ausliest, hochzählt und dann den neuen Wert und einige andere Details, z.B. die
IP-Adresse u.ä. (zur Befriedigung meiner persönlichen Neugierde) wieder zurückschreibt.
Dann wird per header() auf die mp3-Datei weitergeleitet.
So far, so good...

Vielleicht könnt mir folgende Fragen dazu beantworten:

1.)
Was passiert, wenn zwei (oder mehre) Leute gleichzeitig einen Download starten,
also zur gleichen Zeit auf die Text-Datei zugreifen?

2.)
Was genau würde es bringen, die Text-Datei mit der Funktion flock() zu sperren?

3.)
Was passiert, wenn das PHP-Script auf eine mit flock() gesperrte Datei zugreifen will?
Bricht das Script ab, verweigert also den Download der mp3-Datei?
Oder wird gewartet bis die Datei wieder "frei" ist?
Bekommt der User irgendeine Fehlermeldung zu sehen?

Fragen über Fragen, vielleicht kann sie mir auch jemand beantworten...  :-)

Vielen Dank im Voraus und euch allen noch einen schönen Ostermontag.

Gruß
OLZU

  1. Hi!

    1.)
    Was passiert, wenn zwei (oder mehre) Leute gleichzeitig einen Download starten,
    also zur gleichen Zeit auf die Text-Datei zugreifen?

    Das ist relativ unwahrscheinlich, wenn die Anfragen sehr kurz sind, und trotzdem ist es besser, eine Sicherung zu programmieren, wie du vorschlägst.

    2.)
    Was genau würde es bringen, die Text-Datei mit der Funktion flock() zu sperren?

    Die Datei ist dann im internen System gesperrt und kann nicht mehr von anderen PHP-Dateien gelesen bzw. beschrieben werden.

    3.)
    Was passiert, wenn das PHP-Script auf eine mit flock() gesperrte Datei zugreifen will?
    Bricht das Script ab, verweigert also den Download der mp3-Datei?
    Oder wird gewartet bis die Datei wieder "frei" ist?
    Bekommt der User irgendeine Fehlermeldung zu sehen?

    PHP verweigert dann sicherlich den Zugriff und wird lediglich eine Fehlermeldung "Konnte nicht auf Datei xyz zugreifen, da..." (oder so etwas) ausgeben.
    Es wird sicherlich nicht immer weiter warten, bis die Datei wieder frei ist.
    Das kannst du aber programmieren, indem du einfach eine Schleife programmierst, in der die Datei versucht wird zu öffnen (vielleicht so etwa 10 Versuche maximal, so würde ich es zumindest machen).
    Bei positivem Ergebnis wird die Datei dann gelockt, beschrieben [gelesen], entlockt und (wichtig!!!) geschlossen.

    cu, hoffe es hilft!

    Marc Reichelt || http://www.step2identity.com/

    --
    Linux is like a wigwam - no windows, no gates and an Apache inside!!!
    1. Hallo Marc,

      vielen Dank für deine informativen Antworten.

      PHP verweigert dann sicherlich den Zugriff und wird lediglich eine Fehlermeldung "Konnte nicht auf Datei xyz zugreifen, da..." (oder so etwas) ausgeben.
      Es wird sicherlich nicht immer weiter warten, bis die Datei wieder frei ist.
      Das kannst du aber programmieren, indem du einfach eine Schleife programmierst, in der die Datei versucht wird zu öffnen (vielleicht so etwa 10 Versuche maximal, so würde ich es zumindest machen).
      Bei positivem Ergebnis wird die Datei dann gelockt, beschrieben [gelesen], entlockt und (wichtig!!!) geschlossen.

      Die Idee ist gut - so werde ich das wohl probieren.
      Das werde ich auch hinbringen, evtl. hast du aber schon ein Bsp. griffbereit...  :-))

      Nur eine Frage noch:
      Wie frage ich in der Schleife ab, ob die Datei "gelockt" ist, bzw. wie finde ich
      heraus, ob die Datei erfolgreich geöffnet wurde?

      Danke nochmals.

      Gruß
      OLZU

  2. Hi!

    Ich hatte das Problem auch mal, da ging es um notwendigerweise unique IDs, bei einem Counter ist es ja nicht _ganz_ so wichtig.

    Die einzige 100%ige Möglichkeit die ich gefunden habe war folgende:

    Du erstellst eine extra-Lock Datei, "lock"

    Dann lockst Du diese Datei für Lesezugriffe, erhöhst Deine Counter-Datei, und danach unlockst Du die "lock"-Datei wenn Du mit dem Counter fertig bist. Alle anderen Prozesse warten also so lange sie keinen Zugriff auf die "lock"-Datei haben.

    Grüße
    Andreas

    1. Hallo Andreas,

      auch dir vielen Dank für deine Antwort...

      Du erstellst eine extra-Lock Datei, "lock"

      Dann lockst Du diese Datei für Lesezugriffe, erhöhst Deine Counter-Datei, und danach unlockst Du die "lock"-Datei wenn Du mit dem Counter fertig bist. Alle anderen Prozesse warten also so lange sie keinen Zugriff auf die "lock"-Datei haben.

      ... aber um ehrlich zu sein:
      Ich verstehe überhaupt nicht, was du mir sagen willst...  :-(
      Kannst mir das evtl. nochmals (mit Bsp?) erklären.

      Danke und Gruß
      OLZU

      1. Hi!

        ... aber um ehrlich zu sein:
        Ich verstehe überhaupt nicht, was du mir sagen willst...  :-(
        Kannst mir das evtl. nochmals (mit Bsp?) erklären.

        Kein Problem *kram...*

        $lock = fopen("lock", "w+");  //öffne Datei "lock"
        flock($lock, LOCK_EX);  // Sperre Datei "lock" exklusiv
        $fp = fopen("count.txt", r);  // öffne counter-Datei lesend
        if($fp) {
          $count = fread($fp, filesize("count.txt"));  // lese counter
          fclose($fp);  // schließe counter-Datei
        }
        $count++;  // erhöhe counter
        $fp = fopen("count.txt", "w");  // öffne counter-Datei schreibend
        if($fp) {
          fputs($fp, $count);  // schreibe neuen counter
          fclose($fp);  // schließe counter-Datei
        }
        fclose($lock);  // schließe Datei "lock" und gebe somit Datei für andere Prozesse frei

        Alle Prozesse warten so lange bis die Datei "lock" wieder geschlossen wurde, wenn sie den Counter verändern wollen.

        Grüße
        Andreas

        1. Nochmals hallo.

          Vielen Dank für deine Bemühungen.

          $lock = fopen("lock", "w+");  //öffne Datei "lock"
          flock($lock, LOCK_EX);  // Sperre Datei "lock" exklusiv
          $fp = fopen("count.txt", r);  // öffne counter-Datei lesend
          if($fp) {
            $count = fread($fp, filesize("count.txt"));  // lese counter
            fclose($fp);  // schließe counter-Datei
          }
          $count++;  // erhöhe counter
          $fp = fopen("count.txt", "w");  // öffne counter-Datei schreibend
          if($fp) {
            fputs($fp, $count);  // schreibe neuen counter
            fclose($fp);  // schließe counter-Datei
          }
          fclose($lock);  // schließe Datei "lock" und gebe somit Datei für andere Prozesse frei

          Ähhh, ich hab's immer noch nicht ganz verstanden...  :-(
          (Vielleicht liegt's auch daran, daß ich langsam sehr müde werde und eigentlich
          nicht mehr klar denken kann.)

          Kannst du mir bitte trotzdem diese Fragen beantworten:

          1.) Die Datei "lock" sieht wie aus? Welches Format, welcher Inhalt?

          2.) Warum öffnest du die Counter-Datei zweimal und nicht nur einmal (mit "r+")?

          3.) Warum "schützt" das Sperren der Datei "lock" die Datei count.txt?

          Wenn du es nicht für komplett sinnlos hälst würde ich mich über deine Antworten
          freuen...   :-)

          Gruß
          OLZU

          1. Hi!

            1.) Die Datei "lock" sieht wie aus? Welches Format, welcher Inhalt?

            nix, die Datei ist leer. Hast Du nix mit zu tun, PHP erstellt einfach ne leere Datei.

            2.) Warum öffnest du die Counter-Datei zweimal und nicht nur einmal (mit "r+")?

            Weiß ich gerade nicht, aber das ging glaube ich irgendwie nicht.

            3.) Warum "schützt" das Sperren der Datei "lock" die Datei count.txt?

            Das funktioniert nur wenn Du immer diese Datei "lock" sperrst, also immer so wie oben schreibend drauf zugreifst. Beim nur-lesen ist es egal. Alle anderen Requests müssen dann halt immer so lange warten bis die Sperre auf "lock" aufgehoben wurde, wenn sie in die Datei "count.txt" schreiben wollen.  Wenn man die Datei count.txt sperren würde ändert das nichts daran dass theoretisch innerhalb von millisekunden 2 Prozesse den gleichen Wert aus count.txt lesen knnten, und zwar wenn nach fopen("count.txt") und noch vor flock ein anderer Prozess ebenfalls fopen("count.txt") versucht. Wobei, im Augenblick bin ich gar nicht mehr sicher ob das nötig ist, denn eigenlich sollte der Prozess der als 2. flock ausführt erst dann lesen können, wenn der LOCK des 1. Prozesses beendet wurde. Hm, vielleicht lag es doch daran das ein fopen("count.txt", "r+") nicht funktioniert und so der LOCK nicht während des ganzen Vorgangs aufrecht erhalten werden kann, bin mir da gerade nicht mehr so sicher... mit der "lock"-Datei ist es jedenfalls 100%ig.

            Wenn du es nicht für komplett sinnlos hälst würde ich mich über deine Antworten freuen...   :-)

            Quatsch, wer vernünftig fragt bekommt ne vernünftige Antwort ;-)

            Grüße
            Andreas