MySQL PDO Update

  • Hallo Community,


    ich komme bei einem MySQL Problem nicht weiter...
    ich habe folgenden Code:


    Ich vergleiche hier 2 Arrays die genau gleich aufgebaut sind.
    Die IFs erweitern den SQL Befehl wenn die 2 Arrays unterschiedlich sind.
    Ist nichts unterschiedlich wird auch kein Update gemacht.
    Das vardump vom Statement liefert folgendes:

    Code
    object(PDOStatement)#3 (1) {
      ["queryString"]=>
      string(141) "UPDATE `bilderdatenbank` SET `kommentar_kon` = ? , 
    `erledigt` = ? , `erledigt_von` = ? , `erledigt_am` = ? , `merker_kon` =
     ?  WHERE `id` = ?"
    }


    Leerzeichen, Backticks, alles ist so wie es sein sollte.
    Das vardump von Werte liefert folgendes:

    Code
    string(58) "" jetzt gehts wieder ned", "1", "rb", "2017-03-22", "true""


    Kurze Erklärung:
    Der lange Text ist von einem Textarea, Feld in der DB ist varchar.
    Der zweite Wert "1" ist von einem Dropdown welches 0,1 und e enthält. Das Feld ist varchar.
    Der dritte Wert wird bei Login gesetzt und kommt aus der Session, DB varchar.
    Der vierte Wert spuckt eine Funktion aus und ist immer " heute". Feld in DB ist DATE.
    Der letzte Wert ist von einer Checkbox, Feld in DB ist BOOL.


    Das Textarea wird vorher nacher verglichen und der neue Teil soll in eine neue Tabellenspalte "kommentar_kon" (varchar) geschrieben werden.
    IDs stehen in beiden Arrays und nach denen richtet sich alles.


    Mein Problem ist:
    Der Code den vardump ausspuckt stimmt ja und wenn ich die ? durch die Werte ersetze und im SQL direkt ausführe geht es ja auch.

    SQL
    UPDATE `bilderdatenbank` SET `erledigt`='1' ,`erledigt_von`='rb' ,`erledigt_am`='2017-08-12' ,`merker_kon`='1' ,`kommentar_kon`='mach jetzt' WHERE `id` = '16'


    Das errorinfo spuckt HY093 aus.
    Onkel Google sagt, das kann alles sein. Ein Schreibfehler.
    Spaltennamen, Leerzeichen, Anführungsstrichchen alles schon probiert.


    Falls mir jemand helfen kann.
    Danke schonmal.


    Gruß Humbi

  • Hallo,


    ich tippe (erstmal) auf den hier:

    PHP
    $statement->execute(array($werte, "$neu[id]"));


    Da sollten keine Anführungszeichen sein.


    Ausserdem: Da das Update nur ausgeführt wird, wenn
    if($alt[id]==$neu[id])
    ist und $neu[id] sich ja innerhalb eines foreach-Durchlaufs nicht ändert, kannst Du $neu[id] auch gleich in das prepare stecken (also:
    ("UPDATE `bilderdatenbank` SET $code WHERE `id` = ' " . $neu[id] . " ' " );
    bzw. bei Integer-Spalte:
    ("UPDATE `bilderdatenbank` SET $code WHERE `id` = " . $neu[id] . " );


    und das execute dann
    execute(array($werte))


    Das prepare muss ja in jedem Durchlauf erneut gesetzt werden, da sich ja Eingabedaten ändern können.

    Einmal editiert, zuletzt von EBM () aus folgendem Grund: Code wird durch Tags verändert

  • Hallo EBM,


    danke erstmal für deine Antwort.
    Hab beides probiert, beides half leider nicht.


    Was ich glaub vergessen habe zu erwähnen aber aus dem Code hervorgehen sollte.
    Die drei Elemente Textarea, Dropdown und Checkbox sind unabhängig voneinander.
    Es funktioniert nicht mit 3, 2 oder einzeln.
    Die DB bleibt unverändert.


    EDIT: ich meld mich nochmal.
    Hab herausgefunden das mit der checkbox was nicht stimmt.
    Die steht im Prepare immer drin aber es fehlt der Wert dazu :pinch:


    Gruß Humbi

  • Man, dieses pdo ist ganz schön launisch ^^
    Das Textfeld und der Merker funktionieren jetzt (einzeln).
    Das Problem bleiben mehrere Einträge auf einmal.


    Die Auskommentierten Zeilen funktionieren alle drei einzeln! Also Datum, User und erledigt.
    Sobald ein zweites dazu kommt gehts nicht mehr.
    Das ist so empfindlich was Leerzeichen und Anführungszeichen angeht :wacko:
    Ausgabe ist:


    Fazit:
    Textfeld geht
    Merker geht
    Textfeld und Merker geht ned
    Datum, User, Zustand jeweils alleine geht
    sobald es irgendwo 2 sind, geht es nicht mehr.
    Sind ' oder " im execute nötig bzw zwingend nötig?
    eher ja, wegen unterschiedlich langen Strings oder?


    Gruß Humbi

  • Also das
    string(13) "2017-03-23, 0"
    deutet schon an, dass der Zusammenbau nicht funktioniert hat, wenn es an den execute geht, denn das müssen da, beim execute, 2 Werte sein, sofern das hierzu
    string(82) "UPDATE `bilderdatenbank` SET `erledigt_am` = ? , `erledigt` = ? WHERE `id` = '16'"
    gehört.
    Du brauchst also ein "echtes" Array mit mehreren Elementen (klar, 1 Element wäre auch ein Array).
    Für den execute darfst Du also keinen String zusammenbauen, sondern ein Array, z. B.
    $ar[0] = $heute;
    $ar[1] = $id;
    (halt die richtigen Werte nehmen, ich habe jetzt irgendelche Variablen hingeschrieben.)


    der execute braucht dann:
    execute($ar)
    (ja, ohne zusätzliche Array-Angabe ! )


    Dann sollte es klappen.



    P.S.: Fals das bei ID mit '16' eine Integerspalte ist würde ich auf die Apostrophe verzichten. Aber wenn es klappt, ist auch ok :)

  • EBM,
    danke, das wars :)
    Das Array kam mit dem zusammenbau im execute nicht klar.
    Mit einem richtigen Array funktioniert es :thumbup:


    ergibt


    Manchmal sieht man den Wald vor lauter ' " space nicht mehr.
    Hat mich Stunden gekostet und dauerte 2 min :pinch:


    Danke und Gruß
    Humbi

  • Da fehlen " und '.

    $neu[melden] sollte sicherlich $neu['melden'] sein.


    Teste mal deine Scripte mit allen Errorausgaben:

    PHP
    // an den anfang des scripts oder am besten in das eingangsscript (index.php)
    error_reporting(E_ALL);
    ini_set('display_errors', 1);

    Da werden einige Warnings und Notices fliegen.



    Und sowas hier:

    PHP
    "UPDATE `bilderdatenbank` SET $code WHERE `id` = $neu[id]"

    kann böse enden (SQL injection).

    Ich weiß, dass Du die Daten hier selbst setzt.

    Aber bei einem Update, oder wenn Du mal einen Codeblock zum wiederverwenden kopierst, ...

    kann es schnell passieren, dass Du auf einmal Unsichere Daten in die Query schreibst.


    Wie dann:

    Die id per platzhalter dürfte keine große Sache sein. (Empfehle btw :platzhalter statt ? )

    Die Column $code allerdings musst Du in die Query schreiben (Platzhalter sind nur bei Values erlaubt)

    aber in solchen Fällen nutzt man Whitelists

    PHP
    $whiteListCode = ['abc', 'def', '...'];
    if (in_array($code, $whiteListCode, true)) {
        $sql = "UPDATE `bilderdatenbank` SET `{$code}` WHERE `id` = :id";
        // ...
    } else {
        // ERROR, unerlaubter wert
        // die oder exit oder throw new Exception ...
        die("nope");
    }

    oder du rennst mit nem Regex drüber und lässt nur bestimmte Zeichen zu:

    PHP
    // bad input:
    $code  = "id` = `id`; DROP TABLE admin; -- .";
    
    // letter number underscore only
    $cleanColumnName = preg_replace("/[^\w]/", '', (string)$code);
    
    $sql = "UPDATE `bilderdatenbank` SET `{$cleanColumnName}` WHERE `id` = :id";
    
    var_dump($sql);
    // UPDATE `bilderdatenbank` SET `ididDROPTABLEadmin` WHERE `id` = :id
  • Hallo cottton,

    danke für deine Antwort. Das mit dem Whitelisting werde ich mir bei Bedarf nochmal anschauen.

    Und sowas hier:

    PHP
    "UPDATE `bilderdatenbank` SET $code WHERE `id` = $neu[id]"

    kann böse enden (SQL injection).

    Ich weiß, dass Du die Daten hier selbst setzt.

    Aber bei einem Update, oder wenn Du mal einen Codeblock zum wiederverwenden kopierst, ...

    kann es schnell passieren, dass Du auf einmal Unsichere Daten in die Query schreibst.

    Ja, prinzipiell hast du Recht. Das war jetzt mein erstes richtiges Projekt. (Erste Projekte sollte man meiner Meinung nach nie kopieren ^^).

    Aber grundsätzlich habe ich schon auf Sicherheit geachtet und alle eingehenden Daten die von Menschen ausgefüllt werden erstmal durch Funktionen gejagt.

    Code
    function reinigung ($text)
    {
        //eliminiere Leerzeichen vor und nach dem Text
        $bereinigt = trim($text);
        //eliminiere HTML Tags
        $bereinigt = strip_tags($bereinigt);
        return ($bereinigt);
    }

    Sollten in einer Zeichenkette eh nur Zahlen oder Text vorkommen gibt es dafür weitere Funktionen, so dass wirklich nur durchkommt was muss.

    Ich weiß, dass man auch Session- und Postvariablen manipulieren kann. Aber dadurch, dass das Script nur im Intranet eingesetzt wird sah ich jetzt keinen Grund so tief abzusteigen.

    Ich werde deinen Vorschlag fürs nächste Mal bzw. für ein Update im Hinterkopf behalten.


    Gruß Humbi

  • Wenn Du dafür sorgen willst, dass alle eingehenden Daten sauber sind, machst Du Dir zu viel Arbeit.


    Du brauchst einfach nur PDO oder mysqli_ mit Platzhaltern nutzen, und schon ist es egal, was der Nutzer schickt.

    Dafür sind die "Dinger" ja da - die values werden sicher an die Stelle der Platzhalter gesetzt.

    trim ist in Ordnung. Alles Andere (strip_tags ...) kannst Du vergessen.


    PDO: http://php.net/manual/en/pdo.prepare.php


    Und es ist egal, wo das Script ausgeführt werden soll.

    Solange es nicht ein Testscript ist, ist es den kleinen Aufwand mehr wert.

    Denn 3 Wochen später soll es doch öffentlich erreichbar sein.

    Was dann?

    1. Mhh. Mist, hätt ich doch gleich richtig machen sollen" --und gehst alles noch mal durch (wenn Du darfst und kannst)

    oder

    2. "Naja, wird schon schief gehen" --und gehst ein Risiko ein.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!