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 .__ entspricht. Ihre MySQL-Server-Version für die richtige Syntax, die in der Nähe von '' 15 ', 15' um .__ verwendet werden soll. Linie 1
Es scheint, dass PDO meinen Variablen im LIMIT-Teil des SQL-Codes einfache Anführungszeichen hinzufügt. Ich habe nachgeschlagen. Ich habe diesen Fehler gefunden, von dem ich denke, dass er damit zusammenhängt: http://bugs.php.net/bug.php?id=44639
Ist das, was ich sehe? Dieser Fehler ist seit April 2008 geöffnet worden. Was sollen wir in der Zwischenzeit tun?
Ich muss etwas Paginierung erstellen und muss sicherstellen, dass die Daten sauber sind, SQL-Injection-sicher, bevor die SQL-Anweisung gesendet wird.
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);
Die einfachste Lösung wäre, den Emulationsmodus auszuschalten. Sie können dies entweder als Verbindungsoption oder einfach durch Hinzufügen der folgenden Zeile tun
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
Es löst nicht nur Ihr Problem mit bind param, sondern ermöglicht Ihnen auch das Senden von Werten in execute (), wodurch Ihr Code drastisch zum Shoter wird
$skip = (isset($_GET['skip'])):$_GET['skip']:0;
$sql = "SELECT * FROM pictures WHERE album = ? ORDER BY id ASC LIMIT ?, ?";
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
$stm = $PDO->prepare($sql);
$stm->execute(array($_GET['albumid'],$skip,$max));
$pictures = $stm->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 nach der Zahl nur one zu geben (im Gegensatz zur ganzen Zahl, die in Anführungszeichen eingeschlossen ist). Dies könnte auch ein Fehler bei Ihren eingehenden Daten sein. Können Sie eine print_r($_GET);
machen, um das herauszufinden?
für LIMIT :init, :end
Sie müssen auf diese Weise binden. Wenn Sie etwas wie $req->execute(Array());
hatten, funktioniert es nicht, da es PDO::PARAM_STR
in alle Variablen im Array umwandelt, und für die LIMIT
benötigen Sie unbedingt eine Integer . bindValue oder BindParam, wie Sie möchten.
$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
Dies nur als Zusammenfassung.
Es gibt vier Optionen zum Parametrieren von LIMIT/OFFSET-Werten:
Deaktivieren Sie PDO::ATTR_EMULATE_PREPARES
wie oben oben .
Dadurch wird verhindert, dass Werte, die per ->execute([...])
übergeben werden, immer als Zeichenfolgen angezeigt werden.
Wechseln Sie zur manuellen ->bindValue(..., ..., PDO::PARAM_INT)
-Parameterauffüllung.
Was jedoch weniger bequem ist als eine -> Ausführungsliste [].
Machen Sie hier einfach eine Ausnahme und interpolieren Sie bei der Vorbereitung der SQL-Abfrage einfach Ganzzahlen.
$limit = intval($limit);
$s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");
Das Casting ist wichtig. Normalerweise sehen Sie ->prepare(sprintf("SELECT ... LIMIT %d", $num))
, das für solche Zwecke verwendet wird.
Wenn Sie nicht MySQL verwenden, sondern beispielsweise SQLite oder Postgres. Sie können gebundene Parameter auch direkt in SQL umsetzen.
SELECT * FROM tbl LIMIT (1 * :limit)
Auch hier unterstützen MySQL/MariaDB keine Ausdrücke in der LIMIT-Klausel. Noch nicht.
Da niemand erklärt hat, warum das so ist, füge ich eine Antwort hinzu. Der Grund dafür ist, dass Sie trim()
verwenden. Wenn Sie sich das PHP Handbuch für trim
anschauen, ist der Rückgabetyp string
. Sie versuchen dann, dies als PDO::PARAM_INT
zu übergeben. Einige Möglichkeiten, dies zu umgehen, sind:
filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
, um sicherzustellen, dass Sie eine Ganzzahl übergeben.intval()
(int)
is_int()
Es gibt viel mehr Möglichkeiten, aber dies ist im Grunde die Hauptursache.
bindValue offset und limit mit PDO :: PARAM_INT und es wird funktionieren
PDO::ATTR_EMULATE_PREPARES
gab mir das
Der Treiber unterstützt diese Funktion nicht: Dieser Treiber unterstützt nicht Fehler beim Einstellen der Attribute.
Meine Problemumgehung bestand darin, eine $limit
-Variable als Zeichenfolge festzulegen und diese dann in der Vorbereitungsanweisung wie im folgenden Beispiel zu kombinieren:
$limit = ' LIMIT ' . $from . ', ' . $max_results;
$stmt = $pdo->prepare( 'SELECT * FROM users WHERE company_id = :cid ORDER BY name ASC' . $limit . ';' );
try {
$stmt->execute( array( ':cid' => $company_id ) );
...
}
catch ( Exception $e ) {
...
}
// VOR (gegenwärtiger Fehler) $ Query = ".... LIMIT: p1, 30;"; ... $ Stmt-> bindParam (': p1', $ limiteInferior);
// AFTER (Fehler behoben) $ Query = ".... LIMIT: p1, 30;"; ... $ LimiteInferior = (int) $ limiteInferior; $ Stmt- > bindParam (': p1', $ limiteInferior, PDO :: PARAM_INT);