Wie wende ich die binValue-Methode in der LIMIT-Klausel an?

Lesezeit: 7 Minuten

Wie wende ich die binValue Methode in der LIMIT Klausel an
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.

  • 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


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);

  • Danke! Aber in PHP 5.3 hat der obige Code einen Fehler ausgegeben, der besagte: “Fatal error: Cannot pass parameter 2 by reference”. Es mag es nicht, dort ein int zu casten. Anstatt (int) trim($_GET['skip'])Versuchen intval(trim($_GET['skip'])).

    – Will Martin

    8. April 2011 um 17:01 Uhr

  • wäre cool, wenn jemand die Erklärung geben würde, warum das so ist … vom Standpunkt des Designs / der Sicherheit (oder eines anderen) aus.

    – Roß

    25. September 2012 um 0:23 Uhr


  • Das funktioniert nur, wenn Emulierte vorbereitete Anweisungen sind aktiviert. Es schlägt fehl, wenn es deaktiviert ist (und es sollte deaktiviert werden!)

    – Madaras Geist

    15. November 2012 um 19:32 Uhr

  • @Ross Ich kann das nicht speziell beantworten – aber ich kann darauf hinweisen, dass LIMIT und OFFSET Funktionen sind, die aufgeklebt wurden, NACHDEM dieser ganze PHP/MYSQL/PDO-Wahnsinn die Entwicklerkreise getroffen hatte … Tatsächlich glaube ich, dass es Lerdorf selbst war, der die Aufsicht führte LIMIT-Implementierung vor ein paar Jahren. Nein, es beantwortet die Frage nicht, aber es zeigt an, dass es sich um ein Aftermarket-Add-On handelt, und Sie wissen, wie gut sie manchmal funktionieren können ….

    – FredTheWebGuy

    13. Oktober 2013 um 0:55 Uhr

  • @Ross PDO erlaubt keine Bindung an Werte – eher an Variablen. Wenn Sie bindParam(‘:something’, 2) versuchen, erhalten Sie einen Fehler, da PDO einen Zeiger auf die Variable verwendet, die eine Zahl nicht haben kann (wenn $i 2 ist, können Sie einen Zeiger auf $i haben, aber nicht auf die Nummer 2).

    – Kristijan

    20. Juni 2014 um 8:34 Uhr

Wie wende ich die binValue Methode in der LIMIT Klausel an
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);

  • SQLSTATE[IM001]: Driver does not support this function: This driver doesn't support setting attributes…Warum ist es nie so einfach für mich 🙂 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 Heads-up für zukünftige Leser!

    – Matthäus Johnson

    8. Mai 2014 um 21:36 Uhr


  • @MatthewJohnson welcher Treiber ist es?

    – Ihr gesunder Menschenverstand

    9. Mai 2014 um 5:35 Uhr

  • Ich bin mir nicht sicher, aber in das Handbuch es sagt 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. Normalerweise verwende ich mysqli, aber ich dachte, ich würde versuchen, meinen Horizont zu erweitern.

    – Matthäus Johnson

    9. Mai 2014 um 13:49 Uhr

  • @MatthewJohnson Wenn Sie PDO für MySQL verwenden, unterstützt der Treiber diese Funktion in Ordnung. Sie erhalten diese Nachricht also aufgrund eines Fehlers

    – Ihr gesunder Menschenverstand

    9. Mai 2014 um 14:07 Uhr

  • Wenn Sie eine Treiber-Support-Problemmeldung erhalten haben, versuchen Sie es erneut, wenn Sie anrufen setAttribute für die Anweisung ($stm, $stmt), nicht für das pdo-Objekt.

    – Jehong Ahn

    21. Dezember 2016 um 6:44 Uhr

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?

  • „15“, 15“. Die erste Zahl ist vollständig in Anführungszeichen eingeschlossen. Die zweite Zahl hat überhaupt keine Anführungszeichen. Also ja, die Daten sind gut.

    – Nathan H

    16. Februar 2010 um 0:37 Uhr

Dies nur als Zusammenfassung.
Es gibt vier Möglichkeiten, LIMIT/OFFSET-Werte zu parametrieren:

  1. Deaktivieren PDO::ATTR_EMULATE_PREPARES wie oben erwähnt.

    Was verhindert, dass Werte pro übergeben werden ->execute([...]) immer als Strings erscheinen.

  2. Auf Manuell umschalten ->bindValue(..., ..., PDO::PARAM_INT) Parameterpopulation.

    Was jedoch weniger bequem ist als eine -> Ausführungsliste[].

  3. 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.

  4. 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.

1647074048 185 Wie wende ich die binValue Methode in der LIMIT Klausel an
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);

1647074048 361 Wie wende ich die binValue Methode in der LIMIT Klausel an
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 trimder Rückgabetyp ist string. Sie versuchen dann, dies als weiterzugeben PDO::PARAM_INT. Ein paar Möglichkeiten, dies zu umgehen, sind:

  1. Verwenden filter_var($integer, FILTER_VALIDATE_NUMBER_INT) um sicherzustellen, dass Sie eine Ganzzahl übergeben.
  2. Wie andere sagten, mit intval()
  3. Gießen mit (int)
  4. 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.

1647074048 292 Wie wende ich die binValue Methode in der LIMIT Klausel an
Karl

bindValue Offset und Limit mit PDO::PARAM_INT und es wird funktionieren

993160cookie-checkWie wende ich die binValue-Methode in der LIMIT-Klausel an?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy