Ankündigung

Einklappen
Keine Ankündigung bisher.

Funktion mit Array und prepare in Datenbank schreiben

Einklappen

Neue Werbung 2019

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

  • #61
    Ich kann nur nochmal auf #54 verweisen. Schreib den Query per Hand und vergleich den mit deinem Code.

    Kommentar


    • #62
      Zitat von mfeske Beitrag anzeigen
      Ich wollte mir eine Funktion bauen, die ich für all meine Formulare anwenden kann, egal welche Felder dort verwendet werden Ich bin also auf dem völlig falschen Weg ? Ich glaube ich werde mir mal ein mini Beispiel zusammenbauen und testen. Ich bin halt davon ausgegangen, das ich es so umsetzen könnte. Das array ist ja befüllt und könnte dann für das schreiben in die datenbank zerlegt werden.
      Nehmen wir an du hast 4 Tabellen.
      Dann hast du wenn du die 3. Normalform angewendest hast als einziges Feld die Id als immer wiederkehrendes Feld in allen Tabellen.

      Mit einer DB kannst du Daten nun selektieren, ändern, löschen und neue hinzufügen.
      Entsprechend
      SELECT...
      UPDATE...
      DELETE...
      INSERT...

      Wenn du das auf 4 Tabellen anwendest hast du 16 mögliche Formulare, wenn du diese nicht doppelt verwendest.

      Wenn du also aus 16 Formularen eine universelle Abfrage, die alles abdecken soll erstellen möchtest, musst du wissen welche Abfrage in Frage kommt und welche Tabelle betroffen sein wird.
      Man braucht also im Formular den Namen der Tabelle die zur Anwendung kommt in einem hidden Feld.
      Dann brauchst du noch die Art der Anwendung: Löschen, Neu hinzufügen, etc. in einem hidden Feld, denn irgendwie musst du ja an diese Information gelangen.

      Da die Statements alle unterschiedlich sind, kannst du da also schon mal nicht ansetzen, brauchst also dennoch 4 Statements die du dir individuell zusammenbaust, was demnach dann wohl auf 4 Funktionen hinauslaufen dürfte.

      Da du aber manchmal nicht weisst wie ein SELECT aussehen soll, denn ein WHERE LIKE ist ja schon mal anders als ein WHERE Id>1234 ORDER BY Nachname, lässt sich dein Vorhaben meiner Meinung nach nicht sinnvoll umsetzen.

      Einzig vielleicht Löschen anhand einer id kann man für alle Tabellen nehmen.

      Darüber hinaus, wenn du dir die Mühe machen solltest 16 Formulare zu entwickeln, dann ist das vom Aufwand wesentlich mehr Zeit als mal eben 16 SQL Anweisungen runterzuschreiben, meine Meinung.





      Kommentar


      • #63
        Danke, das hat mir schon ein wenig die Augen geöffnet Als erstes habe ich jetzt in mein Formular ergänzt um:
        HTML-Code:
        <input id="dbtable" name="dbtable" class="form-control input-sm" type="hidden" value="my_log">
        <input id="dbstatement" name="dbstatement" class="form-control input-sm" type="hidden" value="INSERT INTO">
        Auf den vardump $dbh erhalte ich jetzt in der Funktion auch ein
        Code:
        object(PDO)#1 (0) { }
        Die Funktion sieht jetzt so aus:
        PHP-Code:
        function dbin($dbh) {

            
        $felder $_POST['feld'];
            
        $dbtable $_POST['dbtable'];
            
        $dbstatement $_POST['dbstatement'];

            echo 
        "begin debug<br />\n";
            echo 
        "function: dbin<br />\n";
            echo 
        "DB: $dbstatement $dbtable<br />\n";
            echo 
        "mysql:host=$dbserver;dbname=$dbname$dbuser$dbpass<br />\n";

            foreach (
        $felder as $field => $value) {

                    echo 
        "$field = $value<br />\n";

                }

            echo 
        "<br />\nvardump stmt<br />\n";
            
        var_dump($stmt);

            echo 
        "<br />\nvardump dbh<br />\n";
            
        var_dump($dbh);

            echo 
        "<br />\nend debug<br />\n"//debug ende

            
        foreach($felder as $field => $val) {

                
        $stmt $dbh->prepare("$dbstatement $dbtable ($field) VALUES (?)");
                
        $stmt->execute(array(':field' => $field':value' => $val));

                echo 
        "field $field value $val<br />\n";

            }


        Mein Fehler scheint in den Zeilen:
        $stmt = $dbh->prepare("$dbstatement $dbtable ($field) VALUES (?)");
        $stmt->execute(array(':field' => $field, ':value' => $val))

        zu liegen, da ich die Fehlermeldung "Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /.../_function.php on line 42" erhalte in der Anzahl der Werte die ich übergebe. Ich muss vermutlich irgendwie ermitteln, wie viele Werte ich übergebe ?!

        Kommentar


        • #64
          Zitat von mfeske Beitrag anzeigen
          PHP-Code:
          $stmt $dbh->prepare("$dbstatement $dbtable ($field) VALUES (?)");
          $stmt->execute(array(':field' => $field':value' => $val)) 
          Das ist doch auch Qautsch was du da schreibst.

          PHP-Code:
          $stmt $dbh->prepare("$dbstatement $dbtable ($field) VALUES (:value)");
          $stmt->execute([':value' => $val]); 
          so müsste es aussehen, aber dann macht $prepare kein Sinn mehr, weil man vor einer Schleife prepared und in der Schleife dann ausführt. Da kannst du dann auch ohne prepare, einfach dein SQL Query zusammen setzen und mit http://php.net/manual/de/pdo.exec.php die Abfrage ausführen

          Kommentar


          • #65
            PHP-Code:
            foreach($felder as $field => $val) {

                
            $stmt $dbh->prepare("$dbstatement $dbtable ($field) VALUES (?)");
                
            $stmt->execute(array(':field' => $field':value' => $val));

                echo 
            "field $field value $val<br />\n";

                } 
            Was Du da machst ist leider Unsinn ( Edit: hat BlackScorp schon geschrieben ).

            Entweder Du verwendest die QuestionMark- oder NamedPlaceholder-Logik.
            Hab es jetzt nicht getestet, aber so in etwa müsste das ohne Schleife aber mit prepare() funktionieren:
            PHP-Code:
            $sFieldList implode','array_keys($felder) );
            $sPlaceholders trimstr_repeat('?,'count($felder)), ',' );

            $stmt $dbh->prepare'INSERT INTO table (' $sFieldList ') VALUES (' $sPlaceholders ')' );
            $stmt->execute$felder ); 

            Kommentar


            • #66
              Das leuchtet mir ein, die Schleife ist also Quatsch. Lieber zerlegen und zählen. Okay.
              Aber ich bekomme jetzt noch ein PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in /.../_function.php on line 51 bei der Version von Arne Drews
              Ein echo hat ergeben
              Array ( [kdnr] => 2000 [renr] => 2017-05-01 [mandat] => 000 [mmgroup] => Buchhaltung [mmtype] => Neue Bankverbindung [benutzername] => Mr. Test )
              kdnr,renr,mandat,mmgroup,mmtype,benutzername
              ?,?,?,?,?,?

              das sollte doch so passen ?

              mit
              PHP-Code:
                  foreach($felder as $field => $val) {
                         
              stmt $dbh->prepare("$dbstatement $dbtable ($field) VALUES (:value)");
                  
              stmt->execute([':value' => $val]);
                  } 
              erhalte ich zwar keine Fehlermeldung, aber die Werte stehen auch nicht in der Tabelle

              Nachtrag: Ich nehme es zurück. Letztere Version schreibt in die Datenbank, allerdings für jedes Feld ein eigener Datensatz

              Kommentar


              • #67
                Zitat von mfeske Beitrag anzeigen
                Letztere Version schreibt in die Datenbank, allerdings für jedes Feld ein eigener Datensatz
                Wie das wohl zu stande kommt...

                Zitat von mfeske Beitrag anzeigen
                Das leuchtet mir ein, die Schleife ist also Quatsch. Lieber zerlegen und zählen. Okay.
                Aber ich bekomme jetzt noch ein PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in /.../_function.php on line 51
                Mit namenlosen Parametern kannst kein assoziativen Array verwenden.

                PHP-Code:
                $stmt->execute(array_values($felder)); 
                Den Code von Arne solltest du aber nicht 1:1 übernehmen. Wenn die Feldnamen in der Form übernommen werden, sind SQL Injections möglich.

                Kommentar


                • #68
                  Oder.. Prepared Statments auch "sinngemäß" nutzen: https://stackoverflow.com/a/8362114

                  Statt DRY halt in einer Schleife.

                  Kommentar


                  • #69
                    Anmerkung zur Problemstellung:
                    Spätestens wenn mit einem Insert mehrere Zeilen eingefügt werden sollen, die samt Feldnamen aus einem mehrdimensionalen Array kommen, wird die Verwendung von Prepared Statments an dieser Stelle fraglich.
                    Wenn für die Generierung der Platzhalter schon eine Schleife (oder Array-Funktion) notwendig ist, dann können auch gleich die Werte selbst (s.a. PDO::quote) und zur Sicherheit auch die Feldnamen escaped werden und die komplette SQL-anweisung als String zusammengebaut werden. Die Verfügbarkeit der kompletten SQL-Anweisung bringt dann für Test und Debugging große Vorteile.

                    Kommentar


                    • #70
                      Hallo zusammen,
                      wenn ich das stmt außerhalb der Schleife durchführe wird natürlich auch nur noch ein Datensatz geschrieben, allerdings auch nur mit dem Wert Benutzername.

                      PHP-Code:
                      foreach($felder as $field => $val) {          $stmt $dbh->prepare("$dbstatement $dbtable ($field) VALUES (:value)"); } $stmt->execute([':value' => $val]); var_dump($stmt); 
                      var_dump ergibt object(PDOStatement)#3 (1) { ["queryString"]=> string(49) "INSERT INTO my_log (benutzername) VALUES (:value)" } Wenn ich es mit $stmt->execute(array_values($felder)); statt $stmt->execute($felder); versuche erhalte ich keine Fehlermeldung aber auch keinen Datenbankeintrag.
                      PHP-Code:
                       $sFieldList implode','array_keys($felder) ); $sPlaceholders trimstr_repeat('?,'count($felder)), ',' ); echo "$sFieldList<br />\n"; echo "$sPlaceholders<br />\n"; echo "<br />\n"$stmt $dbh->prepare'$dbstatement $dbtable (' $sFieldList ') VALUES (' $sPlaceholders ')' ); #$stmt->execute($felder); $stmt->execute(array_values($felder)); 
                      jspit welches Infos fehlen noch ? Wie gesagt Ziel war es diese Funktion mit jedem Formular für ein insert zu nutzen.

                      Kommentar


                      • #71
                        Hi mfeske,

                        Zitat von mfeske Beitrag anzeigen
                        welches Infos fehlen noch ? Wie gesagt Ziel war es diese Funktion mit jedem Formular für ein insert zu nutzen.
                        Ich würde das eher umgekehrt machen: Die Spaltennamen einer Tabelle auslesen und daraus ein Formular generieren.

                        Nehmen wir mal eine einfache Tabelle: id, vorname, nachname, plz, ort, strasse.

                        Das folg. Script fragt einen Datensatz ab und generiert die entsprechenden Textfelder nebst Label. Die Textfelder werden als

                        assoziatives Array "feld" angelegt mit den Spaltennamen der Tabelle als ArrayKey. (siehe Kommentare im Script)

                        Nach Senden des Formulars wird die Abfrage eingeleitet.

                        PHP-Code:
                        $query 'insert into '.$table.'('.implode(','array_keys($_POST['feld'])).')'
                        Ausgabe $query: insert into test(vorname,nachname,plz,ort,strasse)

                        Anschließend wird der values-Teil mit den Platzhaltern für das prepare-Statement erstellt.

                        PHP-Code:
                         /* Die Platzhalter für das Prepare-Statement */
                         
                        $values 'values(';
                         foreach(
                        array_keys($_POST['feld']) as $key => $value){
                          
                        $values.=':'.$value.',';
                         }
                         
                        /* Das letzte Komma entfernen und die schließende Klammer anhängen */
                         
                        $values substr($values0, -1);
                         
                        $values.=')'
                        Ausgabe $values: values(: vorname,: nachname,: plz,: ort,: strasse)

                        Zum Schluß $query und $values zusammensetzen.

                        PHP-Code:
                        $query.=$values
                        Ausgabe $query mit Platzhalter für prepare ist jetzt: insert into test(vorname,nachname,plz,ort,strasse)values(: vorname,: nachname,: plz,: ort,: strasse)

                        Nach Ausführen von PDOStatement->prepare($query) werden die ArrayKeys und die ArrayValues der Textfelder "feld" mittels array_combine in ein Array abgelegt.

                        PHP-Code:
                        $data_array array_combine(array_keys($_POST['feld']), array_values($_POST['feld'])); 
                        Ausgabe $data_array:
                        Array
                        (
                        [vorname] => Micky
                        [nachname] => Mouse
                        [plz] => 7123
                        [ort] => Disneyland
                        [strasse] => Walt-Disney-Street
                        )

                        Zum Schluß noch die Abfrage ausführen.

                        PHP-Code:
                         /* Abfrage ausführen */
                         
                        if(!$stmt->execute($data_array)){
                          
                        print_r($stmt->errorInfo());
                         }else{
                             echo 
                        "Abfrage wurde erfolgreich ausgeführt.";
                             } 
                        Das komplette Script.

                        PHP-Code:
                        <?php
                        session_start
                        ();
                        ini_set('error_reporting'E_ALL);
                        $conn = new PDO("mysql:host=localhost;dbname=test2""guenni""guenni");
                        /*
                        * Abgefragte Tabelle
                        */
                        $table "test";
                        /*
                        * Einen Datensatz abfragen zur Ermittlung der Spaltennamen
                        * PDO::query gibt (bei Erfolg) ein PDOStatementObjekt zurück
                        */
                        $columns $conn->query('SELECT * FROM '.$table.' limit 1');
                        ?>
                        <!DOCTYPE HTML>
                        <html>
                        <head>
                        <title>Untitled</title>
                        </head>
                        <body>
                        <h3></h3>
                        <form action="" method="post">
                        <?php
                        /*
                        * Die Funktion PDOStatement::getColumnMeta liefert ein Array mit Info über eine Tabellenspalte
                        * wobei hier nur der Name der Spalte gebraucht wird.
                        * Zum Anschauen den folg. TestCode auskommentieren
                        */
                        /* TestCode
                        $i=0;
                        echo '<pre>Info über Tabellenspalten der tabelle '.$table.'<br>';
                        while($column = $columns->getColumnMeta($i++)){
                         print_r($column);
                        }
                        exit;
                        Ende TestCode */
                        /*
                        * Das Tabellenfeld ID ist vom Typ PrimaryKey/AutoIncrement
                        * Das wird übersprungen und $i auf 1 gesetzt
                        * Der folgende Code erzeugt für jede Tabellenspalte ein Label und ein Textfeld
                        * Beispiel Spalte "Vorname":
                        * <p><label for=vorname>Vorname:&nbsp;</label><input type="text" id="vorname" name="feld[vorname]"/></p>
                        * Die Textfelder werden als assoziatives Array angelegt, die ArrayKeys sind jeweils die Spaltennamen
                        * Die ArrayKeys werden gebraucht um die Abfrage aufzubauen (s.u.)
                        */
                        $i=1;
                        while(
                        $column $columns->getColumnMeta($i++)){
                         echo 
                        '<p><label for="'.$column["name"].'">'.ucfirst($column["name"]).':&nbsp;</label>';
                         echo 
                        '<input type="text" id="'.$column["name"].'" name="feld['.$column["name"].']"/></p>';
                        }
                        ?>
                        <p><input type="submit" name="cmd" value="Senden"/></p>
                        </form>
                        <?php
                        /* Das Formular wurde gesendet */
                        if(isset($_POST['cmd'])){
                         
                        /* Die Abfrage */
                         
                        $query 'insert into '.$table.'('.implode(','array_keys($_POST['feld'])).')';
                         
                        /* Die Platzhalter für das Prepare-Statement */
                         
                        $values 'values(';
                         foreach(
                        array_keys($_POST['feld']) as $key => $value){
                          
                        $values.=':'.$value.',';
                         }
                         
                        /* Das letzte Komma entfernen und die schließende Klammer anhängen */
                         
                        $values substr($values0, -1);
                         
                        $values.=')';
                         
                        /* Query und Values zusammensetzen und Prepare-Statement ausführen */
                         
                        $query.=$values;
                         
                        $stmt $conn->prepare($query);
                         
                        /* Die Arrayschlüssel und Arraywerte in einem Array ablegen */
                         
                        $data_array array_combine(array_keys($_POST['feld']), array_values($_POST['feld']));
                         
                        /* Abfrage ausführen */
                         
                        if(!$stmt->execute($data_array)){
                          
                        print_r($stmt->errorInfo());
                         }else{
                             echo 
                        "Abfrage wurde erfolgreich ausgeführt.";
                             }
                        }
                        ?>
                        </body>
                        </html>
                        Das Ganze war mal ein Versuch, einen Formulargenerator zu erstellen. Was fehlt?

                        - Überprüfen der Formularfelder auf Vollständigkeit/Gültigkeit
                        - Sicherheit
                        - Wie erkennt das Script, ob ein Input-, Checkbox- oder Radiofeld erstellt werden soll
                        - und was einem sonst noch so auf(ein)fällt

                        Gruß
                        Günni

                        Kommentar

                        Lädt...
                        X