วิธีแก้ไขข้อผิดพลาด“ ส่วนหัวที่ส่งไปแล้ว” ใน PHP


831

เมื่อเรียกใช้สคริปต์ของฉันฉันได้รับข้อผิดพลาดหลายอย่างเช่นนี้:

คำเตือน: ไม่สามารถแก้ไขข้อมูลส่วนหัว - ส่วนหัวที่ส่งไปแล้ว ( เอาต์พุตเริ่มที่ /some/file.php:12 ) ใน/some/file.phpที่บรรทัดที่ 23

บรรทัดที่กล่าวถึงในข้อความแสดงข้อผิดพลาดประกอบด้วยheader()และการsetcookie()โทร

อะไรคือสาเหตุของสิ่งนี้ และจะแก้ไขอย่างไร?



ตรวจสอบให้แน่ใจว่าไม่มีข้อความใดแสดงผล ( ob_startและob_end_clean() อาจพิสูจน์ได้ว่ามีประโยชน์ที่นี่) จากนั้นคุณสามารถตั้งค่าคุกกี้หรือเซสชันเท่ากับob_get_contents()และใช้ob_end_clean()เพื่อล้างบัฟเฟอร์
Jack Tuck

ใช้safeRedirectฟังก์ชั่นในห้องสมุด PHP ของฉัน: github.com/heinkasner/PHP-Library/blob/master/extra.php
heinkasner

5
~~~~~~~~~~ ไฟล์การเข้ารหัสของคุณไม่ควรเป็นUTF-8แต่UTF-8 (Without BOM)~~~~~~~~~~~~
T.Todua

คำตอบ:


2997

ไม่มีเอาต์พุตก่อนส่งส่วนหัว!

ฟังก์ชั่นที่ส่ง / ปรับเปลี่ยนส่วนหัว HTTP จะต้องถูกเรียกก่อนที่จะส่งออกใด ๆ ที่จะทำ summary ⇊ มิฉะนั้นการโทรจะล้มเหลว:

คำเตือน: ไม่สามารถแก้ไขข้อมูลส่วนหัว - ส่วนหัวที่ส่งไปแล้ว (เอาต์พุตเริ่มต้นที่สคริปต์: บรรทัด )

บางฟังก์ชั่นการปรับเปลี่ยนส่วนหัว HTTP คือ:

ผลผลิตสามารถ:

  • โดยไม่ได้ตั้งใจ:

  • เจตนา:

    • 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นั่นคือสิ่งที่คุณต้องมองหาผลลัพธ์ก่อนกำหนด

