Saya memiliki skrip Perl yang tidak berfungsi dan saya tidak tahu bagaimana memulai mempersempit masalah. Apa yang dapat saya?
Catatan: Saya menambahkan pertanyaan karena saya benar-benar ingin menambahkan jawaban saya yang sangat panjang ke Stackoverflow. Saya terus menautkannya secara eksternal di jawaban lain dan itu layak untuk berada di sini. Jangan malu mengedit jawaban saya jika Anda memiliki sesuatu untuk ditambahkan.
Jawaban:
Jawaban ini dimaksudkan sebagai kerangka kerja umum untuk mengatasi masalah dengan skrip Perl CGI dan aslinya muncul di Perlmonks sebagai Pemecahan Masalah Skrip Perl CGI . Ini bukan panduan lengkap untuk setiap masalah yang mungkin Anda temui, atau tutorial tentang bug squashing. Ini hanyalah puncak dari pengalaman saya men-debug skrip CGI selama dua puluh (plus!) Tahun. Halaman ini tampaknya memiliki banyak rumah yang berbeda, dan saya sepertinya lupa bahwa halaman ini ada, jadi saya menambahkannya ke StackOverflow. Anda dapat mengirimkan komentar atau saran apa pun kepada saya di [email protected]. Ini juga wiki komunitas, tetapi jangan terlalu gila. :)
Apakah Anda menggunakan fitur bawaan Perl untuk membantu Anda menemukan masalah?
Aktifkan peringatan agar Perl memperingatkan Anda tentang bagian-bagian kode yang meragukan. Anda dapat melakukan ini dari baris perintah dengan
-w
sakelar sehingga Anda tidak perlu mengubah kode apa pun atau menambahkan pragma ke setiap file:Namun, Anda harus memaksakan diri untuk selalu membersihkan kode yang dipertanyakan dengan menambahkan
warnings
pragma ke semua file Anda:Jika Anda membutuhkan lebih banyak informasi daripada pesan peringatan singkat, gunakan
diagnostics
pragma untuk mendapatkan lebih banyak informasi, atau lihat di dokumentasi perldiag :Apakah Anda mengeluarkan header CGI yang valid terlebih dahulu?
Server mengharapkan keluaran pertama dari skrip CGI menjadi header CGI. Biasanya itu mungkin sesederhana
print "Content-type: text/plain\n\n";
atau dengan CGI.pm dan turunannyaprint header()
,. Beberapa server sensitif terhadap keluaran kesalahan (onSTDERR
) yang muncul sebelum keluaran standar (onSTDOUT
).Coba kirim kesalahan ke browser
Tambahkan baris ini
ke skrip Anda. Ini juga mengirimkan kesalahan kompilasi ke jendela browser. Pastikan untuk menghapus ini sebelum pindah ke lingkungan produksi, karena informasi tambahan dapat menimbulkan risiko keamanan.
Apa isi log kesalahan?
Server menyimpan log kesalahan (atau seharusnya, setidaknya). Keluaran kesalahan dari server dan dari skrip Anda seharusnya muncul di sana. Temukan log kesalahan dan lihat isinya. Tidak ada tempat standar untuk file log. Lihat di konfigurasi server untuk lokasinya, atau tanyakan pada admin server. Anda juga dapat menggunakan alat seperti CGI :: Carp untuk menyimpan file log Anda sendiri.
Apa izin skrip?
Jika Anda melihat kesalahan seperti "Izin ditolak" atau "Metode tidak diterapkan", itu mungkin berarti bahwa skrip Anda tidak dapat dibaca dan dijalankan oleh pengguna server web. Mengenai rasa Unix, disarankan untuk mengubah mode ke 755:
chmod 755 filename
. Jangan pernah menyetel mode ke 777!Apakah Anda menggunakan
use strict
?Ingatlah bahwa Perl secara otomatis membuat variabel saat Anda pertama kali menggunakannya. Ini adalah fitur, tetapi terkadang dapat menyebabkan bug jika Anda salah mengetik nama variabel. Pragma
use strict
akan membantu Anda menemukan kesalahan semacam itu. Ini menjengkelkan sampai Anda terbiasa, tetapi pemrograman Anda akan meningkat secara signifikan setelah beberapa saat dan Anda akan bebas membuat kesalahan yang berbeda.Apakah skrip dikompilasi?
Anda dapat memeriksa kesalahan kompilasi dengan menggunakan
-c
sakelar. Berkonsentrasi pada kesalahan pertama yang dilaporkan. Bilas, ulangi. Jika Anda mendapatkan kesalahan yang sangat aneh, periksa untuk memastikan bahwa skrip Anda memiliki akhiran baris yang benar. Jika Anda FTP dalam mode biner, checkout dari CVS, atau sesuatu yang lain yang tidak menangani terjemahan akhir baris, server web mungkin melihat skrip Anda sebagai satu baris besar. Transfer skrip Perl dalam mode ASCII.Apakah skrip mengeluh tentang dependensi yang tidak aman?
Jika skrip Anda mengeluh tentang dependensi yang tidak aman, Anda mungkin menggunakan
-T
sakelar untuk mengaktifkan mode taint, yang merupakan hal yang baik karena ini membuat Anda tetap meneruskan data yang tidak dicentang ke shell. Jika ia mengeluh, ia melakukan tugasnya untuk membantu kami menulis skrip yang lebih aman. Setiap data yang berasal dari luar program (yaitu lingkungan) dianggap tercemar. Variabel lingkungan sepertiPATH
danLD_LIBRARY_PATH
sangat merepotkan. Anda harus mengatur ini ke nilai yang aman atau membatalkannya sepenuhnya, seperti yang saya rekomendasikan. Anda tetap harus menggunakan jalur absolut. Jika pemeriksaan noda mengeluh tentang hal lain, pastikan Anda memiliki data yang tidak ternoda. Lihat halaman manual perlsec untuk detailnya.Apa yang terjadi jika Anda menjalankannya dari baris perintah?
Apakah skrip menghasilkan apa yang Anda harapkan saat dijalankan dari baris perintah? Apakah output header lebih dulu, diikuti dengan baris kosong? Ingat bahwa
STDERR
mungkin akan digabungkan denganSTDOUT
jika Anda berada di terminal (misalnya sesi interaktif), dan karena buffering mungkin muncul dalam urutan campur aduk. Aktifkan fitur autoflush Perl dengan menyetel$|
ke nilai sebenarnya. Biasanya Anda mungkin melihat$|++;
di program CGI. Setelah disetel, setiap pencetakan dan penulisan akan langsung masuk ke keluaran daripada di-buffer. Anda harus mengatur ini untuk setiap filehandle. Gunakanselect
untuk mengubah penanganan file default, seperti:Bagaimanapun, keluaran hal pertama haruslah header CGI diikuti dengan baris kosong.
Apa yang terjadi jika Anda menjalankannya dari baris perintah dengan lingkungan mirip CGI?
Lingkungan server web biasanya jauh lebih terbatas daripada lingkungan baris perintah Anda, dan memiliki informasi tambahan tentang permintaan tersebut. Jika skrip Anda berjalan dengan baik dari baris perintah, Anda dapat mencoba mensimulasikan lingkungan server web. Jika masalah muncul, Anda memiliki masalah lingkungan.
Batalkan pengaturan atau hapus variabel ini
PATH
LD_LIBRARY_PATH
ORACLE_*
variabelTetapkan variabel-variabel ini
REQUEST_METHOD
(set keGET
,HEAD
atauPOST
yang sesuai)SERVER_PORT
(diatur ke 80, biasanya)REMOTE_USER
(jika Anda melakukan hal-hal dengan akses yang dilindungi)Versi terbaru
CGI.pm
(> 2.75) memerlukan-debug
flag untuk mendapatkan perilaku lama (berguna), jadi Anda mungkin harus menambahkannya keCGI.pm
impor Anda .Apakah Anda menggunakan
die()
atauwarn
?Fungsi-fungsi itu mencetak ke
STDERR
kecuali Anda telah mendefinisikannya kembali. Mereka juga tidak mengeluarkan header CGI. Anda bisa mendapatkan fungsionalitas yang sama dengan paket seperti CGI :: CarpApa yang terjadi setelah Anda menghapus cache browser?
Jika menurut Anda skrip Anda melakukan hal yang benar, dan saat Anda melakukan permintaan secara manual, Anda mendapatkan hasil yang tepat, mungkin browser penyebabnya. Kosongkan cache dan setel ukuran cache ke nol saat pengujian. Ingatlah bahwa beberapa browser sangat bodoh dan tidak benar-benar memuat ulang konten baru meskipun Anda menyuruhnya melakukannya. Ini terutama lazim dalam kasus di mana jalur URL sama, tetapi konten berubah (misalnya gambar dinamis).
Apakah naskahnya sesuai dengan keinginan Anda?
Jalur sistem file ke skrip tidak selalu terkait langsung dengan jalur URL ke skrip. Pastikan Anda memiliki direktori yang benar, meskipun Anda harus menulis skrip pengujian singkat untuk mengujinya. Lebih lanjut, apakah Anda yakin bahwa Anda memodifikasi file yang benar? Jika Anda tidak melihat efek apa pun dengan perubahan Anda, Anda mungkin memodifikasi file lain, atau mengupload file ke tempat yang salah. (Ngomong-ngomong, inilah penyebab saya yang paling sering dari masalah seperti itu;)
Apakah Anda menggunakan
CGI.pm
, atau turunannya?Jika masalah Anda berkaitan dengan parsing input CGI dan Anda tidak menggunakan modul diuji secara luas seperti
CGI.pm
,CGI::Request
,CGI::Simple
atauCGI::Lite
, menggunakan modul dan melanjutkan hidup.CGI.pm
memilikicgi-lib.pl
mode kompatibilitas yang dapat membantu Anda memecahkan masalah input karena implementasi parser CGI yang lebih lama.Apakah Anda menggunakan jalur absolut?
Jika Anda menjalankan perintah eksternal dengan
system
, tanda centang kembali, atau fasilitas IPC lainnya, Anda harus menggunakan jalur absolut ke program eksternal. Anda tidak hanya tahu persis apa yang Anda jalankan, tetapi Anda juga terhindar dari beberapa masalah keamanan. Jika Anda membuka file untuk membaca atau menulis, gunakan jalur absolut. Skrip CGI mungkin memiliki ide yang berbeda tentang direktori saat ini daripada yang Anda lakukan. Atau, Anda dapat melakukan eksplisitchdir()
untuk menempatkan Anda di tempat yang tepat.Apakah Anda memeriksa nilai pengembalian Anda?
Sebagian besar fungsi Perl akan memberi tahu Anda apakah berfungsi atau tidak dan akan
$!
menyebabkan kegagalan. Apakah Anda memeriksa nilai pengembalian dan memeriksa$!
pesan kesalahan? Apakah Anda sudah memeriksa$@
apakah Anda sedang menggunakaneval
?Versi Perl mana yang Anda gunakan?
Versi stabil terbaru dari Perl adalah 5.28 (atau tidak, tergantung kapan terakhir kali ini diedit). Apakah Anda menggunakan versi yang lebih lama? Versi Perl yang berbeda mungkin memiliki ide peringatan yang berbeda.
Server web mana yang Anda gunakan?
Server yang berbeda dapat bertindak berbeda dalam situasi yang sama. Produk server yang sama dapat bertindak berbeda dengan konfigurasi yang berbeda. Sertakan sebanyak mungkin informasi ini dalam permintaan bantuan apa pun.
Apakah Anda memeriksa dokumentasi server?
Pemrogram CGI yang serius harus mengetahui sebanyak mungkin tentang server - termasuk tidak hanya fitur dan perilaku server, tetapi juga konfigurasi lokal. Dokumentasi untuk server Anda mungkin tidak tersedia untuk Anda jika Anda menggunakan produk komersial. Jika tidak, dokumentasi harus ada di server Anda. Jika tidak, cari di web.
Apakah Anda mencari arsip dari
comp.infosystems.www.authoring.cgi
?Ini berguna tetapi semua poster yang bagus telah mati atau hilang.
Sepertinya seseorang pernah mengalami masalah Anda sebelumnya, dan seseorang (mungkin saya) telah menjawabnya di newsgroup ini. Meskipun grup berita ini telah melewati masa kejayaannya, hikmah yang dikumpulkan dari masa lalu terkadang dapat bermanfaat.
Dapatkah Anda mereproduksi masalah dengan skrip pengujian singkat?
Dalam sistem yang besar, mungkin sulit untuk melacak bug karena begitu banyak hal yang terjadi. Cobalah untuk mereproduksi perilaku masalah dengan skrip sesingkat mungkin. Mengetahui masalahnya adalah sebagian besar perbaikannya. Ini mungkin memakan waktu, tetapi Anda belum menemukan masalahnya dan Anda kehabisan pilihan. :)
Apakah Anda memutuskan untuk pergi menonton film?
Sungguh. Terkadang kita bisa begitu terbungkus dalam masalah sehingga kita mengembangkan "perseptual narrowing" (tunnel vision). Istirahat, minum secangkir kopi, atau meledakkan beberapa orang jahat di [Duke Nukem, Quake, Doom, Halo, COD] mungkin memberi Anda perspektif baru bahwa Anda perlu mendekati kembali masalah tersebut.
Sudahkah Anda menyuarakan masalahnya?
Serius lagi. Terkadang menjelaskan masalah dengan lantang membawa kita ke jawaban kita sendiri. Bicaralah dengan penguin (mainan mewah) karena rekan kerja Anda tidak mendengarkan. Jika Anda tertarik dengan ini sebagai alat debugging yang serius (dan saya merekomendasikannya jika Anda belum menemukan masalahnya sekarang), Anda mungkin juga ingin membaca The Psychology of Computer Programming .
sumber
$|=1
bukan$|++
?$|=1
bukan$|++
? Itu tidak benar-benar membuat perbedaan, dan bahkan kemudian,$|
ajaib.use strict
umumnya baik untuk digunakan setiap saat, sedangkan penggunaanfatalsToBrowser
mungkin tidak disarankan dalam produksi, terutama jika Anda menggunakandie
.Saya pikir CGI :: Debug juga layak untuk disebutkan.
sumber
die
pernyataan dan kesalahan run-time dan waktu kompilasi fatal lainnya dicetakSTDERR
, yang mungkin sulit ditemukan dan mungkin digabungkan dengan pesan dari halaman web lain di situs Anda. Saat Anda men-debug skrip Anda, ada baiknya untuk menampilkan pesan kesalahan fatal di browser Anda.Salah satu cara untuk melakukannya adalah dengan menelepon
di bagian atas skrip Anda. Panggilan itu akan menginstal
$SIG{__DIE__}
penangan (lihat perlvar ) menampilkan kesalahan fatal di browser Anda, menambahkannya dengan header yang valid jika perlu. Trik debugging CGI lain yang saya gunakan sebelum saya pernah mendengarCGI::Carp
adalah menggunakaneval
denganDATA
dan__END__
fasilitas pada script untuk menangkap kesalahan saat kompilasi:Teknik yang lebih bertele-tele ini memiliki sedikit keunggulan
CGI::Carp
karena akan menangkap lebih banyak kesalahan waktu kompilasi.Pembaruan: Saya belum pernah menggunakannya, tetapi sepertinya
CGI::Debug
, seperti yang disarankan Mikael S, juga merupakan alat yang sangat berguna dan dapat dikonfigurasi untuk tujuan ini.sumber
<DATA>
adalah filehandle ajaib yang membaca skrip saat ini dimulai dengan__END__
. Gabung menyediakan konteks daftar, jadi <fh> mengembalikan larik, satu baris per item. Kemudian gabung menyatukannya kembali (gabungkan dengan ''). Terakhir, eval.eval join(q{}, <DATA>);
Saya bertanya-tanya kenapa tidak ada yang menyebutkan
PERLDB_OPTS
opsi yang disebutRemotePort
; meskipun memang, tidak banyak contoh yang berfungsi di web (RemotePort
bahkan tidak disebutkan dalam perldebug ) - dan agak bermasalah bagi saya untuk membuat yang ini, tapi ini dia (ini adalah contoh Linux).Untuk melakukan contoh yang tepat, pertama saya membutuhkan sesuatu yang dapat melakukan simulasi yang sangat sederhana dari server web CGI, sebaiknya melalui satu baris perintah. Setelah menemukan server web baris perintah sederhana untuk menjalankan cgis. (perlmonks.org) , saya menemukan IO :: All - A Tiny Web Server dapat digunakan untuk pengujian ini.
Di sini, saya akan bekerja di
/tmp
direktori; skrip CGI akan/tmp/test.pl
(disertakan di bawah). Perhatikan bahwaIO::All
server hanya akan melayani file yang dapat dieksekusi di direktori yang sama dengan CGI, jadichmod +x test.pl
diperlukan di sini. Jadi, untuk melakukan uji coba CGI biasa, saya mengubah direktori ke/tmp
di terminal, dan menjalankan server web satu baris di sana:Perintah server web akan memblokir di terminal, dan sebaliknya akan memulai server web secara lokal (pada 127.0.0.1 atau
localhost
) - setelah itu, saya dapat membuka browser web, dan meminta alamat ini:... dan saya harus mengamati apa
print
yang dibuat olehtest.pl
dimuat - dan ditampilkan - di browser web.Sekarang, untuk men-debug skrip ini
RemotePort
, pertama-tama kita memerlukan listener di jaringan, yang akan digunakan untuk berinteraksi dengan Perl debugger; kita dapat menggunakan alat baris perintahnetcat
(nc
, lihat di sini: Perl 如何 remote debug? ). Jadi, pertama-tama jalankannetcat
listener di satu terminal - di mana ia akan memblokir dan menunggu koneksi di port 7234 (yang akan menjadi port debug kami):Kemudian, kami ingin
perl
memulai dalam mode debug denganRemotePort
, ketikatest.pl
telah dipanggil (bahkan dalam mode CGI, melalui server). Ini, di Linux, dapat dilakukan dengan menggunakan skrip "shebang wrapper" berikut - yang di sini juga perlu dimasukkan/tmp
, dan harus dibuat dapat dieksekusi:Ini agak rumit - lihat skrip shell - Bagaimana saya bisa menggunakan variabel lingkungan di shebang saya? - Unix & Linux Stack Exchange . Tapi, triknya di sini tampaknya bukan untuk memotong
perl
penerjemah yang menanganitest.pl
- jadi begitu kita menekannya, kita tidak melakukannyaexec
, melainkan kita memanggilperl
"dengan jelas", dan pada dasarnya "sumber"test.pl
skrip kita menggunakando
(lihat Bagaimana cara menjalankan Skrip Perl dari dalam skrip Perl? ).Sekarang setelah kita
perldbgcall.sh
masuk/tmp
- kita dapat mengubahtest.pl
file, sehingga merujuk ke file yang dapat dieksekusi ini pada baris shebang-nya (bukan interpreter Perl biasa) - di sini/tmp/test.pl
diubah menjadi:Sekarang, keduanya
test.pl
dan pawang shebang barunyaperldbgcall.sh
,, ada di/tmp
; dan kami telahnc
mendengarkan koneksi debug pada port 7234 - jadi kami akhirnya dapat membuka jendela terminal lain, mengubah direktori ke/tmp
, dan menjalankan server web satu-liner (yang akan mendengarkan koneksi web pada port 8080) di sana:Setelah ini selesai, kita bisa pergi ke browser web kita, dan meminta alamat yang sama
http://127.0.0.1:8080/test.pl
,. Namun, sekarang ketika server web mencoba untuk mengeksekusi skrip, itu akan melakukannya melaluiperldbgcall.sh
shebang - yang akan dimulaiperl
dalam mode debugger jarak jauh. Dengan demikian, eksekusi skrip akan dijeda - dan browser web akan mengunci, menunggu data. Sekarang kita dapat beralih kenetcat
terminal, dan kita harus melihat teks debugger Perl yang sudah dikenal - namun, keluaran melaluinc
:Seperti yang ditunjukkan cuplikan, sekarang pada dasarnya kita menggunakan
nc
sebagai "terminal" - jadi kita dapat mengetikr
(dan Enter) untuk "run" - dan skrip akan menjalankan pernyataan breakpoint (lihat juga Dalam perl, apa perbedaan antara $ DB :: single = 1 dan 2? ), Sebelum berhenti lagi (perhatikan saat itu, browser akan tetap terkunci).Jadi, sekarang kita dapat, katakanlah, melewati sisa
test.pl
, melaluinc
terminal:... namun, juga pada saat ini, browser mengunci dan menunggu data. Hanya setelah kita keluar dari debugger dengan
q
:... apakah browser berhenti mengunci - dan akhirnya menampilkan output (lengkap) dari
test.pl
:Tentu saja, jenis debug ini dapat dilakukan bahkan tanpa menjalankan server web - namun, hal yang menarik di sini, adalah kita tidak menyentuh server web sama sekali; kami memicu eksekusi "secara asli" (untuk CGI) dari browser web - dan satu-satunya perubahan yang diperlukan dalam skrip CGI itu sendiri, adalah perubahan shebang (dan tentu saja, kehadiran skrip pembungkus shebang, sebagai file yang dapat dieksekusi dalam direktori).
Yah, semoga ini membantu seseorang - saya pasti akan senang jika tersandung pada ini, daripada menulisnya sendiri
:)
Cheers!
sumber
Bagi saya, saya menggunakan log4perl . Ini cukup berguna dan mudah.
sumber
Jujur saja Anda bisa melakukan semua hal menyenangkan di atas postingan ini. MESKIPUN, solusi paling sederhana dan paling proaktif yang saya temukan adalah hanya "mencetaknya".
Misalnya: (Kode normal)
Untuk melihat apakah itu melakukan apa yang saya benar-benar ingin lakukan: (Trouble shooting)
sumber
Mungkin juga layak untuk disebutkan bahwa Perl akan selalu memberi tahu Anda pada baris apa kesalahan terjadi saat Anda menjalankan skrip Perl dari baris perintah. (Sesi SSH misalnya)
Saya biasanya akan melakukan ini jika semuanya gagal. Saya akan SSH ke server dan secara manual menjalankan script Perl. Sebagai contoh:
Jika ada masalah maka Perl akan memberitahu Anda tentang itu. Metode debugging ini menghilangkan masalah terkait izin file atau masalah browser web atau server web.
sumber
Anda dapat menjalankan skrip perl cgi di terminal menggunakan perintah di bawah ini
Itu menafsirkan kode dan memberikan hasil dengan kode HTML. Itu akan melaporkan kesalahan jika ada.
sumber
perl -c filename
memang hanya akan memeriksa sintaks. Tapiperl filename
mencetak output HTML. Tidak ada jaminan bahwa tidak akan ada kesalahan 500 CGI, tetapi ini adalah tes pertama yang bagus.