Probleme mit mysli::real_escape_string in Verbindung mit magic_quotes_gpc

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

  • #16
    Moment, ich mach das gleich.

    Kommentar


    • #17
      Sorry, ich will jetzt nicht alle meine Methoden erklären.
      Dann nicht!
      Aber dir ist schon klar, das es unmöglich ist dir zu helfen, wenn du deinen Code geheim hältst.
      Oder?

      Zumindest meine Glaskugel ist gerade in Urlaub.
      Wir werden alle sterben

      Kommentar


      • #18
        Zitat von tim-gt Beitrag anzeigen
        Die $args in Methode execute($args) werden dann so behandelt
        Was nutzt du da, MySQLi? Dann wäre es nicht sonderlich clever, die execute-Methode von MySQLi_STMT mit einer eigenen zu überschreiben.

        $this->sql wird dann in der Methode execute() ganz normal mit $mysqli->query($this->sql) ausgeführt.
        Damit nutzt du dann aber keine prepared statements, sondern gehst den "herkömmlichen" Weg.

        Das bei so einem Mischmasch Fehler entstehen, ist ja kein Wunder.

        Du scheinst die Unterschiede im Arbeiten mit prepared statements im Gegensatz zu "normalen" Queries, die einfach als Text an die Datenbank übergeben werden, noch gar nicht verstanden zu haben - also solltest du dir diesen erst mal klar machen!

        EDIT:
        OK, du nutzt also bewusst keine prepared statements.
        Aber dafür bastelst du dir dann selber etwas, dass mit analog benannten Objekten (Statement) und Methoden (prepare, execute) arbeitet, aber dann trotzdem nach wie vor nur den "alten" Weg des Zusammenbastelns von Queries als Text und Übergabe dieser an die DB zur Ausführung via mysqli->query geht?
        Das ist ziemlich pervers. Das suggeriert ja trotzdem, dass prepared statements genutzt würden, obwohl's gar nicht der Fall ist. Sorry, aber das ist m.E. ein Riesen-Humbug. Lohnt sich gar nicht, das noch zwecks Suche nach der Ursache des konkreten Fehlers weiter zu verfolgen - das gehört gleich in die Tonne, weil es absolut nichts taugt.

        Zuletzt geändert von wahsaga; 29.07.2009, 13:39.
        I don't believe in rebirth. Actually, I never did in my whole lives.

        Kommentar


        • #19
          Also erstmal habe ich das Ganze mehr oder weniger aus dem Buch Dynamische Webseiten in der Praxis. Mit PHP, MySQL 4/5, XHTML, CSS, JavaScript und Eclipse: Amazon.de: Philipp Rieber: Bücher.

          Zweitens verstehe ich den Unterschied zwischen Prepared Statements und normalen Queries sehr wohl. Der Autor hat in diesem Fall wohl einfach die gleichen Namen gebraucht, ich kann euch aber versichern, dass in fast keinem Fall mysqli-Methoden überschrieben werden, nur z.B. die Methode mysqli::fetch_row und derweitern, um diese noch mit einer gut lesbaren Fehlermeldung auszustatten.

          Anstatt hier jetzt auf dieser Architektur rumzuhacken, könntet ihr sicher besseres machen, arbeiten oder so. Ich könnte schon meinen ganzen Code hier reinhauen, aber das wäre ein riesen Aufwand und zudem bin ich mir absolut sicher dass - wie schon erwähnt - die einzige Schnittstelle zur Datenbank über diese Methode execute() geht, und das einzige Nadelöhr, wo der SQL-String durchmuss, dieses preg_replace(...) ist.

          Aber eben, ich habe schon in anderen Threads gesehen, dass gewisse von euch schnell mal gross auf der Architektur rumhacken. Nicht jeder ist ein PHP-Profi und verbringt den ganzen Tag hier auf dem Board oder sonstwo vor der Kiste, hat sein eigenes Framework und Informatik studiert oder was weiss ich. Nur so nebenbei. Und nicht jeder ist ein absoluter Standards-Puritaner und was weiss ich, es muss schliesslich auch nicht jeder mit der Sache Geld verdienen und vertrauliche Daten beschützen und was weiss ich- in meinem Fall ist es ein Hobby. Und ja, ich weiss das sauber programmieren das Beste und Nachhaltigste ist, aber das will auch zuerst einmal gelernt sein.
          Zuletzt geändert von tim-gt; 29.07.2009, 13:53.

          Kommentar


          • #20
            @ h3ll:
            PHP-Code:
                  var_dump($this->sql);
                  
            var_dump($this->con->real_escape_string($this->sql));
                  
            var_dump($this->con); 
            Ausgegeben wird das hier:
            Code:
            string(81) "SELECT *
                          FROM core_user
                          WHERE Name = :0 AND PW = :1"
            string(85) "SELECT *\r\n              FROM core_user\r\n              WHERE Name = :0 AND PW = :1"
            object(mysqli)#5 (0) {}
            Das zeigt, das die Methode funktioniert und $this->con ein mysqli-Objekt ist, wie bereits erwähnt.


            So :
            PHP-Code:
                  var_dump($this->sql);
                  
            $this->sql preg_replace($exp,'\''.$this->con->real_escape_string($value).'\'',$this->sql);   /* PHP-Manual: Characters encoded are NUL (ASCII 0), \n, \r, \, ', ", and Control-Z. */
                  
            var_dump($this->sql); 
            Wird jedoch das hier ausgegeben:

            Code:
            string(85) "SELECT *
                          FROM core_user
                          WHERE Name = 'root' AND PW = :1"
            string(117) "SELECT *
                          FROM core_user
                          WHERE Name = 'root' AND PW = '81dc9bdb52d04dc20036dbd8313ed055'"
            Das Zeug wird also nicht escaped. Hier vermute ich schon den Fehler, ich hab aber keine Ahnung wieso. Also es wird einfach nicht der ganze String escaped, sondern nur die Eingaben, die dann per :0 - Platzhalter gemacht werden. War ja auch so gedacht. Bis jetzt hat es immer funkioniert, und wie schon etwa 3 mal erwähnt, funktioniert es auch, wenn man ' und " verwendet.
            Zuletzt geändert von tim-gt; 29.07.2009, 13:57.

            Kommentar


            • #21
              Das Zeug wird also nicht escaped.
              Was gibts da zu escapen?

              Etwa 81dc9bdb52d04dc20036dbd8313ed055 ??
              Hihihi....
              Wir werden alle sterben

              Kommentar


              • #22
                Zitat von tim-gt Beitrag anzeigen
                @ h3ll:
                PHP-Code:
                      var_dump($this->sql);
                      
                var_dump($this->con->real_escape_string($this->sql));
                      
                var_dump($this->con); 
                Ausgegeben wird das hier:
                Code:
                string(81) "SELECT *
                              FROM core_user
                              WHERE Name = :0 AND PW = :1"
                string(85) "SELECT *\r\n              FROM core_user\r\n              WHERE Name = :0 AND PW = :1"
                object(mysqli)#5 (0) {}
                Das zeigt, das die Methode funktioniert und $this->con ein mysqli-Objekt ist, wie bereits erwähnt.
                Und wo ist der Sinn dabei, wenn du den String "SELECT * FROM core_user WHERE Name = :0 AND PW = :1" escapest, aber nicht die Werte, die du einfügst?

                Ich seh überhaupt nicht, dass da irgendwas funktioniert. Zeig den relevanten Teil, dort wo du den String escapest, den du anfangs erwähnt hast.

                Ich will das sehen, genau _das_:
                PHP-Code:
                var_dump($value);
                var_dump($this->con->real_escape_string($value));
                var_dump($this->con); 
                $this->sql interessiert niemanden. Warum machen die Leute nie das, was man ihnen sagt?
                Zuletzt geändert von h3ll; 29.07.2009, 14:00.

                Kommentar


                • #23
                  Also: Jetzt mal alle Methoden ganz, die eine Rolle spielen.


                  Die allseits gehasste Methode execute()

                  Wie gesagt: $this->con ist ein myslqi-Objekt.
                  PHP-Code:

                  public function execute(){
                      if((
                  $this->con === false) || (is_null($this->sql))){               // Wenn Verbindungsobjekt noch nicht gesetzt ist oder SQL nicht übergeben wurde
                        
                  throw new ExcDB('Vor DBStmt::execute() muss DB::prepare($sql) ausgeführt werden');       // diese Fehlermeldung ist eigentlich überflüssig
                      
                  }

                      
                  $args func_get_args();    // Optionale Argumente auslesen
                      
                  $this->replaceSQL($args);    // String ersetzen
                      
                  Error::get()->setHandler('noHandler');     // Meldungen unterdrücken
                      
                  $this->starttime microtime();
                        
                  $this->result $this->con->query($this->sql);                // Abfrage starten
                      
                  $this->endtime microtime();
                      
                  Error::get()->restoreHandler();           // alten Handler wiederherstellen

                      
                  if($this->result === false){  // Fehler abfangen, wenn Query nicht erfolgreich war
                        
                  throw new ExcDBQuery($this->con$this->sql);
                      }

                  Die noch mehr gehasste Methode replaceSQL():
                  PHP-Code:
                    private function replaceSQL($args){      /* Ersetzt die Platzhalter :$key in einem SQL-String */
                      
                  $oldsql $this->sql;

                      
                  /* Eingaben überprüfen */
                      
                  $count preg_match_all('!:\d+\b!',$oldsql,$matches);  // herausfinden, wie häufig ein Platzhalter gesetzt wurde

                      
                  if( ($count === false && count($args)>0) || ($count !== false && (count($args)>$count) ) ){
                        throw new 
                  ExcDBQuery(NULL$oldsqlNULL'DBStmt::execute($args) wurden mehr Argumente übergeben, als Platzhalter vorhanden sind.');
                      }
                      if(
                  $count !== false && (count($args)<$count)){
                        throw new 
                  ExcDBQuery(NULL$oldsqlNULL'DBStmt::execute($args) wurden weniger Argumente übergeben, als Platzhalter vorhanden sind.');
                      }
                      
                      
                  /* Platzhalter ersetzen */
                      
                  foreach ($args as $key=>$value){
                        
                  $exp '!:'.$key.'\b!';
                        
                  var_dump($value);
                        
                  var_dump($this->con->real_escape_string($value));
                        
                  var_dump($this->con);
                        
                  $this->sql preg_replace($exp,'\''.$this->con->real_escape_string($value).'\'',$this->sql);   /* PHP-Manual: Characters encoded are NUL (ASCII 0), \n, \r, \, ', ", and Control-Z. */


                        
                  if(preg_last_error() !== 0){
                          throw new 
                  ExcDBQuery(NULL$oldsqlpreg_last_error(), 'Querystring konnte nicht ersetzt werden.');
                        }
                        
                      }
                    } 
                  @ h3ll: Du siehst, ich bin deiner Aufforderung jetzt genau _SO_ nachgegangen, wie du wolltest ;-)
                  Hier das Ergebnis bei der Eingabe von:
                  PHP-Code:
                  $arg1 'webasdf\';
                  $sql = '
                  SELECT FROM WHERE test = :0';
                  $st = $this->db->prepare($sql);
                  $st->execute($arg1); 
                  Ausgabe:
                  Code:
                  string(8) "webasdf\" string(9) "webasdf\\" object(mysqli)#10 (0) { }
                  Und noch einmal: $db->prepare macht nichts anderes als eine Verbindung herzustellen falls noch keine besteht und $this->sql zu belegen. Nichts mit PS.

                  Und noch das Ergebnis bei folgender Eingabe:
                  PHP-Code:
                  $arg2 'web\sdf';
                  $sql 'SELECT FROM * WHERE test = :0';
                  $st $this->db->prepare($sql);
                  $st->execute($arg2); 
                  Ausgabe:

                  Code:
                  string(7) "web\sdf" string(8) "web\\sdf" object(mysqli)#10 (0) { }
                  Von mir aus gesehen genau das Gleiche! 1. Fall erzeugt einen Fehler, zweiter Fall nicht.


                  Sorry, dass ich meinen Thread laufend ändere, hier noch etwas weiteres:

                  Wenn ich nach $this->sql = preg_replace(..) noch dies hier anfüge:
                  var_dump($this->sql);

                  Gibt er folgende Ausgabe:

                  Im 1. Fall:

                  Code:
                  string(7) "webasdf\" string(8) "webasdf\\" object(mysqli)#10 (0) { } string(58) "UPDATE mm_core               SET WebOfficePub = 'webasdf\'"
                  Im 2. Fall:
                  Code:
                  string(7) "web\sdf" string(8) "web\\sdf" object(mysqli)#10 (0) { } string(58) "UPDATE mm_core               SET WebOfficePub = 'web\sdf'"
                  Auch hier sehe ich leider Gottes keinen Unterschied.

                  PS: Ja und ich weiss, das SQL Statement in den beiden Beispielen oben ist qreuzfalsch, dient nur der Veranschaulichung.
                  Zuletzt geändert von tim-gt; 29.07.2009, 14:21.

                  Kommentar


                  • #24
                    Dein preg_replace tut nicht das, was du denkst. Bei Regular Expressions müssen bestimmte Zeichen (zB. das Backslash) nämlich auch escaped werden. Warum verwendest du überhaupt preg_replace() und nicht str_replace()?

                    PHP-Code:
                    $sql "SELECT * FROM tbl WHERE val = :0";
                    $pattern ":0";
                    $replace "'foo\\\\bar'";

                    var_dump(preg_replace("!" $pattern "!"$replace$sql));
                    // string(39) "SELECT * FROM tbl WHERE val = 'foo\bar'"

                    var_dump(str_replace($pattern$replace$sql));
                    // string(40) "SELECT * FROM tbl WHERE val = 'foo\\bar'" 
                    Zuletzt geändert von h3ll; 29.07.2009, 14:27.

                    Kommentar


                    • #25
                      Der Autor meint dazu, dass somit auch :10 richtig ersetzt wird, und nicht versucht wird, :1 zu ersetzen. Aber ich werds mal mit str_replace probieren, da ich sowieso meistens nur 2-4 Platzhalter brauche. Was müsste denn in preg_replace noch getan werden?

                      Kommentar


                      • #26
                        Ok, ich sehs. Ich hab das mit preg_replace nicht gewusst. Dann hat sich der Autor das nicht überlegt oder ich hab irgendwo sonst noch was komisches angestellt. Ich muss dazu sagen, dass ich den Code zwar einigermassen übernommen habe, aber vielerorts ausgebaut habe.
                        So funktioniert alles:

                        PHP-Code:
                         $this->sql str_replace($exp,'\''.$this->con->real_escape_string($value).'\'',$this->sql); 
                        Hier noch das Zitat aus dem Buch:

                        ¨Für jeden Schlüssel wird ein passender regulärer Ausdruck generiert (!:0\b!, !:1\b!
                        usw.). Die Zeichenfolge \b steht dabei für eine Wortgrenze, die dem Platzhalter folgen muss. Dann wird
                        mit der Funktion preg_replace() der Platzhalter im SQL-Kommando (das in $this->sql vorliegt,
                        siehe Konstruktor) gegen den passenden, mit der Methode real_escape_string() des Verbindungsobjekts
                        maskierten Wert ausgetauscht und mit Hochkommas versehen. Wir verwenden übrigens
                        preg_replace() und nicht str_replace(), da sich mit dem regulären Ausdruck so auch einfach
                        Werte größer als :9 ersetzen lassen, sonst würde bei einer :10 im zweiten foreach()-Durchlauf die :1
                        schon separat ersetzt werden.

                        Kommentar


                        • #27
                          Zitat von tim-gt Beitrag anzeigen
                          Der Autor meint dazu, dass somit auch :10 richtig ersetzt wird, und nicht versucht wird, :1 zu ersetzen. Aber ich werds mal mit str_replace probieren, da ich sowieso meistens nur 2-4 Platzhalter brauche. Was müsste denn in preg_replace noch getan werden?
                          Ich bin übrigens auch der Meinung von wahsaga, dass du da einen Murks drehst. Warum nennst du eine Methode "prepare", obwohl sie nicht das tut, was der Name aussagt? Nur weil etwas irgendwo in einem Buch steht, muss es noch lange nicht gold wert sein. Auch Buchautoren machen Fehler.

                          Kommentar


                          • #28
                            Keine Angst, ich studiere auch (zwar Geographie und nicht Informatik) und weiss schon lange, dass man nicht alles in Lehrbüchern für bare Münze oder für das einzig Wahre halten soll.

                            Ich finde den Namen prepare() aber gar nicht so unsinnig, schliesslich wird mit dem Verbindungsaufbau eine Abfrage vorbereitet. Klar, die Überschneidung mit mysqli:repare() ist da, aber überschrieben wird hier definitiv nichts. Stellt sich mir jetzt nur noch die Frage, wieso der Autor preg_replace genommen hat.

                            Kommentar


                            • #29
                              Zitat von tim-gt Beitrag anzeigen
                              Klar, die Überschneidung mit mysqli:repare() ist da, aber überschrieben wird hier definitiv nichts.
                              Ob überschrieben oder nicht ist hier m.E. auch nicht das Ding - aber dieser Methodenname im Umfeld von DB-Klassen hat nun mal eine Bedeutung, die man als defakto-Standard ansehen kann. Und damit besteht eine hohe Verwechslungsgefahr, wenn irgendjemand anderes diese deine Klasse mal nutzen wird, oder auch du selber in einem Jahr, wenn prepared statements für dich längst normales Handwerkszeug geworden sind - und dann suggeriert sie fälschlicherweise ein Vorgehen, das gar nicht wirklich dahinter steckt.
                              I don't believe in rebirth. Actually, I never did in my whole lives.

                              Kommentar


                              • #30
                                Zitat von wahsaga Beitrag anzeigen
                                Ob überschrieben oder nicht ist hier m.E. auch nicht das Ding - aber dieser Methodenname im Umfeld von DB-Klassen hat nun mal eine Bedeutung, die man als defakto-Standard ansehen kann. Und damit besteht eine hohe Verwechslungsgefahr, wenn irgendjemand anderes diese deine Klasse mal nutzen wird, oder auch du selber in einem Jahr, wenn prepared statements für dich längst normales Handwerkszeug geworden sind - und dann suggeriert sie fälschlicherweise ein Vorgehen, das gar nicht wirklich dahinter steckt.
                                Ok, danke für den Tipp, das verstehe ich. Du kannst es ja anscheinend auch normal sagen.

                                Zum Abschluss noch dies:

                                webflips --- Design * Dynamik * Datenbanken für Ihre Internetpräsenz

                                siehe Bug im MySQL-Wrapper.

                                Kommentar

                                Lädt...
                                X