สาเหตุทั่วไป:

  1. พิมพ์ echo

    เอาต์พุตโดยเจตนาจากprintและechoข้อความสั่งจะยุติโอกาสในการส่งส่วนหัว HTTP โฟลว์แอปพลิเคชันต้องถูกปรับโครงสร้างใหม่เพื่อหลีกเลี่ยงปัญหานั้น ใช้ฟังก์ชั่น และแผนการสร้างเทมเพลต ให้แน่ใจheader()ว่ามีการโทรเกิดขึ้นก่อนข้อความจะถูกเขียนออกมา

    ฟังก์ชั่นที่ผลิตผลผลิตรวมถึง

    • print, echo, printf,vprintf
    • trigger_error, ob_flush, ob_end_flush, var_dump,print_r
    • readfile, passthru, flush, imagepng,imagejpeg


    ในหมู่ผู้อื่นและฟังก์ชั่นที่ผู้ใช้กำหนด

  2. พื้นที่ HTML ดิบ

    ส่วน HTML ที่ไม่ได้แยกวิเคราะห์ใน.phpไฟล์เป็นเอาต์พุตโดยตรงเช่นกัน เงื่อนไขของสคริปต์ที่จะทริกเกอร์การheader()โทรต้องถูกบันทึกไว้ก่อนบล็อกดิบใด ๆ<html>

    <!DOCTYPE html>
    <?php
        // Too late for headers already.

    ใช้ชุดรูปแบบ templating เพื่อแยกการประมวลผลจากตรรกะเอาต์พุต

    • วางโค้ดการประมวลผลแบบฟอร์มบนสคริปต์
    • ใช้ตัวแปรสตริงชั่วคราวเพื่อเลื่อนข้อความ
    • ตรรกะเอาท์พุทที่เกิดขึ้นจริงและเอาท์พุท HTML ผสมควรจะปฏิบัติตามล่าสุด

  3. ช่องว่างก่อน<?phpสำหรับ "script.php บรรทัด 1คำเตือน "

    หากคำเตือนหมายถึงเอาต์พุตในบรรทัดแสดง1ว่าส่วนใหญ่จะเป็นช่องว่างนำหน้าข้อความหรือ HTML หน้า<?phpโทเค็นการเปิด

     <?php
    # There's a SINGLE space/newline before <? - Which already seals it.

    ในทำนองเดียวกันมันสามารถเกิดขึ้นได้สำหรับสคริปต์ต่อท้ายหรือส่วนของสคริปต์:

    ?>
    
    <?php

    PHP กินค่าการทำลายบรรทัดเดียวหลังจากแท็กปิด แต่จะไม่ชดเชยบรรทัดใหม่หรือแท็บหรือช่องว่างหลายรายการที่เปลี่ยนเป็นช่องว่างดังกล่าว

  4. UTF-8 BOM

    Linebreaks และช่องว่างเพียงอย่างเดียวอาจเป็นปัญหาได้ แต่ยังมีลำดับอักขระที่ "มองไม่เห็น" ซึ่งอาจทำให้เกิดสิ่งนี้ ส่วนใหญ่ชื่อเสียง UTF-8 BOM (Byte-Order-Mark) ซึ่งไม่ได้แสดงโดยแก้ไขข้อความมากที่สุด เป็นลำดับไบต์EF BB BFซึ่งเป็นทางเลือกและซ้ำซ้อนสำหรับเอกสารที่เข้ารหัส UTF-8 อย่างไรก็ตาม PHP ต้องถือว่ามันเป็นผลดิบ มันอาจปรากฏเป็นตัวละครในผลลัพธ์ (ถ้าไคลเอนต์ตีความเอกสารเป็นละติน -1) หรือ "ขยะ" ที่คล้ายกัน

    โดยเฉพาะตัวแก้ไขกราฟิกและ IDEs ที่ใช้ Java จะไม่สนใจสถานะของมัน พวกเขาไม่เห็นภาพ (บังคับโดยมาตรฐาน Unicode) โปรแกรมเมอร์และคอนโซลส่วนใหญ่อย่างไรก็ตาม:

    เครื่องมือแก้ไข joes แสดงตัวยึดตำแหน่ง BOM UTF-8 และจุดแก้ไข MC

    มันง่ายที่จะรับรู้ปัญหาก่อน บรรณาธิการอื่น ๆ อาจระบุว่ามีอยู่ในเมนูไฟล์ / การตั้งค่า (Notepad ++ บน Windows สามารถระบุและ แก้ไขปัญหาที่เกิดขึ้น ) ตัวเลือกในการตรวจสอบการปรากฏ BOMs ก็คือการหันไปยังHexEditor hexdumpโดยปกติแล้วในระบบ * nix จะใช้งานได้หากไม่ใช่ตัวแปรแบบกราฟิกซึ่งช่วยให้การตรวจสอบง่ายขึ้นและปัญหาอื่น ๆ :

    beav hexeditor แสดง utf-8 bom

    การแก้ไขที่ง่ายคือการตั้งค่าเครื่องมือแก้ไขข้อความเพื่อบันทึกไฟล์เป็น "UTF-8 (ไม่มี BOM)" หรือชื่อที่คล้ายกัน ผู้ใช้ใหม่มักจะหันไปใช้การสร้างไฟล์ใหม่และเพียงแค่คัดลอกและวางโค้ดก่อนหน้านี้อีกครั้ง

    ยูทิลิตี้การแก้ไข

    นอกจากนี้ยังมีเครื่องมืออัตโนมัติเพื่อตรวจสอบและเขียนไฟล์ข้อความ ( sed/awkหรือrecode ) สำหรับ PHP เฉพาะมีของtidierphptags แท็ก มันเขียนแท็กปิดและเปิดในรูปแบบที่ยาวและสั้น แต่ยังสามารถแก้ไขช่องว่างชั้นนำและต่อท้ายปัญหา Unicode และ UTF-x BOM ได้อย่างง่ายดาย:

    phptags  --whitespace  *.php

    มันมีเหตุผลที่จะใช้ในไดเรกทอรีรวมหรือโครงการ

  5. ช่องว่างหลังจาก ?>

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

    แนะนำโดยเฉพาะอย่างยิ่งกับผู้มาใหม่ที่?>ควรหลีกเลี่ยงแท็กปิด PHP ต่อท้าย นี้หลีกเลี่ยงส่วนเล็ก ๆ ของกรณีเหล่านี้ ค่อนข้างบ่อยinclude()dสคริปต์เป็นผู้ร้าย)

  6. แหล่งข้อผิดพลาดที่กล่าวถึงเป็น "ไม่รู้จักในบรรทัด 0"

    โดยทั่วไปแล้วจะเป็นการตั้งค่าส่วนขยาย PHP หรือ php.ini หากไม่มีการแก้ไขข้อผิดพลาดที่มา

    • เป็นการgzipตั้งค่าการเข้ารหัสสตรีม เป็นครั้งคราวหรือob_gzhandlerหรือ
    • แต่มันก็อาจจะเป็นextension=โมดูลที่โหลดเป็นสองเท่าสร้างข้อความเริ่มต้น / เตือน PHP โดยปริยาย

  7. ก่อนข้อความผิดพลาด

    หากคำสั่งหรือนิพจน์ 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 เป็นวิธีแก้ไขปัญหาเพื่อบรรเทาปัญหานี้ มันมักจะทำงานได้อย่างน่าเชื่อถือ แต่ไม่ควรแทนที่การสร้างแอปพลิเคชันที่เหมาะสมและแยกออกจากตรรกะการควบคุม วัตถุประสงค์ที่แท้จริงคือลดการถ่ายโอนข้อมูลจำนวนน้อยไปยังเว็บเซิร์ฟเวอร์

  1. การoutput_buffering= ตั้งค่าสามารถช่วยได้ กำหนดค่าในphp.ini หรือผ่าน. htaccess หรือ . user.iniในการตั้งค่า FPM / FastCGI ที่ทันสมัย
    การเปิดใช้งานจะช่วยให้ PHP สามารถบัฟเฟอร์เอาต์พุตแทนที่จะส่งไปยังเว็บเซิร์ฟเวอร์ทันที PHP จึงสามารถรวมส่วนหัว HTTP

  2. นอกจากนี้ยังสามารถมีส่วนร่วมกับการเรียกร้องให้ob_start(); อยู่เหนือสคริปต์ภาวนา ซึ่งมีความน่าเชื่อถือน้อยกว่าด้วยเหตุผลหลายประการ:

    • แม้ว่า<?php ob_start(); ?>จะเริ่มต้นสคริปต์แรกช่องว่างหรือ BOM อาจได้รับการสับก่อนการกระทำมันไม่ได้ผล

    • มันสามารถปกปิดช่องว่างสำหรับการส่งออก HTML แต่ทันทีที่แอปพลิเคชันตรรกะพยายามส่งเนื้อหาไบนารี (รูปภาพที่สร้างขึ้น) เอาต์พุตภายนอกที่บัฟเฟอร์จะกลายเป็นปัญหา (จำเป็นob_clean() ต้องมีวิธีแก้ปัญหาแบบเร่งด่วน)

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

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

