วิธีแก้ไขข้อผิดพลาด“ ส่วนหัวที่ส่งไปแล้ว” ใน PHP
เมื่อเรียกใช้สคริปต์ของฉันฉันได้รับข้อผิดพลาดหลายประการดังนี้:
คำเตือน: ไม่สามารถแก้ไขข้อมูลส่วนหัว - ส่วนหัวที่ส่งไปแล้ว ( เอาต์พุตเริ่มต้นที่ /some/file.php:12 ) ใน/some/file.phpในบรรทัดที่ 23
บรรทัดที่กล่าวถึงในข้อความแสดงข้อผิดพลาดประกอบด้วยheader()และการsetcookie()โทร
อะไรคือสาเหตุของเรื่องนี้? แล้วแก้ไขยังไง?
คำตอบ
ไม่มีเอาต์พุตก่อนส่งส่วนหัว!
ฟังก์ชั่นที่ส่ง / ปรับเปลี่ยนส่วนหัว HTTP จะต้องถูกเรียกก่อนที่จะส่งออกใด ๆ ที่จะทำ summary ⇊มิฉะนั้นการโทรล้มเหลว:
คำเตือน: ไม่สามารถแก้ไขข้อมูลส่วนหัว - ส่งส่วนหัวไปแล้ว (เอาต์พุตเริ่มต้นที่script: line )
ฟังก์ชันบางอย่างที่แก้ไขส่วนหัว HTTP ได้แก่ :
- header / header_remove
- session_start / session_regenerate_id
- setcookie / setrawcookie
เอาต์พุตสามารถ:
โดยไม่ได้ตั้งใจ:
- เว้นวรรคก่อน
<?php
หรือหลัง?>
- UTF-8 Byte มาร์คสั่งซื้อสินค้าโดยเฉพาะ
- ข้อความแสดงข้อผิดพลาดหรือประกาศก่อนหน้านี้
- เว้นวรรคก่อน
เจตนา:
print
,echo
และฟังก์ชั่นอื่น ๆ การผลิตการส่งออก- รหัส
<html>
ก่อนหน้าของส่วนดิบ<?php
ทำไมมันถึงเกิดขึ้น?
เพื่อให้เข้าใจว่าเหตุใดจึงต้องส่งส่วนหัวก่อนที่จะส่งออกจึงจำเป็นต้องดูการตอบสนองHTTPทั่วไป สคริปต์ PHP ส่วนใหญ่สร้างเนื้อหา HTML แต่ยังส่งชุดของส่วนหัว HTTP / CGI ไปยังเว็บเซิร์ฟเวอร์:
HTTP/1.1 200 OK
Powered-By: PHP/5.3.7
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
<html><head><title>PHP page output page</title></head>
<body><h1>Content</h1> <p>Some more output follows...</p>
and <a href="/"> <img src=internal-icon-delayed> </a>
เพจ / เอาต์พุตจะตามหลังส่วนหัวเสมอ PHP ต้องส่งส่วนหัวไปยังเว็บเซิร์ฟเวอร์ก่อน ทำได้เพียงครั้งเดียว หลังจากการแตกไลน์สองครั้งจะไม่สามารถแก้ไขได้อีกต่อไป
เมื่อ PHP ได้รับการส่งออกครั้งแรก ( print
, echo
, <html>
) มันจะล้างหัวเก็บรวบรวมทั้งหมด หลังจากนั้นก็สามารถส่งเอาต์พุตทั้งหมดที่ต้องการได้ แต่การส่งส่วนหัว HTTP เพิ่มเติมนั้นเป็นไปไม่ได้แล้ว
คุณจะทราบได้อย่างไรว่าผลผลิตก่อนกำหนดเกิดขึ้นได้อย่างไร?
header()
เตือนมีข้อมูลที่เกี่ยวข้องทั้งหมดเพื่อหาสาเหตุปัญหา:
คำเตือน: ไม่สามารถแก้ไขข้อมูลส่วนหัว - ส่วนหัวที่ส่งไปแล้ว(เอาต์พุตเริ่มต้นที่ / www / usr2345 / htdocs / auth.php: 52 ) ใน /www/usr2345/htdocs/index.php ในบรรทัด 100
ในที่นี้ "บรรทัดที่ 100" หมายถึงสคริปต์ที่การheader()
เรียกใช้ล้มเหลว
หมายเหตุ " เอาต์พุตเริ่มต้นที่ " ภายในวงเล็บมีความสำคัญมากกว่า มันหมายถึงแหล่งที่มาของเอาต์พุตก่อนหน้านี้ ในตัวอย่างนี้มันauth.php
และบรรทัด 52
นั่นคือจุดที่คุณต้องมองหาผลผลิตก่อนกำหนด
สาเหตุทั่วไป:
พิมพ์เสียงสะท้อน
การส่งออกโดยเจตนาจาก
print
และecho
คำสั่งจะยุติโอกาสในการส่งส่วนหัว HTTP ขั้นตอนการสมัครต้องได้รับการปรับโครงสร้างใหม่เพื่อหลีกเลี่ยงสิ่งนั้น ใช้ฟังก์ชันและโครงร่างเทมเพลต ตรวจสอบให้แน่ใจheader()
ว่ามีการโทรก่อนที่จะเขียนข้อความฟังก์ชั่นที่สร้างผลลัพธ์ ได้แก่
print
,echo
,printf
,vprintf
trigger_error
,ob_flush
,ob_end_flush
,var_dump
,print_r
readfile
,passthru
,flush
,imagepng
,imagejpeg
ท่ามกลางฟังก์ชันอื่น ๆ และฟังก์ชันที่ผู้ใช้กำหนดเองพื้นที่ HTML ดิบ
ส่วน HTML ที่ไม่ได้แยกวิเคราะห์ใน
.php
ไฟล์เป็นเอาต์พุตโดยตรงเช่นกัน เงื่อนไขของสคริปต์ที่จะทริกเกอร์การheader()
โทรจะต้องสังเกตก่อนบล็อกดิบใด ๆ<html>
<!DOCTYPE html> <?php // Too late for headers already.
ใช้โครงร่างเทมเพลตเพื่อแยกการประมวลผลออกจากตรรกะเอาต์พุต
- วางโค้ดการประมวลผลแบบฟอร์มบนสคริปต์
- ใช้ตัวแปรสตริงชั่วคราวเพื่อเลื่อนข้อความ
- ลอจิกเอาต์พุตจริงและเอาต์พุต HTML แบบผสมควรเป็นไปตามลำดับสุดท้าย
<?php
เว้นวรรคก่อนสำหรับคำเตือน"script.php line 1 "หากคำเตือนอ้างถึงผลลัพธ์ในบรรทัดแสดง
1
ว่าส่วนใหญ่เป็นช่องว่างข้อความหรือ HTML ก่อน<?php
โทเค็นเปิด<?php # There's a SINGLE space/newline before <? - Which already seals it.
ในทำนองเดียวกันอาจเกิดขึ้นสำหรับสคริปต์ต่อท้ายหรือส่วนของสคริปต์:
?> <?php
PHP กินบรรทัดเดียวหลังจากปิดแท็ก แต่จะไม่ชดเชยการขึ้นบรรทัดใหม่หรือแท็บหรือช่องว่างหลายรายการที่เลื่อนเข้ามาในช่องว่างดังกล่าว
UTF-8 BOM
การแบ่งเส้นและการเว้นวรรคเพียงอย่างเดียวอาจเป็นปัญหาได้ แต่ยังมีลำดับอักขระที่ "มองไม่เห็น" ซึ่งอาจทำให้เกิดสิ่งนี้ได้ UTF-8 BOM (Byte-Order-Mark)ที่มีชื่อเสียงที่สุดซึ่งไม่ได้แสดงโดยโปรแกรมแก้ไขข้อความส่วนใหญ่ เป็นลำดับไบต์
EF BB BF
ซึ่งเป็นทางเลือกและซ้ำซ้อนสำหรับเอกสารที่เข้ารหัส UTF-8 อย่างไรก็ตาม PHP ต้องถือว่าเป็นเอาต์พุตดิบ อาจแสดงเป็นอักขระ
ในเอาต์พุต (หากไคลเอ็นต์ตีความเอกสารเป็นละติน -1) หรือ "ขยะ" ที่คล้ายกันโดยเฉพาะอย่างยิ่งโปรแกรมแก้ไขกราฟิกและ IDE ที่ใช้ Java จะไม่หลงลืมการมีอยู่ พวกเขาไม่เห็นภาพ (บังคับโดยมาตรฐาน Unicode) อย่างไรก็ตามโปรแกรมเมอร์และบรรณาธิการคอนโซลส่วนใหญ่ทำ:
การรับรู้ปัญหาตั้งแต่เนิ่นๆจึงเป็นเรื่องง่าย บรรณาธิการอื่น ๆ อาจระบุการแสดงตนในเมนูไฟล์ / การตั้งค่า (Notepad ++ บน Windows สามารถระบุและแก้ไขปัญหาที่เกิดขึ้น ) ตัวเลือกในการตรวจสอบการปรากฏ BOMs ก็คือการหันไปยังHexEditor โดยทั่วไปในระบบ * nix hexdumpจะพร้อมใช้งานหากไม่ใช่ตัวแปรกราฟิกที่ช่วยลดความซับซ้อนในการตรวจสอบปัญหาเหล่านี้และปัญหาอื่น ๆ :
วิธีแก้ไขง่ายๆคือตั้งค่าโปรแกรมแก้ไขข้อความให้บันทึกไฟล์เป็น "UTF-8 (no BOM)" หรือระบบการตั้งชื่อที่คล้ายกัน บ่อยครั้งที่ผู้มาใหม่มักใช้วิธีสร้างไฟล์ใหม่และเพียงแค่คัดลอกและวางโค้ดก่อนหน้านี้กลับเข้าไป
ยูทิลิตี้การแก้ไข
นอกจากนี้ยังมีเครื่องมืออัตโนมัติในการตรวจสอบและเขียนไฟล์ข้อความอีกครั้ง ( sed/awkหรือ
recode
) สำหรับ PHP เฉพาะมีของtidierphptags แท็ก มันเขียนแท็กปิดและเปิดใหม่เป็นรูปแบบยาวและสั้น แต่ยังแก้ไขช่องว่างนำหน้าและต่อท้ายปัญหา Unicode และ UTF-x BOM ได้อย่างง่ายดาย:phptags --whitespace *.php
เป็นสิ่งที่ดีที่จะใช้กับไดเร็กทอรีรวมหรือโปรเจ็กต์ทั้งหมด
ช่องว่างหลัง
?>
หากแหล่งที่มาของข้อผิดพลาดถูกกล่าวถึงอยู่หลังการปิด?>นี่คือที่ที่มีการเขียนช่องว่างหรือข้อความดิบ เครื่องหมายปิดท้าย PHP ไม่ยุติการเรียกใช้สคริปต์ในจุดนี้ อักขระข้อความ / เว้นวรรคใด ๆ หลังจากนั้นจะถูกเขียนเป็นเนื้อหาของหน้า
โดยเฉพาะอย่างยิ่งสำหรับผู้มาใหม่
?>
ควรละเว้นแท็กปิด PHP ต่อท้าย ซึ่งเป็นการหลีกเลี่ยงกรณีเหล่านี้เพียงเล็กน้อย (include()d
สคริปต์โดยทั่วไปมักเป็นตัวการ)แหล่งที่มาของข้อผิดพลาดระบุว่า "ไม่ทราบที่บรรทัด 0"
โดยทั่วไปจะเป็นนามสกุล PHP หรือการตั้งค่า php.ini หากไม่มีแหล่งที่มาของข้อผิดพลาดเป็นคอนกรีต
- ในบางครั้งอาจเป็นการ
gzip
ตั้งค่าการเข้ารหัสสตรีมหรือไฟล์ob_gzhandler . - แต่อาจเป็น
extension=
โมดูลที่โหลดเป็นสองเท่าซึ่งสร้างข้อความเริ่มต้น / คำเตือน PHP โดยปริยาย
- ในบางครั้งอาจเป็นการ
ข้อความแสดงข้อผิดพลาดก่อนหน้า
หากคำสั่งหรือนิพจน์ PHP อื่นทำให้เกิดข้อความเตือนหรือการแจ้งเตือนถูกพิมพ์ออกมาสิ่งนั้นก็นับเป็นการส่งออกก่อนกำหนดเช่นกัน
ในกรณีนี้คุณจำเป็นต้องหลีกเลี่ยงข้อผิดพลาดชะลอการดำเนินการคำสั่งหรือระงับข้อความด้วยเช่นisset()หรือ@()- เมื่ออย่างใดอย่างหนึ่งไม่ขัดขวางการดีบักในภายหลัง
ไม่มีข้อความแสดงข้อผิดพลาด
หากคุณมีerror_reporting
หรือdisplay_errors
ปิดใช้งานphp.ini
จะไม่มีคำเตือนปรากฏขึ้น แต่การเพิกเฉยต่อข้อผิดพลาดจะไม่ทำให้ปัญหาหมดไป ยังไม่สามารถส่งส่วนหัวได้หลังจากเอาต์พุตก่อนกำหนด
ดังนั้นเมื่อการheader("Location: ...")
เปลี่ยนเส้นทางล้มเหลวโดยไม่ได้ตั้งใจขอแนะนำให้ตรวจสอบคำเตือน เปิดใช้งานอีกครั้งด้วยคำสั่งง่ายๆสองคำสั่งบนสคริปต์การเรียกใช้:
error_reporting(E_ALL);
ini_set("display_errors", 1);
หรือset_error_handler("var_dump");
ถ้าทุกอย่างล้มเหลว
เมื่อพูดถึงส่วนหัวการเปลี่ยนเส้นทางคุณควรใช้สำนวนเช่นนี้สำหรับพา ธ โค้ดขั้นสุดท้าย:
exit(header("Location: /finished.html"));
ควรเป็นฟังก์ชันยูทิลิตี้ซึ่งพิมพ์ข้อความผู้ใช้ในกรณีที่เกิดheader()
ความล้มเหลว
การบัฟเฟอร์เอาต์พุตเป็นวิธีแก้ปัญหาชั่วคราว
PHPs บัฟเฟอร์เอาต์พุตเป็นวิธีแก้ปัญหาเพื่อบรรเทาปัญหานี้ มักจะทำงานได้อย่างน่าเชื่อถือ แต่ไม่ควรแทนที่การจัดโครงสร้างแอปพลิเคชันที่เหมาะสมและแยกเอาต์พุตออกจากตรรกะการควบคุม จุดประสงค์ที่แท้จริงคือลดการถ่ายโอนที่เป็นก้อนไปยังเว็บเซิร์ฟเวอร์ให้น้อยที่สุด
output_buffering=การตั้งค่ายังคงสามารถช่วย กำหนดค่าในphp.iniหรือผ่าน. htaccessหรือแม้แต่. user.iniบนการตั้งค่า FPM / FastCGI ที่ทันสมัย
การเปิดใช้งานจะทำให้ PHP สามารถบัฟเฟอร์เอาต์พุตแทนที่จะส่งผ่านไปยังเว็บเซิร์ฟเวอร์ได้ทันที PHP จึงสามารถรวมส่วนหัว HTTPนอกจากนี้ยังสามารถมีส่วนร่วมกับการเรียกไปที่ob_start();ด้านบนสคริปต์การเรียกร้อง อย่างไรก็ตามมีความน่าเชื่อถือน้อยกว่าด้วยเหตุผลหลายประการ:
แม้ว่า
<?php ob_start(); ?>
จะเริ่มต้นสคริปต์แรกช่องว่างหรือ BOM อาจได้รับการสับก่อนการกระทำมันไม่ได้ผลสามารถปกปิดช่องว่างสำหรับเอาต์พุต HTML แต่ทันทีที่ตรรกะของแอปพลิเคชันพยายามส่งเนื้อหาไบนารี (เช่นรูปภาพที่สร้างขึ้น) เอาต์พุตภายนอกที่บัฟเฟอร์จะกลายเป็นปัญหา (จำเป็นต้อง
ob_clean()
เป็นวิธีแก้ปัญหาที่ยาวขึ้น)บัฟเฟอร์มีขนาด จำกัด และสามารถบุกรุกได้ง่ายเมื่อปล่อยให้เป็นค่าเริ่มต้น และนั่นไม่ใช่เหตุการณ์ที่เกิดขึ้นได้ยากเช่นกันยากที่จะติดตามเมื่อมันเกิดขึ้น
ดังนั้นแนวทางทั้งสองจึงไม่น่าเชื่อถือโดยเฉพาะอย่างยิ่งเมื่อสลับระหว่างการตั้งค่าการพัฒนาและ / หรือเซิร์ฟเวอร์ที่ใช้งานจริง ด้วยเหตุนี้การบัฟเฟอร์เอาต์พุตจึงถูกพิจารณาอย่างกว้างขวางว่าเป็นเพียงแค่ไม้ค้ำยัน / วิธีแก้ปัญหาอย่างเคร่งครัด
ดูตัวอย่างการใช้งานพื้นฐานในคู่มือและข้อดีข้อเสียเพิ่มเติม:
- บัฟเฟอร์เอาต์พุตคืออะไร?
- เหตุใดจึงต้องใช้การบัฟเฟอร์เอาต์พุตใน PHP
- การใช้บัฟเฟอร์เอาต์พุตถือเป็นการปฏิบัติที่ไม่ดีหรือไม่?
- ใช้กรณีสำหรับการบัฟเฟอร์เอาต์พุตเป็นวิธีแก้ปัญหาที่ถูกต้องสำหรับ "ส่วนหัวที่ส่งไปแล้ว"
แต่มันทำงานบนเซิร์ฟเวอร์อื่น!?
หากคุณไม่ได้รับคำเตือนส่วนหัวมาก่อนแสดงว่าการตั้งค่า php.ini บัฟเฟอร์เอาต์พุตมีการเปลี่ยนแปลง มีแนวโน้มว่าจะไม่ได้กำหนดค่าบนเซิร์ฟเวอร์ปัจจุบัน / เซิร์ฟเวอร์ใหม่
กำลังตรวจสอบกับ headers_sent()
คุณสามารถใช้headers_sent()เพื่อตรวจสอบได้ตลอดเวลาว่ายัง ... ส่งส่วนหัวได้หรือไม่ ซึ่งมีประโยชน์ในการพิมพ์ข้อมูลตามเงื่อนไขหรือใช้ตรรกะทางเลือกอื่น ๆ
if (headers_sent()) {
die("Redirect failed. Please click on this link: <a href=...>");
}
else{
exit(header("Location: /user.php"));
}
วิธีแก้ปัญหาทางเลือกที่เป็นประโยชน์ ได้แก่ :
<meta>
แท็กHTMLหากแอปพลิเคชันของคุณมีโครงสร้างที่แก้ไขได้ยากวิธีที่ง่าย (แต่ค่อนข้างไม่เป็นมืออาชีพ) ในการอนุญาตให้เปลี่ยนเส้นทางคือการแทรก
<meta>
แท็กHTML การเปลี่ยนเส้นทางสามารถทำได้ด้วย:<meta http-equiv="Location" content="http://example.com/">
หรือด้วยการหน่วงเวลาสั้น ๆ :
<meta http-equiv="Refresh" content="2; url=../target.html">
สิ่งนี้นำไปสู่ HTML ที่ไม่ถูกต้องเมื่อใช้ผ่าน
<head>
ส่วนนี้ เบราว์เซอร์ส่วนใหญ่ยังรับได้เปลี่ยนเส้นทาง JavaScript
อีกทางเลือกหนึ่งคือสามารถใช้การเปลี่ยนเส้นทาง JavaScriptสำหรับการเปลี่ยนเส้นทางหน้า:
<script> location.replace("target.html"); </script>
แม้ว่าสิ่งนี้มักจะเป็นไปตาม HTML มากกว่า
<meta>
วิธีแก้ปัญหา แต่ก็ต้องพึ่งพาไคลเอ็นต์ที่สามารถใช้ JavaScript ได้
อย่างไรก็ตามทั้งสองวิธีสร้างทางเลือกที่ยอมรับได้เมื่อการเรียกส่วนหัว HTTP () ของแท้ล้มเหลว ตามหลักการแล้วคุณมักจะรวมสิ่งนี้เข้ากับข้อความที่ใช้งานง่ายและลิงก์ที่คลิกได้เป็นทางเลือกสุดท้าย (ซึ่งเป็นสิ่งที่ส่วนขยายhttp_redirect () PECL ทำ)
ทำไมsetcookie()
และsession_start()
ยังได้รับผลกระทบ
ทั้งสองอย่างsetcookie()
และsession_start()
จำเป็นต้องส่งSet-Cookie:
ส่วนหัว HTTP ดังนั้นจึงใช้เงื่อนไขเดียวกันและข้อความแสดงข้อผิดพลาดที่คล้ายกันจะถูกสร้างขึ้นสำหรับสถานการณ์เอาต์พุตก่อนกำหนด
(แน่นอนว่าพวกเขาได้รับผลกระทบจากคุกกี้ที่ปิดใช้งานในเบราว์เซอร์หรือแม้แต่ปัญหาเกี่ยวกับพร็อกซีเห็นได้ชัดว่าฟังก์ชันเซสชันขึ้นอยู่กับเนื้อที่ว่างในดิสก์และการตั้งค่า php.ini อื่น ๆ เป็นต้น)
ลิงค์เพิ่มเติม
- Google มีรายการยาวของการอภิปรายที่คล้ายกัน
- และแน่นอนว่ามีการครอบคลุมกรณีเฉพาะจำนวนมากใน Stack Overflow ด้วยเช่นกัน
- คำถามที่พบบ่อยของ Wordpress อธิบายฉันจะแก้ปัญหาส่วนหัวที่ส่งคำเตือนไปแล้วได้อย่างไร ในลักษณะทั่วไป
- Adobe Community: การพัฒนา PHP: ทำไมการเปลี่ยนเส้นทางไม่ทำงาน (ส่งส่วนหัวไปแล้ว)
- คำถามที่พบบ่อยเกี่ยวกับนิวเคลียส: "ส่วนหัวของหน้าถูกส่งไปแล้ว" หมายความว่าอย่างไร
- หนึ่งในคำอธิบายที่ละเอียดกว่านี้คือHTTP Headers และ PHP header () Function - บทช่วยสอนโดย NicholasSolutions (ลิงก์ Internet Archive) ครอบคลุมรายละเอียด HTTP และให้แนวทางบางประการสำหรับการเขียนสคริปต์ใหม่
ข้อความแสดงข้อผิดพลาดนี้จะถูกทริกเกอร์เมื่อมีการส่งสิ่งใด ๆก่อนที่คุณจะส่งส่วนหัว HTTP (มีsetcookieหรือheader) สาเหตุทั่วไปในการส่งออกบางสิ่งก่อนส่วนหัว HTTP คือ:
ช่องว่างโดยบังเอิญมักอยู่ที่จุดเริ่มต้นหรือจุดสิ้นสุดของไฟล์เช่นนี้
<?php // Note the space before "<?php" ?>
เพื่อหลีกเลี่ยงปัญหานี้เพียงแค่ละทิ้งการปิด?>
- ไม่จำเป็นต้องใช้อีกต่อไป
- ลำดับไบต์ทำเครื่องหมายที่จุดเริ่มต้นของไฟล์ php ตรวจสอบไฟล์ php ของคุณด้วยตัวแก้ไขฐานสิบหกเพื่อดูว่าเป็นเช่นนั้นหรือไม่
3F 3C
พวกเขาควรจะเริ่มต้นด้วยไบต์ คุณสามารถลบ BOM ได้อย่างปลอดภัยEF BB BF
ตั้งแต่เริ่มต้นไฟล์ - การส่งออกอย่างชัดเจนเช่นการโทรไป
echo
,printf
,readfile
,passthru
รหัสก่อน<?
ฯลฯ - คำเตือนออกมาโดย php หากdisplay_errorsคุณสมบัติ php.ini ถูกตั้งค่าไว้ แทนที่จะหยุดทำงานด้วยความผิดพลาดของโปรแกรมเมอร์ php จะแก้ไขข้อผิดพลาดและส่งเสียงเตือน ในขณะที่คุณสามารถแก้ไขการกำหนดค่าdisplay_errorsหรือerror_reporting ได้แต่คุณควรแก้ไขปัญหาดังกล่าว
สาเหตุทั่วไปคือการเข้าถึงองค์ประกอบที่ไม่ได้กำหนดของอาร์เรย์ (เช่น$_POST['input']
โดยไม่ใช้emptyหรือissetเพื่อทดสอบว่าอินพุตถูกตั้งค่าไว้หรือไม่) หรือใช้ค่าคงที่ที่ไม่ได้กำหนดแทนสตริงลิเทอรัล (เช่นใน$_POST[input]
หมายเหตุเครื่องหมายคำพูดที่ขาดหายไป)
การเปิดบัฟเฟอร์เอาต์พุตควรทำให้ปัญหาหายไป การส่งออกทั้งหมดหลังจากการเรียกร้องให้มีบัฟเฟอร์ในหน่วยความจำจนกว่าคุณจะปล่อยบัฟเฟอร์เช่นกับob_startob_end_flush
อย่างไรก็ตามในขณะที่การบัฟเฟอร์เอาต์พุตหลีกเลี่ยงปัญหาคุณควรพิจารณาว่าเหตุใดแอปพลิเคชันของคุณจึงส่งออกเนื้อหา HTTP ก่อนส่วนหัว HTTP นั่นก็เหมือนกับการรับโทรศัพท์และพูดคุยเกี่ยวกับวันและสภาพอากาศของคุณก่อนที่จะบอกผู้โทรว่าเขาได้รับหมายเลขผิด
ฉันได้รับข้อผิดพลาดนี้หลายครั้งก่อนหน้านี้และฉันมั่นใจว่าโปรแกรมเมอร์ PHP ทุกคนได้รับข้อผิดพลาดนี้อย่างน้อยหนึ่งครั้งก่อนหน้านี้
แนวทางแก้ไขที่เป็นไปได้ 1
ข้อผิดพลาดนี้อาจเกิดจากช่องว่างก่อนเริ่มไฟล์หรือหลังสิ้นสุดไฟล์ช่องว่างเหล่านี้ไม่ควรอยู่ที่นี่
เช่นไม่ควรมีพื้นที่ว่างที่นี่
echo "your code here";
?>
THERE SHOULD BE NO BLANK SPACES HERE
ตรวจสอบไฟล์ทั้งหมดที่เกี่ยวข้องกับไฟล์ที่ทำให้เกิดข้อผิดพลาดนี้
หมายเหตุ: บางครั้ง EDITOR (IDE) เช่น gedit (ตัวแก้ไข linux เริ่มต้น) จะเพิ่มบรรทัดว่างหนึ่งบรรทัดในไฟล์บันทึก สิ่งนี้ไม่ควรเกิดขึ้น หากคุณใช้ Linux คุณสามารถใช้ตัวแก้ไข VI เพื่อลบช่องว่าง / บรรทัดหลัง?> ที่ท้ายเพจ
แนวทางที่เป็นไปได้ 2:หากไม่ใช่กรณีของคุณให้ใช้ob_startเพื่อส่งออกบัฟเฟอร์:
<?php
ob_start();
// code
ob_end_flush();
?>
การดำเนินการนี้จะเปิดการบัฟเฟอร์เอาต์พุตและส่วนหัวของคุณจะถูกสร้างขึ้นหลังจากที่เพจถูกบัฟเฟอร์
แทนบรรทัดด้านล่าง
//header("Location:".ADMIN_URL."/index.php");
เขียน
echo("<script>location.href = '".ADMIN_URL."/index.php?msg=$msg';</script>");
หรือ
?><script><?php echo("location.href = '".ADMIN_URL."/index.php?msg=$msg';");?></script><?php
มันจะแก้ปัญหาของคุณได้อย่างแน่นอน ฉันประสบปัญหาเดียวกัน แต่ฉันแก้ไขด้วยการเขียนตำแหน่งส่วนหัวด้วยวิธีข้างต้น
คุณทำ
printf ("Hi %s,</br />", $name);
ก่อนตั้งค่าคุกกี้ซึ่งไม่ได้รับอนุญาต คุณไม่สามารถส่งเอาต์พุตก่อนส่วนหัวหรือแม้แต่บรรทัดว่าง
ปัญหาทั่วไป:
(คัดลอกมาจาก: แหล่งที่มา )
====================
1)ไม่ควรมีเอาต์พุตใด ๆ (เช่นecho..
หรือโค้ด HTML) ก่อนheader(.......);
คำสั่ง
2)ลบช่องว่าง (หรือขึ้นบรรทัดใหม่ ) ก่อน<?php
และหลัง?>
แท็ก
3) กฎทองคำ! - ตรวจสอบว่าไฟล์ php นั้น (และถ้าเป็นinclude
ไฟล์อื่นของคุณ) มีUTF8 โดยไม่มีการเข้ารหัสBOM (ไม่ใช่แค่UTF-8 ) นั่นเป็นปัญหาในหลาย ๆ กรณี (เนื่องจากไฟล์ที่เข้ารหัสUTF8มีอักขระพิเศษบางอย่างในจุดเริ่มต้นของไฟล์ php ซึ่งโปรแกรมแก้ไขข้อความของคุณไม่แสดง) !!!!!!!!!!!
4)หลังจากที่header(...);
คุณต้องใช้exit;
5)ใช้การอ้างอิง 301 หรือ 302 เสมอ:
header("location: http://example.com", true, 301 ); exit;
6) เปิดการรายงานข้อผิดพลาดและค้นหาข้อผิดพลาด ข้อผิดพลาดของคุณอาจเกิดจากฟังก์ชันที่ไม่ทำงาน เมื่อคุณเปิดการรายงานข้อผิดพลาดคุณควรแก้ไขข้อผิดพลาดสูงสุดก่อนเสมอ ตัวอย่างเช่นอาจเป็น "คำเตือน: date_default_timezone_get (): ไม่ปลอดภัยที่จะพึ่งพาการตั้งค่าเขตเวลาของระบบ" - จากนั้นยิ่งลงไปอีกคุณอาจเห็นข้อผิดพลาด "ไม่ได้ส่งส่วนหัว" หลังจากแก้ไขข้อผิดพลาดสูงสุด (อันดับแรก) แล้วให้โหลดหน้าเว็บของคุณใหม่ หากคุณยังคงมีข้อผิดพลาดให้แก้ไขข้อผิดพลาดสูงสุดอีกครั้ง
7)หากไม่สามารถช่วยได้ให้ใช้การเปลี่ยนเส้นทาง JAVSCRIPT (อย่างไรก็ตามวิธีที่ไม่แนะนำอย่างยิ่ง) อาจเป็นโอกาสสุดท้ายในกรณีที่กำหนดเอง ... :
echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;
เป็นเพราะบรรทัดนี้:
printf ("Hi %s,</br />", $name);
คุณไม่ควรพิมพ์ / สะท้อนสิ่งใด ๆ ก่อนส่งส่วนหัว
เคล็ดลับง่ายๆ: ช่องว่างง่ายๆ (หรืออักขระพิเศษที่มองไม่เห็น) ในสคริปต์ของคุณก่อน<?php
แท็กแรกสามารถทำให้เกิดสิ่งนี้ได้! โดยเฉพาะอย่างยิ่งเมื่อคุณทำงานเป็นทีมและมีใครบางคนกำลังใช้ IDE ที่ "อ่อนแอ" หรือยุ่งเกี่ยวกับไฟล์ด้วยโปรแกรมแก้ไขข้อความแปลก ๆ
ฉันได้เห็นสิ่งเหล่านี้แล้ว;)
การปฏิบัติที่ไม่ดีอีกประการหนึ่งอาจทำให้เกิดปัญหานี้ซึ่งยังไม่ได้ระบุไว้
ดูข้อมูลโค้ดนี้:
<?php
include('a_important_file.php'); //really really really bad practise
header("Location:A location");
?>
ของก็โอเคใช่มั้ย?
จะเกิดอะไรขึ้นถ้า "a_important_file.php" เป็นดังนี้:
<?php
//some php code
//another line of php code
//no line above is generating any output
?>
----------This is the end of the an_important_file-------------------
นี้จะไม่ทำงาน? เพราะมีการสร้างบรรทัดใหม่แล้ว
ตอนนี้แม้ว่านี่จะไม่ใช่สถานการณ์ทั่วไปถ้าคุณใช้เฟรมเวิร์ก MVC ซึ่งโหลดไฟล์จำนวนมากก่อนที่จะส่งมอบสิ่งต่างๆไปยังคอนโทรลเลอร์ของคุณ? นี่ไม่ใช่สถานการณ์ที่ผิดปกติ เตรียมพร้อมสำหรับเรื่องนี้
จากPSR-2 2.2:
- ไฟล์ PHP ทั้งหมดต้องใช้ไฟล์
Unix LF (linefeed) line ending
. - ไฟล์ PHP ทั้งหมดต้องลงท้ายด้วยไฟล์
single blank line
. - แท็กปิด?> ต้องมา
omitted
จากไฟล์ที่มีonly php
เชื่อฉันเถอะว่าการทำตามมาตรฐานนี้สามารถช่วยชีวิตคุณได้หลายชั่วโมง :)
บางครั้งเมื่อกระบวนการ dev มีทั้งสถานีงาน WIN และระบบ LINUX (โฮสติ้ง) และในโค้ดคุณไม่เห็นผลลัพธ์ใด ๆ ก่อนบรรทัดที่เกี่ยวข้องอาจเป็นการจัดรูปแบบของไฟล์และไม่มีการสิ้นสุดบรรทัดUnix LF (linefeed) .
สิ่งที่เรามักจะทำเพื่อแก้ไขปัญหานี้อย่างรวดเร็วคือการเปลี่ยนชื่อไฟล์และบนระบบ LINUX สร้างไฟล์ใหม่แทนไฟล์ที่เปลี่ยนชื่อจากนั้นคัดลอกเนื้อหาลงในนั้น หลายครั้งการแก้ปัญหานี้เนื่องจากไฟล์บางไฟล์ที่สร้างขึ้นใน WIN เมื่อย้ายไปที่โฮสติ้งทำให้เกิดปัญหานี้
การแก้ไขนี้เป็นการแก้ไขที่ง่ายสำหรับไซต์ที่เราจัดการโดย FTP และบางครั้งอาจช่วยสมาชิกทีมใหม่ของเราได้บ้าง
โดยทั่วไปข้อผิดพลาดนี้จะเกิดขึ้นเมื่อเราส่งส่วนหัวหลังจากสะท้อนหรือพิมพ์ start_session()
หากข้อผิดพลาดนี้เกิดขึ้นบนหน้าเว็บที่เฉพาะเจาะจงแล้วให้แน่ใจว่าหน้าไม่ได้สะท้อนอะไรก่อนที่โทรไป
ตัวอย่างข้อผิดพลาดที่คาดเดาไม่ได้:
<?php //a white-space before <?php also send for output and arise error
session_start();
session_regenerate_id();
//your page content
อีกหนึ่งตัวอย่าง:
<?php
includes 'functions.php';
?> <!-- This new line will also arise error -->
<?php
session_start();
session_regenerate_id();
//your page content
สรุป: อย่าส่งออกอักขระใด ๆ ก่อนที่จะเรียกsession_start()
หรือheader()
ฟังก์ชันที่ไม่เว้นแม้แต่ช่องว่างหรือบรรทัดใหม่