Mendapatkan string kueri SQL mentah dari pernyataan yang disiapkan PDO
130
Apakah ada cara untuk mendapatkan string SQL mentah dieksekusi ketika memanggil PDOStatement :: execute () pada pernyataan yang disiapkan? Untuk keperluan debugging ini akan sangat berguna.
Cara terbersih yang saya temukan adalah perpustakaan E_PDOStatement . Anda lakukan saja $stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;. Ia bekerja dengan memperluas kelas PDOStatement , karenanya elegan seperti API PDO memungkinkan.
ComFreek
Jawaban:
110
Saya berasumsi Anda berarti bahwa Anda ingin query SQL final, dengan nilai parameter diinterpolasi ke dalamnya. Saya mengerti bahwa ini akan berguna untuk debugging, tetapi ini bukan cara pernyataan yang disiapkan bekerja. Parameter tidak digabungkan dengan pernyataan yang disiapkan di sisi klien, jadi PDO seharusnya tidak pernah memiliki akses ke string kueri yang dikombinasikan dengan parameternya.
Pernyataan SQL dikirim ke server database ketika Anda melakukan prep (), dan parameter dikirim secara terpisah ketika Anda mengeksekusi (). Log kueri umum MySQL memang menunjukkan SQL final dengan nilai yang diinterpolasi setelah Anda mengeksekusi (). Di bawah ini adalah kutipan dari log kueri umum saya. Saya menjalankan pertanyaan dari CLI mysql, bukan dari PDO, tetapi prinsipnya sama.
08101616:51:282Query prepare s1 from'select * from foo where i = ?'2Prepare[2]select*from foo where i =?08101616:51:392Queryset@a=108101616:51:472Query execute s1 using@a2Execute[2]select*from foo where i =1
Anda juga bisa mendapatkan apa yang Anda inginkan jika Anda menetapkan atribut PDO PDO :: ATTR_EMULATE_PREPARES. Dalam mode ini, PDO menginterpolasi parameter ke dalam kueri SQL dan mengirimkan seluruh kueri saat Anda mengeksekusi (). Ini bukan permintaan yang disiapkan dengan benar. Anda akan menghindari manfaat dari kueri yang disiapkan dengan menginterpolasi variabel ke dalam string SQL sebelum dieksekusi ().
Komentar dari @afilina:
Tidak, permintaan SQL tekstual tidak digabungkan dengan parameter selama eksekusi. Jadi tidak ada yang bisa ditunjukkan PDO kepada Anda.
Secara internal, jika Anda menggunakan PDO :: ATTR_EMULATE_PREPARES, PDO membuat salinan kueri SQL dan menginterpolasi nilai parameter ke dalamnya sebelum melakukan persiapan dan eksekusi. Tetapi PDO tidak mengekspos permintaan SQL yang dimodifikasi ini.
Objek PDOStatement memiliki properti $ queryString, tetapi ini hanya diatur dalam konstruktor untuk PDOStatement, dan itu tidak diperbarui ketika kueri ditulis ulang dengan parameter.
Ini akan menjadi permintaan fitur yang masuk akal bagi PDO untuk meminta mereka mengekspos kueri yang ditulis ulang. Tetapi bahkan itu tidak akan memberi Anda permintaan "lengkap" kecuali Anda menggunakan PDO :: ATTR_EMULATE_PREPARES.
Inilah sebabnya saya menunjukkan solusi di atas menggunakan log kueri umum server MySQL, karena dalam hal ini bahkan kueri yang disiapkan dengan placeholder parameter ditulis ulang di server, dengan nilai parameter yang dikembalikan ke string kueri. Tapi ini hanya dilakukan saat logging, bukan saat eksekusi query.
Dan bagaimana Anda mendapatkan kueri lubang saat PDO :: ATTR_EMULATE_PREPARES disetel ke TRUE?
Yasen Zhelev
2
@Yasen Zhelev: Jika PDO mengemulasi prepares, maka ia akan menginterpolasi nilai parameter ke dalam query sebelum ia menyiapkan query. Jadi MySQL tidak pernah melihat versi kueri dengan penampung parameter. MySQL hanya mencatat permintaan penuh.
Bill Karwin
2
@ Bill: 'Parameter tidak digabungkan dengan pernyataan yang disiapkan di sisi klien' - tunggu - tetapi apakah mereka digabungkan di sisi server? Atau bagaimana mysql memasukkan nilai ke dalam DB?
Stann
1
@afilina, tidak, kamu tidak bisa. Lihat penjelasan saya di atas.
Bill Karwin
3
Wow, downvote? Tolong jangan tembak kurirnya. Saya hanya menjelaskan cara kerjanya.
Bill Karwin
107
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* @param string $query The sql query with parameter placeholders
* @param array $params The array of substitution parameters
* @return string The interpolated query
*/publicstaticfunction interpolateQuery($query, $params){
$keys = array();# build a regular expression for each parameterforeach($params as $key => $value){if(is_string($key)){
$keys[]='/:'.$key.'/';}else{
$keys[]='/[?]/';}}
$query = preg_replace($keys, $params, $query,1, $count);#trigger_error('replaced '.$count.' keys');return $query;}
mengapa tidak menggunakan saja strtr(): lebih cepat, lebih sederhana, hasil yang sama. strtr($query, $params);
Tony Chiboucas
Apa gunanya ini?
Hanya ingin mampir dan mengucapkan terima kasih juga, berada di luar seluruh kelas tambahan untuk ini yang sekarang saya hapus mendukung ini karena kecil dan cemerlang :). Jadi sangat berguna untuk debbug semua permintaan aplikasi lakukan pada setiap halaman dengan login mereka: D
NaughtySquid
Melihat fungsi ini dan itu membuat saya sangat senang, meskipun, sesuatu yang saya tidak mengerti, mengapa Anda memeriksa $keymenjadi stringdan tidak $value? Apakah saya melewatkan sesuatu? Alasan saya bertanya ini karena output ini, parameter kedua tidak dilihat sebagai string:string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
Kerwin Sneijders
1
Ini adalah awal yang baik, tetapi gagal jika nilai $ param itu sendiri menyertakan tanda tanya ("?").
chickenchilli
32
Saya memodifikasi metode untuk menyertakan penanganan keluaran array untuk pernyataan seperti WHERE IN (?).
UPDATE: Baru saja menambahkan periksa untuk nilai NULL dan duplikasi $ params sehingga nilai-nilai $ param aktual tidak dimodifikasi.
Kerja bagus bigwebguy dan terima kasih!
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* @param string $query The sql query with parameter placeholders
* @param array $params The array of substitution parameters
* @return string The interpolated query
*/publicfunction interpolateQuery($query, $params){
$keys = array();
$values = $params;# build a regular expression for each parameterforeach($params as $key => $value){if(is_string($key)){
$keys[]='/:'.$key.'/';}else{
$keys[]='/[?]/';}if(is_string($value))
$values[$key]="'". $value ."'";if(is_array($value))
$values[$key]="'". implode("','", $value)."'";if(is_null($value))
$values[$key]='NULL';}
$query = preg_replace($keys, $values, $query);return $query;}
Saya pikir harus Anda lakukan $values = $params;bukan $values = array().
menguji
Sepotong kecil lain yang terlewatkan di sini adalah string. Untuk menangkap mereka, letakkan ini di atas is_arraycek:if (is_string($value)) $values[$key] = "'" . $value . "'";
treeface
Ini hanya nilai ikatan terbatas hanya sekali di preg_replace. tambahkan baris ini setelah $values = $params;$values_limit = []; $words_repeated = array_count_values(str_word_count($sql, 1, ':_')); tambahkan ini di dalam terlebih dahulu jika di foreach $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);dan ini di yang lain di foreach $values_limit = [];gunakan foreach loop $ values lagi untuk preg_replace denganisset($values_limit[$key])
vee
misalnya nilai loop $. if (is_array($values)) { foreach ($values as $key => $val) { if (isset($values_limit[$key])) { $sql = preg_replace(['/:'.$key.'/'], [$val], $sql, $values_limit[$key], $count); } } unset($key, $val); } else { $sql = preg_replace($keys, $values, $sql, 1, $count); }
vee
12
Agak terlambat mungkin tapi sekarang ada PDOStatement::debugDumpParams
Membuang informasi yang terkandung oleh pernyataan yang disiapkan langsung pada output. Ini akan memberikan query SQL yang digunakan, jumlah parameter yang digunakan (Params), daftar parameter, dengan nama mereka, tipe (paramtype) sebagai integer, nama kunci atau posisi mereka, dan posisi dalam permintaan (jika ini didukung oleh driver PDO, jika tidak, itu akan menjadi -1).
Anda dapat menemukan lebih banyak di dokumen resmi php
Contoh:
<?php
/* Execute a prepared statement by binding PHP variables */
$calories =150;
$colour ='red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindValue(':colour', $colour, PDO::PARAM_STR,12);
$sth->execute();
$sth->debugDumpParams();?>
dan untuk keterbacaan yang lebih baik:echo '<pre>'; $sth->debugDumpParams(); echo '</pre>';
SandroMarques
10
Solusi adalah dengan secara sukarela menempatkan kesalahan dalam kueri dan untuk mencetak pesan kesalahan:
//Connection to the database
$co =new PDO('mysql:dbname=myDB;host=localhost','root','');//We allow to print the errors whenever there is one
$co->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);//We create our prepared statement
$stmt = $co->prepare("ELECT * FROM Person WHERE age=:age");//I removed the 'S' of 'SELECT'
$stmt->bindValue(':age','18',PDO::PARAM_STR);try{
$stmt->execute();}catch(PDOException $e){
echo $e->getMessage();}
Output standar:
SQLSTATE [42000]: Kesalahan sintaksis atau pelanggaran akses: [...] dekat 'MEMILIH * DARI ORANG DI MANA usia = 18' pada baris 1
Penting untuk dicatat bahwa itu hanya mencetak 80 karakter pertama dari permintaan.
Saya tidak tahu mengapa ini diturunkan. Sederhana dan berhasil. Ini bekerja dengan cepat. Jauh lebih cepat daripada menyalakan log, mencari baris yang tepat di log, lalu menonaktifkan log, lalu membersihkan file log.
Bojan Hrnkas
@ BojanHrnkas panjang sampel kesalahan sangat terbatas. Untuk permintaan sederhana seperti itu, lebih mudah untuk mengganti placeholder dengan variabel hanya secara manual. Dan metode ini hanya berfungsi jika Anda mengaktifkan emulasi.
Akal Sehat Anda
9
Menambahkan sedikit lebih banyak ke kode oleh Mike - nilai berjalan untuk menambahkan tanda kutip tunggal
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* @param string $query The sql query with parameter placeholders
* @param array $params The array of substitution parameters
* @return string The interpolated query
*/publicfunction interpolateQuery($query, $params){
$keys = array();
$values = $params;# build a regular expression for each parameterforeach($params as $key => $value){if(is_string($key)){
$keys[]='/:'.$key.'/';}else{
$keys[]='/[?]/';}if(is_array($value))
$values[$key]= implode(',', $value);if(is_null($value))
$values[$key]='NULL';}// Walk the array to see if we can add single-quotes to strings
array_walk($values, create_function('&$v, $k','if (!is_numeric($v) && $v!="NULL") $v = "\'".$v."\'";'));
$query = preg_replace($keys, $values, $query,1, $count);return $query;}
Sangat berguna, saya melakukan beberapa modifikasi untuk mengesampingkan fungsi bindParam dari kelas PDOStatement dan memvalidasi jika nilainya adalah string atau integer dengan nilai PDO: PARAMS .
Sergio Flores
Di mana kita bisa melihat itu?
Mawg mengatakan mengembalikan Monica
8
PDOStatement memiliki properti publik $ queryString. Itu harus menjadi apa yang Anda inginkan.
Saya baru saja memperhatikan bahwa PDOStatement memiliki metode debugDumpParams () yang tidak didokumentasikan yang mungkin ingin Anda lihat.
Nggak. $ queryString tidak menampilkan nilai param yang disertakan.
Andreas
5
Anda bisa memperluas kelas PDOStatement untuk menangkap variabel terikat dan menyimpannya untuk digunakan nanti. Kemudian 2 metode dapat ditambahkan, satu untuk sanitasi variabel (debugBindedVariables) dan lainnya untuk mencetak kueri dengan variabel-variabel tersebut (debugQuery):
Dan kemudian Anda bisa menggunakan kelas bawaan ini untuk tujuan debugging.
$dbh =newDebugPDO('mysql:host=localhost;dbname=test;','user','pass');
$var='user_test';
$sql=$dbh->prepare("SELECT user FROM users WHERE user = :test");
$sql->bindValue(':test', $var, PDO::PARAM_STR);
$sql->execute();
$sql->debugQuery();
print_r($sql->debugBindedVariables());
Yang menghasilkan
PILIH pengguna DARI pengguna DI MANA pengguna = 'user_test'
Saya menghabiskan banyak waktu meneliti situasi ini untuk kebutuhan saya sendiri. Ini dan beberapa utas SO lainnya sangat membantu saya, jadi saya ingin membagikan apa yang saya hasilkan.
Meskipun memiliki akses ke string kueri yang diinterpolasi adalah manfaat yang signifikan saat pemecahan masalah, kami ingin dapat mempertahankan log hanya dari kueri tertentu (oleh karena itu, menggunakan log basis data untuk tujuan ini tidak ideal). Kami juga ingin dapat menggunakan log untuk menciptakan kembali kondisi tabel pada waktu tertentu, oleh karena itu, kami perlu memastikan string yang diinterpolasi lolos dengan benar. Akhirnya, kami ingin memperluas fungsionalitas ini ke seluruh basis kode kami harus menulis ulang sesedikit mungkin (tenggat waktu, pemasaran, dan semacamnya; Anda tahu bagaimana ini).
Solusi saya adalah untuk memperluas fungsionalitas objek PDOStatement default untuk cache nilai parameter (atau referensi), dan ketika pernyataan dieksekusi, gunakan fungsionalitas objek PDO untuk keluar dari parameter dengan benar ketika mereka disuntikkan kembali ke permintaan tali. Kami kemudian dapat mengikat untuk mengeksekusi metode objek pernyataan dan mencatat permintaan aktual yang dieksekusi pada waktu itu ( atau setidaknya setepat reproduksi mungkin) .
Seperti yang saya katakan, kami tidak ingin memodifikasi seluruh basis kode untuk menambahkan fungsionalitas ini, jadi kami menimpa default bindParam()dan bindValue()metode objek PDOStatement, melakukan caching kami terhadap data yang terikat, kemudian memanggil parent::bindParam()atau induk :: bindValue(). Ini memungkinkan basis kode kami yang ada untuk terus berfungsi seperti biasa.
Akhirnya, ketika execute()metode dipanggil, kami melakukan interpolasi kami dan memberikan string yang dihasilkan sebagai properti baru E_PDOStatement->fullQuery. Ini bisa berupa output untuk melihat kueri atau, misalnya, ditulis ke file log.
Ekstensi, bersama dengan petunjuk pemasangan dan konfigurasi, tersedia di github:
PENOLAKAN :
Jelas, seperti yang saya sebutkan, saya menulis ekstensi ini. Karena ini dikembangkan dengan bantuan dari banyak utas di sini, saya ingin memposting solusi saya di sini kalau-kalau ada orang lain menemukan utas ini, sama seperti yang saya lakukan.
Terima kasih telah berbagi. Tidak upvote karena jawaban terlalu lama dengan kode terlalu sedikit
T30
1
Properti $ queryString yang disebutkan mungkin hanya akan mengembalikan permintaan yang diteruskan, tanpa parameter diganti dengan nilainya. Di .Net, saya memiliki bagian tangkapan dari query saya melakukan pencarian sederhana menggantikan pada parameter dengan nilai-nilai mereka yang disediakan sehingga log kesalahan dapat menunjukkan nilai aktual yang digunakan untuk permintaan. Anda harus dapat menghitung parameter dalam PHP, dan mengganti parameter dengan nilai yang ditetapkan.
Saya tahu pertanyaan ini agak lama, tapi, saya menggunakan kode ini sejak beberapa waktu yang lalu (saya telah menggunakan respons dari @ chris-go), dan sekarang, kode ini sudah usang dengan PHP 7.2
Saya akan memposting versi terbaru dari kode ini (Kredit untuk kode utama berasal dari @bigwebguy , @mike dan @ chris-go , semuanya menjawab pertanyaan ini):
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* @param string $query The sql query with parameter placeholders
* @param array $params The array of substitution parameters
* @return string The interpolated query
*/publicfunction interpolateQuery($query, $params){
$keys = array();
$values = $params;# build a regular expression for each parameterforeach($params as $key => $value){if(is_string($key)){
$keys[]='/:'.$key.'/';}else{
$keys[]='/[?]/';}if(is_array($value))
$values[$key]= implode(',', $value);if(is_null($value))
$values[$key]='NULL';}// Walk the array to see if we can add single-quotes to strings
array_walk($values,function(&$v, $k){if(!is_numeric($v)&& $v !="NULL") $v ="\'". $v ."\'";});
$query = preg_replace($keys, $values, $query,1, $count);return $query;}
Perhatikan bahwa perubahan pada kode berada pada fungsi array_walk (), menggantikan create_function dengan fungsi anonim. Ini membuat kode yang baik ini berfungsi dan kompatibel dengan PHP 7.2 (dan juga berharap versi yang akan datang).
Agak terkait ... jika Anda hanya mencoba membersihkan variabel tertentu, Anda dapat menggunakan PDO :: quote . Misalnya, untuk mencari beberapa kondisi LIKE sebagian jika Anda terjebak dengan kerangka kerja terbatas seperti CakePHP:
$pdo = $this->getDataSource()->getConnection();
$results = $this->find('all', array('conditions'=> array('Model.name LIKE '. $pdo->quote("%{$keyword1}%"),'Model.name LIKE '. $pdo->quote("%{$keyword2}%"),),);
Jawaban Mike bekerja dengan baik sampai Anda menggunakan nilai ikat "gunakan kembali".
Sebagai contoh:
SELECT * FROM `an_modules` AS `m` LEFT JOIN `an_module_sites` AS `ms` ON m.module_id = ms.module_id WHERE 1 AND `module_enable`=:module_enable AND `site_id`=:site_id AND (`module_system_name` LIKE :search OR `module_version` LIKE :search)
Jawaban Mike hanya dapat menggantikan yang pertama: cari tetapi bukan yang kedua.
Jadi, saya menulis ulang jawabannya untuk bekerja dengan beberapa parameter yang dapat digunakan kembali dengan benar.
preg_replace tidak berfungsi untuk saya dan ketika binding_ lebih dari 9, binding_1 dan binding_10 diganti dengan str_replace (meninggalkan 0 di belakang), jadi saya membuat penggantian ke belakang:
Saya perlu login string kueri penuh setelah mengikat param jadi ini adalah bagian dalam kode saya. Semoga bermanfaat bagi setiap orang yang memiliki masalah yang sama.
$stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;
. Ia bekerja dengan memperluas kelas PDOStatement , karenanya elegan seperti API PDO memungkinkan.Jawaban:
Saya berasumsi Anda berarti bahwa Anda ingin query SQL final, dengan nilai parameter diinterpolasi ke dalamnya. Saya mengerti bahwa ini akan berguna untuk debugging, tetapi ini bukan cara pernyataan yang disiapkan bekerja. Parameter tidak digabungkan dengan pernyataan yang disiapkan di sisi klien, jadi PDO seharusnya tidak pernah memiliki akses ke string kueri yang dikombinasikan dengan parameternya.
Pernyataan SQL dikirim ke server database ketika Anda melakukan prep (), dan parameter dikirim secara terpisah ketika Anda mengeksekusi (). Log kueri umum MySQL memang menunjukkan SQL final dengan nilai yang diinterpolasi setelah Anda mengeksekusi (). Di bawah ini adalah kutipan dari log kueri umum saya. Saya menjalankan pertanyaan dari CLI mysql, bukan dari PDO, tetapi prinsipnya sama.
Anda juga bisa mendapatkan apa yang Anda inginkan jika Anda menetapkan atribut PDO PDO :: ATTR_EMULATE_PREPARES. Dalam mode ini, PDO menginterpolasi parameter ke dalam kueri SQL dan mengirimkan seluruh kueri saat Anda mengeksekusi (). Ini bukan permintaan yang disiapkan dengan benar. Anda akan menghindari manfaat dari kueri yang disiapkan dengan menginterpolasi variabel ke dalam string SQL sebelum dieksekusi ().
Komentar dari @afilina:
Tidak, permintaan SQL tekstual tidak digabungkan dengan parameter selama eksekusi. Jadi tidak ada yang bisa ditunjukkan PDO kepada Anda.
Secara internal, jika Anda menggunakan PDO :: ATTR_EMULATE_PREPARES, PDO membuat salinan kueri SQL dan menginterpolasi nilai parameter ke dalamnya sebelum melakukan persiapan dan eksekusi. Tetapi PDO tidak mengekspos permintaan SQL yang dimodifikasi ini.
Objek PDOStatement memiliki properti $ queryString, tetapi ini hanya diatur dalam konstruktor untuk PDOStatement, dan itu tidak diperbarui ketika kueri ditulis ulang dengan parameter.
Ini akan menjadi permintaan fitur yang masuk akal bagi PDO untuk meminta mereka mengekspos kueri yang ditulis ulang. Tetapi bahkan itu tidak akan memberi Anda permintaan "lengkap" kecuali Anda menggunakan PDO :: ATTR_EMULATE_PREPARES.
Inilah sebabnya saya menunjukkan solusi di atas menggunakan log kueri umum server MySQL, karena dalam hal ini bahkan kueri yang disiapkan dengan placeholder parameter ditulis ulang di server, dengan nilai parameter yang dikembalikan ke string kueri. Tapi ini hanya dilakukan saat logging, bukan saat eksekusi query.
sumber
sumber
strtr()
: lebih cepat, lebih sederhana, hasil yang sama.strtr($query, $params);
$key
menjadistring
dan tidak$value
? Apakah saya melewatkan sesuatu? Alasan saya bertanya ini karena output ini, parameter kedua tidak dilihat sebagai string:string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
Saya memodifikasi metode untuk menyertakan penanganan keluaran array untuk pernyataan seperti WHERE IN (?).
UPDATE: Baru saja menambahkan periksa untuk nilai NULL dan duplikasi $ params sehingga nilai-nilai $ param aktual tidak dimodifikasi.
Kerja bagus bigwebguy dan terima kasih!
sumber
$values = $params;
bukan$values = array()
.is_array
cek:if (is_string($value)) $values[$key] = "'" . $value . "'";
$values = $params;
$values_limit = []; $words_repeated = array_count_values(str_word_count($sql, 1, ':_'));
tambahkan ini di dalam terlebih dahulu jika di foreach$values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);
dan ini di yang lain di foreach$values_limit = [];
gunakan foreach loop $ values lagi untuk preg_replace denganisset($values_limit[$key])
if (is_array($values)) { foreach ($values as $key => $val) { if (isset($values_limit[$key])) { $sql = preg_replace(['/:'.$key.'/'], [$val], $sql, $values_limit[$key], $count); } } unset($key, $val); } else { $sql = preg_replace($keys, $values, $sql, 1, $count); }
Agak terlambat mungkin tapi sekarang ada
PDOStatement::debugDumpParams
Anda dapat menemukan lebih banyak di dokumen resmi php
Contoh:
sumber
echo '<pre>'; $sth->debugDumpParams(); echo '</pre>';
Solusi adalah dengan secara sukarela menempatkan kesalahan dalam kueri dan untuk mencetak pesan kesalahan:
Output standar:
Penting untuk dicatat bahwa itu hanya mencetak 80 karakter pertama dari permintaan.
sumber
Menambahkan sedikit lebih banyak ke kode oleh Mike - nilai berjalan untuk menambahkan tanda kutip tunggal
sumber
PDOStatement memiliki properti publik $ queryString. Itu harus menjadi apa yang Anda inginkan.
Saya baru saja memperhatikan bahwa PDOStatement memiliki metode debugDumpParams () yang tidak didokumentasikan yang mungkin ingin Anda lihat.
sumber
Anda bisa memperluas kelas PDOStatement untuk menangkap variabel terikat dan menyimpannya untuk digunakan nanti. Kemudian 2 metode dapat ditambahkan, satu untuk sanitasi variabel (debugBindedVariables) dan lainnya untuk mencetak kueri dengan variabel-variabel tersebut (debugQuery):
Dan kemudian Anda bisa menggunakan kelas bawaan ini untuk tujuan debugging.
Yang menghasilkan
sumber
Saya menghabiskan banyak waktu meneliti situasi ini untuk kebutuhan saya sendiri. Ini dan beberapa utas SO lainnya sangat membantu saya, jadi saya ingin membagikan apa yang saya hasilkan.
Meskipun memiliki akses ke string kueri yang diinterpolasi adalah manfaat yang signifikan saat pemecahan masalah, kami ingin dapat mempertahankan log hanya dari kueri tertentu (oleh karena itu, menggunakan log basis data untuk tujuan ini tidak ideal). Kami juga ingin dapat menggunakan log untuk menciptakan kembali kondisi tabel pada waktu tertentu, oleh karena itu, kami perlu memastikan string yang diinterpolasi lolos dengan benar. Akhirnya, kami ingin memperluas fungsionalitas ini ke seluruh basis kode kami harus menulis ulang sesedikit mungkin (tenggat waktu, pemasaran, dan semacamnya; Anda tahu bagaimana ini).
Solusi saya adalah untuk memperluas fungsionalitas objek PDOStatement default untuk cache nilai parameter (atau referensi), dan ketika pernyataan dieksekusi, gunakan fungsionalitas objek PDO untuk keluar dari parameter dengan benar ketika mereka disuntikkan kembali ke permintaan tali. Kami kemudian dapat mengikat untuk mengeksekusi metode objek pernyataan dan mencatat permintaan aktual yang dieksekusi pada waktu itu ( atau setidaknya setepat reproduksi mungkin) .
Seperti yang saya katakan, kami tidak ingin memodifikasi seluruh basis kode untuk menambahkan fungsionalitas ini, jadi kami menimpa default
bindParam()
danbindValue()
metode objek PDOStatement, melakukan caching kami terhadap data yang terikat, kemudian memanggilparent::bindParam()
atau induk ::bindValue()
. Ini memungkinkan basis kode kami yang ada untuk terus berfungsi seperti biasa.Akhirnya, ketika
execute()
metode dipanggil, kami melakukan interpolasi kami dan memberikan string yang dihasilkan sebagai properti baruE_PDOStatement->fullQuery
. Ini bisa berupa output untuk melihat kueri atau, misalnya, ditulis ke file log.Ekstensi, bersama dengan petunjuk pemasangan dan konfigurasi, tersedia di github:
https://github.com/noahheck/E_PDOStatement
PENOLAKAN :
Jelas, seperti yang saya sebutkan, saya menulis ekstensi ini. Karena ini dikembangkan dengan bantuan dari banyak utas di sini, saya ingin memposting solusi saya di sini kalau-kalau ada orang lain menemukan utas ini, sama seperti yang saya lakukan.
sumber
Properti $ queryString yang disebutkan mungkin hanya akan mengembalikan permintaan yang diteruskan, tanpa parameter diganti dengan nilainya. Di .Net, saya memiliki bagian tangkapan dari query saya melakukan pencarian sederhana menggantikan pada parameter dengan nilai-nilai mereka yang disediakan sehingga log kesalahan dapat menunjukkan nilai aktual yang digunakan untuk permintaan. Anda harus dapat menghitung parameter dalam PHP, dan mengganti parameter dengan nilai yang ditetapkan.
sumber
Kamu bisa memakai
sprintf(str_replace('?', '"%s"', $sql), ...$params);
Berikut ini sebuah contoh:
Perhatikan ini hanya berfungsi untuk PHP> = 5.6
sumber
Saya tahu pertanyaan ini agak lama, tapi, saya menggunakan kode ini sejak beberapa waktu yang lalu (saya telah menggunakan respons dari @ chris-go), dan sekarang, kode ini sudah usang dengan PHP 7.2
Saya akan memposting versi terbaru dari kode ini (Kredit untuk kode utama berasal dari @bigwebguy , @mike dan @ chris-go , semuanya menjawab pertanyaan ini):
Perhatikan bahwa perubahan pada kode berada pada fungsi array_walk (), menggantikan create_function dengan fungsi anonim. Ini membuat kode yang baik ini berfungsi dan kompatibel dengan PHP 7.2 (dan juga berharap versi yang akan datang).
sumber
Agak terkait ... jika Anda hanya mencoba membersihkan variabel tertentu, Anda dapat menggunakan PDO :: quote . Misalnya, untuk mencari beberapa kondisi LIKE sebagian jika Anda terjebak dengan kerangka kerja terbatas seperti CakePHP:
sumber
Jawaban Mike bekerja dengan baik sampai Anda menggunakan nilai ikat "gunakan kembali".
Sebagai contoh:
Jawaban Mike hanya dapat menggantikan yang pertama: cari tetapi bukan yang kedua.
Jadi, saya menulis ulang jawabannya untuk bekerja dengan beberapa parameter yang dapat digunakan kembali dengan benar.
sumber
preg_replace tidak berfungsi untuk saya dan ketika binding_ lebih dari 9, binding_1 dan binding_10 diganti dengan str_replace (meninggalkan 0 di belakang), jadi saya membuat penggantian ke belakang:
}
Semoga seseorang menemukan itu berguna.
sumber
Saya perlu login string kueri penuh setelah mengikat param jadi ini adalah bagian dalam kode saya. Semoga bermanfaat bagi setiap orang yang memiliki masalah yang sama.
sumber