ดูตัวอย่างการใช้งานพื้นฐาน ในคู่มือและดูข้อดีและข้อเสียเพิ่มเติมได้ที่:

แต่มันทำงานบนเซิร์ฟเวอร์อื่น!

หากคุณไม่ได้รับคำเตือนส่วนหัวมาก่อนการตั้งค่าบัฟเฟอร์บัฟเฟอร์เอาต์พุต จะเปลี่ยนไป อาจไม่ได้กำหนดค่าไว้ในเซิร์ฟเวอร์ปัจจุบัน / ใหม่

กำลังตรวจสอบกับ headers_sent()

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

if (headers_sent()) {
    die("Redirect failed. Please click on this link: <a href=...>");
}
else{
    exit(header("Location: /user.php"));
}

วิธีแก้ปัญหาทางเลือกที่มีประโยชน์คือ:

  • HTML <meta>แท็ก

    หากแอปพลิเคชันของคุณมีโครงสร้างที่ยากต่อการแก้ไขวิธีที่ง่าย (แต่ค่อนข้างไม่เป็นมืออาชีพ) ในการอนุญาตการเปลี่ยนเส้นทางคือการฉีด<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 อื่น ๆ ด้วย)

ลิงค์เพิ่มเติม


นอกจากนี้ notepad.exe ปกตินั้นยังมีความยุ่งยาก ฉันมักใช้ NetBeans ซึ่งไม่ได้เพิ่ม BOM แม้ว่าไฟล์จะถูกเข้ารหัส การแก้ไขไฟล์ในภายหลังใน Notepad จะทำให้เกิดความยุ่งเหยิงโดยเฉพาะอย่างยิ่งต่อ IIS ในฐานะเว็บเซิร์ฟเวอร์ ดูเหมือนว่าอาปาเช่ทิ้ง BOM (เพิ่มเข้าหน่วย)
Teson

