Kleines Counter-Problem

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Kleines Counter-Problem

    Hallo

    Vielleicht kann mir jemand helfen:
    Seit mehreren Monaten benutze ich einen selbstgeschriebenen PHP-Counter auf Textdateibasis.
    Dabei tritt in rein zufälligen Zeitabständen das Problem auf, das der Counterstand auf 0 gesetzt wird,
    was natürlich nicht sein darf. Ich komme einfach nicht dahinter, warum das so ist.
    Hat jemand eine Idee woran es liegen könnte?
    Hier der komplette Quellcode des Counters:

    PHP-Code:
    <?php
    /* --------------------------- KONFIGURATION ------------------------------ */

    $pfad         "counter/";      /* Pfad zum Counterordner */
    $counter         0;         /* Counter Startwert */
    $sperrzeit    3600;           /* IP-Sperrzeit in Sekunden */

    /* --------------------------- KONFIGURATION ENDE ------------------------- */

    $ip                 getenv("REMOTE_ADDR");
    $max                 1000;
    $zeit             time();
    $ip_exist     false;

    /* --------------------------- Neue Datei anlegen ------------------------- */
    if(!file_exists($pfad."counter.txt"))
    {
      
    $counter++;
        
    $daten         = array();
      
    $daten[0] = $counter;
      
    $daten[1] = $ip;
      
    $daten[2] = $zeit;
        
    $teile        implode("|"$daten);
        
    $handle     = @fopen($pfad."counter.txt""a");
      @
    fputs($handle$teile);
      @
    fclose($handle);
    }

    /* --------------------------- Daten aus Datei lesen ---------------------- */
    $read_handle = @fopen($pfad."counter.txt""r+");
    @
    flock($read_handle,LOCK_SH);
    $daten    = @fgets($read_handle);
    @
    flock($read_handle,LOCK_UN);
    @
    fclose($read_handle);
    $teile    explode("|"$daten);
    $anzahl    =    count($teile);

    /* -- Datei aufräumen, wenn bestimmte Besucheranzahl überschritten wird --- */
    if($anzahl $max)
    {
        for(
    $n=1$n<$anzahl$n++)
      {
          unset (
    $teile[$n]);
      }
        
    $anzahl 1;
    }

    /* -- Prüfen, ob IP schon gespeichert und dessen Sperrzeit überschritten ist -- */
    for($n=1$n<$anzahl$n++)
    {
        if(
    $teile[$n] == $ip)
      {
          
    $ip_exist true;
           if(
    $zeit $teile[$n+1]+$sperrzeit)
          {
                
    $ip_exist false;
          unset (
    $teile[$n]);
          unset (
    $teile[$n+1]);
                break;
        }
      }
    }

    /* --------------------------- Daten ändern & speichern ------------------- */
    if($read_handle == true)
    {
        if(
    $ip_exist == false)
        {
          
    $teile[0]++;
          
    $teile[]  = $ip;
          
    $teile[]  = $zeit;
          
    $daten    implode("|"$teile);
          
    $handle   = @fopen($pfad."counter.txt""w");
          @
    flock($handle,LOCK_EX);
          @
    fputs($handle$daten);
          @
    flock($handle,LOCK_UN);
          @
    fclose($handle);
        }
        echo 
    $teile[0];
    }
    ?>

  • #2
    Entferne alle @s, setze display_errors=off, error_reporting=E_ALL und per error_log=<dateiname> lass dir eventuelle Fehler in eine Datei schreiben.

    Ein netter Guide zum übersichtlichen Schreiben von PHP/MySQL-Code!

    bei Klammersetzung bevorzuge ich jedoch die JavaCoding-Standards
    Wie man Fragen richtig stellt

    Kommentar


    • #3
      display_errors=on

      Kommentar


      • #4
        Original geschrieben von PHP-Desaster
        display_errors=on
        Ne, eben gerade nicht, damit die Fehler nicht jedem Benutzer um die Ohren gekloppt werden ^^,

        Ein netter Guide zum übersichtlichen Schreiben von PHP/MySQL-Code!

        bei Klammersetzung bevorzuge ich jedoch die JavaCoding-Standards
        Wie man Fragen richtig stellt

        Kommentar


        • #5
          Ne, eben gerade nicht, damit die Fehler nicht jedem Benutzer um die Ohren gekloppt werden ^^,
          Hehe, hast recht, habe dein error_log wohl verdrängt
          Für das direkte Debuggen kann er natürlich auf das Log verzichten!

          Kommentar


          • #6
            Danke.
            "error_log" wäre ja eventuell was um der Sache auf die Spuhr zu kommen. Etwas blöd nur, das es unter umständen Wochen oder gar Monate dauern kann bis der besagte Fehler wieder einmal auftritt.
            Mit "error_reporting=E_ALL" und ohne @ entwerfe und teste ich übrigens grundsätzlich alle PHP-Scripte - is ja klar.

            Ich dachte mir, das vielleicht doch noch jemand einen Fehler im Code entdeckt, denn lang oder unübersichtlich ist je ja nun wirklich nicht.

            Mir fällt ein, ich muss noch etwas wichtiges zum Code sagen:
            Der Startwert der Variable "$counter" ist bei mir in der Praxis nicht = 0,
            so wie oben im Quellcode zu sehen ist (sondern liegt derweil bei über 50000). Ich halte dies für wichtig zu erwähnen, denn durch diese Tatsache lässt sich ausschliessen, das ein gelegentliches löschen der Countertextdatei (aus welchem Grund auch immer) auszuschliessen ist,
            da der Counterstand nach auftreten des Fehlers immer bei 0 beginnt.
            Nach dem löschen der Countertextdatei würde vom Script also eine neue Countertextdatei angelegt, deren Startwert nicht gleich 0 sein kann.

            Die Problematik ist mir ein echtes Rätzel
            Zuletzt geändert von doppelstern; 20.02.2008, 08:22.

            Kommentar


            • #7
              Mal so eine ganz blöde Frage am Rande: Wieso benutzt du nicht einfach eine Datenbank?
              Ich kann mir kaum vorstellen, dass dieses ganze Rumgespiele mit den Locks performant ist (allein schon deshalb, weil eine zu große Anzahl von Einträgen eventuell gleich von mehreren Skriptaufrufen bereinigt wird) und abgesehen davon funktioniert das ja eh nicht immer (per NFS z.B. nicht)

              Wenn du einfach eine Datenbank nimmst, kann dir die Anzahl der Einträge egal sein, du kannst alles mögliche an Werten einfacher speichern (IP, eventuell kombiniert mit UserAgent), per Unique-Key darauf kannst du dir das Auslesen der Datenbank selber sparen und einfach per REPLACE INTO die Datensätze einfügen,
              und wenn du Lust hast noch per random oder Cronjob die Tabelle alle 15 Minuten einmal leeren lassen oder so, was MySQL auch so praktisch gar nicht kratzt.

              Ich bin kein Freund von Text-Dateien

              Ein netter Guide zum übersichtlichen Schreiben von PHP/MySQL-Code!

              bei Klammersetzung bevorzuge ich jedoch die JavaCoding-Standards
              Wie man Fragen richtig stellt

              Kommentar


              • #8
                Sicherlich hast du da recht. Zu der Zeit als ich den Counter programmierte waren meine beiden DB die zur Verfügung stehen schon belegt (Gästebuch und Linkliste). Derweil ist eine davon wieder frei geworden, da ich die Linkliste nun manuell manage.
                Es würde mich zum einen nur etwas ärgern, dieses ansich schöne Script auf den Müll zu werfen und zum anderen könnte es sein, das ich die derzeit freie DB später noch für eine Kunden-Datenverwaltung benötige.
                Es ist natürlich auch eine Frage des Ehrgeizes, diesen Fehler zu finden und zu beseitigen. Zudem lerne ich dabei ja auch etwas dazu, denn dieser Fehler ist schon etwas seltsam und ich möchte doch zugern wissen, woran es liegt.

                Eine Theorie die ich habe wäre, das es vielleicht unter ungünstigen Umständen zu einem Dateizugriffskonflikt kommt, wenn zwei oder mehrere Besucher auf die Countertextdatei zur selben Zeit zugreifen. Der Pointer dabei Daten an einer falschen Position einliest. Vielleicht passiert das gerade in dem Augenblick, wo die Countertextdatei "aufgeräumt" wird. Aber eigentlich müsste der Einsatz von "flock" dies ja verhindern.
                Könnte es sein, das "flock" falsch positioniert ist? Vielleicht sollte "flock" besser direkt zu Anfang und am Ende des Sripts stehen und nicht für jeden Dateizugriff einzeln gesetzt werden? Oder ist jemanden bekannt, das "flock" fehlerhaft arbeitet?
                Zuletzt geändert von doppelstern; 20.02.2008, 16:14.

                Kommentar


                • #9
                  Original geschrieben von doppelstern
                  SZu der Zeit als ich den Counter programmierte waren meine beiden DB die zur Verfügung stehen schon belegt
                  Du brauchst dazu doch keine eigene DB, da ist doch eine Tabelle innerhalb einer bestehenden DB mehr als genug.
                  flock() funktioniert meines Wissens nur, wenn immer auf die gleiche Art zugeriffen wird. Du merkst das auch daran, dass du eine exklusiv gelockte Datei problemlos manuell editieren kannst.
                  Gruss
                  H2O

                  Kommentar

                  Lädt...
                  X