
Nathan H
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, um sie in der Nähe von ”15′, 15′ in Zeile 1 zu verwenden
Es scheint, dass PDO meinen Variablen im LIMIT-Teil des SQL-Codes einfache Anführungszeichen hinzufügt. Ich habe nachgesehen und diesen Fehler gefunden, von dem ich glaube, dass er damit zusammenhängt:
http://bugs.php.net/bug.php?id=44639
Ist es das, was ich sehe? Dieser Bug ist 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-injektionssicher sind, bevor ich die SQL-Anweisung sende.
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.
$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);

Ihr gesunder Menschenverstand
Die einfachste Lösung wäre, den Emulationsmodus auszuschalten. Sie können dies tun, indem Sie einfach die folgende Zeile hinzufügen
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
Außerdem kann dieser Modus als Konstruktorparameter gesetzt werden, wenn Erstellen einer PDO-Verbindung. Es könnte eine bessere Lösung sein, da einige berichten, dass ihr Treiber dies nicht unterstützt setAttribute()
Funktion.
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. Angenommen, der Emulationsmodus wurde bereits eingestellt, dauert die ganze Angelegenheit bis zu einem halben Dutzend Codezeilen
$skip = isset($_GET['skip']) ? (int)trim($_GET['skip']) : 0;
$sql = "SELECT * FROM pictures WHERE album = ? ORDER BY id LIMIT ?, ?";
$stmt = $PDO->prepare($sql);
$stmt->execute([$_GET['albumid'], $skip, $max]);
$pictures = $stmt->fetchAll(PDO::FETCH_ASSOC);
Wenn Sie sich den Fehlerbericht ansehen, könnte Folgendes funktionieren:
$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
$fetchPictures->bindValue(':skip', (int)trim($_GET['skip']), PDO::PARAM_INT);
aber sind Sie sicher, dass Ihre eingehenden Daten korrekt sind? Denn in der Fehlermeldung scheint es nur zu stehen ein nach der Zahl in Anführungszeichen setzen (im Gegensatz dazu, dass die ganze Zahl in Anführungszeichen gesetzt wird). Dies könnte auch ein Fehler bei Ihren eingehenden Daten sein. Kannst du ein print_r($_GET);
herausfinden?
Dies nur als Zusammenfassung.
Es gibt vier Möglichkeiten, LIMIT/OFFSET-Werte zu parametrieren:
-
Deaktivieren PDO::ATTR_EMULATE_PREPARES
wie oben erwähnt.
Was verhindert, dass Werte pro übergeben werden ->execute([...])
immer als Strings erscheinen.
-
Auf Manuell umschalten ->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.
$limit = intval($limit);
$s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");
Das Gießen ist wichtig. Häufiger sehen Sie ->prepare(sprintf("SELECT ... LIMIT %d", $num))
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.
SELECT * FROM tbl LIMIT (1 * :limit)
Auch hier unterstützen MySQL/MariaDB keine Ausdrücke in der LIMIT-Klausel. Noch nicht.

Nikolaus Manzini
zum LIMIT :init, :end
Du musst so binden. wenn du sowas hättest $req->execute(Array());
es wird nicht funktionieren, da es gegossen wird PDO::PARAM_STR
zu allen Vars im Array und für die LIMIT
Sie brauchen unbedingt eine ganze Zahl. bindValue oder BindParam, wie Sie möchten.
$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

Allan Pereira
Da niemand erklärt hat, warum dies geschieht, füge ich eine Antwort hinzu. Der Grund, warum es sich so verhält, ist, weil Sie es verwenden trim()
. Schaut man sich das PHP-Handbuch an trim
der Rückgabetyp ist string
. Sie versuchen dann, dies als weiterzugeben PDO::PARAM_INT
. Ein paar Möglichkeiten, dies zu umgehen, sind:
- Verwenden
filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
um sicherzustellen, dass Sie eine Ganzzahl übergeben.
- Wie andere sagten, mit
intval()
- Gießen mit
(int)
- Prüfen, ob es sich um eine ganze Zahl mit handelt
is_int()
Es gibt noch viel mehr Möglichkeiten, aber das ist im Grunde die Hauptursache.

Karl
bindValue Offset und Limit mit PDO::PARAM_INT und es wird funktionieren
9931600cookie-checkWie wende ich die binValue-Methode in der LIMIT-Klausel an?yes
Hier ist eine verwandte Frage, aber stattdessen mit bindParam
– Timo Huovinen
24. Oktober 2013 um 18:49 Uhr
Bemerkenswerte Antwort in einer doppelten Frage: Parametrisierte PDO-Abfrage und `LIMIT`-Klausel – funktioniert nicht [duplicate] (August 2013; von Bill Karwin)
– hakre
29. März 2015 um 11:37 Uhr