4
การลบการปิด?>ออกจากท้ายไฟล์ php มักเป็นวิธีปฏิบัติที่ดีซึ่งจะช่วยลดข้อผิดพลาดเหล่านี้ให้น้อยที่สุดเช่นกัน ช่องว่างที่ไม่ต้องการจะไม่เกิดขึ้นในตอนท้ายของไฟล์และคุณจะยังสามารถเพิ่มส่วนหัวในการตอบสนองในภายหลัง นอกจากนี้ยังมีประโยชน์ถ้าคุณใช้บัฟเฟอร์การส่งออกและไม่ต้องการที่จะเห็นช่องว่างที่ไม่พึงประสงค์เพิ่มในตอนท้ายของชิ้นส่วนที่สร้างขึ้นโดยไฟล์ที่รวม
Nikita 웃

ฉันย้ายไฟล์ของฉันจาก cPanel Linux Hosting ไปที่ VPS ก่อนที่มันจะทำงานอย่างถูกต้อง แต่ที่นี่มันแสดงให้เห็นข้อผิดพลาดนี้ (ฉันมีรหัส html ก่อนส่วนหัว) ทำไม?
Pablo Escobar

@Purushotamrawat คุณอ่านส่วนเกี่ยวกับ " แต่มันทำงานบนเซิร์ฟเวอร์อื่น ๆ ! "
mario

1
@PeterSMcIntyre UTF8 BOM น่าจะเป็น (แก้ไขนั้น) / ไม่เปิดใช้งานการบัฟเฟอร์เอาต์พุต (ไม่ต้องพึ่งพาสิ่งนั้น)
มาริโอ

199

ข้อความแสดงข้อผิดพลาดนี้จะถูกทริกเกอร์เมื่อมีการส่งสิ่งใดก่อนที่คุณจะส่งส่วนหัว HTTP (ด้วยsetcookieหรือheader) สาเหตุทั่วไปของการแสดงผลบางอย่างก่อนส่วนหัว HTTP คือ:

  • ช่องว่างที่เกิดขึ้นบ่อยครั้งที่จุดเริ่มต้นหรือจุดสิ้นสุดของไฟล์เช่นนี้:

     <?php
    // Note the space before "<?php"
    ?>

       เพื่อหลีกเลี่ยงปัญหานี้เพียงแค่ปิดการปิด?>เอาไว้ - มันไม่จำเป็นเลย

  • ทำเครื่องหมายคำสั่งไบต์ที่จุดเริ่มต้นของไฟล์ php ตรวจสอบไฟล์ php ของคุณด้วยโปรแกรมแก้ไข hex เพื่อตรวจสอบว่าเป็นจริงหรือไม่ 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 นั่นก็เหมือนกับการรับโทรศัพท์และพูดคุยเกี่ยวกับวันของคุณและสภาพอากาศก่อนที่จะบอกผู้โทรว่าเขามีเบอร์ผิด


ช่วยฉันด้วยขอบคุณ
Vishwa Pratap

122

