Diberikan array id $galleries = array(1,2,5)
Saya ingin memiliki query SQL yang menggunakan nilai-nilai array di klausa WHERE-nya seperti:
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
Bagaimana saya bisa menghasilkan string kueri ini untuk digunakan dengan MySQL?
Jawaban:
sumber
$galleries
harus divalidasi input sebelum pernyataan ini! Pernyataan yang disiapkan tidak dapat menangani array AFAIK, jadi jika Anda terbiasa dengan variabel terikat, Anda dapat dengan mudah membuat injeksi SQL menjadi mungkin di sini.$galleries
memiliki nilai berikut:array('1); SELECT password FROM users;/*')
. Jika Anda tidak membersihkannya, kueri akan membacaSELECT * FROM galleries WHERE id IN (1); SELECT password FROM users;/*)
. Ubah nama tabel & kolom menjadi sesuatu yang Anda miliki di database Anda dan coba kueri itu, periksa hasilnya. Anda akan menemukan daftar kata sandi sebagai hasil, bukan daftar galeri. Bergantung pada bagaimana data di-output, atau apa yang dilakukan skrip dengan berbagai data yang tidak terduga, yang mungkin membuat output ke tampilan publik ... aduh.$galleries
disediakan dalam pertanyaan dan Anda mengeksploitasinya menggunakan "kerentanan injeksi sql" yang disebutkan di atas. Jika Anda tidak bisa - Anda membayar saya USD200. Bagaimana tentang itu?Menggunakan PDO: [1]
Menggunakan MySQLi [2]
Penjelasan:
Gunakan SQL
IN()
operator untuk memeriksa apakah ada nilai dalam daftar yang diberikan.Secara umum terlihat seperti ini:
Kita dapat membangun ekspresi untuk ditempatkan di dalam
()
dari array kita. Perhatikan bahwa harus ada setidaknya satu nilai di dalam tanda kurung atau MySQL akan mengembalikan kesalahan; ini sama dengan memastikan bahwa array input kami memiliki setidaknya satu nilai. Untuk membantu mencegah serangan injeksi SQL, pertama-tama buat a?
untuk setiap item input untuk membuat kueri parameter. Di sini saya berasumsi bahwa array yang berisi id Anda disebut$ids
:Diberikan array input dari tiga item
$select
akan terlihat seperti:Sekali lagi perhatikan bahwa ada
?
untuk setiap item dalam larik input. Kemudian kita akan menggunakan PDO atau MySQLi untuk menyiapkan dan mengeksekusi kueri seperti disebutkan di atas.Menggunakan
IN()
operator dengan stringMudah untuk mengubah antara string dan integer karena parameter yang terikat. Untuk PDO tidak diperlukan perubahan; untuk perubahan MySQLi
str_repeat('i',
menjadistr_repeat('s',
jika Anda perlu memeriksa string.[1]: Saya telah menghilangkan beberapa kesalahan saat memeriksa singkatnya. Anda perlu memeriksa kesalahan yang biasa untuk setiap metode database (atau mengatur driver DB Anda untuk membuang pengecualian).
[2]: Membutuhkan PHP 5.6 atau lebih tinggi. Sekali lagi saya telah menghilangkan beberapa kesalahan memeriksa singkatnya.
sumber
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
maka...
sedang memperluas id dari array ke beberapa parameter. Jika Anda merujukexpr IN (value,...)
maka itu hanya berarti bahwa bisa ada lebih banyak nilai misalnyaWHERE id IN (1, 3, 4)
. Hanya perlu ada setidaknya satu....
: wiki.php.net/rfc/argument_unpackingint:
string:
sumber
Dengan asumsi Anda membersihkan dengan benar input Anda sebelumnya ...
Kemudian sesuaikan kueri Anda:
Nilai penawaran tepat tergantung pada dataset Anda.
sumber
Menggunakan:
for each
Lingkaran sederhana akan berhasil.Cara Flavius / AvatarKava lebih baik, tetapi pastikan bahwa tidak ada nilai array yang mengandung koma.
sumber
Sebagai jawaban Flavius Stef , Anda dapat menggunakan
intval()
untuk memastikan semuaid
nilai int:sumber
Untuk MySQLi dengan fungsi pelarian:
Untuk PDO dengan pernyataan yang disiapkan:
sumber
Kita harus merawat kerentanan injeksi SQL dan kondisi kosong . Saya akan menangani keduanya seperti di bawah ini.
Untuk array numerik murni, gunakan konversi jenis yang sesuai yaitu
intval
ataufloatval
atau didoubleval
atas setiap elemen. Untuk tipe stringmysqli_real_escape_string()
yang juga dapat diterapkan ke nilai numerik jika diinginkan. MySQL memungkinkan angka dan varian tanggal sebagai string .Untuk menghindari nilai-nilai sebelum meneruskan ke kueri, buat fungsi yang mirip dengan:
Fungsi seperti itu kemungkinan besar sudah tersedia untuk Anda di aplikasi Anda, atau mungkin Anda sudah membuatnya.
Sanitasi array string seperti:
Array angka dapat dibersihkan dengan menggunakan
intval
ataufloatval
ataudoubleval
sebaliknya sesuai:Kemudian akhirnya membangun kondisi permintaan
atau
Karena kadang-kadang array juga bisa kosong,
$galleries = array();
karena itu kita harus mencatat bahwaIN ()
tidak mengizinkan daftar kosong. Satu juga bisa menggunakanOR
, tetapi masalahnya tetap. Jadi cek di atascount($values)
,, adalah untuk memastikan hal yang sama.Dan tambahkan ke permintaan terakhir:
sumber
$query = 'SELECT * FROM galleries WHERE ' . (count($gallaries) ? "id IN ('" . implode("', '", array_map('escape', $gallaries)) . "')" : 0);
Lebih aman
sumber
SafeMySQL library Kolonel Shrapnel untuk PHP menyediakan placeholder yang diisyaratkan tipe dalam kueri parametris, dan menyertakan beberapa placeholder yang nyaman untuk bekerja dengan array. Itu
?a
placeholder memperluas keluar array ke daftar dipisahkan koma string lolos *.Sebagai contoh:
* Perhatikan bahwa karena MySQL melakukan paksaan tipe otomatis, tidak masalah bahwa SafeMySQL akan mengonversi id di atas menjadi string - Anda masih akan mendapatkan hasil yang benar.
sumber
Kita dapat menggunakan klausa "WHERE id IN" ini jika kita memfilter array input dengan benar. Sesuatu seperti ini:
Seperti contoh di bawah ini:
Yaitu sekarang Anda harus menggunakan aman
$query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
sumber
Anda mungkin memiliki meja
texts
(T_ID (int), T_TEXT (text))
dan mejatest
(id (int), var (varchar(255)))
Dalam
insert into test values (1, '1,2,3') ;
output kehendak baris berikut dari teks-teks meja tempatT_ID IN (1,2,3)
:Dengan cara ini Anda dapat mengelola relasi basis data n2m sederhana tanpa tabel tambahan dan hanya menggunakan SQL tanpa perlu menggunakan PHP atau bahasa pemrograman lain.
sumber
Lebih banyak contoh:
sumber
Selain menggunakan kueri IN, Anda memiliki dua opsi untuk melakukannya seperti dalam kueri IN ada risiko kerentanan injeksi SQL. Anda dapat menggunakan perulangan untuk mendapatkan data yang tepat yang Anda inginkan atau Anda dapat menggunakan kueri dengan huruf ATAU
sumber
Cara aman tanpa PDO:
(array)$ids
Keluarkan$ids
variabel ke arrayarray_map
Ubah semua nilai array menjadi bilangan bulatarray_unique
Hapus nilai berulangarray_filter
Hapus nilai nolimplode
Gabungkan semua nilai ke seleksi INsumber
Karena pertanyaan awal terkait dengan array angka dan saya menggunakan array string saya tidak bisa membuat contoh yang diberikan berfungsi.
Saya menemukan bahwa setiap string perlu diringkas dalam tanda kutip tunggal untuk bekerja dengan
IN()
fungsi.Ini solusinya
Seperti yang Anda lihat, fungsi pertama membungkus masing-masing variabel array
single quotes (\')
dan kemudian mengimplementasikan array.CATATAN:
$status
tidak memiliki tanda kutip tunggal dalam pernyataan SQL.Mungkin ada cara yang lebih baik untuk menambahkan tanda kutip tetapi ini berhasil.
sumber
$filter = "'" . implode("','",$status) . "'";
'
di dalam string? Injeksi SQL rentan. Gunakan PDO :: quote atau mysqli_real_escape_string.Di bawah ini adalah metode yang saya gunakan, menggunakan PDO dengan placeholder bernama untuk data lainnya. Untuk mengatasi injeksi SQL, saya memfilter array untuk menerima hanya nilai yang integer dan menolak yang lainnya.
sumber
Metode dasar untuk mencegah injeksi SQL adalah:
Menggunakan pernyataan yang disiapkan dan kueri parameterisasi dianggap praktik yang lebih baik, tetapi jika Anda memilih metode karakter melarikan diri maka Anda dapat mencoba contoh saya di bawah ini.
Anda dapat membuat kueri dengan menggunakan
array_map
untuk menambahkan satu kutipan ke setiap elemen di$galleries
:$ Sql var yang dihasilkan akan:
sumber