คำตอบนี้มีวัตถุประสงค์เพื่อเป็นกรอบทั่วไปสำหรับการทำงานผ่านปัญหากับ Perl สคริปต์ CGI และปรากฏบน Perlmonks แต่เดิมการแก้ไขปัญหาสคริปต์ CGI Perl ไม่ใช่คำแนะนำที่สมบูรณ์สำหรับทุกปัญหาที่คุณอาจพบหรือบทช่วยสอนเกี่ยวกับการกำจัดข้อผิดพลาด มันเป็นเพียงจุดสุดยอดของประสบการณ์ของฉันในการแก้ไขข้อบกพร่องสคริปต์ CGI เป็นเวลายี่สิบปี (บวก!) หน้านี้ดูเหมือนจะมีบ้านหลายหลังและดูเหมือนว่าฉันจะลืมไปแล้วดังนั้นฉันจึงเพิ่มมันลงใน StackOverflow คุณสามารถส่งความคิดเห็นหรือข้อเสนอแนะถึงฉันได้ที่ bdfoy@cpan.org นอกจากนี้ยังเป็นวิกิชุมชน แต่อย่าไปบ้าเกินไป :)
คุณใช้คุณสมบัติในตัวของ Perl เพื่อช่วยคุณค้นหาปัญหาหรือไม่?
เปิดคำเตือนเพื่อให้ Perl เตือนคุณเกี่ยวกับส่วนที่น่าสงสัยของโค้ดของคุณ คุณสามารถทำได้จากบรรทัดคำสั่งด้วย-w
สวิตช์ดังนั้นคุณไม่ต้องเปลี่ยนรหัสใด ๆ หรือเพิ่ม pragma ลงในทุกไฟล์:
% perl -w program.pl
อย่างไรก็ตามคุณควรบังคับตัวเองให้ล้างโค้ดที่น่าสงสัยอยู่เสมอโดยการเพิ่มwarnings
pragma ลงในไฟล์ทั้งหมดของคุณ:
use warnings;
หากคุณต้องการข้อมูลเพิ่มเติมนอกเหนือจากข้อความเตือนสั้น ๆ ให้ใช้diagnostics
pragma เพื่อรับข้อมูลเพิ่มเติมหรือดูในเอกสารperldiag :
use diagnostics;
คุณส่งออกส่วนหัว CGI ที่ถูกต้องก่อนหรือไม่?
เซิร์ฟเวอร์คาดหวังให้เอาต์พุตแรกจากสคริปต์ CGI เป็นส่วนหัว CGI โดยปกติที่อาจจะเป็นง่ายๆเป็นprint "Content-type: text/plain\n\n";
หรือCGI.pmprint header()
และอนุพันธ์ของมัน เซิร์ฟเวอร์บางตัวมีความไวต่อเอาต์พุตข้อผิดพลาด (เปิดSTDERR
) ที่แสดงก่อนเอาต์พุตมาตรฐาน (เปิดSTDOUT
)
ลองส่งข้อผิดพลาดไปยังเบราว์เซอร์
เพิ่มบรรทัดนี้
use CGI::Carp 'fatalsToBrowser';
กับสคริปต์ของคุณ นอกจากนี้ยังส่งข้อผิดพลาดในการคอมไพล์ไปยังหน้าต่างเบราว์เซอร์ อย่าลืมลบสิ่งนี้ออกก่อนที่จะย้ายไปยังสภาพแวดล้อมการใช้งานจริงเนื่องจากข้อมูลเพิ่มเติมอาจเสี่ยงต่อความปลอดภัย
บันทึกข้อผิดพลาดบอกว่าอย่างไร
เซิร์ฟเวอร์เก็บบันทึกข้อผิดพลาด (หรืออย่างน้อยก็ควร) ผลลัพธ์ข้อผิดพลาดจากเซิร์ฟเวอร์และจากสคริปต์ของคุณควรปรากฏขึ้นที่นั่น ค้นหาบันทึกข้อผิดพลาดและดูว่ามีอะไรบ้าง ไม่มีสถานที่มาตรฐานสำหรับไฟล์บันทึก ดูในการกำหนดค่าเซิร์ฟเวอร์สำหรับตำแหน่งของพวกเขาหรือสอบถามผู้ดูแลระบบเซิร์ฟเวอร์ คุณยังสามารถใช้เครื่องมือต่างๆเช่นCGI :: Carp
เพื่อเก็บไฟล์บันทึกของคุณเอง
สิทธิ์ของสคริปต์คืออะไร?
หากคุณเห็นข้อผิดพลาดเช่น "ปฏิเสธการอนุญาต" หรือ "วิธีที่ไม่ได้ใช้งาน" อาจหมายความว่าสคริปต์ของคุณไม่สามารถอ่านและเรียกใช้งานได้โดยผู้ใช้เว็บเซิร์ฟเวอร์ รสชาติของ Unix เปลี่ยนโหมดไปที่ 755
chmod 755 filename
เป็นที่แนะนำ: อย่าตั้งโหมดเป็น 777!
คุณกำลังใช้use strict
?
โปรดจำไว้ว่า Perl จะสร้างตัวแปรโดยอัตโนมัติเมื่อคุณใช้ครั้งแรก นี่เป็นคุณสมบัติ แต่บางครั้งอาจทำให้เกิดข้อบกพร่องหากคุณพิมพ์ชื่อตัวแปรผิด pragma
use strict
จะช่วยคุณค้นหาข้อผิดพลาดประเภทนั้น มันน่ารำคาญจนกว่าคุณจะชิน แต่การเขียนโปรแกรมของคุณจะดีขึ้นอย่างมากหลังจากนั้นสักครู่และคุณจะมีอิสระที่จะทำผิดพลาดต่างๆ
รวบรวมสคริปต์หรือไม่
คุณสามารถตรวจสอบข้อผิดพลาดในการคอมไพล์ได้โดยใช้-c
สวิตช์ จดจ่อกับข้อผิดพลาดแรกที่รายงาน ล้างทำซ้ำ หากคุณได้รับข้อผิดพลาดแปลก ๆ ให้ตรวจสอบให้แน่ใจว่าสคริปต์ของคุณมีการลงท้ายบรรทัดที่ถูกต้อง หากคุณ FTP ในโหมดไบนารีชำระเงินจาก CVS หรืออย่างอื่นที่ไม่จัดการการแปลปลายบรรทัดเว็บเซิร์ฟเวอร์อาจเห็นสคริปต์ของคุณเป็นบรรทัดใหญ่เส้นเดียว โอนสคริปต์ Perl ในโหมด ASCII
สคริปต์บ่นเกี่ยวกับการอ้างอิงที่ไม่ปลอดภัยหรือไม่?
หากสคริปต์ของคุณบ่นเกี่ยวกับการอ้างอิงที่ไม่ปลอดภัยคุณอาจกำลังใช้-T
สวิตช์เพื่อเปิดโหมดที่ไม่ปลอดภัยซึ่งเป็นสิ่งที่ดีเนื่องจากช่วยให้คุณส่งข้อมูลที่ไม่ได้ตรวจสอบไปยังเชลล์ได้ หากมีการร้องเรียนแสดงว่ากำลังทำงานเพื่อช่วยให้เราเขียนสคริปต์ที่ปลอดภัยยิ่งขึ้น ข้อมูลใด ๆ ที่มาจากภายนอกโปรแกรม (เช่นสภาพแวดล้อม) จะถือว่าเป็นมลทิน ตัวแปรสภาพแวดล้อมเช่นPATH
และ
LD_LIBRARY_PATH
เป็นปัญหาโดยเฉพาะอย่างยิ่ง คุณต้องตั้งค่าเหล่านี้เป็นค่าที่ปลอดภัยหรือยกเลิกการตั้งค่าทั้งหมดตามที่ฉันแนะนำ คุณควรใช้เส้นทางที่แน่นอนอยู่แล้ว หากการตรวจสอบสิ่งสกปรกมีการร้องเรียนเกี่ยวกับสิ่งอื่นตรวจสอบให้แน่ใจว่าคุณไม่ได้รับการเคลือบข้อมูล ดู
รายละเอียดได้ที่หน้า man perlsec
จะเกิดอะไรขึ้นเมื่อคุณเรียกใช้จากบรรทัดคำสั่ง
สคริปต์แสดงผลลัพธ์ตามที่คุณคาดหวังเมื่อเรียกใช้จากบรรทัดคำสั่งหรือไม่ เอาต์พุตส่วนหัวก่อนตามด้วยบรรทัดว่างหรือไม่ โปรดจำไว้ว่าSTDERR
อาจรวมเข้ากับSTDOUT
หากคุณอยู่บนเทอร์มินัล (เช่นเซสชันแบบโต้ตอบ) และเนื่องจากการบัฟเฟอร์อาจแสดงขึ้นในลำดับที่สับสน เปิดใช้งานคุณสมบัติฟลัชอัตโนมัติของ Perl โดยตั้งค่า$|
เป็นค่าจริง โดยทั่วไปคุณอาจเห็น$|++;
ในโปรแกรม CGI เมื่อตั้งค่าแล้วการพิมพ์และการเขียนทุกครั้งจะไปที่เอาต์พุตทันทีแทนที่จะถูกบัฟเฟอร์ คุณต้องตั้งค่านี้สำหรับแต่ละ filehandle ใช้select
เพื่อเปลี่ยนการจัดการไฟล์เริ่มต้นดังนี้:
$|++; #sets $| for STDOUT
$old_handle = select( STDERR ); #change to STDERR
$|++; #sets $| for STDERR
select( $old_handle ); #change back to STDOUT
ไม่ว่าจะด้วยวิธีใดผลลัพธ์สิ่งแรกควรเป็นส่วนหัว CGI ตามด้วยบรรทัดว่าง
จะเกิดอะไรขึ้นเมื่อคุณเรียกใช้จากบรรทัดคำสั่งที่มีสภาพแวดล้อมเหมือน CGI
โดยปกติสภาพแวดล้อมของเว็บเซิร์ฟเวอร์จะ จำกัด มากกว่าสภาพแวดล้อมบรรทัดคำสั่งของคุณและมีข้อมูลเพิ่มเติมเกี่ยวกับคำขอ หากสคริปต์ของคุณทำงานได้ดีจากบรรทัดคำสั่งคุณอาจลองจำลองสภาพแวดล้อมเว็บเซิร์ฟเวอร์ หากปัญหาปรากฏขึ้นแสดงว่าคุณมีปัญหาด้านสิ่งแวดล้อม
ยกเลิกการตั้งค่าหรือลบตัวแปรเหล่านี้
PATH
LD_LIBRARY_PATH
ORACLE_*
ตัวแปรทั้งหมด
ตั้งค่าตัวแปรเหล่านี้
REQUEST_METHOD
(ตั้งค่าให้GET
, HEAD
หรือPOST
ตามความเหมาะสม)
SERVER_PORT
(ตั้งค่าเป็น 80 โดยปกติ)
REMOTE_USER
(หากคุณกำลังทำสิ่งที่มีการป้องกันการเข้าถึง)
เวอร์ชันล่าสุดของCGI.pm
(> 2.75) ต้องการ-debug
แฟล็กเพื่อรับพฤติกรรมเก่า (มีประโยชน์) ดังนั้นคุณอาจต้องเพิ่มลงในCGI.pm
การนำเข้าของคุณ
use CGI qw(-debug)
คุณกำลังใช้die()
หรือwarn
?
ฟังก์ชันเหล่านั้นจะพิมพ์ไปSTDERR
จนกว่าคุณจะกำหนดนิยามใหม่ พวกเขาไม่ส่งออกส่วนหัว CGI เช่นกัน คุณสามารถใช้ฟังก์ชันเดียวกันกับแพ็คเกจต่างๆเช่นCGI :: Carp
จะเกิดอะไรขึ้นหลังจากคุณล้างแคชของเบราว์เซอร์
หากคุณคิดว่าสคริปต์ของคุณทำในสิ่งที่ถูกต้องและเมื่อคุณดำเนินการตามคำขอด้วยตนเองคุณจะได้ผลลัพธ์ที่ถูกต้องเบราว์เซอร์อาจเป็นตัวการ ล้างแคชและตั้งค่าขนาดแคชเป็นศูนย์ขณะทดสอบ โปรดจำไว้ว่าเบราว์เซอร์บางตัวนั้นโง่มากและจะไม่โหลดเนื้อหาใหม่แม้ว่าคุณจะบอกให้ทำก็ตาม โดยเฉพาะอย่างยิ่งในกรณีที่เส้นทาง URL เหมือนกัน แต่เนื้อหาเปลี่ยนไป (เช่นภาพไดนามิก)
สคริปต์ที่คุณคิดว่ามันคืออะไร?
เส้นทางระบบไฟล์ไปยังสคริปต์ไม่จำเป็นต้องเกี่ยวข้องโดยตรงกับเส้นทาง URL ไปยังสคริปต์ ตรวจสอบให้แน่ใจว่าคุณมีไดเร็กทอรีที่ถูกต้องแม้ว่าคุณจะต้องเขียนสคริปต์ทดสอบสั้น ๆ เพื่อทดสอบสิ่งนี้ นอกจากนี้คุณแน่ใจหรือไม่ว่าคุณกำลังแก้ไขไฟล์ที่ถูกต้อง หากคุณไม่เห็นผลใด ๆ กับการเปลี่ยนแปลงของคุณคุณอาจกำลังแก้ไขไฟล์อื่นหรืออัปโหลดไฟล์ไปยังตำแหน่งที่ไม่ถูกต้อง (นี่คือสาเหตุของปัญหาที่เกิดขึ้นบ่อยที่สุดของฉัน)
คุณกำลังใช้CGI.pm
หรืออนุพันธ์ของมัน?
หากปัญหาของคุณเกี่ยวข้องกับการแยกการป้อนข้อมูล CGI และคุณไม่ได้ใช้โมดูลทดสอบกันอย่างแพร่หลายเช่นCGI.pm
, CGI::Request
,
CGI::Simple
หรือCGI::Lite
ใช้โมดูลและได้รับในชีวิต
CGI.pm
มีcgi-lib.pl
โหมดความเข้ากันได้ซึ่งสามารถช่วยคุณแก้ปัญหาการป้อนข้อมูลเนื่องจากการใช้งานตัวแยกวิเคราะห์ CGI รุ่นเก่า
คุณใช้เส้นทางสัมบูรณ์หรือไม่?
หากคุณกำลังเรียกใช้คำสั่งภายนอกด้วย
system
เครื่องหมายย้อนกลับหรือสิ่งอำนวยความสะดวก IPC อื่น ๆ คุณควรใช้เส้นทางแบบสัมบูรณ์ไปยังโปรแกรมภายนอก คุณไม่เพียง แต่รู้แน่ชัดว่าคุณกำลังใช้งานอะไรอยู่ แต่คุณยังหลีกเลี่ยงปัญหาด้านความปลอดภัยบางอย่างอีกด้วย หากคุณกำลังเปิดไฟล์เพื่ออ่านหรือเขียนให้ใช้พา ธ สัมบูรณ์ สคริปต์ CGI อาจมีแนวคิดเกี่ยวกับไดเร็กทอรีปัจจุบันที่แตกต่างจากที่คุณทำ หรืออีกวิธีหนึ่งคุณสามารถพูดอย่างชัดเจนchdir()
เพื่อให้คุณอยู่ในสถานที่ที่เหมาะสม
คุณตรวจสอบค่าส่งคืนหรือไม่
ฟังก์ชัน Perl ส่วนใหญ่จะบอกคุณว่าทำงานหรือไม่และจะตั้งค่าเป็น$!
ความล้มเหลว คุณตรวจสอบค่าส่งคืนและตรวจสอบ$!
ข้อความแสดงข้อผิดพลาดหรือไม่ คุณตรวจสอบ
$@
ว่าคุณใช้อยู่eval
หรือไม่?
คุณใช้ Perl เวอร์ชันใดอยู่
เวอร์ชันเสถียรล่าสุดของ Perl คือ 5.28 (หรือไม่ขึ้นอยู่กับเวลาที่แก้ไขครั้งล่าสุด) คุณใช้รุ่นเก่ากว่านี้หรือไม่? Perl เวอร์ชันต่างๆอาจมีแนวคิดเกี่ยวกับคำเตือนที่แตกต่างกัน
คุณใช้เว็บเซิร์ฟเวอร์ใด
เซิร์ฟเวอร์ที่แตกต่างกันอาจทำงานแตกต่างกันในสถานการณ์เดียวกัน ผลิตภัณฑ์เซิร์ฟเวอร์เดียวกันอาจทำงานแตกต่างกันไปตามการกำหนดค่าที่แตกต่างกัน ใส่ข้อมูลนี้ให้มากที่สุดเท่าที่จะทำได้ในการร้องขอความช่วยเหลือ
คุณตรวจสอบเอกสารเซิร์ฟเวอร์หรือไม่
โปรแกรมเมอร์ CGI ที่จริงจังควรรู้เกี่ยวกับเซิร์ฟเวอร์ให้มากที่สุด - ไม่เพียง แต่คุณสมบัติและพฤติกรรมของเซิร์ฟเวอร์เท่านั้น แต่ยังรวมถึงการกำหนดค่าภายในเครื่องด้วย เอกสารสำหรับเซิร์ฟเวอร์ของคุณอาจไม่มีให้คุณหากคุณใช้ผลิตภัณฑ์เชิงพาณิชย์ มิฉะนั้นเอกสารควรอยู่บนเซิร์ฟเวอร์ของคุณ หากไม่เป็นเช่นนั้นให้ค้นหาบนเว็บ
การใช้งานนี้เป็นประโยชน์ แต่ผู้โพสต์ที่ดีทั้งหมดเสียชีวิตหรือสูญหายไป
เป็นไปได้ว่ามีคนเคยมีปัญหาของคุณมาก่อนและมีคน (อาจเป็นฉัน) ตอบคำถามนี้ในกลุ่มข่าวนี้ แม้ว่ากลุ่มข่าวนี้จะผ่านพ้นช่วงรุ่งเรืองไปแล้ว แต่บางครั้งภูมิปัญญาที่รวบรวมมาจากอดีตก็มีประโยชน์
คุณสามารถสร้างปัญหาซ้ำโดยใช้สคริปต์ทดสอบสั้น ๆ ได้หรือไม่?
ในระบบขนาดใหญ่อาจเป็นเรื่องยากที่จะติดตามจุดบกพร่องเนื่องจากมีหลายสิ่งเกิดขึ้น พยายามจำลองพฤติกรรมของปัญหาด้วยสคริปต์ที่สั้นที่สุด การรู้ปัญหาเป็นส่วนใหญ่ของการแก้ไข อาจใช้เวลานานอย่างแน่นอน แต่คุณยังไม่พบปัญหาและคุณไม่มีตัวเลือก :)
คุณตัดสินใจไปดูหนังหรือไม่?
อย่างจริงจัง. บางครั้งเราอาจจมอยู่กับปัญหาที่เราพัฒนา "การรับรู้แคบ" (การมองเห็นในอุโมงค์) การหยุดพักดื่มกาแฟสักแก้วหรือระเบิดผู้ร้ายใน [Duke Nukem, Quake, Doom, Halo, COD] อาจทำให้คุณมีมุมมองใหม่ ๆ ที่คุณต้องแก้ไขปัญหาอีกครั้ง
คุณมีปัญหาหรือไม่?
อย่างจริงจังอีกครั้ง. บางครั้งการอธิบายปัญหาดัง ๆ ทำให้เราได้รับคำตอบของเราเอง คุยกับนกเพนกวิน (ของเล่นตุ๊กตา) เพราะเพื่อนร่วมงานของคุณไม่ฟัง หากคุณมีความสนใจในเรื่องนี้เป็นเครื่องมือในการแก้ไขข้อบกพร่องที่ร้ายแรง (และฉันจะแนะนำให้มันถ้าคุณยังไม่พบปัญหาที่เกิดขึ้นโดยขณะนี้) คุณอาจจะยังชอบที่จะอ่านจิตวิทยาของการเขียนโปรแกรมคอมพิวเตอร์