ฉันได้รับข้อผิดพลาดนี้หลายครั้งก่อนและฉันมั่นใจว่าโปรแกรมเมอร์ 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();
?> 

นี่จะเป็นการเปิดบัฟเฟอร์การส่งออกและส่วนหัวของคุณจะถูกสร้างขึ้นหลังจากที่หน้าถูกบัฟเฟอร์


18
ob_start()เพียงซ่อนปัญหา อย่าใช้เพื่อแก้ปัญหานี้
Ja͢ck

@ Ja͢ckถ้าฉันไม่ใช้ob_start()แล้วฉันควรทำอย่างไรเพื่อแก้ปัญหานี้:Headers already sent
Shafizadeh

@Sadad หากคุณได้รับข้อผิดพลาดโดยเฉพาะเนื่องจากตัวแก้ไขที่คุณใช้อยู่คุณควรเล่นซอกับการตั้งค่าเพื่อหยุดปัญหาที่เกิดขึ้นหรือสลับผู้แก้ไข หากคุณได้รับข้อผิดพลาดด้วยเหตุผลอื่นคุณควรอ่านคำตอบในคำถามนี้ (โดยเฉพาะคำตอบที่ยอมรับ) เพื่อหาว่าปัญหาคืออะไรจริงและแก้ปัญหาได้
Samsquanch

3
ob_start()ไม่ได้"ซ่อน"ปัญหา แต่จะแก้ปัญหาได้
TMS

1
ฉันมีปัญหาดังกล่าวเมื่อฉันอัปโหลดไฟล์ไปยังเซิร์ฟเวอร์ซึ่งรองรับแม้กระทั่ง PHP5.3 ใช้เซิร์ฟเวอร์ที่มี PHP 5.6 ขึ้นไป
GGSoft

86

แทนที่จะเป็นบรรทัดด้านล่าง

//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

แน่นอนมันจะแก้ปัญหาของคุณ ฉันประสบปัญหาเดียวกัน แต่ฉันแก้ไขด้วยการเขียนตำแหน่งส่วนหัวด้วยวิธีด้านบน


41

คุณทำ

printf ("Hi %s,</br />", $name);

ก่อนตั้งค่าคุกกี้ซึ่งไม่ได้รับอนุญาต คุณไม่สามารถส่งออกก่อนส่วนหัวไม่ได้เป็นบรรทัดว่าง


32

มันเป็นเพราะสายนี้:

printf ("Hi %s,</br />", $name);

คุณไม่ควรพิมพ์ / echoอะไรก่อนส่งส่วนหัว


31

ปัญหาทั่วไป:

(คัดลอกมาจาก: แหล่งที่มา )

====================

1)ไม่ควรมีผลลัพธ์ (เช่นecho..หรือรหัส HTML) ก่อนหน้าheader(.......);คำสั่ง

2)ลบwhite-space (หรือขึ้นบรรทัดใหม่ ) ก่อน<?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 (): ไม่ปลอดภัยที่จะเชื่อถือการตั้งค่าเขตเวลาของระบบ" - จากนั้นยิ่งลดลงคุณอาจเห็นข้อผิดพลาด "ส่วนหัวที่ไม่ได้ส่ง" หลังจากแก้ไขข้อผิดพลาดสูงสุด (อันดับที่ 1) ให้โหลดหน้าเว็บของคุณอีกครั้ง หากคุณยังคงมีข้อผิดพลาดให้แก้ไขข้อผิดพลาดบนสุดอีกครั้ง

7)หากไม่มีวิธีการข้างต้นให้ใช้การเปลี่ยนเส้นทาง JAVSCRIPT (อย่างไรก็ตามวิธีการที่ไม่แนะนำอย่างยิ่ง) อาจเป็นโอกาสสุดท้ายในกรณีที่กำหนดเอง ... :

echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;

ทำไมการตั้งค่า301หรือ302มีความสำคัญอย่างชัดเจน?
Jānis Elmeris

26

เคล็ดลับง่ายๆ: พื้นที่ว่าง (หรืออักขระพิเศษที่มองไม่เห็น) ในสคริปต์ของคุณตรงหน้า<?phpแท็กแรกอาจทำให้เกิดสิ่งนี้! โดยเฉพาะอย่างยิ่งเมื่อคุณทำงานในทีมและมีคนใช้ IDE "อ่อน" หรือมีไฟล์ในโปรแกรมแก้ไขข้อความแปลก ๆ

