it-swarm.com.de

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

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.

106
Nathan H

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);
150
Stephen Curran

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

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?

15
Pekka 웃

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);
6
Nicolas Manzini

Dies nur als Zusammenfassung.
Es gibt vier Optionen zum Parametrieren von LIMIT/OFFSET-Werten:

  1. Deaktivieren Sie PDO::ATTR_EMULATE_PREPARES wie oben oben .

    Dadurch wird verhindert, dass Werte, die per ->execute([...]) übergeben werden, immer als Zeichenfolgen angezeigt werden.

  2. Wechseln Sie zur manuellen ->bindValue(..., ..., PDO::PARAM_INT)-Parameterauffüllung.

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

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

6
mario

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:

  1. Verwenden Sie filter_var($integer, FILTER_VALIDATE_NUMBER_INT), um sicherzustellen, dass Sie eine Ganzzahl übergeben.
  2. Wie schon gesagt, mit intval()
  3. Casting mit (int)
  4. Überprüfen, ob es sich um eine Ganzzahl handelt, mit is_int()

Es gibt viel mehr Möglichkeiten, aber dies ist im Grunde die Hauptursache.

2

bindValue offset und limit mit PDO :: PARAM_INT und es wird funktionieren

1
Karel

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 ) {
    ...
}
0
Fins

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