Laurin: Einfacher PHP Counter

Hey,
ich habe folgendes Script geschrieben:

  
<?php  
            $datei = fopen("counter.txt","r+");  
            $counterstand = fgets($datei, 10);  
  
    if ($_COOKIE['User'] != '10')  
        {  
            $counterstand++;  
            setcookie("User", "10", time()+60*60*24);  
            echo "<br><p class=\"artikel\">Besucher:<br>$counterstand</p>";  
            rewind($datei);  
            fwrite($datei, $counterstand);  
            fclose($datei);  
        }  
    else  
        {  
            echo "<br><p class=\"artikel\">Besucher:<br>$counterstand</p>";  
            rewind($datei);  
            fwrite($datei, $counterstand);  
            fclose($datei);  
            }  
?>  

Doch irgendwo muss ein Fehler sein, da der Zähler jeden klick zählt!..
Vielleicht kann mir jemand weiterhelfen.

PS: Gutes Neues!

Grüße
Laurin

  1. Hallo,

    vielleicht erstmal an der Übersicht arbeiten und mit PHP5?

      
    <?php  
       $counterFileName = "counter.txt";  
    	$counterstand = (int) file_get_contents($counterFileName);  
        if ($_COOKIE['User'] != '10') {  
             $counterstand++;  
             setcookie("User", "10", time()+60*60*24);  
    	} else {  
    		file_put_contents($counterFileName, $counterstand);  
    	}  
    ?>  
    <br><p class="artikel">Besucher:<br><?=$counterstand?></p>  
    
    

    und mal

    var_dump($_COOKIE) testen ...;

    error_reporting (E_NOTICE, E_ALL) auch immer gut.

    Gruß

    jobo

    1. Hier die fertige Lösung:

        
      <?php  
         $counterFileName = "counter.txt";  
        
      		$counterstand = (int) file_get_contents($counterFileName);  
      		  
          if ($_SESSION['count'] != 'count') {  
              $counterstand++;  
        
              session_start();  
      		$_SESSION['count']='count';  
        
              } else {  
                      fclose ($counterstand);  
              }  
      ?>  
      <br><p class="artikel">Besucher:<br><?=$counterstand?></p></body></html>  
      
      

      Danke an Jobo!

      Gruß
      Laurin

      1. Hi!

        Hier die fertige Lösung:

        die aber fehlerhaft ist.

        [code lang=php]<?php
           $counterFileName = "counter.txt";

          $counterstand = (int) file\_get\_contents($counterFileName);  
        

        Wenn counter.txt nicht vorhanden ist, müsste dieser Zugriffsversuch eine Warnung erzeugen.

        if ($_SESSION['count'] != 'count') {
                $counterstand++;

        session_start();

        Eine Session muss geöffnet werden, bevor sinnvollerweise Werte in $_SESSION gelesen und geschrieben werden. Außerdem ist nach einer neu erstellten Session $_SESSION leer, ein Leseversuch eines in dem Fall nicht vorhandenen Wertes ist im Prinzip ein Fehler, der auch eine E_NOTICE-Meldung ergibt, die PHP jedoch üblicherweise nicht anzeigt. (error_reporting zum Entwickeln auf E_ALL stellen!)

          $\_SESSION['count']='count';  
        

        } else {
                        fclose ($counterstand);

        $counterstand ist der Zählerwert und kein File-Handle, kann also nicht geschlossen werden. Und was ist nun mit dem inkrementierten Zählerwert? Er wird nicht weggeschrieben. Die Anzeige wird deswegen nicht über 1 hinauskommen. Und selbst wenn du das fclose() durch einen richtig notierten file_put_contents()-Aufruf ersetzt, kann es Situationen geben, in denen der Zähler nicht hochzählt - nämlich dann, wenn zwei Anwender nahezu gleichzeitig zugreifen und die eine Scriptinstanz ihren inkrementierten Wert wegschreibt, nachdem die andere Instanz den immer noch gleichen Wert aus der Datei gelesen hat. Solche Fehler lassen sich sehr schwer finden, weil sich solche Situationen üblicherweise im Laborbetrieb nicht auftreten und sich auch nicht besonders einfach nachstellen lassen. Vermutlich kommt es bei diesem Zähler auf diese Ungereimtheit nicht an, wenn du es aber ordentlich lösen willst, wäre eine exklusive Sperre von vor dem Lesen bis zum Datei-Schließen angebracht.

        Lo!

        1. Hallo,

          das mit der Sperre würde ich lassen (bei einem einfachen Zähler, dazu ist das Skript auch zu kurz und zu schnell). Der Rest ist aber korrekt. Das war auch in meinem Beispiel vorhanden. Session ganz zu beginn starten, error_reporting zum Testen entsprechend einschalten, die Datei muss nicht geschlossen werden!

          Gruß

          jobo

          1. Hi,

            das mit der Sperre würde ich lassen (bei einem einfachen Zähler, dazu ist das Skript auch zu kurz und zu schnell).

            grundsätzlich ist der Einwand aber schon berechtigt. Die Frage ist aber hier tatsächlich, ob das Verhältnis von Aufwand und Nutzen gerechtfertigt ist. Was macht es schon, wenn wegen eines Nebenläufigkeits-Problems mal ein Seitenaufruf nicht gezählt wird? Anders sieht's aus, wenn es um Nutzdaten geht, die dadurch verfälscht werden oder verlorengehen könnten.

            die Datei muss nicht geschlossen werden!

            Zur Klarheit: Offene Dateien und andere Ressourcen werden beim Beenden des Scripts automatisch geschlossen; es ist aber guter Stil, das trotzdem selbst zu tun und sich nicht auf die Putztruppe zu verlassen.
            Allerdings schließen die atomaren Funktionen wie file(), file_get_contents() oder file_put_contens() die Datei schon selbst wieder, bevor die Funktion überhaupt zurückkehrt. Deswegen haben diese Funktionen es auch nicht nötig, ein Dateihandle zu liefern.

            Ciao,
             Martin

            --
            Lieber Blödeleien als blöde Laien.
            Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
            1. Hello,

              grundsätzlich ist der Einwand aber schon berechtigt. Die Frage ist aber hier tatsächlich, ob das Verhältnis von Aufwand und Nutzen gerechtfertigt ist. Was macht es schon, wenn wegen eines Nebenläufigkeits-Problems mal ein Seitenaufruf nicht gezählt wird? Anders sieht's aus, wenn es um Nutzdaten geht, die dadurch verfälscht werden oder verlorengehen könnten.

              Da fehlt jetzt aber irgendwie das Ironie-Flag, oder?

              Es ist überhaupt nicht sichergestellt, dass "nur nicht gezählt" wird. Die Datei kann auch zerstört werden durch einen unglücklichen gleichen Zugriff und dann wird falsch gezählt. Da können dann schon leicht mal 1000de von Aufrufen zusätzlich hinzugemogelt werden.

              Apache bietet ein wunderbares Werkzeug, um sowas zu testen und Fehler zu provozieren

              ab

              Apache Benchmark.

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
               ☻_
              /▌
              / \ Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
              1. Hallo,

                grundsätzlich ist der Einwand aber schon berechtigt. Die Frage ist aber hier tatsächlich, ob das Verhältnis von Aufwand und Nutzen gerechtfertigt ist. Was macht es schon, wenn wegen eines Nebenläufigkeits-Problems mal ein Seitenaufruf nicht gezählt wird? Anders sieht's aus, wenn es um Nutzdaten geht, die dadurch verfälscht werden oder verlorengehen könnten.

                Da fehlt jetzt aber irgendwie das Ironie-Flag, oder?

                Es ist überhaupt nicht sichergestellt, dass "nur nicht gezählt" wird. Die Datei kann auch zerstört werden durch einen unglücklichen gleichen Zugriff und dann wird falsch gezählt.

                Das glaube ich bei file_get/put_contents nicht.

                Gruß

                jobo

              2. Hi,

                Was macht es schon, wenn wegen eines Nebenläufigkeits-Problems mal ein Seitenaufruf nicht gezählt wird? Anders sieht's aus, wenn es um Nutzdaten geht, die dadurch verfälscht werden oder verlorengehen könnten.
                Da fehlt jetzt aber irgendwie das Ironie-Flag, oder?

                nein, überhaupt nicht.

                Es ist überhaupt nicht sichergestellt, dass "nur nicht gezählt" wird. Die Datei kann auch zerstört werden durch einen unglücklichen gleichen Zugriff

                Das erklär mir mal - unter der Annahme, dass nur der PHP-Prozess auf die Counterdatei zugreift, das aber gern in mehreren Script-Instanzen überlappend. Wir haben fünf Schritte:

                1. open
                 2. read
                 3. rewind
                 4. write
                 5. close

                Schritt 3 und 4 werden übersprungen, wenn nicht gezählt werden soll. Theoretisch kann diese Schrittkette an jeder Stelle unterbrochen und von einer weiteren Script-Instanz neu begonnen werden. Es kann nie etwas Schlimmeres passieren, als dass der Zählerwert um die Anzahl der gleichzeitig-überlappend laufenden Script-Instanzen "nachgeht". Die Sicherstellung der Integrität des Dateisystems an sich liegt dabei natürlich in der Verantwortung des Betriebssystems, jeder der fünf Schritte muss für sich betrachtet atomar sein.

                und dann wird falsch gezählt. Da können dann schon leicht mal 1000de von Aufrufen zusätzlich hinzugemogelt werden.

                Eher schon ein paar fehlen.

                Aber selbst wenn du Recht hast: Was macht's? Es soll ein Zugriffszähler sein, dessen Sinn und Wert von vornherein fragwürdig ist, und dessen Zählwert sowieso nur als Schätzbasis für den Betreiber der Site dienen kann. Das meinte ich mit dem Verhältnis von Aufwand und Nutzen. Das ist so, als würde ich meine Gartenlaube mit Sicherheitsschloss, Netzhautscanner und Alarmanlage ausrüsten, obwohl nur eine Hacke und ein Spaten drinstehen.

                Liebe Grüße aus dem schönen Oberharz

                ... wo's jetzt bestimmt noch viel Schnee hat und ekelhaft kalt ist. :-)

                Ciao,
                 Martin

                --
                Die Natur ist gnädig: Wer viel verspricht, dem schenkt sie zum Ausgleich ein schlechtes Gedächtnis.
                Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
                1. Hello,

                  Das erklär mir mal - unter der Annahme, dass nur der PHP-Prozess auf die Counterdatei zugreift, das aber gern in mehreren Script-Instanzen überlappend. Wir haben fünf Schritte:

                  1. open
                  2. read
                  3. rewind
                  4. write
                  5. close

                  Schritt 3 und 4 werden übersprungen, wenn nicht gezählt werden soll. Theoretisch kann diese Schrittkette an jeder Stelle unterbrochen und von einer weiteren Script-Instanz neu begonnen werden. Es kann nie etwas Schlimmeres passieren, als dass der Zählerwert um die Anzahl der gleichzeitig-überlappend laufenden Script-Instanzen "nachgeht". Die Sicherstellung der Integrität des Dateisystems an sich liegt dabei natürlich in der Verantwortung des Betriebssystems, jeder der fünf Schritte muss für sich betrachtet atomar sein.

                  Das liegt zum ersten mal am Format, in dem geschrieben wird.
                  Hier wird mit dem PHP-Standard gearbeitet. Der schreibt human readable numbers, also Klartext.

                  Bei einer einzigen Zahl in der Datei ist das System zugegebenermaßen nur "ein bisschen schwanger".

                  Der Zeitablauf könnte so aussehen.

                  0
                  A  1
                  B  2
                  B  ...
                  B  10
                  A  20

                  A holt sich die 0 und schreibt ungestört die 1
                  B holt sich die 1
                  A holt sich die 1
                  B schreibt die 2
                  B holt sich die 2
                  B schreibt die 3
                  ...
                  B schreibt die 10
                  A schreibt die 2, die Null von B's 10 wird nicht überschrieben. So wird aus der 10 eine 20.

                  Das soll jetzt nur die Fehlermöglichkeit verdeutlichen. Warum A solange vom Schreiben abgehalten wurde, ist hier nebensächlich.

                  Wenn man mehr als einen Wert in der Datei hält, wird es noch chaotischer.

                  Warum Du dich nun so dagegebn wärst, es den OP richtig machen zu lassen, verstehe ich allerdings nicht. Ein simples

                  flock($fh, LOCK_EX);

                  vor dem Auslesen zum anschließenden Schreiben reicht doch dafür völlig. Das ist doch kein Aufwand.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                   ☻_
                  /▌
                  / \ Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Hi,

                    Das erklär mir mal [...] Die Sicherstellung der Integrität des Dateisystems an sich liegt dabei natürlich in der Verantwortung des Betriebssystems, jeder der fünf Schritte muss für sich betrachtet atomar sein.
                    Das liegt zum ersten mal am Format, in dem geschrieben wird.
                    Hier wird mit dem PHP-Standard gearbeitet. Der schreibt human readable numbers, also Klartext.

                    das spielt aber keine Rolle.

                    ...
                    B schreibt die 10
                    A schreibt die 2, die Null von B's 10 wird nicht überschrieben. So wird aus der 10 eine 20.

                    Geht nicht, da die write-Aufrufe, wie im vorigen Posting schon als Notwendigkeit formuliert, atomar sind. A schreibt seine 2 also schlimmstenfalls hinter das Trennzeichen (Zeilenumbruch) nach der 10, die B geschrieben hat. Das richtet keinen Schaden an.

                    Wenn man mehr als einen Wert in der Datei hält, wird es noch chaotischer.

                    Wenn man mehr als einen Wert in einer Datei hält, kann es überhaupt erst zu Konflikten kommen.

                    Warum Du dich nun so dagegebn wärst, es den OP richtig machen zu lassen, verstehe ich allerdings nicht.

                    "wärst"? Du meinst "wehrst"?
                    Ich wehre mich nicht dagegen, ich find's ja okay. Ich halte nur den dafür nötigen Aufwand, gemessen am Nutzen der Gesamtoperation, für übertrieben - genauso wie ich nie auf die Idee käme, eine Steckdose auf dem Balkon zu installieren, nur damit ich im Sommer einmal mit Notebook und allem Zubehör draußen sitzen kann.

                    Ein simples

                    flock($fh, LOCK_EX);

                    vor dem Auslesen zum anschließenden Schreiben reicht doch dafür völlig. Das ist doch kein Aufwand.

                    Nur dass man flock() in einer Schleife so lange wiederholen muss, bis es true liefert (was wohl oft schon beim ersten Aufruf der Fall sein dürfte).

                    So long,
                     Martin

                    --
                    Zwei Stammtischbrüder:
                    Hier steht, dass laut Statistik über 60 Prozent aller Ehefrauen fremdgehen.
                    Was soll ich mit dieser Information? Ich brauche Namen, Fotos, Telefonnummern ... !
                    Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
                    1. Hello,

                      Das erklär mir mal [...] Die Sicherstellung der Integrität des Dateisystems an sich liegt dabei natürlich in der Verantwortung des Betriebssystems, jeder der fünf Schritte muss für sich betrachtet atomar sein.
                      Das liegt zum ersten mal am Format, in dem geschrieben wird.
                      Hier wird mit dem PHP-Standard gearbeitet. Der schreibt human readable numbers, also Klartext.

                      das spielt aber keine Rolle.

                      Wie kommst Du darauf?

                      ...
                      B schreibt die 10
                      A schreibt die 2, die Null von B's 10 wird nicht überschrieben. So wird aus der 10 eine 20.

                      Geht nicht, da die write-Aufrufe, wie im vorigen Posting schon als Notwendigkeit formuliert, atomar sind.

                      Was hindert einen in sich atomaren Schreibvorgang, mitten in eine Datei zu schreiben, die in einem anderen Prozess gerade im entstehen ist?

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                       ☻_
                      /▌
                      / \ Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                    2. Hi!

                      Ein simples
                          flock($fh, LOCK_EX);
                      vor dem Auslesen zum anschließenden Schreiben reicht doch dafür völlig. Das ist doch kein Aufwand.
                      Nur dass man flock() in einer Schleife so lange wiederholen muss, bis es true liefert (was wohl oft schon beim ersten Aufruf der Fall sein dürfte).

                      Nein. LOCK_EX ist blocking, wartet also darauf, dass es die Freigabe bekommt. Ob es ein Timeout gibt, wenn das zu lange dauert, steht nicht im PHP-Handbuch. Einige User-Kommentare sagen, dass da nur die generelle Script-Laufzeitbegrenzung einen Abbruch hervorruft.

                      Lo!

                      1. Hallo,

                        flock($fh, LOCK_EX);
                        Nur dass man flock() in einer Schleife so lange wiederholen muss, bis es true liefert (was wohl oft schon beim ersten Aufruf der Fall sein dürfte).
                        Nein. LOCK_EX ist blocking, wartet also darauf, dass es die Freigabe bekommt.

                        danke, das kommt davon, wenn man nur oberflächlich liest:

                        "By default, this function will block until the requested lock is acquired"

                        Das steht in einem Absatz, in dem andererseits LOCK_NB prominent hervorgehoben ist, daher dachte ich beim ersten Lesen, das obige Verhalten gelte speziell bei der Verwendung von LOCK_NB, und sonst nicht. Ich hatte mir noch keine Gedanken gemacht, wofür "NB" wohl stehen könnte. ;-)

                        So long,
                         Martin

                        --
                        Wer barfuß geht, dem kann man nicht die Schuld in die Schuhe schieben.
                        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
          2. Hi!

            das mit der Sperre würde ich lassen (bei einem einfachen Zähler, dazu ist das Skript auch zu kurz und zu schnell).

            Die Abarbeitungsdauer hat auf einem Multiprozess- und Multithread-System nicht direkt etwas mit der Kürze des Codes zu tun, denn die hat keinen Einfluss darauf, wie lange sich der Prozessor zwischendurch anderen Aufgaben widmet.

            die Datei muss nicht geschlossen werden!

            Im Prinzip stimmt das, denn sie wird am Scriptende von PHP geschlossen, wenn das noch nicht erfolgte. Die Frage ist, wie lange das Script nach dem Schreiben der Datei noch weiterläuft und es somit Gelegenheit zu weiteren zufälligen Nebenläufigkeitsproblemen gibt.

            Lo!

            1. Hallo,

              Im Prinzip stimmt das, denn sie wird am Scriptende von PHP geschlossen, wenn das noch nicht erfolgte. Die Frage ist, wie lange das Script nach dem Schreiben der Datei noch weiterläuft und es somit Gelegenheit zu weiteren zufälligen Nebenläufigkeitsproblemen gibt.

              Ach so. Ich dachte file_get_contents macht genau das, was es sagt, nämlich open, read, close. ich erhalte ja kein Filehandle.

              Gruß

              jobo

              1. Hi,

                Im Prinzip stimmt das, denn sie wird am Scriptende von PHP geschlossen, wenn das noch nicht erfolgte. Die Frage ist, wie lange das Script nach dem Schreiben der Datei noch weiterläuft und es somit Gelegenheit zu weiteren zufälligen Nebenläufigkeitsproblemen gibt.
                Ach so. Ich dachte file_get_contents macht genau das, was es sagt, nämlich open, read, close.

                das ist auch so.

                ich erhalte ja kein Filehandle.

                Sag ich doch. :-)

                Ciao,
                 Martin

                --
                Mir geht es gut. Ich mag die kleinen Pillen, die sie mir dauernd geben.
                Aber warum bin ich ans Bett gefesselt?
                Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
                1. Hallo,

                  das ist auch so.

                  ich erhalte ja kein Filehandle.

                  Sag ich doch. :-)

                  Zu spät gelesen (;-).

                  Gruß

                  jobo

              2. Hi!

                Im Prinzip stimmt das, denn sie wird am Scriptende von PHP geschlossen, wenn das noch nicht erfolgte. Die Frage ist, wie lange das Script nach dem Schreiben der Datei noch weiterläuft und es somit Gelegenheit zu weiteren zufälligen Nebenläufigkeitsproblemen gibt.
                Ach so. Ich dachte file_get_contents macht genau das, was es sagt, nämlich open, read, close. ich erhalte ja kein Filehandle.

                Ja, A erhält den Dateiinhalt. B erhält auch den (selben) Dateininhalt. Nun schreibt A die Datei neu mit x+1, B macht nun genau das selbe, ebenfalls mit x+1 und nicht etwa mit (x+1)+1. file_get_contents() ist zwar in sich atomar, aber der insgeamt gewünschte Vorgang ist es nicht.

                Was ich aber meinte: Wenn du die Datei mit fopen() offen hast und Änderungen vornimmst, ist nicht garantiert, dass fwrite() die Datei auch sofort auf der Platte ändert. Es kann da nämlich noch ein Puffer aktiv sein, der erst mit fclose() oder einem fflush() garantiert geleert wird. Erst dann darf die Datei wieder gelesen werden. Wenn nun das fclose() implizit durch das Scriptende passiert und dieses noch ein paar Zeiteinheiten entfernt ist, lesen andere Zugreifer einen falschen Dateininhalt. Insbesondere bei der Handvoll Bytes, die der Zähler-Integer groß ist, wird der Puffer nicht gefüllt und damit ist mit einem Schreiben auf Platte erst beim (impliziten) fclose() zu rechnen.

                Wie gesagt, beim Zähler ist es nicht tragisch, wenn da mal ein Zugriff verloren geht. Es gibt jedoch andere Anwendungen, bei denen das kritischer ist und deswegen versuche ich das hier etwas genauer als für den Zähler notwendig zu erklären.

                Lo!

                1. Hallo,

                  Wie gesagt, beim Zähler ist es nicht tragisch, wenn da mal ein Zugriff verloren geht. Es gibt jedoch andere Anwendungen, bei denen das kritischer ist und deswegen versuche ich das hier etwas genauer als für den Zähler notwendig zu erklären.

                  Ja, das ist schon richtig so, auch darauf hinzuweisen. Nur das fclose() passt (s. Martin) nicht zum file_get_contents(). Da gibts ja nix zu closen. Deshalb in meinem neuen Beispiel auch das error_reporting angestellt.

                  Gruß

                  jobo

                  1. Hi!

                    Wie gesagt, beim Zähler ist es nicht tragisch, wenn da mal ein Zugriff verloren geht. Es gibt jedoch andere Anwendungen, bei denen das kritischer ist und deswegen versuche ich das hier etwas genauer als für den Zähler notwendig zu erklären.
                    Ja, das ist schon richtig so, auch darauf hinzuweisen. Nur das fclose() passt (s. Martin) nicht zum file_get_contents(). Da gibts ja nix zu closen.

                    Deswegen kann man in der Richtig-Mach-Lösung auch nicht file_*_contents() verwenden, sondern muss den herkömmlichen Weg über fopen() gehen und dabei noch flock() hinzufügen.

                    Lo!

                    1. Hallo,

                      Hi!

                      Wie gesagt, beim Zähler ist es nicht tragisch, wenn da mal ein Zugriff verloren geht. Es gibt jedoch andere Anwendungen, bei denen das kritischer ist und deswegen versuche ich das hier etwas genauer als für den Zähler notwendig zu erklären.
                      Ja, das ist schon richtig so, auch darauf hinzuweisen. Nur das fclose() passt (s. Martin) nicht zum file_get_contents(). Da gibts ja nix zu closen.

                      Deswegen kann man in der Richtig-Mach-Lösung auch nicht file_*_contents() verwenden, sondern muss den herkömmlichen Weg über fopen() gehen und dabei noch flock() hinzufügen.

                      Echt? Wieso kann ich nicht ein Lockfile setzen und das am Ende wieder löschen?

                      Gruß

                      jobo

                      1. Hi!

                        [...] sondern muss den herkömmlichen Weg über fopen() gehen und dabei noch flock() hinzufügen.
                        Echt? Wieso kann ich nicht ein Lockfile setzen und das am Ende wieder löschen?

                        Meinetwegen kannst du auch ein Lockfile oder eine andere Sperrmaßnahme ergreifen, aber einfacher wird das Handling dadurch nicht.

                        Lo!

                        1. Hallo,

                          Hi!

                          [...] sondern muss den herkömmlichen Weg über fopen() gehen und dabei noch flock() hinzufügen.
                          Echt? Wieso kann ich nicht ein Lockfile setzen und das am Ende wieder löschen?

                          Meinetwegen kannst du auch ein Lockfile oder eine andere Sperrmaßnahme ergreifen, aber einfacher wird das Handling dadurch nicht.

                          Das mag wohl sein.

                          Gruß

                          jobo

                2. Hallo,

                  hatte grade Crockford on Javascript Loops gesehen (inklusive eines Teils über Blockade beim Lesen und Schreiben). In dem Slide-PDFauf Seite 33 findet sich ein Beispiel mit zwei Threads und zwei Zugriffen. "Almost impossible to find" - meint er, den Fehler, der in dem Fall u.U. noch alteriert, also mal a, mal b ausspuckt, statt das array a, b.

                  Gruß

                  jobo

              3. Hello,

                Ach so. Ich dachte file_get_contents macht genau das, was es sagt, nämlich open, read, close. ich erhalte ja kein Filehandle.

                file_get_contents() ist deshalb auch ungeeignet für die vorgesehene Anwendung

                ## Daten holen
                  ## Daten manipulieren
                  ## Daten wegschreiben ins selbe File

                Hier MUSS zwingend eine Maßnahme ergriffen werden, die die drei Teule der Sequenz zu einem atomistischen Prozess zusammenschweißt. Und bei den bei PHP üblichen advisory Locks müssen sich alle Prozesse, die mit der Datei arbeiten, daran halten.

                Bei Verwendung der DIO-Funktionen von PHP, die 1. mit installiert werden müssen und 2. auf Linuxrechnern ein spezielles Mounting erforderlich machen, ist dies nicht mehr möglich, da hier das OS direkt den Zugriffsschutz gegen andere Prozesse gewährleistet, wenn ein einzelner einnen Lock angefordert und erhalten hat.

                Bei WinDOS ist dieses mandatory Locking im Prinzip Standard. Wie PHP das nun genau auf das advisory Locking abbildet, habe ich vergessen...

                Liebe Grüße aus dem schönen Oberharz

                Tom vom Berg

                --
                 ☻_
                /▌
                / \ Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de
          3. Hello,

            das mit der Sperre würde ich lassen (bei einem einfachen Zähler, dazu ist das Skript auch zu kurz und zu schnell).

            Das mit dem Posten würde ich dann auch besser lassen. Dazu war das Posting zu kurz und zu unsinnig ;-)

            Beim Programmieren ist es ähnlich, wie beim Pimpern. Es gibt zwar verschiedene Methoden, Vater zu werden, aber die Betroffene wird kaum sagen: Jetzt bin ich n8r ein bisschen Schawanger, das vergessen wir mal lieber ganz schnell.

            Beim Programmieren gibt es daher auch nur "richtig" oder "falsch". Ein bisschen richtig ist immer automatisch falsch, genauso, wie ein bisschen schwanger auch immer schwanger bedeutet.

            Zurück zum Thema:
            Wenn also Nebenläufigkeit beachtet werden muss, dann muss man die passenden Maßnahmen ergreifen, um es richtig zu machen.

            Es ist hingegen nicht notwendig bei diesem Script (wenn es denn mal endlich ordentlich notiert wurde), die Gründe für eine Sperre zu erfragen und darauf zu ragieren, also mit einem "Non Blocking Lock" zu arbeiten. Ein Blocking Lock, der durch ein einfaches

            $fh = fopen($filename, 'cb+'); ## [3]

            if (flock($fh, LOCK_EX))
               {
                   ## Daten holen

            ## Daten manipulieren

            ## File zurückspulen  ## [1a]

            ## Daten wegschreiben

            ## Filelänge anpassen  ## [1a]

            ## File schließen und _damit_ auch das Lock wiederhergeben [2]
               }

            [1] kann auch unter a zu einem Truncate() zusammengefasst werden

            [2] i.d.R. ist es falsch, das Lock gesondert wieder aufzuheben, da dann zumindest
                vorher noch ein flush() notwendig wäre, aber auch anschließend nicht wieder
                geschrieben werden darf!

            [3] Bitte auch mal die neuen Openmodes 'x', 'x+' und 'c', 'c+' beachten
                http://de2.php.net/manual/en/function.fopen.php

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
             ☻_
            /▌
            / \ Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
      2. Hallo,

        Hier die fertige Lösung:

        <?php
           $counterFileName = "counter.txt";

          $counterstand = (int) file_get_contents($counterFileName);  
        

        if ($_SESSION['count'] != 'count') {
                $counterstand++;

        session_start();
        $_SESSION['count']='count';

        } else {
                        fclose ($counterstand);
                }
        ?>
        <br><p class="artikel">Besucher:<br><?=$counterstand?></p></body></html>

          
        Wenn du es mit Session statt mit Cookie machen willst, dann wohl eher so:  
        ~~~php
          
        <?php  
        session_start();  
        error_reporting(E_NOTICE|E_ALL);  
        $counterFileName = "counter.txt";  
        $counterValue = (int) file_get_contents($counterFileName);  
        if (!isset($_SESSION['counted'])) {  
        	$_SESSION['counted']="counted";  
        	$counterValue++;  
        	file_put_contents($counterFileName, $counterValue);  
        }  
        ?>  
        <p class="artikel">Besucher: <?=$counterValue?></p>  
        
        

        Gruß

        jobo

  2. Hello,

    Hey,
    ich habe folgendes Script geschrieben:

    <?php
                $datei = fopen("counter.txt","r+");
                $counterstand = fgets($datei, 10);

    if ($_COOKIE['User'] != '10')
            {
                $counterstand++;
                setcookie("User", "10", time()+606024);
                echo "<br><p class="artikel">Besucher:<br>$counterstand</p>";
                rewind($datei);
                fwrite($datei, $counterstand);
                fclose($datei);
            }
        else
            {
                echo "<br><p class="artikel">Besucher:<br>$counterstand</p>";
                rewind($datei);
                fwrite($datei, $counterstand);
                fclose($datei);
                }
    ?>

      
    
    > Doch irgendwo muss ein Fehler sein, da der Zähler jeden klick zählt!..  
    > Vielleicht kann mir jemand weiterhelfen.  
      
    Leider hast Du versäumt, zu beschreiben, was die Programmlogik denn überhaupt tun soll.  
    Unter "Klick" verstehst Du vermutlich einen Request auf die Ressource, die den "Zähler" enthält?  
      
    Da Du mit Cookies arbeitest, nehme ich an, dass Du nur Requests von Clients zählen willst, die keinen passenden Cookie mitsenden?  
      
    Einen weiteren aktiven Thread zu diesem Thema wird es von Dir ja ganz bestimmt nicht geben in diesem Forum, weil Du den dann fortgesetzt hättest, anstatt einen neuen aufzumachen, oder? :-))  
      
    Deine Fehler:  
      
    - Keine Nebenläufigkeitsfähigkeit des Codes  
      <http://aktuell.de.selfhtml.org/artikel/programmiertechnik/dateisperren/>  
      
    - Flasche Abfrage von Globalen Variablen, die nicht immer vorhanden sind  
      
      erst mit  
      
          if (isset($\_COOKIE['user'))  
      
      festsstellen, ob überhaupt ein Cookie vorhanden ist.  
      
    - Ausgabe nicht in die Steuerlogik des Programmes verlegen, sondern in einem  
      gesonderten Ausgabeteil des Programmes ungterbringen.  
      
    - Am besten die Aufgaben in Funktionen verpacken, die an geeigneter Stelle dann  
      nur noch aufgerufen werden müssen und immer wieder verwendet werden können.  
      Auch \_deshalb\_ Berechnung und Darstellung von Ergebnissen nicht mischen!  
      
      
      
      
    Liebe Grüße aus dem schönen Oberharz  
      
      
    Tom vom Berg  
    ![](http://selfhtml.bitworks.de/Virencheck.gif)  
      
    
    -- 
     ☻\_  
    /▌  
    / \ Nur selber lernen macht schlau  
    <http://bergpost.annerschbarrich.de>