ฉันได้เห็นสิ่งเหล่านี้;)


22

การฝึกฝนที่ไม่ดีอีกวิธีหนึ่งสามารถเรียกใช้ปัญหานี้ซึ่งยังไม่ได้ระบุได้

ดูตัวอย่างรหัสนี้:

<?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 ทั้งหมดต้องลงท้ายด้วย a single blank line.
  • แท็กปิด?> ต้องมาomittedจากไฟล์ที่มีonly php

เชื่อฉันการทำตามมาตรฐานเหล่านี้จะช่วยให้คุณประหยัดเวลาได้มากในชีวิต :)


2
ตามมาตรฐานหลายประการ (เช่น Zend) คุณไม่ควรใส่?>แท็กปิดในไฟล์ใด ๆ ไม่ว่ากรณีใด ๆ
Daniel W.

ฉันไม่สามารถทำซ้ำสิ่งนี้ในสภาพแวดล้อม Windows เพราะมันทำงานโดยใช้ชุดค่าผสมใด ๆ (เพิ่มแท็กปิดช่องว่างการกดปุ่ม Enter ฯลฯ ) ดูเหมือนว่าปัญหานี้เกิดขึ้นส่วนใหญ่ในสภาพแวดล้อม Linux
จูเนียร์Mayhé

@JuniorM มันควรจะทำซ้ำได้ คุณสามารถแบ่งปันรหัสที่คุณกำลังทดลองในส่วนสำคัญหรือสิ่งเดียวกันได้หรือไม่?
นพ. Sahib Bin Mahboob

ฉันใช้ Windows 7 พร้อมติดตั้ง Wamp ล่าสุด ฉันคิดว่าข้อผิดพลาดนี้เกี่ยวข้องกับตัวละครที่ซ่อนอยู่ตอนท้ายบรรทัด shortcodes.php My Wordpress ของฉันเป็นสาเหตุของปัญหา ฉันเพิ่มลงในไฟล์นี้เป็นฟังก์ชั่นง่าย ๆ และมันเริ่มทำงานผิดพลาด "ส่วนหัวที่ส่ง" นี้ ฉันได้เปรียบเทียบ shortcodes.php ของฉันกับ wordpress 'และมันก็โอเคยกเว้นCR LF(ปลายทั่วไปของ Windows) ฉันแก้มันด้วยการดาวน์โหลดไฟล์ต้นฉบับจาก Wordpress repo ที่มีLF(Linux end of line) แทนCR LFและฉันก็ย้ายฟังก์ชั่นของฉันไปเป็นฟังก์ชั่นของ theme.php ขึ้นอยู่กับ: bit.ly/1Gh6mzN
Junior Mayhé

@Sahib สังเกตว่าฉันยังคงไม่สามารถทำซ้ำสิ่งที่ระบุไว้ในคำตอบนี้ คำตอบนั้นดีสำหรับสภาพแวดล้อม Linux ฉันมีการทดสอบสิ่งที่ว่างเปล่าเช่นระหว่างการลบและการเพิ่มบรรทัดว่างเดียวเพิ่มและละเว้นแท็กปิด?> <?php ?>ใน Windows + Wamp ชุดค่าผสมทั้งหมดทำงานได้ดี Wierd ...
Junior Mayhé

15

บางครั้งเมื่อกระบวนการ dev มีทั้งสถานีงาน WIN และระบบ LINUX (โฮสต์) และในโค้ดที่คุณไม่เห็นผลลัพธ์ใด ๆ ก่อนบรรทัดที่เกี่ยวข้องอาจเป็นการจัดรูปแบบของไฟล์และการ สิ้นสุดบรรทัดUnix LF (linefeed) .

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

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


2

โดยทั่วไปแล้วข้อผิดพลาดนี้เกิดขึ้นเมื่อเราส่งส่วนหัวหลังจากสะท้อนหรือพิมพ์ 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()ฟังก์ชั่นที่ไม่เว้นแม้แต่ white-space หรือ new-line

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.