Nama Tabel dan Kolom TIDAK BISA digantikan oleh parameter dalam PDO.
Dalam hal ini Anda hanya ingin memfilter dan membersihkan data secara manual. Salah satu cara untuk melakukan ini adalah dengan mengirimkan parameter singkat ke fungsi yang akan mengeksekusi kueri secara dinamis dan kemudian menggunakan switch()
pernyataan untuk membuat daftar putih nilai yang valid yang akan digunakan untuk nama tabel atau nama kolom. Dengan begitu tidak ada input pengguna yang langsung masuk ke kueri. Jadi misalnya:
function buildQuery( $get_var )
{
switch($get_var)
{
case 1:
$tbl = 'users';
break;
}
$sql = "SELECT * FROM $tbl";
}
Dengan tidak meninggalkan kasing standar atau menggunakan kasing standar yang mengembalikan pesan kesalahan, Anda memastikan bahwa hanya nilai yang ingin Anda gunakan yang digunakan.
array('u'=>'users', 't'=>'table', 'n'=>'nonsensitive_data')
. Dll.)default
. Jika menggunakan pola ini, Anda harus memberi label salah satu dari Andacase
sebagaidefault
, atau menambahkan kasus kesalahan eksplisit sepertidefault: throw new InvalidArgumentException;
if ( in_array( $tbl, ['users','products',...] ) { $sql = "SELECT * FROM $tbl"; }
. Terima kasih untuk idenya.mysql_real_escape_string()
. Mungkin di sini saya dapat mengatakannya tanpa seseorang melompat masuk dan berkata "Tetapi Anda tidak membutuhkannya dengan PDO"Untuk memahami mengapa pengikatan nama tabel (atau kolom) tidak berfungsi, Anda harus memahami cara kerja placeholder dalam pernyataan yang disiapkan: mereka tidak hanya diganti sebagai string (lolos secara tepat), dan SQL yang dihasilkan dieksekusi. Alih-alih, DBMS yang diminta untuk "menyiapkan" pernyataan muncul dengan rencana kueri lengkap untuk bagaimana ia akan mengeksekusi kueri itu, termasuk tabel dan indeks yang akan digunakan, yang akan tetap sama terlepas dari bagaimana Anda mengisi placeholder.
Paket untuk
SELECT name FROM my_table WHERE id = :value
akan sama apa pun yang Anda gantikan:value
, tetapi yang tampaknya serupaSELECT name FROM :table WHERE id = :value
tidak dapat direncanakan, karena DBMS tidak tahu tabel apa yang sebenarnya akan Anda pilih.Ini bukan sesuatu perpustakaan abstraksi seperti PDO dapat atau harus bekerja di sekitar, baik, karena akan mengalahkan 2 tujuan utama dari pernyataan yang disiapkan: 1) untuk memungkinkan database untuk memutuskan terlebih dahulu bagaimana kueri akan dijalankan, dan menggunakan yang sama rencanakan beberapa kali; dan 2) untuk mencegah masalah keamanan dengan memisahkan logika kueri dari input variabel.
sumber
TOP
/LIMIT
/OFFSET
klausa, jadi ini akan sedikit keluar dari tempatnya sebagai fitur.Saya melihat ini adalah posting lama, tetapi saya merasa berguna dan saya pikir saya akan membagikan solusi yang mirip dengan yang disarankan @kzqai:
Saya memiliki fungsi yang menerima dua parameter seperti ...
Di dalam saya mengecek terhadap array yang telah saya atur untuk memastikan hanya tabel dan kolom dengan tabel "diberkati" yang dapat diakses:
Kemudian pemeriksaan PHP sebelum menjalankan PDO terlihat seperti ...
sumber
$pdo->query($sql)
Menggunakan yang pertama tidak secara inheren lebih aman daripada yang terakhir, Anda perlu membersihkan input apakah itu bagian dari array parameter atau variabel sederhana. Jadi saya tidak melihat ada yang salah dengan menggunakan formulir yang terakhir
$table
, asalkan Anda memastikan bahwa konten$table
aman (alphanum plus menggarisbawahi?) Sebelum menggunakannya.sumber
(Jawaban terlambat, lihat catatan samping saya).
Aturan yang sama berlaku ketika mencoba membuat "database".
Anda tidak dapat menggunakan pernyataan yang disiapkan untuk mengikat basis data.
Yaitu:
tidak akan berfungsi. Gunakan daftar aman sebagai gantinya.
Catatan tambahan: Saya menambahkan jawaban ini (sebagai wiki komunitas) karena sering digunakan untuk menutup pertanyaan, di mana beberapa orang memposting pertanyaan yang mirip dengan ini dalam mencoba untuk mengikat database dan bukan tabel dan / atau kolom.
sumber
Sebagian dari saya bertanya-tanya apakah Anda dapat menyediakan fungsi sanitasi sendiri sesederhana ini:
Saya belum benar-benar memikirkannya, tetapi sepertinya menghapus apa pun kecuali karakter dan garis bawah mungkin berfungsi.
sumber
MyLongTableName
mudah dibaca dengan benar, tetapi jika Anda memeriksa nama yang tersimpan itu (kemungkinan) adalahMYLONGTABLENAME
yang tidak terlalu mudah dibaca, jadiMY_LONG_TABLE_NAME
sebenarnya lebih mudah dibaca.Select * From $table
. Daftar putih atau pencocokan pola ketat (mis. "Nama yang memulai laporan_ diikuti hanya oleh 1 hingga 3 digit") sangat penting di sini.Adapun pertanyaan utama di utas ini, postingan lain menjelaskan mengapa kita tidak dapat mengikat nilai ke nama kolom saat menyiapkan pernyataan, jadi di sini ada satu solusi:
Di atas hanyalah sebuah contoh, jadi tak perlu dikatakan, copy-> paste tidak akan berfungsi. Sesuaikan dengan kebutuhan Anda. Sekarang ini mungkin tidak memberikan keamanan 100%, tetapi memungkinkan beberapa kontrol atas nama kolom ketika mereka "masuk" sebagai string dinamis dan dapat diubah pada akhir pengguna. Selain itu, tidak perlu untuk membangun beberapa array dengan nama dan tipe kolom tabel Anda karena mereka diambil dari information_schema.
sumber