Hier ist eine Momentaufnahme meines Codes:
$fetchPictures = $PDO->prepare("SELECT *
FROM pictures
WHERE album = :albumId
ORDER BY id ASC
LIMIT :skip, :max");
$fetchPictures->bindValue(':albumId', $_GET['albumid'], PDO::PARAM_INT);
if(isset($_GET['skip'])) {
$fetchPictures->bindValue(':skip', trim($_GET['skip']), PDO::PARAM_INT);
} else {
$fetchPictures->bindValue(':skip', 0, PDO::PARAM_INT);
}
$fetchPictures->bindValue(':max', $max, PDO::PARAM_INT);
$fetchPictures->execute() or die(print_r($fetchPictures->errorInfo()));
$pictures = $fetchPictures->fetchAll(PDO::FETCH_ASSOC);
Ich bekomme
Sie haben einen Fehler in Ihrer SQL-Syntax. Überprüfen Sie das Handbuch, das Ihrer MySQL-Serverversion entspricht, auf die richtige Syntax für die Verwendung in der Nähe von '' 15 ', 15' in Zeile 1
Es scheint, dass PDO meinen Variablen im LIMIT-Teil des SQL-Codes einfache Anführungszeichen hinzufügt. Ich habe nachgeschlagen und diesen Fehler gefunden, von dem ich denke, dass er damit zusammenhängt: http://bugs.php.net/bug.php?id=44639
Ist es das, was ich sehe? Dieser Bug wurde seit April 2008 geöffnet! Was sollen wir in der Zwischenzeit tun?
Ich muss eine Paginierung erstellen und sicherstellen, dass die Daten sauber und SQL-Injection-sicher sind, bevor ich die SQL-Anweisung sende.
Antworten:
Ich erinnere mich, dass ich dieses Problem schon einmal hatte. Wandeln Sie den Wert in eine Ganzzahl um, bevor Sie ihn an die Bindefunktion übergeben. Ich denke das löst es.
quelle
(int) trim($_GET['skip'])
Versuchen Sie es stattdessenintval(trim($_GET['skip']))
.Die einfachste Lösung wäre, den Emulationsmodus auszuschalten. Sie können dies tun, indem Sie einfach die folgende Zeile hinzufügen
Dieser Modus kann auch als Konstruktorparameter beim Erstellen einer PDO-Verbindung festgelegt werden . Es könnte eine bessere Lösung sein, da einige berichten, dass ihr Treiber die
setAttribute()
Funktion nicht unterstützt .Es wird nicht nur Ihr Problem mit der Bindung lösen, sondern Sie können auch Werte direkt an senden
execute()
, wodurch Ihr Code erheblich kürzer wird. Vorausgesetzt, der Emulationsmodus wurde bereits eingestellt, dauert die gesamte Angelegenheit bis zu einem halben Dutzend Codezeilenquelle
SQLSTATE[IM001]: Driver does not support this function: This driver doesn't support setting attributes
... Warum ist es für mich nie so einfach :) Obwohl ich sicher bin, dass dies die meisten Leute dorthin bringen wird, musste ich in meinem Fall etwas Ähnliches wie die akzeptierte Antwort verwenden. Nur ein Kopf hoch für zukünftige Leser!PDO::ATTR_EMULATE_PREPARES Enables or disables emulation of prepared statements. Some drivers do not support native prepared statements or have limited support for them
. Es ist neu für mich, aber andererseits fange ich gerade erst mit PDO an. Verwenden Sie normalerweise mysqli, aber ich dachte, ich würde versuchen, meinen Horizont zu erweitern.setAttribute
die Anweisung ($ stm, $ stmt) und nicht das pdo-Objekt aufrufen.Wenn Sie sich den Fehlerbericht ansehen, könnte Folgendes funktionieren:
Aber sind Sie sicher, dass Ihre eingehenden Daten korrekt sind? Da in der Fehlermeldung, es scheint nur zu sein , ein Zitat nach der Nummer (in Bezug auf die gesamte Anzahl entgegengesetzt ist in Anführungszeichen eingeschlossen). Dies kann auch ein Fehler bei Ihren eingehenden Daten sein. Können Sie etwas tun
print_r($_GET);
, um es herauszufinden?quelle
Dies nur als Zusammenfassung.
Es gibt vier Optionen zur Parametrisierung von LIMIT / OFFSET-Werten:
Deaktivieren Sie
PDO::ATTR_EMULATE_PREPARES
wie erwähnt oben .Dadurch wird verhindert, dass pro übergebene Werte
->execute([...])
immer als Zeichenfolgen angezeigt werden.Wechseln Sie zur manuellen
->bindValue(..., ..., PDO::PARAM_INT)
Parameterpopulation.Was jedoch weniger bequem ist als eine -> Ausführungsliste [].
Machen Sie hier einfach eine Ausnahme und interpolieren Sie bei der Vorbereitung der SQL-Abfrage nur einfache Ganzzahlen.
Das Casting ist wichtig. Häufiger
->prepare(sprintf("SELECT ... LIMIT %d", $num))
wird dies für solche Zwecke verwendet.Wenn Sie nicht MySQL verwenden, sondern beispielsweise SQLite oder Postgres; Sie können gebundene Parameter auch direkt in SQL umwandeln.
Auch hier unterstützt MySQL / MariaDB keine Ausdrücke in der LIMIT-Klausel. Noch nicht.
quelle
{$_GET->int["limit"]}
für solche Fälle verwenden.zum
LIMIT :init, :end
Sie müssen auf diese Weise binden. Wenn Sie so etwas hatten, wird
$req->execute(Array());
es nicht funktionieren, da esPDO::PARAM_STR
auf alle Variablen im Array übertragen wird und für dieLIMIT
Sie unbedingt eine Ganzzahl benötigen. bindValue oder BindParam wie Sie möchten.quelle
Da niemand erklärt hat, warum dies geschieht, füge ich eine Antwort hinzu. Der Grund dafür ist, dass Sie verwenden
trim()
. Wenn Sie sich das PHP-Handbuch ansehentrim
, ist der Rückgabetypstring
. Sie versuchen dann, dies als zu übergebenPDO::PARAM_INT
. Einige Möglichkeiten, dies zu umgehen, sind:filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
Sie diese Option , um sicherzustellen, dass Sie eine Ganzzahl übergeben.intval()
(int)
is_int()
Es gibt viel mehr Möglichkeiten, aber dies ist im Grunde die Hauptursache.
quelle
bindValue Offset und Limit mit PDO :: PARAM_INT und es wird funktionieren
quelle
// BEFORE (Present error) $ query = ".... LIMIT: p1, 30;"; ... $ stmt-> bindParam (': p1', $ limiteInferior);
// AFTER (Fehler korrigiert) $ query = ".... LIMIT: p1, 30;"; ... $ limiteInferior = (int) $ limiteInferior; $ stmt-> bindParam (': p1', $ limiteInferior, PDO :: PARAM_INT);
quelle
PDO::ATTR_EMULATE_PREPARES
gab mir dasMeine Problemumgehung bestand darin, eine
$limit
Variable als Zeichenfolge festzulegen und sie dann in der prepare-Anweisung wie im folgenden Beispiel zu kombinieren:quelle
Es gibt viel zwischen verschiedenen Versionen von PHP und den Kuriositäten von PDO. Ich habe hier 3 oder 4 Methoden ausprobiert, konnte LIMIT jedoch nicht zum Laufen bringen.
Mein Vorschlag ist, die Formatierung / Konkatination von Zeichenfolgen MIT einem intval () - Filter zu verwenden:
Es ist sehr wichtig, intval () zu verwenden, um eine SQL-Injection zu verhindern, insbesondere wenn Sie Ihr Limit von $ _GET oder ähnlichem erhalten. Wenn Sie dies tun, ist dies der einfachste Weg, um LIMIT zum Laufen zu bringen.
Es wird viel über 'Das Problem mit LIMIT in PDO' gesprochen, aber ich denke hier, dass PDO-Parameter nie für LIMIT verwendet werden sollten, da sie immer ganze Zahlen sind, funktioniert ein schneller Filter. Trotzdem ist es etwas irreführend, da die Philosophie immer darin bestand, keine SQL-Injection-Filterung selbst durchzuführen, sondern "PDO damit umgehen zu lassen".
quelle