Ini adalah cuplikan dari kode saya:
$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);
saya mendapat
Ada kesalahan dalam sintaks SQL Anda; periksa manual yang sesuai dengan versi server MySQL Anda untuk sintaks yang benar untuk digunakan di dekat '' 15 ', 15' di baris 1
Tampaknya PDO menambahkan tanda kutip tunggal ke variabel saya di bagian LIMIT dari kode SQL. Saya mencarinya Saya menemukan bug ini yang menurut saya terkait: http://bugs.php.net/bug.php?id=44639
Itukah yang saya lihat? Bug ini telah dibuka sejak April 2008! Apa yang harus kami lakukan sementara itu?
Saya perlu membuat beberapa pagination, dan perlu memastikan datanya bersih, sql injection-safe, sebelum mengirim pernyataan sql.
Jawaban:
Saya ingat pernah mengalami masalah ini sebelumnya. Transmisikan nilai ke integer sebelum meneruskannya ke fungsi bind. Saya pikir ini menyelesaikannya.
sumber
(int) trim($_GET['skip'])
, cobaintval(trim($_GET['skip']))
.Solusi paling sederhana adalah dengan mematikan mode emulasi. Anda dapat melakukannya hanya dengan menambahkan baris berikut
Selain itu, mode ini dapat disetel sebagai parameter konstruktor saat membuat koneksi PDO . Ini bisa menjadi solusi yang lebih baik karena beberapa melaporkan bahwa driver mereka tidak mendukung
setAttribute()
fungsi tersebut.Ini tidak hanya akan menyelesaikan masalah Anda dengan pengikatan, tetapi juga memungkinkan Anda mengirim nilai secara langsung
execute()
, yang akan membuat kode Anda lebih pendek secara dramatis. Dengan asumsi mode emulasi telah disetel, keseluruhan urusan akan mengambil sebanyak setengah lusin baris kodesumber
SQLSTATE[IM001]: Driver does not support this function: This driver doesn't support setting attributes
... Mengapa tidak pernah sesederhana itu bagi saya :) Meskipun saya yakin ini akan membuat kebanyakan orang di sana, dalam kasus saya, saya akhirnya harus menggunakan sesuatu yang mirip dengan jawaban yang diterima. Hanya kepala untuk pembaca yang akan datang!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
. Ini hal baru bagi saya, tapi sekali lagi saya baru mulai dengan PDO. Biasanya menggunakan mysqli, tapi saya pikir saya akan mencoba memperluas wawasan saya.setAttribute
pernyataan ($ stm, $ stmt) bukan untuk objek pdo.Melihat laporan bug, berikut ini mungkin berhasil:
tetapi apakah Anda yakin data yang masuk sudah benar? Karena dalam pesan kesalahan, sepertinya hanya ada satu kutipan setelah nomor (berlawanan dengan seluruh angka yang diapit tanda kutip). Ini juga bisa menjadi kesalahan dengan data masuk Anda. Bisakah Anda melakukan
print_r($_GET);
untuk mencari tahu?sumber
Ini hanya sebagai ringkasan.
Ada empat opsi untuk membuat parameter nilai LIMIT / OFFSET:
Nonaktifkan
PDO::ATTR_EMULATE_PREPARES
seperti yang disebutkan di atas .Yang mencegah nilai yang diteruskan per
->execute([...])
untuk selalu muncul sebagai string.Beralih ke
->bindValue(..., ..., PDO::PARAM_INT)
populasi parameter manual .Yang bagaimanapun kurang nyaman daripada -> jalankan daftar [].
Cukup buat pengecualian di sini dan cukup interpolasi bilangan bulat biasa saat menyiapkan kueri SQL.
Pengecoran itu penting. Lebih umum Anda lihat
->prepare(sprintf("SELECT ... LIMIT %d", $num))
digunakan untuk tujuan seperti itu.Jika Anda tidak menggunakan MySQL, tetapi misalnya SQLite, atau Postgres; Anda juga dapat mentransmisikan parameter terikat langsung di SQL.
Sekali lagi, MySQL / MariaDB tidak mendukung ekspresi di klausa LIMIT. Belum.
sumber
{$_GET->int["limit"]}
untuk kasus seperti itu.untuk
LIMIT :init, :end
Anda perlu mengikat seperti itu. jika Anda memiliki sesuatu seperti
$req->execute(Array());
itu tidak akan berfungsi karena itu akan dilemparkanPDO::PARAM_STR
ke semua vars dalam array danLIMIT
Anda benar-benar membutuhkan Integer. bindValue atau BindParam sesuai keinginan Anda.sumber
Karena tidak ada yang menjelaskan mengapa ini terjadi, saya menambahkan jawaban. Alasan mengapa berperilaku ini adalah karena Anda sedang menggunakan
trim()
. Jika Anda melihat manual PHPtrim
, jenis kembaliannya adalahstring
. Anda kemudian mencoba untuk melewatkan ini sebagaiPDO::PARAM_INT
. Beberapa cara untuk menyiasatinya adalah:filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
untuk memastikan Anda meneruskan integer.intval()
(int)
is_int()
Ada lebih banyak cara, tetapi ini pada dasarnya adalah akar penyebabnya.
sumber
bindValue offset dan limit menggunakan PDO :: PARAM_INT dan itu akan berhasil
sumber
// SEBELUM (Kesalahan saat ini) $ query = ".... LIMIT: p1, 30;"; ... $ stmt-> bindParam (': p1', $ limiteInferior);
// SETELAH (Error dikoreksi) $ query = ".... LIMIT: p1, 30;"; ... $ limiteInferior = (int) $ limiteInferior; $ stmt-> bindParam (': p1', $ limiteInferior, PDO :: PARAM_INT);
sumber
PDO::ATTR_EMULATE_PREPARES
memberi sayaSolusi saya adalah menetapkan
$limit
variabel sebagai string, lalu menggabungkannya dalam pernyataan persiapan seperti pada contoh berikut:sumber
Ada banyak hal yang terjadi di antara berbagai versi PHP dan keanehan PDO. Saya mencoba 3 atau 4 metode di sini tetapi tidak berhasil LIMIT.
Saran saya adalah menggunakan pemformatan / penggabungan string DENGAN filter intval () :
Sangat penting untuk menggunakan intval () untuk mencegah injeksi SQL, terutama jika Anda mendapatkan batas dari $ _GET atau sejenisnya. Jika Anda melakukannya, ini adalah cara termudah untuk membuat LIMIT bekerja.
Ada banyak pembicaraan tentang 'Masalah dengan LIMIT di PDO' tetapi pemikiran saya di sini adalah bahwa parameter PDO tidak pernah digunakan untuk LIMIT karena mereka selalu akan menjadi bilangan bulat dan filter cepat berfungsi. Namun, ini agak menyesatkan karena filosofi selalu untuk tidak melakukan penyaringan injeksi SQL sendiri melainkan 'Minta PDO menanganinya'.
sumber