Lupinius: Probleme bei Registrierung über PHP.

Ich probiere gerade eine PHP-Testseite zu programmieren, mit Registration etc.
Die funktioniert auch schon, nur das Es unendlich viele Benutzer mit dem gleichen Namen geben kann. Was ich dagegen größtenteils von php-quake.net geklaut habe funtioniert nicht. UNd ich komme einfach nicht dahinter warum nihct. Wäre nett wenn ich Hilfe bekommen könnte. Das Skript ist:

$db = @new mysqli( SQL_HOST, SQL_USER, SQL_PASS, SQL_BASE);  
$sql = "SELECT  
	ID  
FROM  
	users  
WHERE  
	Nickname = ?  
LIMIT  
	1";  
$stmt = $db->prepare($sql);  
$stmt->bind_param("s", $User);  
$stmt->execute();  
$stmt->store_result();  
if (!$stmt->num-rows) {  
echo "Der Benutzername wird bereits verwendet.";  
} else {  
//Registrierung

Die Datenbankverbindung stimmt so, und der SQL-Query auch (seperat getestet).

  1. Hi,

    Die funktioniert auch schon, nur das Es unendlich viele Benutzer mit dem gleichen Namen geben kann.

    Das kann man uebrigens sinnvoller verhindern, in dem man die Spalte in der Tabelle unique macht, und dann beim Versuch des nochmaligen Einfuegens des gleichen Namens den entsprechenden Fehler abfaengt.

    $sql = "SELECT
    ID
    FROM
    users
    WHERE
    Nickname = ?
    LIMIT
    1";

    OK, "selektiere von all den Datensaetzen mit bestimmtem Nickname wahllos einen".

    if (!$stmt->num-rows) {
    echo "Der Benutzername wird bereits verwendet.";

    Dann ueberleg jetzt mal, was num-rows in den einzelnen, zu betrachtenden Testfaellen liefern wird.

    MfG ChrisB

    --
    „This is the author's opinion, not necessarily that of Starbucks.“
    1. Ähm...
      Kann sein das es für mein Hirn einfach schon zu spät ist, aber gehts auch etwas direkter?

      1. Hi,

        Ähm...
        Kann sein das es für mein Hirn einfach schon zu spät ist, aber gehts auch etwas direkter?

        Nein. Ich habe dir eine Frage gestellt, und die zu beantworten ist deine Aufgabe als Ersteller des Scriptes.

        Du beabsichtigst dort in deinem Code aus num_rows irgendwelche Schluesse zu ziehen - also *musst* du dir doch ueberlegt haben, was num_rows in den jeweils potentiell auftretenden Faellen fuer Werte liefern kann.
        Denn ohne dies ueberdacht zu haben, waere es ja unsinnig, Schluesse ziehen zu wollen.

        Also: *Was* soll num_rows dort *wann* liefern?

        MfG ChrisB

        --
        „This is the author's opinion, not necessarily that of Starbucks.“
        1. Achso. War dann wohl doch die Uhrzeit.

          Also: Wenn in der Datenbank ein Eintrag mit dem Namen gefunden wurde ist die Länge = 1. Wenn nicht = NULL.

          1. Hi,

            Also: Wenn in der Datenbank ein Eintrag mit dem Namen gefunden wurde ist die Länge = 1. Wenn nicht = NULL.

            Na dann schau dir jetzt den Schluss noch mal an, den du daraus ziehst.

            Du hast ein negierendes ! vor den Wert in der If-Bedingung gesetzt, also ...?

            MfG ChrisB

            --
            „This is the author's opinion, not necessarily that of Starbucks.“
          2. echo $begrüßung;

            Also: Wenn in der Datenbank ein Eintrag mit dem Namen gefunden wurde ist die Länge = 1. Wenn nicht = NULL.

            Zum einen entsteht nicht NULL, denn das ist im Datenbankkontext ein spezieller Wert. Es entsteht vielmehr eine leere Menge und num_rows liefert 0.

            Dann sagt dein Codeschnipsel
              if (!$stmt->num-rows) {
            dass von der Eigenschaft $stmt->num der Wert der Konstanten rows subtrahiert werden soll. Solche Fehler bekommst du indirekt angezeigt, wenn du das error_reporting auf E_ALL stellst, was beim Entwickeln immer eine gute Idee ist.

            Abgesehen von Vinzenz' Vorschlag, der in deinem Fall einer Zählung vorzuziehen ist, machst du den üblichen Unfug, erst mal alle Datensätze anzufordern und sie dann zählen zu wollen. Um dies tun zu können, müssen sie vollständig zum Client übertragen werden. Und anschließend wirfst du die Datenmenge ungenutzt weg. In deinem Fall mit dem einen zu erwartenden Datensatz ist das kein gravierendes Problem, aber wenn du das Prinzip auf eine große Datenmenge anwendest, ist das deutlicher spürbar. Zum Zählen von Daten gibt es die Funktion COUNT() im DBMS. Diese liefert definiert ein einziges Ergebnis.

            echo "$verabschiedung $name";

            1. Moin!

              Abgesehen von Vinzenz' Vorschlag, der in deinem Fall einer Zählung vorzuziehen ist, machst du den üblichen Unfug, erst mal alle Datensätze anzufordern und sie dann zählen zu wollen.

              Stimmt nicht. Siehe Code:

              $sql = "SELECT  
                      ID  
              FROM  
                      users  
              WHERE  
                      Nickname = ?  
              LIMIT  
                      1";  
              $stmt = $db->prepare($sql);  
              $stmt->bind_param("s", $User);  
              
              

              Noch schöner und übersichtlicher kann man das SQL doch gar nicht mehr schreiben. Und noch vorbildlicher Prepared Statements nutzen auch nicht.

              Das ändert natürlich nichts daran, dass diese Vorgehensweise nicht atomar ist und deshalb potentiell Duplikate erzeugen könnte.

              - Sven Rautenberg

              1. echo $begrüßung;

                » Abgesehen von Vinzenz' Vorschlag, der in deinem Fall einer Zählung vorzuziehen ist, machst du den üblichen Unfug, erst mal alle Datensätze anzufordern und sie dann zählen zu wollen.
                Stimmt nicht. Siehe Code:
                Noch schöner und übersichtlicher kann man das SQL doch gar nicht mehr schreiben. Und noch vorbildlicher Prepared Statements nutzen auch nicht.

                Ach was. Die äußerliche Form ändert nichts daran, dass er zum Zählen die gesamte Datenmenge antreten lässt, statt dem DBMS die Frage nach der Anzahl direkt zu stellen. Der springende Punkt ist der Unterschied zwischen

                SELECT ... FROM ...

                und

                SELECT COUNT(*) FROM ...

                Daran ändert auch ein Prepared Statement nichts.

                echo "$verabschiedung $name";

                1. Hallo

                  Ach was. Die äußerliche Form ändert nichts daran, dass er zum Zählen die gesamte Datenmenge antreten lässt,

                  Mit:

                  ...  
                  LIMIT  
                          1";
                  

                  ... kommt doch eh nur bestenfalls *ein* Datensatz zurück. Dass das bei den Voraussetzungen (bezüglich mehrerer gleicher Benutzernamen) und diesem Query nicht der Richtige sein muss, ist eine andere Sache.

                  Tschö, Auge

                  --
                  Die deutschen Interessen werden am Liechtenstein verteidigt.
                  Veranstaltungsdatenbank Vdb 0.2
                  1. echo $begrüßung;

                    » Ach was. Die äußerliche Form ändert nichts daran, dass er zum Zählen die gesamte Datenmenge antreten lässt,
                    Mit: LIMIT 1 kommt doch eh nur bestenfalls *ein* Datensatz zurück. Dass das bei den Voraussetzungen (bezüglich mehrerer gleicher Benutzernamen) und diesem Query nicht der Richtige sein muss, ist eine andere Sache.

                    Auch wieder wahr. Zumindest in dem Fall. Das Prinzip bleibt trotzdem nicht sinnvoll. Ob es der richtige ist oder nicht ist hier egal, denn er wollte ja überhaupt nur wissen, ob es etwas gibt.

                    echo "$verabschiedung $name";

            2. Vielen Dank, daran (und an dem !) lag es.

    2. Moin!

      »» $sql = "SELECT
      »» ID
      »» FROM
      »» users
      »» WHERE
      »» Nickname = ?
      »» LIMIT
      »» 1";

      OK, "selektiere von all den Datensaetzen mit bestimmtem Nickname wahllos einen".

      Falsch. Hier wird, was lobenswert ist, MySQLi und ein Prepared Statement verwendet. Lies den Code nochmal genauer. :)

      - Sven Rautenberg

      1. echo $begrüßung;

        » » $sql = "SELECT
        » » ID
        » » FROM
        » » users
        » » WHERE
        » » Nickname = ?
        » » LIMIT
        » » 1";
        »
        » OK, "selektiere von all den Datensaetzen mit bestimmtem Nickname wahllos einen".
        Falsch. Hier wird, was lobenswert ist, MySQLi und ein Prepared Statement verwendet. Lies den Code nochmal genauer. :)

        Wieso? "mit bestimmtem Nickname" ist doch genau ein Wert oder als Bedingung ausgedrückt: Nickname = ?. Wenn davon mehrere in der Tabelle stehen, gibt die Abfrage wahllos einen davon zurück. Dass dieser eine Wert per Prepared Statement übergeben wird ändert nichts am Statement.

        echo "$verabschiedung $name";

  2. Hallo,

    es ist keine gute Idee, vorher zu prüfen, ob ein Benutzername bereits verwendet wird, weil dies zu einer Race-Condition führt.

    $db = @new mysqli( SQL_HOST, SQL_USER, SQL_PASS, SQL_BASE);

    $sql = "SELECT
    ID
    FROM
    users
    WHERE
    Nickname = ?
    LIMIT
    1";
    $stmt = $db->prepare($sql);
    $stmt->bind_param("s", $User);
    $stmt->execute();
    $stmt->store_result();
    if (!$stmt->num-rows) {
    echo "Der Benutzername wird bereits verwendet.";
    } else {

      
    Sinnvoller ist es, einen UNIQUE-Index auf die Spalte Nickname zu setzen, das INSERT zu versuchen. Wird das INSERT erfolgreich ausgeführt, ist alles in Butter. Schlägt die INSERT-Operation wegen einer Schlüsselverletzung fehl, gab es den Nickname bereits in der Tabelle, und Du kannst dem Benutzer die traurige Mitteilung machen, dass er sich einen anderen Nick auswählen soll.  
      
    Gibt es irgendeinen anderen Fehler, so informiere den Benutzer, dass die Registrierung im Moment nicht möglich ist - und logge den Fehler, damit Du kontrollieren kannst, wann Fehler auftreten.  
      
    Woher kommt eigentlich der Inhalt der Variablen $User, die Du an das Statement bindest?  
      
      
    Freundliche Grüße  
      
    Vinzenz