Inilah yang sejauh ini saya baca PDO::ATTR_EMULATE_PREPARES
:
- Emulasi persiapan PDO lebih baik untuk kinerja karena persiapan asli MySQL melewati cache kueri .
- Persiapan asli MySQL lebih baik untuk keamanan (mencegah SQL Injection) .
- Persiapan asli MySQL lebih baik untuk pelaporan kesalahan .
Saya tidak tahu seberapa benar pernyataan ini lagi. Perhatian terbesar saya dalam memilih antarmuka MySQL adalah mencegah SQL Injection. Perhatian kedua adalah kinerja.
Aplikasi saya saat ini menggunakan MySQLi prosedural (tanpa pernyataan yang disiapkan), dan menggunakan cache kueri cukup banyak. Ini jarang akan menggunakan kembali pernyataan yang sudah disiapkan dalam satu permintaan. Saya mulai pindah ke PDO untuk parameter bernama dan keamanan pernyataan yang disiapkan.
saya menggunakan MySQL 5.1.61
danPHP 5.3.2
Haruskah saya biarkan PDO::ATTR_EMULATE_PREPARES
diaktifkan atau tidak? Adakah cara untuk memiliki performa cache kueri dan keamanan pernyataan yang disiapkan?
Jawaban:
Untuk menjawab kekhawatiran Anda:
MySQL> = 5.1.17 (atau> = 5.1.21 untuk pernyataan
PREPARE
danEXECUTE
) dapat menggunakan pernyataan yang disiapkan di cache kueri . Jadi versi MySQL + PHP Anda dapat menggunakan pernyataan yang disiapkan dengan cache kueri. Namun, perhatikan peringatan untuk hasil kueri caching di dokumentasi MySQL. Ada banyak jenis kueri yang tidak dapat disimpan dalam cache atau tidak berguna meskipun telah disimpan dalam cache. Menurut pengalaman saya, cache kueri seringkali bukan merupakan kemenangan yang sangat besar. Query dan skema membutuhkan konstruksi khusus untuk memaksimalkan penggunaan cache. Seringkali cache tingkat aplikasi akhirnya diperlukan dalam jangka panjang.Persiapan asli tidak membuat perbedaan apa pun untuk keamanan. Pernyataan pseudo-prepared masih akan lolos dari nilai parameter kueri, itu hanya akan dilakukan di perpustakaan PDO dengan string alih-alih di server MySQL menggunakan protokol biner. Dengan kata lain, kode PDO yang sama akan sama-sama rentan (atau tidak rentan) terhadap serangan injeksi apa pun
EMULATE_PREPARES
setelan Anda . Satu-satunya perbedaan adalah di mana penggantian parameter terjadi - denganEMULATE_PREPARES
, itu terjadi di perpustakaan PDO; tanpaEMULATE_PREPARES
, ini terjadi di server MySQL.Tanpa
EMULATE_PREPARES
Anda mungkin mendapatkan kesalahan sintaks pada waktu persiapan daripada pada waktu eksekusi; denganEMULATE_PREPARES
Anda hanya akan mendapatkan kesalahan sintaks pada waktu eksekusi karena PDO tidak memiliki permintaan untuk diberikan ke MySQL sampai waktu eksekusi. Perhatikan bahwa ini memengaruhi kode yang akan Anda tulis ! Terutama jika Anda menggunakanPDO::ERRMODE_EXCEPTION
!Pertimbangan tambahan:
prepare()
(menggunakan pernyataan yang disiapkan asli), jadiprepare();execute()
dengan pernyataan yang disiapkan asli mungkin sedikit lebih lambat daripada mengeluarkan kueri tekstual biasa menggunakan pernyataan siap yang diemulasi. Pada banyak sistem database, rencana kueri untuk a diprepare()
-cache juga dan dapat dibagikan dengan banyak koneksi, tetapi menurut saya MySQL tidak melakukan ini. Jadi, jika Anda tidak menggunakan kembali objek pernyataan yang Anda siapkan untuk beberapa kueri, eksekusi Anda secara keseluruhan mungkin lebih lambat.Sebagai rekomendasi akhir , saya pikir dengan versi MySQL + PHP yang lebih lama, Anda harus meniru pernyataan yang sudah disiapkan, tetapi dengan versi terbaru Anda, Anda harus mematikan emulasi.
Setelah menulis beberapa aplikasi yang menggunakan PDO, saya telah membuat fungsi koneksi PDO yang menurut saya merupakan pengaturan terbaik. Anda mungkin harus menggunakan sesuatu seperti ini atau menyesuaikan pengaturan pilihan Anda:
sumber
mysql_real_escape_string
dimiliki dengan karakter multi-byte) masih akan membiarkan seseorang terbuka untuk serangan injeksi?mysql_real_escape_string
under the hood dan konsekuensi kerentanan yang dapat muncul (dalam kasus edge yang sangat khusus).Berhati-hatilah saat menonaktifkan
PDO::ATTR_EMULATE_PREPARES
(mengaktifkan persiapan asli) saat PHP Andapdo_mysql
tidak dikompilasimysqlnd
.Karena lama
libmysql
tidak sepenuhnya kompatibel dengan beberapa fungsi, ini dapat menyebabkan bug aneh, misalnya:PDO::PARAM_INT
(0x12345678AB akan dipangkas menjadi 0x345678AB pada mesin 64bit)LOCK TABLES
(itu melemparSQLSTATE[HY000]: General error: 2030 This command is not supported in the prepared statement protocol yet
pengecualian)mysqlnd
atau menyiapkannya, secara otomatis melakukan ini untuk Anda dan tidak keluar dari sinkronisasi dengan server mysql)Bug ini saya temukan dalam proyek sederhana saya ketika bermigrasi ke server lain yang digunakan
libmysql
untukpdo_mysql
modul. Mungkin masih banyak lagi bug, saya tidak tahu. Saya juga menguji pada debian jessie 64bit baru, semua bug yang terdaftar terjadi ketika sayaapt-get install php5-mysql
, dan hilang ketika sayaapt-get install php5-mysqlnd
.Ketika
PDO::ATTR_EMULATE_PREPARES
disetel ke true (sebagai default) - bug ini tidak terjadi, karena PDO tidak menggunakan pernyataan yang disiapkan sama sekali dalam mode ini. Jadi, jika Anda menggunakan substringpdo_mysql
berdasarkanlibmysql
("mysqlnd" tidak muncul di kolom "Versi API Klien"pdo_mysql
di bagian phpinfo) - Anda tidak bolehPDO::ATTR_EMULATE_PREPARES
mematikannya.sumber
Saya akan mematikan emulasi persiapan saat Anda menjalankan 5.1 yang berarti PDO akan memanfaatkan fungsionalitas pernyataan asli yang disiapkan.
http://php.net/manual/en/ref.pdo-mysql.php
Saya membuang MySQLi untuk PDO untuk pernyataan bernama yang disiapkan dan API yang lebih baik.
Namun, untuk diseimbangkan, PDO berkinerja lebih lambat daripada MySQLi, tetapi itu perlu diingat. Saya tahu ini ketika saya membuat pilihan, dan memutuskan bahwa API yang lebih baik dan menggunakan standar industri lebih penting daripada menggunakan pustaka yang lebih cepat dan dapat diabaikan yang mengikat Anda ke mesin tertentu. FWIW Saya pikir tim PHP juga melihat PDO lebih baik daripada MySQLi untuk masa depan juga.
sumber
Saya akan merekomendasikan mengaktifkan
PREPARE
panggilan database nyata karena emulasi tidak menangkap semuanya .., misalnya, itu akan dipersiapkanINSERT;
!Hasil
Saya dengan senang hati akan menerima pukulan kinerja untuk kode yang benar-benar berfungsi.
FWIW
Versi PHP: PHP 5.4.9-4ubuntu2.4 (cli)
Versi MySQL: 5.5.34-0ubuntu0
sumber
prepare
melakukan pekerjaan yang seharusnya. (Selain itu, saya selalu berasumsi bahwa pengurai parameter sisi klien akan memiliki bugnya sendiri.)Saya terkejut tidak ada yang menyebutkan salah satu alasan terbesar untuk menonaktifkan persaingan. Dengan emulasi aktif, PDO mengembalikan semua integer dan float sebagai string . Saat Anda mematikan emulasi, bilangan bulat dan pelampung di MySQL menjadi bilangan bulat dan pelampung di PHP.
Untuk informasi lebih lanjut, lihat jawaban yang diterima untuk pertanyaan ini: PHP + PDO + MySQL: bagaimana cara mengembalikan kolom integer dan numerik dari MySQL sebagai integer dan numerik dalam PHP? .
sumber
https://tech.michaelseiler.net/2016/07/04/dont-emulate-prepared-statements-pdo-mysql/
sumber
Untuk catatan
PDO :: ATTR_EMULATE_PREPARES = true
Itu bisa menghasilkan efek samping yang buruk. Itu bisa mengembalikan nilai int sebagai string.
PHP 7.4, pdo dengan mysqlnd.
Menjalankan kueri dengan PDO :: ATTR_EMULATE_PREPARES = true
Kolom:
Jenis id : integer
Nilai: 1
Menjalankan kueri dengan PDO :: ATTR_EMULATE_PREPARES = false
Kolom:
Jenis id : string
Nilai: "1"
Bagaimanapun, nilai desimal selalu dikembalikan sebagai string, terlepas dari konfigurasinya :-(
sumber