hawkmaster: "quote()" Problem, kein Insert??

Hallo,
Folgende Situation:
Ich möchte mit PDO einen Verzeichnispfad in eine Mysql Tabelle schreiben.
In der Konstante ROOTDIR steht z.b. C:\Programme\Test\wasnoch
so funktioniert es wunderbar:

$valueroot = addslashes(ROOTDIR);
$DBO->exec("UPDATE configdirectories SET ConfigDirectoriesPath='$valueroot' WHERE ConfigDirectoriesName = 'RootDirectories'");

Wenn ich nun aber versuche mit quote() zu maskieren
$valueroot = $DBO->quote(ROOTDIR,PDO::PARAM_STR);

Dann wird nichts eingetragen.
Der Pfad bekommt dann zusätzlich noch Hochkommas vorne und hintern also;
'C:\Programme\Test\wasnoch'

Warum geht das so nicht?

Mal ne dumme Frage:
Wenn man das "addslashes()" weglässt steht in der DB der Pfad ganz ohne Backslashes.
Entfernt das MySQL automatisch?

vielen Dank
Gruss
hawk

  1. echo $begrüßung;

    Das Forum hätte auch nichts dagegen, wenn du die immer noch PDO betreffenden Probleme in einem Thread zusammengefasst hättest.

    $valueroot = addslashes(ROOTDIR);

    addslashes() macht irgendwas, nur nicht das was für die jeweilige Datenbank angemessen ist. Deswegen gibt es ja die Methode quote(), die sich ganz nach den Gegebenheiten des verwendeten Treibers richtet.

    $DBO->exec("UPDATE configdirectories SET ConfigDirectoriesPath='$valueroot' WHERE ConfigDirectoriesName = 'RootDirectories'");

    Wenn ich nun aber versuche mit quote() zu maskieren
    $valueroot = $DBO->quote(ROOTDIR,PDO::PARAM_STR);

    Dann wird nichts eingetragen.
    Der Pfad bekommt dann zusätzlich noch Hochkommas vorne und hintern also;
    'C:\Programme\Test\wasnoch'

    Wenn du quote() verwendest, dann erledigt das im Gegensatz zu addslashes() (und mysql_real_escape_string()) nicht nur das Maskieren sondern auch das Quotieren. Es macht aus dem

    C:\Programme\Test\wasnoch

    ein

    'C:\Programme\Test\wasnoch'

    Das

    $DBO->exec("UPDATE configdirectories SET ConfigDirectoriesPath='$valueroot' WHERE ConfigDirectoriesName = 'RootDirectories'");

    müsste also als

    $DBO->exec("UPDATE configdirectories SET ConfigDirectoriesPath={$DBO->quote(ROOTDIR)} WHERE ConfigDirectoriesName = 'RootDirectories'");

    notiert werden, um ein ordentliches SQL-Statement zu erhalten.

    Mal ne dumme Frage:
    Wenn man das "addslashes()" weglässt steht in der DB der Pfad ganz ohne Backslashes.
    Entfernt das MySQL automatisch?

    Die zusätzlichen Slashes sind die "Transportsicherung". Sie werden nur dann benötigt, wenn der Wert zusammen mit den SQL-Klauseln in einem String notiert werden soll. Dies dient der Unterscheidung zwischen Befehls- und Datenbestandteilen dieses Strings. In der Datenbank werden die Daten ohne Transportsicherung eingetragen. Sie kommen auch ohne diese zurück, weil auf dem Rückweg nur reine Daten ohne Befehlsbestandteile übertragen werden.

    echo "$verabschiedung $name";

    1. Hi dedlfix,
      sorry wegen dem neuen Thread. Ich dachte nur das ist ein anderes Thema

      <<$DBO->exec("UPDATE configdirectories SET ConfigDirectoriesPath={$DBO->quote(ROOTDIR)} WHERE ConfigDirectoriesName = 'RootDirectories'");>>

      So funktioniert das jetzt.
      Aber, warum funktioniert das nicht wenn man das Quote aus dem Query rausnimmt?
      $valueroot = $DBO->quote(ROOTDIR);
      $DBO->exec("UPDATE configdirectories SET ConfigDirectoriesPath='$valueroot' WHERE ConfigDirectoriesName = 'RootDirectories'");

      Nochmals zur Verständnis was MySQL anbetrifft:
      Werden die Backslahses nun von MySQL weg gefiltert oder macht das PHP?

      Das gleiche ist ja auch wenn ein String Anführungszeichen hat '
      Dann wird nichts in die Spalte eingetragen.
      Prüft bzw. verhindert das MySQL selbst?

      Wenn ich einen Verzeichnispfad in einer MySQL Spalte speichern möchte, dann muss ich es doch mit "addslashes()" machen oder?

      vielen Dank für deine Geduld :-)

      Gruss
      hawk

      1. echo $begrüßung;

        Aber, warum funktioniert das nicht wenn man das Quote aus dem Query rausnimmt?
        $valueroot = $DBO->quote(ROOTDIR);
        $DBO->exec("UPDATE configdirectories SET ConfigDirectoriesPath='$valueroot' WHERE ConfigDirectoriesName = 'RootDirectories'");

        Lass dir dein Inhalt von $valueroot ausgeben, dann siehst du es vielleicht. Auch durch aufmerksames Lesen meiner vorigen Antwort hätte dir auffallen können, dass quote() bereits die Anführungszeichen drumrum gemacht hat. Du hast nun SET foo=''bar'', was einen Syntax-Fehler ergibt.

        Nochmals zur Verständnis was MySQL anbetrifft:
        Werden die Backslahses nun von MySQL weg gefiltert oder macht das PHP?

        Entfernst du die Transportsicherung und die Verpackung eines Gerätes im Laden oder erst zu Hause? Dir scheint ja immer noch nicht klar zu sein, warum der ganze Schmus mit den Anführungszeichen einerseits und den Backslashes andererseits gemacht wird.

        Das gleiche ist ja auch wenn ein String Anführungszeichen hat '
        Dann wird nichts in die Spalte eingetragen.
        Prüft bzw. verhindert das MySQL selbst?

        Werte die Fehlermeldungen aus! Du wirst in dem Fall einen Syntax-Fehler bekommen.

        Wenn ich einen Verzeichnispfad in einer MySQL Spalte speichern möchte, dann muss ich es doch mit "addslashes()" machen oder?

        Neien! Vergiss addslashes() und nimm die zum DBMS gehörigen Maskierungen. Nochmal zum Mitschreiben: Du hast ein SQL-Statement:

        SELECT feld1, feld2 FROM tabelle WHERE feld1 = 'foo bar'

        Du hast darin die Befehlsbestandteile SELECT, FROM und WHERE. Du hast weiterhin die Bezeichner tabelle, feld1 und feld2. Und du hast den Wert foo_Leerzeichen_bar. Damit foo bar nicht mit Befehlsbestandteilen oder Bezeichnern verwechselt wird, wird es in Anführungszeichen gesetzt. Wenn nun im Wert Anführungszeichen auftauchen, dann beenden diese diesen. Damit das nicht passiert, werden Anführungszeichen im Wert maskiert. Bei MySQL passiert das durch Voranstellen eines . Da aber auch der Backslash Datenbestandteil sein kann, muss er nun auch maskiert werden, weswegen er nun doppelt vorkommt.
        Das ganze Kongomlerat aus Befehl und Daten bekommt nun der MySQL-Server übergeben, der es auszuwerten hat. Er kann nun genau sehen, was was ist, ist happy und macht was draus. Er speichert die Daten aber nicht zusammen mit SQL-Statement, weswegen er für die Datenhaltung sowohl Quotierung als auch Maskierung entfernt. Doch das was er intern macht, kann uns egal sein. Er kann einfach als Blackbox betrachtet werden. Wenn er die Daten nun auf Anforderung wieder rausrücken muss, verpackt er sie nicht in irgendwelchen Befehlstexten. Er kann sie so übertragen, dass keine Quotierungen oder Maskierungen nötig sind.

        echo "$verabschiedung $name";

        1. Hallo dedlfix,
          vielen Dank für deine Geduld.
          Ich dachte immer ich kenne mich ein wenig mit MySQL aus. Aber mir wird klar das ich mir bisher zu wenig Gedanken über die internen Abläufe gemacht habe, bzw. einfach Befehle und Code geschrieben habe ohne vielleicht die ganzen Zusammenhänge zu kennen.

          Das mit dem Maskieren von bestimmten Zeichen mit einem Backslash war mir bekannt.
          Wie aber kann man denn einen String der viele Backslashes enthält so maskieren?
          $verzeichnis = "C:\Programme\Test\nochwas";

          Noch etwas was mir heute Abend mit meinen DBO Versuchen aufgefallen ist.
          Ich verwende an vielen Stellen die Funktion "mysql_num_rows".

          Könnte man da die PDO Methode
          $count = $del->rowCount();

          nehmen?

          PS: kann man dich auch mal per Email was fragen?
          vielen Dank
          Gruss
          hawk

          1. Hi,

            Das mit dem Maskieren von bestimmten Zeichen mit einem Backslash war mir bekannt.

            Wirklich ...?

            Wie aber kann man denn einen String der viele Backslashes enthält so maskieren?
            $verzeichnis = "C:\Programme\Test\nochwas";

            Erst mal musst du schon hier, PHP-seitig, die Backslashes maskieren.
            Mindestens den vor dem n, wenn es ein n sein soll (denn sonst ist es ein Zeilenumbruch) - und auf jeden Fall den vor dem schliessenden Anfuehrungszeichen, denn sonst ist es kein schliessendes, und du produzierst (hoechstwahrscheinlich) einen Syntaxfehler.

            MfG ChrisB

            1. Hi Chris,
              danke dir für deinen Hinweis.

              Ja das war mit wirklich bekannt mit dem Baclslash auch wenn ich mich hier vielleicht eurer Meinung nach dämlich anstelle mit meiner Fragerei.

              Ich hatte ja daher auch die Funktion "addslashes" verwendet um den Verzeichnis Pfad zu maskieren. Denn ich weiss ja nicht vorher was in der Variablen
              $verzeichnis steht.

              Siehe auch PHP Manual (wobei ich euch das ja nicht sagen muss)

              Zitat:
              ...Diese Funktion ist z.B. für Datenbankabfragen wichtig. Die behandelten Zeichen sind das einfache und der doppelte Anführungszeichen (' und "), der Backslash selbst () sowie NUL (das Null-Byte).

              Ein Beispiel für die Verwendung von addslashes() ist das Schreiben von Daten in eine Datenbank....

              Also kann es doch nicht so ganz falsch gewesen sein oder?

              Kannst du vielleicht auch zufällig was zu meinem Mysql_num_row Problem unter PDO sagen?

              Gruss
              hawk

              1. echo $begrüßung;

                Ich hatte ja daher auch die Funktion "addslashes" verwendet um den Verzeichnis Pfad zu maskieren. Denn ich weiss ja nicht vorher was in der Variablen $verzeichnis steht.

                Im Inhalt einer Variablen sind keine Maskierzeichen mehr vorhanden. Sie werden nur dafür gebraucht, einen String im Programmcode zu notieren, denn auch hier hast du wieder Code und Daten gemischt vorliegen, und musst irgendwie die Daten vom Code unterscheiden.

                Siehe auch PHP Manual (wobei ich euch das ja nicht sagen muss)
                ...Diese Funktion ist z.B. für Datenbankabfragen wichtig. Die behandelten Zeichen sind das einfache und der doppelte Anführungszeichen (' und "), der Backslash selbst () sowie NUL (das Null-Byte).

                Und ist die Behandlung dieser angegebenen Zeichen für das verwendete Datenbanksystem ausreichend? Für MySQL vielleicht. Unter Umständen. Aber hattest du nicht auch anderswo gesagt, dass du vielleicht mal MySQL gegen was anderes austauschen willst? Und kannst du garantieren, dass dort genau die gleichen Zeichen zu behandeln sind, die addslashes() behandelt, und das noch dazu in der gleichen Art, wie es addslashes() macht? Wohl kaum. Deswegen sollst du ja diese allgemeine Funktion vergessen und durch eine jeweils spezialisiertere, genau auf den Kontext zugeschnittene Form austauschen.

                Ein Beispiel für die Verwendung von addslashes() ist das Schreiben von Daten in eine Datenbank....

                Das ist falsch formuliert. Aufgabe der Quotierung und Maskierung ist nicht das Schreiben in eine Datenbank sondern die Notation der Daten in einem SQL-Statement zum Zwecke des Transport zu einem DBMS. Das eigentliche Schreiben in die dem DBMS zugrunde liegende Datenhaltung kann mir als Anwender im Prinzip egal sein.

                Also kann es doch nicht so ganz falsch gewesen sein oder?

                Es war nicht ganz falsch, aber auch nicht ganz richtig.

                Kannst du vielleicht auch zufällig was zu meinem Mysql_num_row Problem unter PDO sagen?

                mysql_num_rows() ist eine Spezialität der MySQL-Client-API. Normalerweise ist es bei den verschiedenen DBMS nicht üblich, die Anzahl der Datensätze der Ergebnismenge zu kennen, bevor man nicht alle Datensätze abgeholt und sie dabei selbst gezählt hat. Die MySQL-Client-API kennt einen Modus, der bereits im Hintergrund alle Datensätze der Ergebnismenge vom Server geholt hat, und hat sie dabei zählen können. Die Fetch-Funktionen, die man selbst aufruft, holen die Datensätze aus diesem Puffer und nicht direkt vom MySQL-Server ab. Da PDO nicht nur für MySQL sondern auch für alle anderen Systeme möglichst mit gleichem Funktionsumfang arbeiten können soll, hat man auf diese Funktionalität verzichtet. Dir bleiben nun drei Möglichkeiten, an die Anzahl zu kommen. Wenn es dir nur um die Anzahl geht, ohne dass du die Daten brauchst, lass sie vom DBMS mittels COUNT(*) zählen. Damit ersparst du dem System das unnötige Im-Hintergrund-Abholen der Daten. Wenn du sowohl Anzahl als auch Daten brauchst, und die Anzahl vor der Verarbeitung der Ergebnismenge benötigst, nutze PDOStatement::fetchAll() und wende dann das herkömmliche count() auf das von fetchAll() gelieferte Array an. Wenn du die Anzahl erst nach der Verarbeitung der Ergebnismenge benötigst, zähle beim Fetchen selbst mit.

                echo "$verabschiedung $name";

                1. Hallo dedlfix bzw. liebe andere Helfer,
                  ich hoffe ich mache es jetzt richtig und schreibe keinen neuen Thread :-)
                  Mir ist ein unterschiedliches Verhalten beim DELETE aufgefallen.
                  Bisher:
                  mysql_query("DELETE FROM login WHERE usr='$USER'") or error(__LINE__,__FILE__,"Konnte Userdaten nicht loeschen",mysql_error());

                  Auch wenn keine Daten des Users in der Tabelle "login" waren gab es keine Fehlermeldung beim Lösch Versuch.

                  Mit DBO muss ich immer das "or .." weglassen weil sonst immer die Meldung kommt.
                  $checkdel = $DBO->exec("DELETE FROM login WHERE usr='$USER'");

                  Hast du eine Idee warum das so unterschiedlich ist?

                  kurz noch eine Frage wegen "mysql_num_rows"

                  Bisher mit mysql:
                  $result = mysql_query("SELECT usr, UserID FROM testuser WHERE usr='".$USER."' && pwd=AES_ENCRYPT('".$PWD."',@pswd_key)") or error(__LINE__,__FILE__,"Konnte Datenbank nich nach angemeldeten Benutzern durchsuchen",mysql_error());
                  if(mysql_num_rows($result) == 0) {

                  ...
                  Ich habe nun versucht das mit DBO und rowCount() so zu lösen:

                  $result = $DBO->query("SELECT usr, UserID FROM testuser WHERE usr='".$USER."' && pwd=AES_ENCRYPT('".$PWD."',@pswd_key)") or error(__LINE__,__FILE__,"Konnte Datenbank nich nach angemeldeten Benutzern durchsuchen","");
                  $count = $result->rowCount();
                  if($count == 0) {

                  Wäre das ok bzw. gleichbedeutend?

                  Zum Schluss noch was spezielles:
                  In einer Tabelle speichere ich ein Passwort ja mit "AES_ENCRYPT('".$PWD."',@pswd_key)""

                  Das wird ja vermutlich mit anderen Datenbanken nicht funktionieren oder?
                  Also was anderes verwenden bzw, die Verschlüsselung mit PHP machen?

                  Gruss und danke
                  Hawk

                  1. Hi,

                    Mir ist ein unterschiedliches Verhalten beim DELETE aufgefallen.
                    Bisher:
                    mysql_query("DELETE FROM login WHERE usr='$USER'") or error(__LINE__,__FILE__,"Konnte Userdaten nicht loeschen",mysql_error());

                    Zitat Manual:
                    "For other type of SQL statements, UPDATE, DELETE, DROP, etc, mysql_query() returns TRUE on success or FALSE on error."

                    Kann das Statement also fehlerfrei verarbeitet werden, bekommst du true als Rueckgabewert von mysql_query, also keine Notwendigkeit, den or-Teil auszufuehren - egal, ob und wie viele Zeilen vom DELETE geloescht wurden.

                    Auch wenn keine Daten des Users in der Tabelle "login" waren gab es keine Fehlermeldung beim Lösch Versuch.

                    Natuerlich, das Statement wurde ja trotzdem fehlerfrei verarbeitet.

                    Mit DBO muss ich immer das "or .." weglassen weil sonst immer die Meldung kommt.
                    $checkdel = $DBO->exec("DELETE FROM login WHERE usr='$USER'");

                    Hast du eine Idee warum das so unterschiedlich ist?

                    Weil, ebenfalls im Manual nachzulesen:
                    "PDO->exec() executes an SQL statement in a single function call, returning the number of rows affected by the statement."

                    Wenn dein DELETE-Statement jetzt aber keine Datensaetze erfasst hat, dann ist die number of rows affected 0 - und 0 wird durch PHP an dieser Stelle mit false gleichgesetzt, also wird der or-Teil ausgefuehrt.

                    MfG ChrisB

                    1. Hi ChrisB,
                      vielen Dank für deine Erklärung.
                      Jetzt ist mir das viel klarer geworden.

                      Hast du vielleicht auch eine Idee wegen der Verschlüsselung?
                      Ich habe das bisher mit der MySQL Funktion "aes_encrypt" gemacht weil ich für einen speziellen Fall der Authentifizierung gegenüber eines Active Directory das Passwort wieder entschlüsselt brauche.

                      vielen dank nochmals
                      Gruss
                      hawk

                  2. echo $begrüßung;

                    kurz noch eine Frage wegen "mysql_num_rows"

                    Bisher mit mysql:
                    $result = mysql_query("SELECT usr, UserID FROM testuser WHERE usr='".$USER."' && pwd=AES_ENCRYPT('".$PWD."',@pswd_key)") or error(__LINE__,__FILE__,"Konnte Datenbank nich nach angemeldeten Benutzern durchsuchen",mysql_error());
                    if(mysql_num_rows($result) == 0) {

                    ...
                    Ich habe nun versucht das mit DBO und rowCount() so zu lösen:

                    rowCount() ist nicht mit mysql_num_rows() gleichzusetzen. Wie du dem Handbuch nicht entnommen hast, liefert diese Funktion nur die Anzahl der betroffenen Datensätze bei Daten verändernden Statements, also nicht bei SELECT.

                    $count = $result->rowCount();
                    Wäre das ok bzw. gleichbedeutend?

                    Nein, ich hab dir doch gesagt, was deine Möglichkeiten sind. rowCount() ist keine.

                    Zum Schluss noch was spezielles:
                    In einer Tabelle speichere ich ein Passwort ja mit "AES_ENCRYPT('".$PWD."',@pswd_key)""
                    Das wird ja vermutlich mit anderen Datenbanken nicht funktionieren oder?
                    Also was anderes verwenden bzw, die Verschlüsselung mit PHP machen?

                    Wenn man auf Austauschbarkeit Wert legt, muss man sich auf die Dinge beschränken, die alle DBMS zur Verfügung stellen, oder die von der Datenbankabstraktion für die restlichen Systeme emuliert werden. Das schränkt teilweise ganz gehörig ein, wenn man die Features eines DBMS nicht nutzen kann, sie stattdessen mit höherem Aufwand - sowohl in Entwicklung als auch Laufzeitverhalten - nachbilden muss. Ein anderer Ansatz ist, eine weitere Zwischenschicht einzuziehen, die nicht die Datenbank abstrahiert sondern allgemein Datenquellen zur Verfügung stellt. Da somit das SQL-Statement und das Drumherum komplett verborgen ist, kann man darin auch native DBMS-Features verwenden. Wenn wirklich einmal ein DBMS-Wechsel ansteht, muss man den meist sowieso sorgfältig planen. Einfach nur den Connect-String austauschen zu wollen halte ich für illusorisch. Es kann nun vorkommen, dass das neue System ein bestimmtes Detail anders löst oder viel bessere Möglichkeiten bereitstellt. Man passt also die Daten-Abstraktionsschicht an und kann wieder die volle Leistung des neuen DBMS nutzen. Ja, selbst ein Wechsel auf ein anderes Speichermedium wäre damit ohne (größere) Eingriffe in die Geschäftslogik möglich.

                    Ich hoffe, du kannst nun selbst entscheiden, ob du die MySQL-spezifische Funktion nutzen willst oder doch nur global-galaktisch gültiges SQL verwendest.

                    echo "$verabschiedung $name";