Moment, ich mach das gleich.
Probleme mit mysli::real_escape_string in Verbindung mit magic_quotes_gpc
Einklappen
X
-
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
-
Zitat von tim-gt Beitrag anzeigenDie $args in Methode execute($args) werden dann so behandelt
$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, 14: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, 14:53.
Kommentar
-
@ h3ll:
PHP-Code:var_dump($this->sql);
var_dump($this->con->real_escape_string($this->sql));
var_dump($this->con);
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 :
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);
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, 14:57.
Kommentar
-
Das Zeug wird also nicht escaped.
Etwa 81dc9bdb52d04dc20036dbd8313ed055 ??
Hihihi....
Kommentar
-
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);
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_:
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, 15: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.
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);
}
}
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:
PHP-Code:$arg1 = 'webasdf\';
$sql = 'SELECT FROM * WHERE test = :0';
$st = $this->db->prepare($sql);
$st->execute($arg1);
Code:string(8) "webasdf\" string(9) "webasdf\\" object(mysqli)#10 (0) { }
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);
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:
Code:string(7) "webasdf\" string(8) "webasdf\\" object(mysqli)#10 (0) { } string(58) "UPDATE mm_core SET WebOfficePub = 'webasdf\'"
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, 15: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, 15: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:
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
-
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
-
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
-
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