Ankündigung

Einklappen
Keine Ankündigung bisher.

Funktion zur Überprüfung von Datenbankeinträgen

Einklappen

Neue Werbung 2019

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

  • Funktion zur Überprüfung von Datenbankeinträgen

    Hallo,

    ich habe festgestellt, dass ich sehr oft prüfen muss, ob ein einzelne bestimmte Werte bereits in bestimmten Tabellen vorhanden sind.
    Damit ich dafür nicht immer 3-4 Zeilen Code tippen muss, möchte ich das mit einer Funktion lösen.

    Das Problem ist, dass ich in Prepared Statements den Tabellenname nicht variabel machen kann, wie ich bereits rausgefunden haben.
    Meine Funktion sollte so wie unten aussehen, aber :table ist ja leider nicht möglich.

    Deswegen wollte ich hier mal nach Alternativen fragen.
    Dazu möchte ich noch erwähnen, dass der Tabellenname sowie Spaltenname immer von mir definiert wird.
    Das einzige was vom User an die Funktion übergeben werden soll, ist der Wert auf den geprüft werden soll.
    Vielleicht brauche ich dann garnicht unbedingt prepared Statements?


    Die Funktion wie ich sie mir gewünscht hätte:
    PHP-Code:
    <?php
     
    function entrycheck($table$column$checkvalue$pdo) {          
    $check $pdo->prepare("SELECT * FROM :table WHERE :column = :checkvalue");          
    $checkresult $check->execute(array(              
    'table' => $table,              
    'column' => $column,              
    'checkvalue' => $checkvalue          
    ));          
    $check2 $check->fetch();          
    if(!
    $check2) {              
    return 
    "false";          
    } else {              
    return 
    "true";          
    }      
    }

    ?>


    So könnte man sie aufrufen.

    PHP-Code:
     <?php      
    $table 
    "user";      
    $column "username";      
    $checkvalue $_GET['username'];

    $usercheck entrycheck($table$column$checkvalue$pdo);      
    if(
    $usercheck == false) {          
    //z.B. Testuser registrieren        
    } else {          
    echo 
    "Benutzername bereits vergeben";      
    }  
    ?>

    Danke schonmal

    Grüße


    Edit: Wieso wurden nach dem Absenden des Themas die Zeilenumbrüche aus meinem Code entfernt?







  • #2
    Bei Prepared Statements werden nur Parameterwerte separat übergeben. Spalten- und Tabellennamen sind keine Werte, sondern Teil der Datenstruktur, also statisch. Da man als Programmierer diese statischen Strukturen kennen sollte, kann man sie auch direkt in SQL-Code schreiben.

    Eventuell hast du ein grundlegendes Problem mit deiner Datenstruktur. Denn die Aufgabenstellung klingt sehr ungewöhnlich. Vielleicht willst du weiter ausholen, damit man dir effektiver helfen kann? Ich nehme an, dass du bereits Unique-Indexes/Constraints einsetzt, die ein Einfügen von Datenduplikaten verhindern und dir geht es nur um die Vorabprüfung?

    Kommentar


    • #3
      Zitat von Eftee Beitrag anzeigen
      Hallo,

      ich habe festgestellt, dass ich sehr oft prüfen muss, ob ein einzelne bestimmte Werte bereits in bestimmten Tabellen vorhanden sind.
      Damit ich dafür nicht immer 3-4 Zeilen Code tippen muss,

      ... wurden UNIQUE CONSTRAINTS erfunden. Nutze sie.
      PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

      Kommentar


      • #4
        Zitat von hellbringer Beitrag anzeigen
        Bei Prepared Statements werden nur Parameterwerte separat übergeben. Spalten- und Tabellennamen sind keine Werte, sondern Teil der Datenstruktur, also statisch. Da man als Programmierer diese statischen Strukturen kennen sollte, kann man sie auch direkt in SQL-Code schreiben.
        Wenn ich das richtig verstanden habe, möchtest er ein- und dieselbe Funktion für verschiedene Tabellen einsetzen. Die erste Zeile der Funktion
        PHP-Code:
        function entrycheck($table$column$checkvalue, ... {... ) 
        sagt das zumindest ganz deutlich. Und damit ist dieser Teil sehr wohl dynamisch, nur eben nicht mit ":ichBinEinParameter"-Angaben angebbar. Hätte der TE, wie von manchem empfohlen, php und MySQL "von der Pike auf" gelernt statt sofort mit OO, Prepard Statements, PDO & Co. zu arbeiten, hätte er das verstanden und würde das eine und das andere nicht durcheinanderwerfen.
        Jedenfalls kannst du, Eftee, das Problem lösen, wenn du dich einfach mal mit dem Thema "Stringoperationen in php" auseinandersetzen würdest. Was hindert dich denn daran, die Zeichenkette
        Code:
        SELECT * FROM myTableXYZ WHERE spalteABCD = :checkvalue"
        per String-Concatenation dynamisch aus den eingebenen Funktions-Parameter-Werten zusammenzusetzen, die in diesem Fall eben mit "myTableXYZ" und "spalteABCD", in einem anderen Fall vielleicht mit "tbl_kunde" und "kundenNr" übergeben wurden?!

        Eventuell hast du ein grundlegendes Problem mit deiner Datenstruktur. ...
        Das würde sich klären, wenn du, Eftee, einfach einen DB-Dump schicken würdest.

        Kommentar


        • #5
          Vorneweg, wenn ich Code von VSC zwischen die php tags kopiere und dann speicher, gehen die zeilenumbrüche verloren, was tue ich dagegen?
          Zum Thema "Unique-Indexes/Constraints" muss ich mich einlesen, danke fuer den Tipp.


          hellbringer

          Genau ich möchte vorab prüfen, ob z.B. ein username bei der Registrierung bereits in der Datenbank existiert.
          Ähnliche Prüfungen werden auch in Zukunft noch an anderen Stellen erfolgen.

          Im Registrierungsformular zum Beispiel würde ich statt:
          PHP-Code:
          //email                
          $mailcheck $pdo->prepare("SELECT email FROM gw_user WHERE email = :email");                  
          $mailcheckresult $mailcheck->execute(array('email' => $email));                  
          $mailcheck2 $mailcheck->fetch();

          //username
          $usercheck $pdo->prepare("SELECT username FROM gw_user WHERE username = :username");                  
          $usercheckresult $usercheck->execute(array('username' => $username));                  
          $usercheck2 $usercheck->fetch();

          //character
          $charcheck $pdo->prepare("SELECT charname FROM gw_characters WHERE charname = :charname");                  
          $charcheckresult $charcheck->execute(array('charname' => $charname));                  
          $charcheck2 $charcheck->fetch(); 
          ...lieber folgendes schreiben können:

          PHP-Code:
          $usercheck entrycheck("gw_user""username""Testuser"$pdo);      
          $emailcheck entrycheck("gw_user""email""testuser@web.de"$pdo);      
          $charactercheck entrycheck("gw_characters""charname""Thor"$pdo); 
          Ist doch so viel einfacher und weniger Code.


          Kommentar


          • #6
            Warum machst du nicht daraus eine einzige SQL-Abfrage? Wozu 3 verschiedene?

            Davon abgesehen finde ich das jetzt auch nicht so dramatisch. Steht halt 3mal ein ähnlicher Code da, der Großteil Copy-Paste ist. Also Tipparbeit quasi null. Warum stört dich das so?

            Du solltest eher an deinen Variabelnamen arbeiten. Nummerierte Variablen sind Quatsch. Davon abgesehen kann man den Code noch ein Eck vereinfachen:

            PHP-Code:
            $emailCount $db
                
            ->prepare("SELECT COUNT(*) FROM gw_user WHERE email = ?")
                ->
            execute([$email])
                ->
            fetchColumn(0); 

            Kommentar


            • #7
              Zitat von Eftee Beitrag anzeigen
              Vorneweg, wenn ich Code von VSC zwischen die php tags kopiere und dann speicher, gehen die zeilenumbrüche verloren, was tue ich dagegen?
              Zum Thema "Unique-Indexes/Constraints" muss ich mich einlesen, danke fuer den Tipp.


              hellbringer

              Genau ich möchte vorab prüfen, ob z.B. ein username bei der Registrierung bereits in der Datenbank existiert.
              Ähnliche Prüfungen werden auch in Zukunft noch an anderen Stellen erfolgen.

              Im Registrierungsformular zum Beispiel würde ich statt:
              PHP-Code:
              //email
              $mailcheck $pdo->prepare("SELECT email FROM gw_user WHERE email = :email");
              ...

              ...
              $emailcheck entrycheck("gw_user""email""testuser@web.de"$pdo);
              $charactercheck entrycheck("gw_characters""charname""Thor"$pdo); 
              Ist doch so viel einfacher und weniger Code.

              Ließ mal #4. Daran anschließend: Sag mal, was du da mit $pdo übergeben willst.

              Im Übrigen: "einfacher" und "weniger Code" ist zunächst mal überhaupt kein Kriterium. So wie du es schreibst, ist es allerdings plausibel, den es heißt ja nicht "weniger Code", sondern Vermeidung der Wiederholung prinzipiell gleicher/gleichartiger Code-Sequenzen.

              Kommentar


              • #8
                Zitat von hellbringer Beitrag anzeigen
                Warum machst du nicht daraus eine einzige SQL-Abfrage? Wozu 3 verschiedene?

                Davon abgesehen finde ich das jetzt auch nicht so dramatisch. Steht halt 3mal ein ähnlicher Code da, der Großteil Copy-Paste ist. Also Tipparbeit quasi null. Warum stört dich das so?

                Du solltest eher an deinen Variabelnamen arbeiten. Nummerierte Variablen sind Quatsch. Davon abgesehen kann man Code noch ein Eck vereinfachen.
                Schon mal was vom Prinzip der "Modularisierung" gehört? Ich komme mir vor wie in "einem falschen Film": Ist es nicht geradezu eine der Aufgaben des Einsatzes von Funktionen, "3mal ein ähnlichen Code" zu vermeiden? Was ist, wenn er sich da noch andere Vorprüfungen überlegt oder einfach nur seinen Code später verbessert/anpaßt/sonstwie verändert. 3mal Copy & Paste? Und peinlich in seiner "Wo-musste-ich-nochmal-mit-Copy&Paste-Anpassen?"-Merkliste abhaken?

                Ich finde das Anliegen des TE vollauf berechtigt.

                Kommentar


                • #9
                  Zitat von Alf2016 Beitrag anzeigen
                  Schon mal was vom Prinzip der "Modularisierung" gehört? Ich komme mir vor wie in "einem falschen Film": Ist es nicht geradezu eine der Aufgaben des Einsatzes von Funktionen, "3mal ein ähnlichen Code" zu vermeiden? Was ist, wenn er sich da noch andere Vorprüfungen überlegt oder einfach nur seinen Code später verbessert/anpaßt/sonstwie verändert. 3mal Copy & Paste? Und peinlich in seiner "Wo-musste-ich-nochmal-mit-Copy&Paste-Anpassen?"-Merkliste abhaken?
                  Man kann Code später, wenn es erforderlich ist, immer noch refaktorisieren. Das ist in der Praxis durchaus üblich. Wenn du den Anspruch hast von Anfang an den perfekten Code zu schreiben, jede Art von Wiederholung zu vermeiden und alles nach Lehrbuch abzuhandeln, bist du den Großteil deiner Zeit damit beschäftigt genau das zu tun und nicht die eigentliche Aufgabe, um die es geht, zu behandeln.

                  Zitat von Alf2016 Beitrag anzeigen
                  Ich finde das Anliegen des TE vollauf berechtigt.
                  Man muss auch Kosten und Nutzen abwiegen. Ich sehe hier ein 50/50. Kann man optimieren, muss man aber nicht.

                  Kommentar


                  • #10
                    Zitat von hellbringer Beitrag anzeigen

                    Man kann Code später, wenn es erforderlich ist, immer noch refaktorisieren. Das ist in der Praxis durchaus üblich. Wenn du den Anspruch hast von Anfang an den perfekten Code zu schreiben, jede Art von Wiederholung zu vermeiden und alles nach Lehrbuch abzuhandeln, bist du den Großteil deiner Zeit damit beschäftigt genau das zu tun und nicht die eigentliche Aufgabe, um die es geht, zu behandeln.



                    Man muss auch Kosten und Nutzen abwägen [korr. Alf2016]. Ich sehe hier ein 50/50. Kann man optimieren, muss man aber nicht.
                    Das kommt darauf an, ob er sich eher in einer "Lernphase" oder "Umsetzungsphase" befindet. Für mich hörte sich das eher nach "Lernphase" bzw. "am Anwendungsbeispiel etwas Allgemein Nützliches hinzulernen" an.

                    Tatsächlich ist es doch so: Die "Frager" haben oft niemals "Grundlagen studiert" (was hier ja zu recht in mind. jedem 2. Beitrag von den "Antwortern" geraten wird), hetzen dann von "Umsetzungsproblem zu Umsetzungsproblem" ohne zu merken, daß sie immer wieder die (fast) gleichen Probleme allenfalls halb lösen, statt ein einziges Mal richtig.

                    Und die Verallgemeinerung einer bestimmten Aufgabe in einer Funktion ist in meinen Augen nicht gerade eine Art Drang danach, "den perfekten Code zu schreiben", sondern eher das "sich Gewöhnen" an Standard-Programmiertechniken, "bevor es dafür zu spät ist" und man sich von "Codeschnipselabschreiberei" zu "Codeschnipselabschreiberei", von Workaround zu Workaround, von ... zu ... usw. usf. hangelt. Only mho.

                    Kommentar


                    • #11
                      Danke schonmal für euer Feedback und Support.

                      Alf2016
                      Korrekt ich bin in der Lernphase. Habe kürzlich nach gut 12-13 Jahren Pause wieder angefangen.
                      In der Zeit hat sich sehr viel getan, ich habe damals nur die php Basics und mysql_query Geschichten gelernt, das Thema mysql wurde aber in den Büchern die ich damals hatte nicht sehr detailiert ausgeführt.
                      Dann habe ich eigentlich learning by doing mein Wissen erweitert.
                      Jetzt bastel ich eine kleine Gildenwebsite und frische so mein Wissen auf.
                      Die von euch genannten Stichworte werde ich mir ansehen, und auch ein paar Grundlagen aus der Linksammlung.

                      Und die Verallgemeinerung einer bestimmten Aufgabe in einer Funktion ist in meinen Augen nicht gerade eine Art Drang danach, "den perfekten Code zu schreiben", sondern eher das "sich Gewöhnen" an Standard-Programmiertechniken, "bevor es dafür zu spät ist" und man sich von "Codeschnipselabschreiberei" zu "Codeschnipselabschreiberei", von Workaround zu Workaround, von ... zu ... usw. usf. hangelt. Only mho.
                      Sehe ich genauso.
                      Dass ich mit meinem Wissens-stand keinen perfekten Code schreiben werde ist mir bewusst.



                      Außerdem finde ich Funktionen einfach sehr nützlich und werde sie so oft es geht einsetzen. Natürlich nur sofern es sinn macht. Ich sehe auch keine Argumente die gegen Funktionen sprechen würde.
                      Zumal in meinem Fall ja eigentlich auch garnicht die Funktion, sondern die prepared statements das Problem sind.


                      Jedenfalls kannst du,
                      Eftee
                      , das Problem lösen, wenn du dich einfach mal mit dem Thema "Stringoperationen in php" auseinandersetzen würdest.
                      Mach ich, danke.

                      Was hindert dich denn daran, die

                      Zeichenkette
                      Code:
                      SELECT * FROM myTableXYZ WHERE spalteABCD = :checkvalue"
                      per String-Concatenation dynamisch aus den eingebenen Funktions-Parameter-Werten zusammenzusetzen, die in diesem Fall eben mit "myTableXYZ" und "spalteABCD", in einem anderen Fall vielleicht mit "tbl_kunde" und "kundenNr" übergeben wurden?!

                      Was
                      String-Concatenation ist, weis ich leider nicht. Werde es mal nachschlagen.

                      $pdo sieht wie folgt aus:
                      PHP-Code:
                      $pdo = new PDO('mysql:host=localhost;dbname=test''username''password'); 
                      Meinst du ich sollte es so machen?
                      PHP-Code:
                      function entrycheck($table$column$checkvalue$pdo) {          
                      $sql "SELECT * FROM ".$table." WHERE ".$column." = :checkvalue";          
                      $check $pdo->prepare($sql);          
                      $checkresult $check->execute(array(              
                      'checkvalue' => $checkvalue          
                      ));          
                      $check2 $check->fetch();          
                      if(!
                      $check2) {              
                      return 
                      "false";          
                      } else {              
                      return 
                      "true";          
                      }      

                      Kommentar


                      • #12
                        Vorab String concatination ist das, was du hier machst
                        PHP-Code:
                        WHERE ".$column. = 
                        also der Punkt Operator.

                        Nun zum eigentlichen Problem.
                        Abfrage in PDO ob ein User mit Namen Max in der Tabelle Members vorhanden ist.
                        PHP-Code:
                        $username 'Max';

                        $stmt $pdo->prepare("SELECT COUNT(*) FROM members WHERE firstName=?");
                        $stmt->execute([$username]);
                        $name $stmt->fetchColumn();

                        var_dump($name); // int 0 
                        Hier wird der Wert von PDO behandelt, ein Angriff mittels SQL-Injection ist nicht möglich.
                        Mit Count wird die Anzahl der Treffer, sprich Datensätze zurückgegeben. Vorhanden wäre dann 1 oder grösser und nicht vorhanden gäbe ein 0 Integer zurück.
                        Mittels Konvertierung(casten) zu einem Wahrheitswert könnte man das auch als TRUE oder FALSE auswerten.
                        Hier mal der Vollständigkeit halber explizit zu bool konvertiert.
                        PHP-Code:
                        var_dump((bool)$name); 
                        Als Funktion sähe das dann so aus:
                        PHP-Code:
                        function entrycheck($table$column$checkvalue$pdo)
                        {          
                            
                        $stmt $pdo->prepare("SELECT COUNT(*) FROM {$table} WHERE {$column}=?");
                            
                        $stmt->execute([$checkvalue]);

                            return (bool)
                        $name $stmt->fetchColumn();          
                        }

                        $username 'Max';
                        var_dumpentrycheck('members','firstName',$username,$pdo) ); 
                        Dies führt dazu, dass man den String der im prepared Teil fix sein sollte dynamisch zusammenbaut. Die Werte werden zwar immer noch geprüft durch PDO und geben hier Sicherheit, aber da der Tabellenname sowie der Spaltenname nicht mehr fest in der Abfrage steht ist hier keine Sicherheit mehr gegenüber SQL-Injection gegeben.
                        Man müsste also den Tabellennamen gegen eine Whitelist prüfen und anschliessend schauen, ob zu der Tabelle die übergebene Spalte tatsächlich vorhanden ist.
                        Ich würde behaupten wollen, dass es das Wirkprinzip von prepared Statements ad absurdum führt.

                        Man könnte jedoch stattedessen folgendes zusammen bauen
                        PHP-Code:
                        function checkMember($checkvalue$pdo)
                        {          
                            
                        $stmt $pdo->prepare("SELECT COUNT(*) FROM members WHERE firstName=?");
                            
                        $stmt->execute([$checkvalue]);

                            return (bool)
                        $name $stmt->fetchColumn();          
                        }

                        $username 'Max';
                        var_dumpcheckMember($username,$pdo) ); 
                        Braucht man die Abfrage checkMembers öfter innerhalb eines Sripts, könnte es sinnvoll sein so vorzugehen, ansonsten ist der PDO-Dreizeiler wohl die bessere Wahl, da auch sofort die Abfrage ersichtlich ist und man nicht nachschauen muss welchen Rückgabewert man denn nun zu erwarten hat.







                        Kommentar


                        • #13
                          Zitat von Eftee Beitrag anzeigen
                          Danke schonmal für euer Feedback und Support.

                          Alf2016
                          ...
                          Was
                          String-Concatenation ist, weis ich leider nicht. Werde es mal nachschlagen.

                          $pdo sieht wie folgt aus:
                          PHP-Code:
                          $pdo = new PDO('mysql:host=localhost;dbname=test''username''password'); 
                          Meinst du ich sollte es so machen?
                          PHP-Code:
                          function entrycheck($table$column$checkvalue$pdo) {
                          $sql "SELECT * FROM ".$table." WHERE ".$column." = :checkvalue";
                          $check $pdo->prepare($sql);
                          $checkresult $check->execute(array(
                          'checkvalue' => $checkvalue
                          ));
                          $check2 $check->fetch();
                          if(!
                          $check2) {
                          return 
                          "false";
                          } else {
                          return 
                          "true";
                          }

                          Exakt das meinte ich.

                          Und mit "von der Pike auf" lernen meinte ich, daß man, wenn man nicht sofort mit PDO usw. beginnt, um Dinge wie die Verkettung von statischen Texten mit Variablen, wie du es oben machst, nicht herum kommt. Auch die Maskierung von bestimmten Sonderzeichen, Verhinderung von SQL-Injections usw. muß man sich selbst kümmern. Bei objektorientierte Verwendung von mysqli oder gar PDO wird einem das alles abgenommen. Dann passiert es, daß man prepared statements arbeitet, obwohl das gar nicht nötig wäre. Oder noch häufiger wird völlig unnötigerweise mit Bindung von Parametern gearbeitet, obwohl die nur ein einziges Mal vorkommen bzw. benutzt werden.

                          Das heißt ja nicht, daß man dabei stehen bleiben muß. Aber ich glaube, wer sich ein bisschen mit den "steinzeitlichen" Methoden beschäftigt hat, kann auch differenzierter mit den modernen Dingern umgehen.

                          Natürlich: hellbringer hat mit seinem "abwägen/Optimierungsansatz" genauso Recht, wie die Pädagogen, Didaktiker, Lehrer, Dozenten. "Lehrmeister" usw. egal welchen Standpunkt sie in dieser uralten Debatte vertreten. Die "Alten", Universalgenies wie Da Vinci usw. hatten dieses Problem nicht, sie hatten nur die "Steinzeit-Tools".

                          Wenn dich das Thema interessiert. In der kleinen Novelle (?, heißt das so? keine Ahnung) "Die neuen Leiden des jungen W." wird der Lehrmeister mit der Anforderung an seinen Schützling zitiert:
                          "Hier habt Ihr ein Stück Eisen! Wenn Ihr aus dem eine Uhr machen könnt, habt Ihr ausgelernt. Nicht früher und nicht später."
                          Das geht sicher um einiges zu weit, aber alles, was "vor unserer Zeit" war, zu ignorieren, ist auch nichts gescheites...

                          Kommentar


                          • #14
                            protestix

                            als Alternative:

                            Code:
                            function entrycheck ($query, $pdo, $checkvalue)...
                            
                            entrycheck("SELECT COUNT(*) FROM members WHERE firstName=?", $pdo, $username)....

                            Kommentar


                            • #15
                              Noch eine kleine Ergänzung:
                              Zitat von Eftee Beitrag anzeigen
                              PHP-Code:
                              []
                              if(!
                              $check2) {
                              return 
                              "false";
                              } else {
                              return 
                              "true";
                              }

                              Hier würde ich false und true zurückliefern, nicht die Strings "false" und "true" (die geben beide wieder true) …

                              Kommentar

                              Lädt...
                              X