Moment, ich mach das gleich.
Probleme mit mysli::real_escape_string in Verbindung mit magic_quotes_gpc
Einklappen
X
-
Dann nicht!Sorry, ich will jetzt nicht alle meine Methoden erklären.
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.
Kommentar
-
Was nutzt du da, MySQLi? Dann wäre es nicht sonderlich clever, die execute-Methode von MySQLi_STMT mit einer eigenen zu überschreiben.Zitat von tim-gt Beitrag anzeigenDie $args in Methode execute($args) werden dann so behandelt
Damit nutzt du dann aber keine prepared statements, sondern gehst den "herkömmlichen" Weg.$this->sql wird dann in der Methode execute() ganz normal mit $mysqli->query($this->sql) ausgeführt.
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
-
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
-
@ h3ll:
Ausgegeben wird das hier:PHP-Code:var_dump($this->sql);
var_dump($this->con->real_escape_string($this->sql));
var_dump($this->con);
Das zeigt, das die Methode funktioniert und $this->con ein mysqli-Objekt ist, wie bereits erwähnt.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) {}
So :
Wird jedoch das hier ausgegeben: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);
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.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'"Zuletzt geändert von tim-gt; 29.07.2009, 13:57.
Kommentar
-
Was gibts da zu escapen?Das Zeug wird also nicht escaped.
Etwa 81dc9bdb52d04dc20036dbd8313ed055 ??
Hihihi....
Kommentar
-
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?Zitat von tim-gt Beitrag anzeigen@ h3ll:
Ausgegeben wird das hier:PHP-Code:var_dump($this->sql);
var_dump($this->con->real_escape_string($this->sql));
var_dump($this->con);
Das zeigt, das die Methode funktioniert und $this->con ein mysqli-Objekt ist, wie bereits erwähnt.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) {}
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_:
$this->sql interessiert niemanden. Warum machen die Leute nie das, was man ihnen sagt?PHP-Code:var_dump($value);
var_dump($this->con->real_escape_string($value));
var_dump($this->con);
Zuletzt geändert von h3ll; 29.07.2009, 14:00.
Kommentar
-
Also: Jetzt mal alle Methoden ganz, die eine Rolle spielen.
Die allseits gehasste Methode execute()
Wie gesagt: $this->con ist ein myslqi-Objekt.
Die noch mehr gehasste Methode replaceSQL():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);
}
}
@ h3ll: Du siehst, ich bin deiner Aufforderung jetzt genau _SO_ nachgegangen, wie du wolltest ;-)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, $oldsql, NULL, 'DBStmt::execute($args) wurden mehr Argumente übergeben, als Platzhalter vorhanden sind.');
}
if($count !== false && (count($args)<$count)){
throw new ExcDBQuery(NULL, $oldsql, NULL, '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, $oldsql, preg_last_error(), 'Querystring konnte nicht ersetzt werden.');
}
}
}
Hier das Ergebnis bei der Eingabe von:
Ausgabe:PHP-Code:$arg1 = 'webasdf\';
$sql = 'SELECT FROM * WHERE test = :0';
$st = $this->db->prepare($sql);
$st->execute($arg1);
Und noch einmal: $db->prepare macht nichts anderes als eine Verbindung herzustellen falls noch keine besteht und $this->sql zu belegen. Nichts mit PS.Code:string(8) "webasdf\" string(9) "webasdf\\" object(mysqli)#10 (0) { }
Und noch das Ergebnis bei folgender Eingabe:
Ausgabe:PHP-Code:$arg2 = 'web\sdf';
$sql = 'SELECT FROM * WHERE test = :0';
$st = $this->db->prepare($sql);
$st->execute($arg2);
Von mir aus gesehen genau das Gleiche! 1. Fall erzeugt einen Fehler, zweiter Fall nicht.Code:string(7) "web\sdf" string(8) "web\\sdf" object(mysqli)#10 (0) { }
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:
Im 2. Fall:Code:string(7) "webasdf\" string(8) "webasdf\\" object(mysqli)#10 (0) { } string(58) "UPDATE mm_core SET WebOfficePub = 'webasdf\'"
Auch hier sehe ich leider Gottes keinen Unterschied.Code:string(7) "web\sdf" string(8) "web\\sdf" object(mysqli)#10 (0) { } string(58) "UPDATE mm_core SET WebOfficePub = 'web\sdf'"
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
-
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
-
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
-
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:
Hier noch das Zitat aus dem Buch:PHP-Code:$this->sql = str_replace($exp,'\''.$this->con->real_escape_string($value).'\'',$this->sql);
¨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
-
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.Zitat von tim-gt Beitrag anzeigenDer 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
-
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
-
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.Zitat von tim-gt Beitrag anzeigenKlar, die Überschneidung mit mysqli:
repare() ist da, aber überschrieben wird hier definitiv nichts.I don't believe in rebirth. Actually, I never did in my whole lives.
Kommentar
-
Ok, danke für den Tipp, das verstehe ich. Du kannst es ja anscheinend auch normal sagen.Zitat von wahsaga Beitrag anzeigenOb ü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.
Zum Abschluss noch dies:
webflips --- Design * Dynamik * Datenbanken für Ihre Internetpräsenz
siehe Bug im MySQL-Wrapper.
Kommentar
Kommentar