Blabla: korrekte schreibweise von SQL-Statements

Hallo!

Beschäftige mich seit längerer Zeit wiedermal mit PHP und MySQL. Macht soweit auch Spass nur möchte ich's gleich richtig machen. Bitte daher um Aufklärung zu folgenden Fragen.

Mir ist aufgefallen, dass in div. Foren, Manuals oder Tutorials SQL-Statments in Bezug auf Hochkommas immer wieder eine andere Schreibweise verwenden. Funktionieren tun jedoch alle. Ich Frage mich nun wie es korrekt ist.

z.B.
INSERT INTO tabelle1 (wert1, wert2) VALUES (1, 2)
INSERT INTO tabelle1 (wert1, wert2) VALUES (1, 2)
INSERT INTO tabelle1 (wert1,wert2) VALUES ('1', '2')

Weiters wundert mich, dass im folgenden mysql_query die Variablen direkt im String stehen und das auch funktioniert.

z.B.
mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('$value1', '$value2')")

Ich hätte es eher so gemacht:
mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('".$value1."', '".$value2."')")

Bitte um Hilfe wie man es nun richtig macht. Ich will es mir nicht falsch angewöhnen.
Danke!

  1. Bitte um Hilfe wie man es nun richtig macht. Ich will es mir nicht falsch angewöhnen.

    Es gibt hier kein falsch, wenn man von der kontextgerechten Behandlung absieht.

    ich würde aus übersichtsgründen allerdings nicht zu Stringverkettung greifen sondern zu funktionen wie z.B. printf().

  2. Hello,

    *ui*
    Das muss eine lange Antwort werden.

    Zu Beachten sind dabei

    • die Notation von Bezeichnern in MySQL
    • die Notation von Zahlenwerten in MySQL
    • die Notation von Stringwerten in MySQL
    • das Escapen von Zahlen- und Stringwerten in MySQL und PHP
    • das Ersetzen von Variablen in Strings bei PHP
    • das Zusammenbauen von Query-Strings in PHP für MySQL und die Beachtung der Spaltentypen
        in Bezug auf das Escapen, Quotieren, usw.

    Mir ist aufgefallen, dass in div. Foren, Manuals oder Tutorials SQL-Statments in Bezug auf Hochkommas immer wieder eine andere Schreibweise verwenden. Funktionieren tun jedoch alle. Ich Frage mich nun wie es korrekt ist.

    z.B.
    INSERT INTO tabelle1 (wert1, wert2) VALUES (1, 2)

    so geschrieben vollkommen OK, weil sowohl die Bezeichner nicht reserviert sind, als auch die Werte numerische Werte darstellen, WENN wert1 und wert2 auch numerische Spaltentypen darstellen.

    INSERT INTO tabelle1 (wert1, wert2) VALUES (1, 2)

    Immer noch OK, obwohl die Kennzeichnung der Bezeichner durch Backticks hier nicht notwendig ist, da sie keine reservierten Begriffe in MySQL darstellen. Es ist aber auch nicht schädlich, sie zu kennzeichnen. Restliches siehe voriges Statement

    INSERT INTO tabelle1 (wert1,wert2) VALUES ('1', '2')

    Hier wäre davon auszugehen, dass die Spaltentypen von wert1 und wert2 auch Stringtypen sein dürften. Bei Stringwerten ('1', '2') ist es notwendig, diese in Quotierung zu setzen. Es ist allerdings auch bei numerischen Spaltentypen erlaubt, die Werte in Quotierung zu setzen, wenn nicht direkt im Querystring damit gerechnet werden soll.

    Wer macht hier mal weiter?

    Weiters wundert mich, dass im folgenden mysql_query die Variablen direkt im String stehen und das auch funktioniert.

    z.B.
    mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('$value1', '$value2')")

    Ich hätte es eher so gemacht:
    mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('".$value1."', '".$value2."')")

    Bitte um Hilfe wie man es nun richtig macht. Ich will es mir nicht falsch angewöhnen.
    Danke!

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hallo!

      Wer macht hier mal weiter?

      Ich! ;)

      Weiters wundert mich, dass im folgenden mysql_query die Variablen direkt im String stehen und das auch funktioniert.

      Das liegt daran, dass der PHP-Interpreter von doppelten Hochkommas "angewiesen" wird, den Code nach Variablennamen zu durchkämmen - wenn du einfache Hochkommas verwendest, musst du Variablen wie in deinem zweiten Beispiel schreiben.

      Liebe Grüße aus Norddeutschland.

      --
      ie:{ fl:( br:> va:} ls:[ fo:| rl:? n4:~ ss:) de:> js:| ch:? sh:( mo:) zu:)
      1. Danke, so einfach ist das also (wenn man es mal weiß)!

      2. Hello,

        Wer macht hier mal weiter?
        Ich! ;)

        Etwas genauer hatte ich es mir eben schon vorgestellt. Leider klingelte es gerade an der Tür...
        Na gut, dann gebe ich eben den Link doch noch dazu ;-)

        Weiters wundert mich, dass im folgenden mysql_query die Variablen direkt im String stehen und das auch funktioniert.

        Das liegt daran, dass der PHP-Interpreter von doppelten Hochkommas "angewiesen" wird, den Code nach Variablennamen zu durchkämmen - wenn du einfache Hochkommas verwendest, musst du Variablen wie in deinem zweiten Beispiel schreiben.

        http://de2.php.net/manual/en/language.types.string.php

        Da wird fast alles erklärt.
        Es fehlt mMn eine direkte Erklärung zur Blockbildung z.B. für Array-Elemente.

        Bsp.:

        echo "Sie bekommen 250g {$_produkt['name']{1]} für {$_produkt['preis'][1]} Euro";

        Das findet man dann etwas genauer beschrieben unter
        http://de2.php.net/manual/en/language.types.string.php#language.types.string.parsing

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
    2. Danke, damit kann ich schon mal etwas anfangen!
      Bezeichner können also im Normalfall ohne Backticks geschreiben werden. Values je nach Daten-/Spaltentyp.

      Thx!

    3. Mahlzeit Tom,

      bis hier IMHO gut erklärt.

      Wer macht hier mal weiter?

      Ich versuch's mal:

      Weiters wundert mich, dass im folgenden mysql_query die Variablen direkt im String stehen und das auch funktioniert.

      z.B.
      mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('$value1', '$value2')")

      In dem Fall gibt es natürlich spätestens dann ein Problem, wenn in einer der Variablen ein String enthalten ist, der einzelne Hochkommata (') enthält. Darüber hinaus *kann* diese Schreibweise Probleme erzeugen, wenn es möglich ist, mehrere SQL-Abfragen in einem Rutsch an die Datenbank zu schicken (Stichwort: "SQL-Injection"). Man stelle sich vor, in der Variablen namens "$value1" würde der String "foo', 'bar'); DELETE FROM tabelle1; --" stehen ... PHP würde daraus insgesamt folgenden String machen:

      "INSERT INTO tabelle1 (wert1,wert2) VALUES ('foo', 'bar'); DELETE FROM tabelle1; --', 'hier würde der Wert der zweiten Variable stehen')"

      Was würde die Datenbank wohl daraus machen?

      Ich hätte es eher so gemacht:
      mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('".$value1."', '".$value2."')")

      Ich nicht - vor allem deshalb nicht, weil sich an der o.g. Problematik nichts ändert. Ich würde eher suits Empfehlung folgen und die Geschichte folgendermaßen schreiben:

      mysql_query([link:http://de.php.net/manual/de/function.sprintf.php@title=sprintf]("INSERT INTO tabelle1 (wert1,wert2) VALUES ('%s', '%s')", [link:http://de.php.net/manual/de/function.mysql-real-escape-string.php@title=mysql_real_escape_string]($value1), mysql_real_escape_string($value2)));

      Bitte um Hilfe wie man es nun richtig macht. Ich will es mir nicht falsch angewöhnen.

      Ein guter Vorsatz!

      MfG,
      EKKi

      --
      sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
      1. Hi!

        mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('$value1', '$value2')")
        In dem Fall gibt es natürlich spätestens dann ein Problem, wenn in einer der Variablen ein String enthalten ist, der einzelne Hochkommata (') enthält. Darüber hinaus *kann* diese Schreibweise Probleme erzeugen, wenn es möglich ist, mehrere SQL-Abfragen in einem Rutsch an die Datenbank zu schicken (Stichwort: "SQL-Injection"). Man stelle sich vor, in der Variablen namens "$value1" würde der String "foo', 'bar'); DELETE FROM tabelle1; --" stehen ... PHP würde daraus insgesamt folgenden String machen:
        "INSERT INTO tabelle1 (wert1,wert2) VALUES ('foo', 'bar'); DELETE FROM tabelle1; --', 'hier würde der Wert der zweiten Variable stehen')"
        Was würde die Datenbank wohl daraus machen?

        Du willst das Prinzip erläutern, insofern ist das ok. Aber mit mysql_query() geht das so nicht. Das hast du ja schon angedeutet. Dieser Fall wird erst dann problematisch, wenn man mysqli_multi_query() nimmt. Allerdings muss man gar nicht solche destruktiven Fälle konstruieren, die meist nicht durchführbar sind. Es reicht, wenn man ein SELECT-Statement so manipulieren kann, dass es mehr oder andere Daten zurückliefert, als vorgesehen sind.

        SELECT COUNT(*) FROM user WHERE user='$user' AND password='$password'

        $user: admin' --
        $password: egal

        und schon ist man Admin ohne dessen Passwort zu kennen, wenn das abfragende Script nur prüft, ob das Ergebnis 1 ist. Oder man hängt mit UNION eine zweite Abfrage auf die Tabelle user der Datenbank mysql an. Hoffentlich hat der root ein Passwort, das nicht in den schon vorhandenen Rainbow-Tabellen auftaucht ...

        Lo!

    4. Hi!

      Mir ist aufgefallen, dass in div. Foren, Manuals oder Tutorials SQL-Statments in Bezug auf Hochkommas immer wieder eine andere Schreibweise verwenden. Funktionieren tun jedoch alle. Ich Frage mich nun wie es korrekt ist.

      Eine Einfache Antwort darauf fällt mir nicht ein, weil im konkreten Fall jeweils die Bedingungen und Rahmenbedingungen angemessen berücksichtigt werden sollten. Wobei: "Mach es so, dass es funktioniert und sich nicht missbrauchen lässt" wäre zwar einfach geantwortet, aber daraus kann man alles und nichts entnehmen.

      INSERT INTO tabelle1 (wert1, wert2) VALUES (1, 2)
      so geschrieben vollkommen OK, weil sowohl die Bezeichner nicht reserviert sind, als auch die Werte numerische Werte darstellen, WENN wert1 und wert2 auch numerische Spaltentypen darstellen.

      Der WENN-Nebensatz muss nicht zwingend so berücksichtigt werden. MySQL kennt auch automatische Typumwandlung. Insofern ist es prinzipiell in Ordnung, Zahlen als Zahlenliteral zu notieren, auch wenn sie in andere Spaltentypen eingefügt werden sollen. Ebenso ist es in Ordnung, sie als Stringliteral zu schreiben, auch wenn das Ziel ein Zahlenfeld ist. Die automatische Typumwandlung richtet es. Natürlich sind nicht alle Kombinationen von Notationsweise und Feldtyp miteinander kompatibel und damit sinnvoll.

      INSERT INTO tabelle1 (wert1, wert2) VALUES (1, 2)
      Immer noch OK, obwohl die Kennzeichnung der Bezeichner durch Backticks hier nicht notwendig ist, da sie keine reservierten Begriffe in MySQL darstellen. Es ist aber auch nicht schädlich, sie zu kennzeichnen.

      Manchmal ist es jedoch erforderlich, Identifier/Bezeichner explizit zu kennzeichnen, weil es Namenskonflikte mit reservierten Wörtern gibt. Nicht immer kann oder will man auf einen alternativen Namen ausweichen.

      Außerdem gibt es neben den `` auch noch den ANSI-kompatiblen Modus (ANSI_QUOTES) - siehe Kapitel Identifier.

      INSERT INTO tabelle1 (wert1,wert2) VALUES ('1', '2')
      Hier wäre davon auszugehen, dass die Spaltentypen von wert1 und wert2 auch Stringtypen sein dürften. Bei Stringwerten ('1', '2') ist es notwendig, diese in Quotierung zu setzen. Es ist allerdings auch bei numerischen Spaltentypen erlaubt, die Werte in Quotierung zu setzen, wenn nicht direkt im Querystring damit gerechnet werden soll.

      Strings- und Zahlen- -Typ und -Notation sind beliebig über Kreuz austauschbar.

      select '2'+'2'; ergibt auch 4, denn zum Stringverbinden muss man CONCAT() verwenden.

      Weiters wundert mich, dass im folgenden mysql_query die Variablen direkt im String stehen und das auch funktioniert.
      mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('$value1', '$value2')")

      Aus PHP-Sicht in Ordnung, aber sicherheitstechnisch problematisch.

      Ich hätte es eher so gemacht:
      mysql_query("INSERT INTO tabelle1 (wert1,wert2) VALUES ('".$value1."', '".$value2."')")

      Ergibt das selbe, inklusive der Sicherheitsbedenken. Besser: Kontextwechsel beachten (beachte dort auch die sprintf()-Notation).

      Lo!