> 1) Ich vermisse eine Möglichkeit, mir die fertige Query anzusehen, also
> die Platzhalter "?" durch die einzelnen Werte ersetzt zu haben.
> Hintergrund: Beim früheren Zusammenbasteln hat man sich einfach zur
> Entwicklungszeit mittels Echo das vollständige Statement ausgeben lassen,
> wenn das erzielte Ergebnis nicht das erwartete war und hat so schnell den
> Fehler im Statement finden können. Bei prepared Statements scheint das
> nicht zu gehen?
Da ist mir nichts bekannt. Und zum Testen kannst Du ja normale Abfragen
verwenden. Das jeweilige DBMS (hier: MySQL) könnte auch selbst
entsprechende Logging-Funktionalität bereitstellen.
Deine Frage deutet jedoch an, dass Du Prepared Statements möglicherweise
falsch einsetzt. Denn ausser den literalen Werten, die Du bereits im
Voraus kennst, sollte sich am Anweisungs-Template, das Du ebenfalls im
Voraus kennst, gerade nichts mehr ändern, um Code Injection zu verhindern.
> 2) In manchen Fällen entscheidet sich erst zur Laufzeit, ob ein Statement
> mit z. B. 19 oder 20 Parametern ausgestattet ist (klassisches Beispiel:
> INSERT vs. UPDATE - Statement mit sonst identischem Inhalt, nur das
> letzteres halt noch ein "WHERE id = ?" enthält). Mit
> mysqli_stmt->bind_param() kann man das offensichtlich nicht abbilden.
> Oder gibt es da doch einen Trick, ohne gleich zwei Endloslisten
> aufzubauen?
Ich verstehe nicht, was Du mit Endloslisten meinst.
$stmt->bind_param() unterstützt normalerweise ein Array als zweites
Argument. Bei mysqli ist das anscheinend leider nicht der Fall, aber Du
solltest mit call_user_func_array() eine variable Anzahl Parameter an die
Funktion/Methode übergeben können, die aus einem Array kommen. Wenn Du
jetzt zwei fast identische Anweisungen hast, kannst Du zwei fast identische
Strings verwenden und aus dem Array (z.B. per array_slice()) nur die
Elemente herausholen, welche Du jeweils für die Anweisung benötigst.
Wichtig ist hier, dass die Array-Elemente Referenzen sein müssen. Mehr
siehe <http://php.net/manual/en/mysqli-stmt.bind-param.php>.
PointedEars
Es gibt bestimmt auch Prepared Statements die man mit Benutzereingaben
füttert statt mit hardgecodeten Werten. Wenn diese Fehlschlagen (zum
Beispiel weil einer der Datensätze einen Unique Index verletzt) wäre das
fertige SQL Statement samt den eingesetzten Werten interessant.
Zumindest hatte ich diesen Fall öfters wo mehrere Datensätze importiert
werden mussten aus irgendwelchen Rohdaten und es dann zu Fehlern kam
weil zum Beispiel Datumsformate nicht korrekt waren oder ähnliches. Der
Aufwand die betroffenen Datensätze zu finden wäre kleiner gewesen hätte
man diese in der Fehlermeldung sehen können.
Was Prepared Statements mit Code Injection zu tun haben weiss ich nicht.
Gerade bei Prepared Statements sind diese in den mir bekannten Systemen
nicht möglich, da alle eingesetzten Werte maskiert werden.
--
Mit freundlichen Grüßen,
Christoph Herrmann
> Thomas 'PointedEars' Lahn:
>> Deine Frage deutet jedoch an, dass Du Prepared Statements möglicherweise
>> falsch einsetzt. Denn ausser den literalen Werten, die Du bereits im
>> Voraus kennst, sollte sich am Anweisungs-Template, das Du ebenfalls im
>> Voraus kennst, gerade nichts mehr ändern, um Code Injection zu
>> verhindern.
>
> Es gibt bestimmt auch Prepared Statements die man mit Benutzereingaben
> füttert statt mit hardgecodeten Werten. Wenn diese Fehlschlagen (zum
> Beispiel weil einer der Datensätze einen Unique Index verletzt) wäre das
> fertige SQL Statement samt den eingesetzten Werten interessant.
Weshalb? Die Benutzereingaben können auch so ausgegeben werden, und damit
sollte auch klar sein, wie die Abfrage aussieht und was nicht funktioniert.
Zumal die entsprechende Fehlermeldung per PHP abrufbar wäre. Und wie ich
schon schrieb: das DBMS hat vermutlich eine entsprechende eingebaute
Logging-Funktionalität.
> Zumindest hatte ich diesen Fall öfters wo mehrere Datensätze importiert
> werden mussten aus irgendwelchen Rohdaten und es dann zu Fehlern kam
> weil zum Beispiel Datumsformate nicht korrekt waren oder ähnliches. Der
> Aufwand die betroffenen Datensätze zu finden wäre kleiner gewesen hätte
> man diese in der Fehlermeldung sehen können.
/* DEBUG */
echo '<pre>' . $benutzerdatum . '</pre>';
$stmt->execute();
// ...
echo '<pre>' . $result. '</pre>';
Abgesehen davon kann man sich mit etwas Phantasie das Statement selbst
zusammenbasteln, oft auch automatisch. Die Werte müssen immerhin per
Variable vorliegen, weil die zweiten usw. Parameter von bind_param()
Referenzen sein müssen.
> Was Prepared Statements mit Code Injection zu tun haben weiss ich nicht.
> Gerade bei Prepared Statements sind diese in den mir bekannten Systemen
> nicht möglich, da alle eingesetzten Werte maskiert werden.
Deshalb schrieb ich ja "um Code Injection zu verhindern".
PointedEars
Klar kann man es so entwickeln dass man im Fehlerfall die
hineingegebenen Variablen mit ausgibt. Aber das erfordert a) dass man
die Datenbankfunktionen abstrahiert hat um es atomatisch überall so zu
haben und b) Damit verbundener Aufwand.
Meine alte Firma hatte sich zu a) wenig Gedanken gemacht gehabt was b)
dann sehr groß werden lies und man doch lieber bei Problemen manuell
schnell an der problematischen Stelle was hingebastelt hat. Da hat man
sich halt gewünscht dass man das fertige Statement samt den Werten doch
automatisch vom DBMS bekommt statt jedesmal zumzubasteln. ;)
Ich kenne weder bei DB2 noch bei MySQL eine Möglichkeit an die Werte
bzw. das fertige Statement ranzukommen. Wenn du mehr Informationen dazu
hast, gerne her damit.
Es ist eines von mehreren moeglichen Hilfsmitteln beim Debugging und als
solches durchaus willkommen. Je nach Art eines Fehlers habe ich die Suche
durchaus schon deutlich beschleunigen koennen, indem ich mir einfach einmal
alle SQL-Statements, die mein Code so produziert hat, der Reihe nach
angesehen habe.
> Ich kenne weder bei DB2 noch bei MySQL eine Möglichkeit an die Werte bzw.
> das fertige Statement ranzukommen.
Fuer einen Entwicklungsrechner durchaus vertretbar:
| [/etc/mysql/my.cnf]
| # Be aware that this log type is a performance killer.
| log = /var/log/mysql/mysql.log
Servus,
Stefan
--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike
Ein Hauch von Ewigkeit - Stefan: singen, welch lahmes Verlangen!
(Sloganizer)
> On Wed, 03 Mar 2010 18:45:43 Christoph Herrmann wrote:
>> Ich kenne weder bei DB2 noch bei MySQL eine Möglichkeit an die Werte bzw.
>> das fertige Statement ranzukommen.
>
> Fuer einen Entwicklungsrechner durchaus vertretbar:
>
> | [/etc/mysql/my.cnf]
> | # Be aware that this log type is a performance killer.
> | log = /var/log/mysql/mysql.log
Und es gibt bei MySQL auch noch weitere, verfeinerte Möglichkeiten für
Logging. Beispielsweise lässt sich das Logging auf Abfragen in einer
bestimmten Datenbank begrenzen, oder es können nur langsame Abfragen in
einer bestimmten Datei mitgeloggt werden.
<http://dev.mysql.com/doc/refman/5.0/en/server-
options.html#option_mysqld_log>
PointedEars