これが私のコードのスナップショットです。
$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インジェクションに対して安全であることを確認する必要があります。
以前にこの問題があったことを覚えています。値を整数にキャストしてから、バインド関数に渡します。これで解決すると思います。
$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);
最も簡単な解決策は、 エミュレーションモード オフに切り替えることです。接続オプションとして、または単に次の行を追加することでそれを行うことができます
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
Bind paramを使用して問題を解決するだけでなく、execute()で値を送信することもできます。これにより、コードが劇的に複雑になります。
$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);
バグレポートを見ると、次のように機能する場合があります。
_$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
$fetchPictures->bindValue(':skip', (int)trim($_GET['skip']), PDO::PARAM_INT);
_
しかし、着信データは正しいと確信していますか?エラーメッセージでは、数字の後にoneだけが引用されているようです(全体を引用符で囲むのではなく)。これは、受信データのエラーである可能性もあります。 print_r($_GET);
を実行して確認できますか?
これはちょうど要約として。
LIMIT/OFFSET値をパラメーター化する4つのオプションがあります。
前述のように_PDO::ATTR_EMULATE_PREPARES
_を無効にします 上記 。
->execute([...])
ごとに渡される値が常に文字列として表示されるのを防ぎます。
手動->bindValue(..., ..., PDO::PARAM_INT)
パラメーターの設定に切り替えます。
ただし、これは-> execute list []よりも便利ではありません。
ここで例外を作成し、SQLクエリを準備するときに単純な整数を補間するだけです。
_ $limit = intval($limit);
$s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");
_
キャストは重要です。より一般的には、 ->prepare(sprintf("SELECT ... LIMIT %d", $num))
がそのような目的で使用されていることがわかります。
MySQLを使用していないが、たとえばSQLiteまたはPostgresを使用している場合。バインドされたパラメーターをSQLで直接キャストすることもできます。
_ SELECT * FROM tbl LIMIT (1 * :limit)
_
繰り返しますが、MySQL/MariaDBはLIMIT句の式をサポートしていません。未だに。
_LIMIT :init, :end
_
そのようにバインドする必要があります。 $req->execute(Array());
のようなものがあれば、_PDO::PARAM_STR
_を配列内のすべての変数にキャストし、LIMIT
には絶対に整数が必要なので、機能しません。 bindValueまたはBindParamを必要に応じて。
_$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
_
なぜこれが起こっているのか誰も説明していないので、私は答えを追加しています。これが動作しているのは、trim()
を使用しているためです。 PHP trim
のマニュアルを見ると、戻り値の型はstring
です。これを_PDO::PARAM_INT
_として渡そうとしています。これを回避するいくつかの方法は次のとおりです。
filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
を使用して、整数を渡していることを確認してください。intval()
を使用して(int)
_を使用したキャストis_int()
で整数かどうかを確認するより多くの方法がありますが、これは基本的に根本的な原因です。
pDO :: PARAM_INTを使用したbindValueのオフセットと制限は機能します
PDO::ATTR_EMULATE_PREPARES
は私に与えた
ドライバーはこの機能をサポートしていません:このドライバーは属性の設定エラーをサポートしていません。
私の回避策は、$limit
変数を文字列として使用し、次の例のように準備ステートメントで結合します。
$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 ) {
...
}
// BEFORE(現在のエラー)$ query = ".... LIMIT:p1、30;"; ... $ stmt-> bindParam( ':p1'、$ limiteInferior);
// AFTER(エラー修正)$ query = ".... LIMIT:p1、30;"; ... $ limiteInferior =(int)$ limiteInferior; $ stmt-> bindParam( ':p1'、$ limiteInferior、PDO :: PARAM_INT);