Antedulvian: Script beschleunigen?

Hi!

Wie kann man denn dieses Script beschleunigen (ist für viele 10000 Benutzer)?
Der Sinn des Scripts ist das er aus einer Textdatei Benutzer (Name, email, ...) ausliest und sie in einer DB speichert.

  
$handle = fopen ($source, "r");  
while (!feof($handle)) {  
    $result = FALSE;  
    $buffer = fgets($handle, 4096);  
    $data = explode("|", $buffer);  
  
    // Name verarbeiten  
    $vorname = str_replace(",", "", $vorname); // manchmal ist ein Beistrich vorhanden  
    $nachname = str_replace(",", "", $nachname); // manchmal ist ein Beistrich vorhanden  
  
    ## email richtig speichern  
    $email = strtolower($email);  
    $email = str_replace("\r", "", $email); // \r entfernen (Zeilenende)  
    $email = str_replace("\n", "", $email); // \n entfernen (Zeilenende)  
  
    ## Branchen richtig speichern  
    $branch = str_replace(":", "", $branch); // : für Branchen  
  
    //echo "<pre>"; print_r($data);  
  
    ## schon vorhanden?  
    $result = mysql_query("SELECT email FROM ".DB_TABLE." WHERE email='".addslashes($email)."'");  
    if(mysql_num_rows($result)) {  
      echo addslashes($email)." ist bereits eingetragen<br>";  
    }  
    else {  
      $query = "INSERT INTO ".DB_TABLE." (title, firstname, lastname, email, [...])".  
      "VALUES ('".addslashes($data[0])."', '".  
                  addslashes($data[1])."', '".  
                  addslashes($data[2])."', '".  
                  [...])";  
      $result = mysql_query ($query) or die ("Der Datenbankeintrag hat leider nicht funktioniert.<br>".mysql_error());  
    }  
}  

  1. Hi!

    ich hatte das Script aus verständnis-Gründen um ein paar unwichtige Sachen gekürzt und da bisschen schlampig gearbeitet :-/

    hier das richtige Script:

      
    $handle = fopen ($source, "r");  
    while (!feof($handle)) {  
        $result = FALSE;  
        $buffer = fgets($handle, 4096);  
        $data = explode("|", $buffer);  
      
        // Name verarbeiten  
        $data[1] = str_replace(",", "", $data[1]); // manchmal ist ein Beistrich vorhanden  
        $data[2] = str_replace(",", "", $data[2]); // manchmal ist ein Beistrich vorhanden  
      
        ## email richtig speichern  
        $data[3] = strtolower(data[3]);  
        $data[3] = str_replace("\r", "", $data[3]); // \r entfernen (Zeilenende)  
        $data[3] = str_replace("\n", "", $data[3]); // \n entfernen (Zeilenende)  
      
        ## schon vorhanden?  
        $result = mysql_query("SELECT email FROM ".DB_TABLE." WHERE email='".addslashes($data[3])."'");  
        if(mysql_num_rows($result)) {  
          echo addslashes($data[3])." ist bereits eingetragen<br>";  
        }  
        else {  
          $query = "INSERT INTO ".DB_TABLE." (title, firstname, lastname, email, [...])".  
          "VALUES ('".addslashes($data[0])."', '".  
                      addslashes($data[1])."', '".  
                      addslashes($data[2])."', '".  
                      [...])";  
          $result = mysql_query ($query) or die ("Der Datenbankeintrag hat leider nicht funktioniert.<br>".mysql_error());  
        }  
    }  
    
    

    Vielen Dank
    Antedulvian

    1. Hi,

      generell würde ich Singe-Quotes statt Double Quotes benutzen:

      z.B.:

      'SELECT email FROM '.DB_TABLE.' WHERE email=''.addslashes($data[3]).'''

      statt

      "SELECT email FROM ".DB_TABLE." WHERE email='".addslashes($data[3])."'"

      Grund:

      in Singe-Quotes wird nicht nach Variablen geparst.

      Eventuell kann man auch folgende Anweisungungen in eine Packen:

      $data[3] = strtolower(data[3]);
      $data[3] = str_replace("\r", "", $data[3]); // \r entfernen (Zeilenende)
      $data[3] = str_replace("\n", "", $data[3]); // \n entfernen (Zeilenende)

      indem man \r\n mit einem regulären ausdruck behandelt und strtolower(data[3]) schon direkt in das replace reinsteckt, ohne erst zuzuwesein.

      Bin mir aber nicht sicher ob 1 Reg Ex schneller ist, als 2 str_replace.

      Ansonsten kannst du vielleicht noch nach performance tests schauen, ob z.B. explode schneller/langsamer als split ist. Beide Funktionen tun ja m.W. das selbe.

      Gruß!

      Gruß!

      1. Hallo Christian,

        $data[3] = str_replace("\r", "", $data[3]); // \r entfernen (Zeilenende)
        $data[3] = str_replace("\n", "", $data[3]); // \n entfernen (Zeilenende)

        indem man \r\n mit einem regulären ausdruck behandelt und strtolower(data[3]) schon direkt in das replace reinsteckt, ohne erst zuzuwesein.

        Bin mir aber nicht sicher ob 1 Reg Ex schneller ist, als 2 str_replace.

        das ist ohnehin irrelevant, da die Originalanweisungen etwas völlig anderes bewirken. Sprich, sie sind gründlicher als Dein geplanter Regex. Ob die Anweisungen das Gewünschte oder gar nur etwas Richtiges tun, steht auf einem anderen Blatt.

        Normalerweise ist die Regexp-Engine etwas so Aufwendiges, dass man sie nach Möglichkeit vermeidet, wenn es eine simple Stringoperation gibt.

        Freundliche Grüße

        Vinzenz

      2. Moin!

        generell würde ich Singe-Quotes statt Double Quotes benutzen:

        z.B.:

        'SELECT email FROM '.DB_TABLE.' WHERE email=''.addslashes($data[3]).'''

        statt

        "SELECT email FROM ".DB_TABLE." WHERE email='".addslashes($data[3])."'"

        Grund:

        in Singe-Quotes wird nicht nach Variablen geparst.

        Sowas würde ich in jedem Fall vermeiden, da man sich damit viel Verwirrung beim Escapen der einfachen Anführungsstriche sparen kann.

        Und die paar Microsekunden mehr Ausführungszeit für das Parsen nichtvorhandener Variablen im String fallen absolut nicht ins Gewicht. Die Stunden für die Fehlersuche bei unkorrektem Escaping dagegen schon eher!

        - Sven Rautenberg

        --
        "Love your nation - respect the others."
      3. echo $begrüßung;

        generell würde ich Singe-Quotes statt Double Quotes benutzen:
        Grund:
        in Singe-Quotes wird nicht nach Variablen geparst.

        Es ist durchaus ein Geschwindigkeitsunterschied messbar, doch der ist meist dermaßen gering, dass er nicht weiter ins Gewicht fällt. Erst bei Größenordnungen von ca. 7- oder 8-stelligen Schleifendurchläufen kommt man in einen spürbaren Bereich. Da man solche Schleifen nicht zum Spaß laufen lässt, entsteht dabei ja auch irgend ein Ergebnis, das weiterverarbeitet werden muss. Die dabei verbrauchte Zeit dürfte die Geschwindigkeitsdifferenz von ' zu " erheblich in den Schatten stellen. Das fällt also unter Mikrooptimierung.

        Eventuell kann man auch folgende Anweisungungen in eine Packen:
        $data[3] = str_replace("\r", "", $data[3]); // \r entfernen (Zeilenende)
        $data[3] = str_replace("\n", "", $data[3]); // \n entfernen (Zeilenende)
        Bin mir aber nicht sicher ob 1 Reg Ex schneller ist, als 2 str_replace.

        Man kann bei str_replace() allen Parametern ein Array übergeben. Hier wäre es sinnvoll,

        $data[3] = str_replace(array("\r", "\n"), "", $data[3]);

        zu verwenden statt zweier Funktionsaufrufe oder über die Regexp-Maschinerie nachzudenken. Aber das ist ebenfalls nur Mikrooptimierung.

        Ansonsten kannst du vielleicht noch nach performance tests schauen, ob z.B. explode schneller/langsamer als split ist. Beide Funktionen tun ja m.W. das selbe.

        explode() verwendet einen feststehenden String als Trennzeichen, split() verwendet einen regulären Ausdruck. explode() dürfte schneller sein. Doch auch das ist Mikrooptimierung.

        Erheblich mehr Rechenzeit lässt sich an den wirklichen Flaschenhälsen sparen, wozu man besser die Ausführungszeiten misst, damit man seinen Erfolg kontrollieren kann. Die Erfahrung sagt, dass das Zusammenfassen der Gibt-es-das-schon-Anfrage und der Einfüge-Anweisung zu einer Einfügen-mit-Unique-Key-Prüfung-Anweisung eine deutlich geringere Laufzeit haben wird. Siehe Vinzenz Antwort. Weiterhin kann hier der Einsatz von Prepared Statements zu einer Ersparnis auf Seiten des MySQL-Servers beitragen, denn dann muss dieser nicht ständig die INSERT-Anweisung neu parsen. Außerdem spart man sich das Zusammensetzen des Statements inklusive der Funktionsaufrufe zur kontextgerechten Behandlung der Werte.

        echo "$verabschiedung $name";

        1. Hi!

          Ich hab keine Ahnung von Prepared Statements, hab mir jetzt ein paar Google-Teffer, sowie php.net durchgelesen, aber ganz klar is es mir immer noch ned...

          Was liegt innerhalb und was außerhalb der Schleife?
          Ich habs mir so gedacht, is das richtig?

            
          $mysqli = new mysqli(DB_SERVER,DB_SERVER_USERNAME,DB_SERVER_PASSWORD, DB_DATABASE);  
          $statement = $mysqli->prepare("INSERT INTO ".DB_TABLE." (title, firstname, lastname, email, postcode, city, branch, business, source, sourcecategorie, got_mail)".  
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, '$source', '$sourcecategorie', '0')");  
          $statement->bind_param('isssisss', $anrede, $vorname, $nachname, $email, $postcode, $city, $branch, $business);  
            
          [div. Code]  
          while-Schleife {  
            
              $anrede = mysqli->real_escape_string($data[0]);  
              $vorname = ...  
              ....  
            
              $statement->execute();  
          }  
          $mysqli->close();  
          
          

          Vielen Dank für die Hilfe!
          Antedulvian

          1. echo $begrüßung;

            $anrede = mysqli->real_escape_string($data[0]);

            Bei einem SQL-Statement handelt es sich um eine Mischung von Anweisung und Daten. Damit die Daten von den Anweisungen unterschieden werden können, müssen sie speziell gekennzeichnet werden. Man verwendet dazu beispielsweise Anführungszeichen (Quotieren). Innerhalb eine solchen Zeichenfolge kann nun kein Anführungszeichen stehen, weil es selbige beendet. Deswegen maskiert man. Bei einem P.S. werden die Daten nicht in einen SQL-String eingefügt sondern gehen einen eigenen Weg. Es ist deshalb weder ein Quotieren noch ein Maskieren notwendig.

            $anrede = $data[0];

            usw. reicht.

            $statement = $mysqli->prepare("INSERT INTO ".DB_TABLE." (title, firstname, lastname, email, postcode, city, branch, business, source, sourcecategorie, got_mail)".
              "VALUES (?, ?, ?, ?, ?, ?, ?, ?, '$source', '$sourcecategorie', '0')");

            $source und $sourcecategorie hingegen sollten sehr wohl maskiert werden, weil du sie hier in den SQL-Kontext einfügst. Vielleicht haben sie momentan kein ' im Namen, aber kannst du das für alle Zukunft definitiv ausschließen?

            Der Rest sah in Ordnung aus, abgesehen von der fehlenden Fehlerbehandlung.

            echo "$verabschiedung $name";

          2. Die Fehlerbehandlung hatte ich noch nicht eingebaut, da ich als Erstes das Konzept verstehen wollte!

            Oben hab ich eine mysql_connect_errorno()-Abfrage und unten:

            Bei der Fehler-Abfrage unten (duplicate entry) muss ich ja nur mysql_errorno() durch $mysqli->errno ersetzen ;)

            Es funktioniert bereits und ich hab ne Zeitersparnis (nur bei einer Datei getestet) von ca. 45% ;)

            Vielen Dank!
            Antedulvian

    2. Hallo!

      ## email richtig speichern
          $data[3] = strtolower(data[3]);
          $data[3] = str_replace("\r", "", $data[3]); // \r entfernen (Zeilenende)
          $data[3] = str_replace("\n", "", $data[3]); // \n entfernen (Zeilenende)

      Wieso strtolower()? E-mailadressen sind nicht case-sensitive.
      Und wieso speicherst du \r und \n bei E-mailadressen?
      \r und \n bei der Ausgabe zu entfernen scheint mir überflüssig.

      Wieso strtolower()? E-mailadressen sind nicht case-sensitive.

      ## schon vorhanden?
          $result = mysql_query("SELECT email FROM ".DB_TABLE." WHERE email='".addslashes($data[3])."'");

      Wieso addslashes()? Die richtige Funktion für den MySQL-Kontext wäre mysql_real_escape_string().

      if(mysql_num_rows($result)) {
            echo addslashes($data[3])." ist bereits eingetragen<br>";
          }

      Wieso addslashes()? Die richtige Funktion für den HTML-Kontext wäre htmlspecialchars().

      "VALUES ('".addslashes($data[0])."', '".
                        addslashes($data[1])."', '".
                        addslashes($data[2])."', '".
                        [...])";

      Warum addslashes()? Siehe oben!

      Grüße, Matze

      1. Hi!

        Wieso strtolower()? E-mailadressen sind nicht case-sensitive.

        eben ;)
        Um zu verhindern das ich Antedulvian@bla.de UND antedulvian@bla.de in der DB drinnen hab ;)

        Und wieso speicherst du \r und \n bei E-mailadressen?
        weil die email der letzte Datensatz der Zeile is und eine Zeile mit \r\n endet, weshalb das zur email hinzugespeichert wurde ;)

        lg
        Antedulvian

    3. Hallo

      $handle = fopen ($source, "r");
      while (!feof($handle)) {
          $result = FALSE;
          $buffer = fgets($handle, 4096);
          $data = explode("|", $buffer);

      warum nicht gleich [link:http://www.php.net/manual/de/function.fgetcsv.php@title=fgetcsv]?

      ## schon vorhanden?

      eine völlig überfüssige DB-Operation:

      $result = mysql_query("SELECT email FROM ".DB_TABLE." WHERE email='".addslashes($data[3])."'");

      addslashes solltest Du zugunsten von [link:http://www.php.net/manual/de/function.mysql-real-escape-string.php@title=mysql_real_escape_string] entsorgen.
                     [...])";

      $result = mysql_query ($query) or die ("Der Datenbankeintrag hat leider nicht funktioniert.<br>".mysql_error());

        
      die() ist keine Fehlerbehandlung!  
        
      Ein UNIQUE-Index auf die Spalte email setzen, das INSERT vornehmen und damit rechnen, dass es zu einer Index-Verletzung kommen kann und diese MySQL-Fehlermeldung entsprechend behandeln (und protokollieren). Sonstige Fehler einfach protokollieren, statt das Skript sterben zu lassen. Zum Schluss Verarbeitungsprotokoll ausgeben.  
        
        
      Freundliche Grüße  
        
      Vinzenz
      
      1. Hallo Vinzenz!

        warum nicht gleich fgetcsv?

        Weil ich das nicht kannte ;)
        Wäre das so richtig?
        [code lang=PHP]
        $handle = fopen ($source, "r");
        while(($data = fgetcsv ($handle, 4096, "|")) !== FALSE)) {
        endet er da eh immer mit Zeilenende!?

        eine völlig überfüssige DB-Operation:

        $result = mysql_query("SELECT email FROM ".DB_TABLE." WHERE email='".addslashes($data[3])."'");

        auf email hab ich in MySQL eh Unique gelegt, ich weiß nur nicht wie ich die MySQL-Fehlermeldung abfangen kann, gibt es sowas ähnliches wie try&catch?
        Wenns nicht funktioniert soll nur ein $counter erhöht werden....

        addslashes solltest Du zugunsten von mysql_real_escape_string entsorgen.

        stimmt ;)

        die() ist keine Fehlerbehandlung!

        Aber wenn der Fehler Eintritt is die DB grad down, weshalb es auch keinen Sinn macht 1000 weitere Anfrage abzuschicken ;)

        danke

        1. Hallo

          auf email hab ich in MySQL eh Unique gelegt, ich weiß nur nicht wie ich die MySQL-Fehlermeldung abfangen kann, gibt es sowas ähnliches wie try&catch?

          prüfe zuerst den Rückgabewert von mysql_query() und dann den Inhalt von mysql_error(). Erwarte, dass es einem bestimmten Fehler kommen kann. Teste mit einem beliebigen Clientprogramm aus, welcher es ist :-)

          die() ist keine Fehlerbehandlung!
          Aber wenn der Fehler Eintritt is die DB grad down, weshalb es auch keinen Sinn macht 1000 weitere Anfrage abzuschicken ;)

          wo ist das Problem. Brich mit break aus der Schleife aus. Es ist eh' eine schlechte Idee innerhalb der Verarbeitung Ausgaben vorzunehmen. Baue alles in einer Variablen zusammen bzw. logge in eine Datei (aufwendiger) und mache die Ausgabe nach Beendigung der Verarbeitung, d.h. nach Ende der Schleife. Somit kannst Du das Skript sauber beenden, ohne unnötig fehlschlagende Abfragen an die DB zu schicken.

          In diesem Fall musst Du sowieso damit rechnen, dass mysql_query fehlschlägt - nämlich bei der Indexverletzung. Du willst das Skript bei einer Indexverletzung nicht sterben lassen, sondern nur Deinen Zähler hochsetzen ...

          Freundliche Grüße

          Vinzenz

          1. Hallo Vinzenz!

            Ich hab jetzt die SELECT-Abfrage rausgelöscht und unterhalb des Datenbankeintrag(-Versuches) folgendes stehen:

            if(mysql_errno($conn)==1062) $alreadyin_count++; // duplicate entry
            elseif(mysql_errno($conn)==NULL) $count++; // entry successfull
            else { $protocol .= "Es trat ein Fehler auf:\r\n".mysql_errno() . ": " . mysql_error(). "\r\n"; break; } // unknown error

            das Feld email is bei mir in der MySQL-DB ein VARCHAR( 64 ) NOT NULL, case-insensitive, UNIQUE

            VIELEN DANK!
            Antedulvian

    4. ## email richtig speichern
          $data[3] = strtolower(data[3]);

      data[3] ist ein Typo!

      Weshalb erklärst du die Schreibweise der Benutzernamen bei Emailadressen für irrelevant?

      mfg Beat

      --
                       /|
        <°)))o><      / |    /|
                  ---- _|___/ |     ><o(((°>
                 OvVVvO    __ |         ><o(((°>
      <°)))o><  /v    v\/  |
       <°)))o>< ^    ^/_/_         ><o(((°>
                 ^^^^/___/
      ><o(((°>    ----       ><o(((°>
         <°)))o><                      ><o(((°>o
      1. Groß- und Kleinschreibung ist ja bei emails egal
        => eine email an Antedulvian@bla.de kommt genauso an wie eine an antedulvian@bla.de
        Um nun doppelte Einträge zu verhindern lass ich es klein schreiben, stimmt das so nicht!?

        danke
        Antedulvian

        1. Hallo Antedulvian!

          Um nun doppelte Einträge zu verhindern lass ich es klein schreiben, stimmt das so nicht!?

          Nein, du speicherst die Daten wie übergeben und ziehst bei deinem Vergleich Groß- und Kleinschreibung in Betracht.

          Grüße, Matze

          1. Irrtun, bei beiden wird die Kleinschreibung gespeichert ;)

            1. Hi,

              Irrtun, bei beiden wird die Kleinschreibung gespeichert ;)

              genau dies ist einer Deiner kapitaleren Fehler.

              Cheatah

              --
              X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
              X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
              X-Will-Answer-Email: No
              X-Please-Search-Archive-First: Absolutely Yes
            2. Hallo!

              Um nun doppelte Einträge zu verhindern lass ich es klein schreiben, stimmt das so nicht!?
              Nein, du speicherst die Daten wie übergeben und ziehst bei deinem Vergleich Groß- und Kleinschreibung in Betracht.
              Irrtun, bei beiden wird die Kleinschreibung gespeichert ;)

              Ich formulier es nochmal neu:
              "Ja, es stimmt so nicht. Du sollst die Daten so speichern wie sie dir übergeben wurden und erst beim Vergleich die Groß- und Kleinschreibung in Betracht ziehen."

              Grüße, Matze

              1. hab ich eh schon geändert, da ich die SELECT-Abfrage gelöscht hab...

                lg

        2. Groß- und Kleinschreibung ist ja bei emails egal
          => eine email an Antedulvian@bla.de kommt genauso an wie eine an antedulvian@bla.de
          Um nun doppelte Einträge zu verhindern lass ich es klein schreiben, stimmt das so nicht!?

          abuse@example.com
          und
          AbUse@example.com

          sind zwei komplett verschiedene User der Maildomain @example.com

          mfg Beat

          --
                           /|
            <°)))o><      / |    /|
                      ---- _|___/ |     ><o(((°>
                     OvVVvO    __ |         ><o(((°>
          <°)))o><  /v    v\/  |
           <°)))o>< ^    ^/_/_         ><o(((°>
                     ^^^^/___/
          ><o(((°>    ----       ><o(((°>
             <°)))o><                      ><o(((°>o
          1. Da musst du jetzt aber zwischen Theorie und Praxis unterscheiden ;)

            Bei allen großen email-Anbietern is die email NICHT case-sensitive!

            lg
            Antedulvian

            1. Da musst du jetzt aber zwischen Theorie und Praxis unterscheiden ;)
              Bei allen großen email-Anbietern is die email NICHT case-sensitive!

              Den Unterschied lass ich mal besser sausen. Ich mach mir aufgrund des Verhaltens _meines_ Mailservers keine Vorstellungen über andere Server, bzw der User die dort Filter etc einrichten.

              mfg Beat

              --
                               /|
                <°)))o><      / |    /|
                          ---- _|___/ |     ><o(((°>
                         OvVVvO    __ |         ><o(((°>
              <°)))o><  /v    v\/  |
               <°)))o>< ^    ^/_/_         ><o(((°>
                         ^^^^/___/
              ><o(((°>    ----       ><o(((°>
                 <°)))o><                      ><o(((°>o
              1. Hallo Beat!

                Den Unterschied lass ich mal besser sausen. Ich mach mir aufgrund des Verhaltens _meines_ Mailservers keine Vorstellungen über andere Server, bzw der User die dort Filter etc einrichten.

                Wenn du darauf aus bist, dass sich ein User nur einmal anmelden, bzw nur einmal seine E-Mailadresse angeben soll, kann so eine Unterscheidung schon Sinn machen.

                Sicher kann man auch noch 20 Postfächer irgendwo einrichten wenn man 'betrügen' will, aber es ist immerhin schwerer geworden.

                Grüße, Matze

                1. Den Unterschied lass ich mal besser sausen. Ich mach mir aufgrund des Verhaltens _meines_ Mailservers keine Vorstellungen über andere Server, bzw der User die dort Filter etc einrichten.
                  Wenn du darauf aus bist, dass sich ein User nur einmal anmelden, bzw nur einmal seine E-Mailadresse angeben soll, kann so eine Unterscheidung schon Sinn machen.

                  Sicher kann man auch noch 20 Postfächer irgendwo einrichten wenn man 'betrügen' will, aber es ist immerhin schwerer geworden.

                  Ich muss jetzt überlegen, ob du mich eventuell missverstanden hast.
                  Einfach nochmals zur Klarstellung.
                  a) ich kenne die Praxis eines Servers XY nicht, deshalb
                  b) halte ich mich an die Theorie welche besagt:
                  c) behandle Usernames in Maildomains Case sensitive.

                  Aber du hast noch einen Punkt indiziert.
                  Manchmal sieht man die Praxis, dass in Communities eine Emailadresse als Username verwendet wird. Bzw, es ist eben Usern möglich, die Emailadresse als Nick einzugeben.
                  Dort wird es dann plötzlich relevant und kritisch.
                  Solches würde ich nie machen. Eine Email-Adresse behandle ich nur als ein Kontaktdatum.
                  Nur Mailserver sollten es als Logindatum verwenden.

                  Angenommen, ich betreibe einen Mailserver.

                  Nun möchte ich ev. dass es zu hans@example.org kein Hans@ geben darf.
                  Ich kann das durch zwei Arten erreichen.
                  a) Ich normalisiere jeden usernameantrag vor der Prüfung (z.B. zu lowercase)
                  b) Ich normalisiere nicht, teste jedoch, ob es im Falle der Normalisierung des Antragsnamens mit einem normalisierten bestehenden Namen einen Konflikt gibt.

                  b) scheint mir weit sinnvoller als a) wenn man hier eine deutliche Differenzierung wünscht.

                  Aber ich bin mir nicht einmal sicher, ob b) wirklich sinnvoll. Im Falle eines Nicknames in einem Forum erschiene mir das eher sinnvoll.

                  mfg Beat

                  --
                                   /|
                    <°)))o><      / |    /|
                              ---- _|___/ |     ><o(((°>
                             OvVVvO    __ |         ><o(((°>
                  <°)))o><  /v    v\/  |
                   <°)))o>< ^    ^/_/_         ><o(((°>
                             ^^^^/___/
                  ><o(((°>    ----       ><o(((°>
                     <°)))o><                      ><o(((°>o
                  1. Hallo Beat!

                    Aber du hast noch einen Punkt indiziert.
                    Manchmal sieht man die Praxis, dass in Communities eine Emailadresse als Username verwendet wird. Bzw, es ist eben Usern möglich, die Emailadresse als Nick einzugeben.

                    Nein das nicht, aber manchmal möchte ich, dass sich ein User nur 1 mal anmelden kann und weil es den meißten Usern zu aufwendig ist zig E-mailadressen anzulegen kann man damit zumindest eine kleine Hürde aufbauen.

                    Ich überleg grad ein Beispiel. Bei E-Bay dürfte es sicher nicht möglich sein um das Bieten auf eigene Auktionen zu verhindern. Evtl. ist es auch bei weniger relevanten Abstimmungen sinnvoll.

                    Du verstehst?

                    Es ist schon ein Kreuz mit den E-mailadressen, die halten sich aber auch an gar nichts[1] ;)

                    Grüße, Matze

                    [1] RFC, ich weiß

                    1. Nein das nicht, aber manchmal möchte ich, dass sich ein User nur 1 mal anmelden kann und weil es den meißten Usern zu aufwendig ist zig E-mailadressen anzulegen kann man damit zumindest eine kleine Hürde aufbauen.

                      Das wird mich nicht daran hindern, mich bei dir mehrmals mit verschiedenem Nick und verschiedener Email-Adresse anzumelden.
                      Wer eine Mailbox bei einem Anbieter hat, kann in der Regel mehrere Mailboxen und zu jeder Box nochmals mehrere Aliasadressen definieren.

                      Da läufst du vollkommen ins Leere und somit auch Ebay, falls du eine solche Praxis dort vermutest.

                      mfg Beat

                      --
                                       /|
                        <°)))o><      / |    /|
                                  ---- _|___/ |     ><o(((°>
                                 OvVVvO    __ |         ><o(((°>
                      <°)))o><  /v    v\/  |
                       <°)))o>< ^    ^/_/_         ><o(((°>
                                 ^^^^/___/
                      ><o(((°>    ----       ><o(((°>
                         <°)))o><                      ><o(((°>o
                    2. Hallo,

                      Ich überleg grad ein Beispiel. Bei E-Bay dürfte es sicher nicht möglich sein um das Bieten auf eigene Auktionen zu verhindern.

                      schlechtes Beispiel: Gerade bei ebay ist es möglich (und erlaubt), mehrere Accounts zu haben. Die Mailadresse muss zwar unterschiedlich sein[*], aber die Real-Life-Anmeldedaten können mehrmals identisch sein.
                      Das Bieten auf eigene Auktionen ist natürlich trotzdem verboten.

                      Ciao,
                       Martin

                      [*] Aber man kann ja nach der Anmeldung die Mailadresse ändern. Wenn ich da eine angebe, die bereits mit einem anderen Account verwendet wird ... hmm, ich glaube, das muss ich irgendwann mal versuchen. ;-)

                      --
                      Zwei Kumpels sitzen vor dem Computer. "Welche Suchmaschine beutzt du eigentlich meistens?" - "Prima Vera." - "Hmm, kenn' ich gar nicht." Dann geht die Tür auf: "Schatz ich habe deine Sonnenbrille wiedergefunden!" - "Prima, Vera!"
                2. Nö, in dem Fall gehts darum das ein (achtung böses Wort, ich bin auch für RSS ;) ) Newsletter ned mehrmals an dieselbe Person versendet wird.

                  lg
                  Antedulvian

          2. Hallo Beat,

            abuse@example.com
            und
            AbUse@example.com

            sind zwei komplett verschiedene User der Maildomain @example.com

            können selbstverständlich genausogut auch die gleiche Mailbox des gleichen Benutzers der Domain example.com sein. Ob Groß- und Kleinschreibung im localpart der Mailadresse unterschieden wird, ist Sache des jeweiligen Systems. Beim Domänennamen spielt Groß- und Kleinschreibung keine Rolle.

            Freundliche Grüße

            Vinzenz

    5. Moin.

      Statt mit fopen() und fgetcsv() ließe sich deine Schleife auch wie folgt formuliere:

        
      foreach(file($source) as $line) {  
       $data = explode('|', $line);  
       if(count($data) != 4) /* Fehlerbehandlung */;  
       [...]  
      }  
      
      

      Ob das performanter ist, musst du aber schon selbst testen...

      Christoph

      1. PS: Vermutlich ist es sinnvoll, file() die Flags FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES mitzugeben...

        Christoph

  2. Hi!

    Ich bin noch auf ein problem gestossen, das Scriptum wird zu früh vom Server gekillt, da es mehrere Minuten laufen würde...

    Deshalb die Idee nen Zeilen-Parameter zu übergeben
    =>

      
    if(round(($alreadyin_count+$count)/10000)==($alreadyin_count+$count)/10000) // gibt es ne Bessere Möglichkeit zu überprüfen, ob 10000 Zeilen abgearbeitet sind?  
    break;  
     Header("Location: ".$_SERVER['PHP_SELF']."?zeile=".($_GET[zeile]+10000));  
     exit();  
    
    

    Wie kann ich dann noch beim Neustart den Zeile auf die Zeile $_GET['zeile'] setzen?

    Danke
    Antedulvian

    1. Hi!

      Ich bin noch auf ein problem gestossen, das Scriptum wird zu früh vom Server gekillt, da es mehrere Minuten laufen würde...

      Also ohne mich jetzt weiter damit zu beschäftigen[1], (sorry) würde ich einfach Ajax nehmen.

      Du nimmst die ersten 1000, dann kannst du evtl. sowas ausgeben wie "1% geschafft" oder "1000 erledigt" (oh, klingt zweideutig) und schickst den nächsten Request an den Server. Dabei immer einen Zähler mitschicken oder irgendwas, dass das Script wissen lässt welche 1000 Datensätze bereits abgearbeitet wurden und welche als nächstes anstehen.

      Ich hoffe du hast verstanden wie ich das meine.

      Grüße, Matze

      (Sry, bin grad "kurz angebunden" und konnte nicht alles lesen aber wollte helfen - also wenn ich total am Thema vorbei bin SRY!)

  3. Moin.

    Vermutlich geht die meiste Zeit dadurch verloren, dass du bei jedem Schleifendurchlauf einen eigenen mysql_query() absetzt. Man könnte auch erst alle Werte in einem Array sammeln und die Datenbank auf einen Schlag aktualisieren.

    Beispiel:

      
    $values = array();  
    $log = array();  
      
    foreach(file($source, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {  
     $data = explode('|', $line);  
      
     if(count($data) != 4) {  
      $log[] = "illegal record $line";  
      continue;  
     }  
      
     // jede mail-Adresse wird maximal einmal hinzugefügt!  
     $values[strtolower($data[3])] = "('".  
      mysql_real_escape_string($data[0])."', '".  
      mysql_real_escape_string(str_replace(',', '', $data[1]))."', '".  
      mysql_real_escape_string(str_replace(',', '', $data[2]))."', '".  
      mysql_real_escape_string($data[3])."')";  
    }  
      
    $query = 'INSERT INTO '.DB_TABLE.' (title, firstname, lastname, email) VALUES '.  
     implode(', ', $values);  
    
    

    Christoph

    1. Ein Array für 50-100.000 Zeilen braucht aber auch ned grad wenig Speicherplatz, da musst ich noch ne Schleife amchen, dass er das ganze immer in z.B. 1.000er-Abfragen erledigt.

      Aber sonst scheint mir das ganze sehr sinnvoll!

      Danke!
      Antedulvian

      1. Hallo Antedulvian.

        Ein Array für 50-100.000 Zeilen braucht aber auch ned grad wenig Speicherplatz, da musst ich noch ne Schleife amchen, dass er das ganze immer in z.B. 1.000er-Abfragen erledigt.

        Wie schon dedlfix geschrieben hat: benutze Prepared Statements, dann hast du das Problem nicht.

        Servus,
        Flo

      2. echo $begrüßung;

        Ein Array für 50-100.000 Zeilen braucht aber auch ned grad wenig Speicherplatz, da musst ich noch ne Schleife amchen, dass er das ganze immer in z.B. 1.000er-Abfragen erledigt.
        Aber sonst scheint mir das ganze sehr sinnvoll!

        Dir geht dann aber die Kontrolle über die doppelten Einträge verloren. Der "Duplicate entry"-Fehler kommt nur noch einmal pro INSERT-Statement. Und nun finde mal heraus, welche(r) der 1000 Einträge es war(en).

        echo "$verabschiedung $name";