122

これが私のコードのスナップショットです:

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

私は得る

SQL構文にエラーがあります。1行目の「15」、「15」の近くで使用する正しい構文については、MySQLサーバーのバージョンに対応するマニュアルを確認してください。

PDOがSQLコードのLIMIT部分の変数に一重引用符を追加しているようです。調べてみたところ、関連していると思われるこのバグが見つかりました:http: //bugs.php.net/bug.php? id=44639

それは私が見ているものですか?このバグは2008年4月から開かれています。その間に私たちは何をすべきでしょうか?

SQLステートメントを送信する前に、ページネーションを作成し、データがクリーンでSQLインジェクションに対して安全であることを確認する必要があります。

4

10 に答える 10

172

私は以前にこの問題を抱えていたことを覚えています。値を整数にキャストしてから、バインド関数に渡します。これで解決すると思います。

$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);
于 2010-02-16T00:35:34.717 に答える
49

最も簡単な解決策は、エミュレーションモードをオフにすることです。次の行を追加するだけで実行できます

$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );

また、このモードは、PDO接続を作成するときにコンストラクターパラメーターとして設定できます。一部のレポートでは、ドライバーがこの機能をサポートしていないため、より良い解決策になる可能性がありsetAttribute()ます。

バインディングの問題を解決するだけでなく、値をに直接送信できるexecute()ため、コードが大幅に短縮されます。エミュレーションモードがすでに設定されていると仮定すると、全体の処理には6行ものコードが必要になります。

$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);
于 2013-08-05T16:52:06.330 に答える
18

バグレポートを見ると、次のことが機能する可能性があります。

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

$fetchPictures->bindValue(':skip', (int)trim($_GET['skip']), PDO::PARAM_INT);  

しかし、受信データが正しいことを確認しますか?エラーメッセージでは、数値の後に引用符が1つしかないように見えるためです(整数が引用符で囲まれているのとは対照的です)。これは、受信データのエラーである可能性もあります。あなたはprint_r($_GET);見つけるために何かをすることができますか?

于 2010-02-16T00:32:02.273 に答える
11

これは要約と同じです。
LIMIT/OFFSET値をパラメーター化するための4つのオプションがあります。

  1. PDO::ATTR_EMULATE_PREPARES上記のように無効にします。

    これにより、渡された値が->execute([...])常に文字列として表示されるのを防ぎます。

  2. 手動->bindValue(..., ..., PDO::PARAM_INT)パラメータ入力に切り替えます。

    ただし、これは-> executelist[]よりも便利ではありません。

  3. ここで例外を作成し、SQLクエリを準備するときに単純な整数を補間するだけです。

     $limit = intval($limit);
     $s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");
    

    キャスティングは重要です。より一般的には->prepare(sprintf("SELECT ... LIMIT %d", $num))、そのような目的で使用されます。

  4. MySQLを使用していない場合、たとえばSQLiteやPostgresを使用している場合。バインドされたパラメータをSQLで直接キャストすることもできます。

     SELECT * FROM tbl LIMIT (1 * :limit)
    

    繰り返しますが、MySQL / MariaDBは、LIMIT句の式をサポートしていません。まだ。

于 2015-01-14T19:22:35.070 に答える
8

にとってLIMIT :init, :end

そのようにバインドする必要があります。配列内のすべての変数に$req->execute(Array());キャストされるため、機能しないようなものがある場合は、整数が絶対に必要です。必要に応じてbindValueまたはBindParam。PDO::PARAM_STRLIMIT

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
于 2011-10-20T19:17:28.857 に答える
2

なぜこれが起こっているのか誰も説明していないので、私は答えを追加しています。これが動作している理由は、を使用しているためですtrim()。のPHPマニュアルを見るとtrim、戻り値のタイプはstringです。次に、これをとして渡そうとしていPDO::PARAM_INTます。これを回避するいくつかの方法は次のとおりです。

  1. filter_var($integer, FILTER_VALIDATE_NUMBER_INT)整数を渡していることを確認するために使用します。
  2. 他の人が言ったように、intval()
  3. でキャスト(int)
  4. それが整数であるかどうかを確認しますis_int()

他にもたくさんの方法がありますが、これが基本的に根本的な原因です。

于 2016-01-27T23:00:00.583 に答える
1

bindValueのオフセットと制限はPDO::PARAM_INTを使用して機能します

于 2015-05-21T20:53:12.037 に答える
-1

// BEFORE(現在のエラー)$ query = ".... LIMIT:p1、30;"; ... $ stmt-> bindParam(':p1'、$ limiteInferior);

// AFTER(エラー修正済み)$ query = ".... LIMIT:p1、30;"; ... $ limiteInferior =(int)$ limiteInferior; $ stmt-> bindParam(':p1'、$ limiteInferior、PDO :: PARAM_INT);

于 2017-08-15T06:51:20.037 に答える
-1

PDO::ATTR_EMULATE_PREPARES私にくれた

ドライバーはこの機能をサポートしていません:このドライバーは属性の設定エラーをサポートしていません。

私の回避策は、$limit変数を文字列として設定し、次の例のようにそれをprepareステートメントで結合することでした。

$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 ) {
    ...
}
于 2018-07-19T12:16:20.297 に答える
-1

PHPのさまざまなバージョンとPDOの奇妙な点の間で多くのことが起こっています。ここで3つまたは4つの方法を試しましたが、LIMITを機能させることができませんでした。私の提案は、 intval()フィルター
で文字列のフォーマット/連結を使用することです。

$sql = 'SELECT * FROM `table` LIMIT ' . intval($limitstart) . ' , ' . intval($num).';';

特に$_GETなどから制限を取得している場合は、SQLインジェクションを防ぐためにintval()を使用することが非常に重要です。 これを行う場合、これがLIMITを機能させる最も簡単な方法です。

「PDOのLIMITの問題」については多くの話がありますが、ここでの私の考えは、PDOパラメーターは常に整数であるためクイックフィルターが機能するため、LIMITに使用されることは決してないということです。それでも、哲学は常に自分でSQLインジェクションフィルタリングを行わず、むしろ「PDOに処理させる」ことであったため、少し誤解を招く恐れがあります。

于 2020-02-26T23:59:56.823 に答える