프로그래밍 언어/PHP

PHP에서 "Headers already sent"오류를 수정하는 방법

Rateye 2021. 7. 21. 10:39
728x90
반응형

 

질문 : PHP에서 "Headers already sent"오류를 수정하는 방법

내 스크립트를 실행할 때 다음과 같은 몇 가지 오류가 발생합니다.

경고 : 헤더 정보를 수정할 수 없습니다 -23 행의 /some/file.php에서 (/some/file.php:12에서 시작된 출력) 이미 보낸 헤더

오류 메시지에 언급 된 줄에는 header()setcookie() 호출이 포함됩니다.

그 이유는 무엇일까요? 그리고 그것을 고치는 방법?

답변

HTTP 헤더를 전송 / 수정하는 함수는 출력이 이루어지기 전에 호출되어야합니다.

요약 ⇊

그렇지 않으면 호출이 실패합니다.

경고 : 헤더 정보를 수정할 수 없습니다. 헤더가 이미 전송되었습니다 ( script : line 에서 시작된 출력).

HTTP 헤더를 수정하는 일부 기능은 다음과 같습니다.

출력은 다음과 같습니다.

 

 

  • 의도적 :
    • print , echo 및 출력을 생성하는 기타 기능
    • <?php 코드 이전의 원시 <html>

 

헤더를 출력하기 전에 전송해야하는 이유를 이해하려면 일반적인 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() 경고에는 문제 원인을 찾기위한 모든 관련 정보가 포함되어 있습니다.

경고 : 헤더 정보를 수정할 수 없습니다-100 행의 /www/usr2345/htdocs/index.php에서 이미 보낸 헤더 (/ www / usr2345 / htdocs / auth.php : 52 에서 시작된 출력 )

여기서 "line 100"은 header() 호출이 실패한 스크립트를 나타냅니다.

괄호 안의 "에서 시작된 "출력이 더 중요합니다. 이전 출력의 소스를 나타냅니다. 이 예에서는 auth.php52 입니다. 그것이 조기 출력을 찾아야하는 곳입니다.

일반적인 원인 :

  1. print, echo
    • printecho 문의 의도적 인 출력은 HTTP 헤더를 보낼 기회를 종료합니다. 이를 방지하기 위해 애플리케이션 흐름을 재구성해야합니다. 함수 와 템플릿 체계를 사용합니다. 메시지를 작성 하기 전에 header() 호출이 발생하는지 확인하십시오. 출력을 생성하는 함수는 다음과 같습니다.
      • print , echo , printf , vprintf
      • trigger_error , ob_flush , ob_end_flush , var_dump , print_r
      • readfile , passthru , flush , imagepng , imagejpeg

      무엇보다도 사용자 정의 함수.
  2. 원시 HTML 영역
    • .php 파일의 구문 분석되지 않은 HTML 섹션도 직접 출력됩니다. 트리거한다 스크립트 조건 header() 호출은 원시 전에 유의해야 <html> 블록.
      <!DOCTYPE html> <?php // Too late for headers already.
      템플릿 체계를 사용하여 출력 논리에서 처리를 분리합니다.
      • 스크립트 위에 양식 처리 코드를 배치합니다.
      • 임시 문자열 변수를 사용하여 메시지를 연기하십시오.
      • 실제 출력 로직과 혼합 된 HTML 출력은 마지막에 따라야합니다.

  3. "script.php line 1 "경고에 <?php 앞의 공백경고가 출력 인라인 1 <?php 토큰 앞에 대부분 공백 , 텍스트 또는 HTML이 표시됩니다.
     <?php # There's a SINGLE space/newline before <? - Which already seals it.
    마찬가지로 추가 된 스크립트 또는 스크립트 섹션에서도 발생할 수 있습니다.
    ?> <?php
    PHP는 실제로 태그 닫기 후 한 줄 바꿈을 먹습니다. 그러나 여러 줄 바꿈이나 탭 또는 이러한 간격으로 이동 한 공백을 보상하지는 않습니다.
  4. UTF-8 BOM줄 바꿈과 공백만으로도 문제가 될 수 있습니다. 그러나이를 유발할 수있는 "보이지 않는"문자 시퀀스도 있습니다. 가장 유명한 것은 대부분의 텍스트 편집기에서 표시되지 않는 UTF-8 BOM (Byte-Order-Mark)입니다. UTF-8 인코딩 문서의 경우 선택 사항이며 중복되는 바이트 시퀀스 EF BB BF 그러나 PHP는이를 원시 출력으로 처리해야합니다. 출력에서 문자  (클라이언트가 문서를 Latin-1로 해석하는 경우) 또는 유사한 "쓰레기"로 표시 될 수 있습니다. 특히 그래픽 편집기와 Java 기반 IDE는 그 존재를 알지 못합니다. 그들은 그것을 시각화하지 않습니다 (유니 코드 표준에 의해 의무화 됨). 그러나 대부분의 프로그래머 및 콘솔 편집기는 다음을 수행합니다. UTF-8 BOM 자리 표시자를 표시하는 joes 편집기 및 점이있는 MC 편집기 초기에 문제를 쉽게 인식 할 수 있습니다. 다른 편집자는 파일 / 설정 메뉴에서 자신의 존재를 식별 할 수 있습니다 (Windows의 메모장 ++ 는 문제를 식별하고 해결할 수 있음). BOM 존재를 검사하는 또 다른 옵션은 hexeditor 를 사용하는 것입니다. * nix 시스템에서 hexdump 는 일반적으로 다음과 같은 문제 및 기타 문제 감사를 단순화하는 그래픽 변형이 아닌 경우 사용할 수 있습니다. utf-8 bom을 보여주는 beav hexeditor 쉬운 수정은 파일을 "UTF-8 (BOM 없음)"또는 이와 유사한 명명법으로 저장하도록 텍스트 편집기를 설정하는 것입니다. 종종 신규 이민자는 새 파일을 만들고 이전 코드를 다시 복사하여 붙여 넣는 방법에 의존합니다.수정 유틸리티sed / awk 또는 recode )을 검사하고 다시 작성하는 자동화 도구도 있습니다. 특히 PHP의 경우 phptags 태그 tidier가 있습니다. 닫기 및 열기 태그를 길고 짧은 형식으로 다시 작성하지만 선행 및 후행 공백, 유니 코드 및 UTF-x BOM 문제도 쉽게 수정합니다.
    phptags --whitespace *.php
    전체 include 또는 프로젝트 디렉토리에서 사용하는 것이 안전합니다.
  5. ?> 뒤에 공백닫는 ?> 뒤에 오류 소스가 언급되면 여기에 공백이나 원시 텍스트가 기록됩니다. PHP 종료 마커는이 시점에서 스크립트 실행을 종료하지 않습니다. 이후의 모든 텍스트 / 공백 문자는 여전히 페이지 콘텐츠로 기록됩니다. 특히 신규 이민자에게는 후행 ?> PHP 닫기 태그를 생략해야한다는 것이 일반적으로 권장됩니다. 이것은 이러한 경우의 작은 부분을 피합니다. (일반적으로 include()d 스크립트가 범인입니다.)
  6. "0 행에서 알 수 없음"으로 언급 된 오류 소스오류 소스가 구체화되지 않은 경우 일반적으로 PHP 확장 또는 php.ini 설정입니다.
    • 때때로 gzip 스트림 인코딩 설정 또는 ob_gzhandler 입니다.
    • 그러나 암시 적 PHP 시작 / 경고 메시지를 생성하는 이중로드 된 extension=

  7. 선행 오류 메시지다른 PHP 문이나 표현식으로 인해 경고 메시지 나 알림이 출력되는 경우에도 조기 출력으로 간주됩니다. 이 경우 나중에 디버깅을 방해하지 않는 경우 오류를 피하거나, 명령문 실행을 지연하거나, 예를 들어 isset() 또는 @()

No error message

php.ini error_reporting 또는 display_errors 비활성화 된 경우 경고가 표시되지 않습니다. 그러나 오류를 무시한다고해서 문제가 해결되는 것은 아닙니다. 조기 출력 후에도 헤더를 보낼 수 없습니다.

따라서 header("Location: ...") 리디렉션이 자동으로 실패하면 경고를 조사하는 것이 좋습니다. 호출 스크립트 위에 두 개의 간단한 명령을 사용하여 다시 활성화하십시오.

error_reporting(E_ALL);
    ini_set("display_errors", 1);
    

또는 set_error_handler("var_dump"); 다른 모든 것이 실패하면.

리디렉션 헤더의 경우 최종 코드 경로에 다음과 같은 관용구를 사용해야하는 경우가 많습니다.

exit(header("Location: /finished.html"));
    

header() 오류의 경우 사용자 메시지를 인쇄하는 유틸리티 함수도 있습니다.

PHP 출력 버퍼링 은이 문제를 완화하기위한 해결 방법입니다. 종종 안정적으로 작동하지만 적절한 애플리케이션 구조화를 대체하고 제어 로직에서 출력을 분리해서는 안됩니다. 실제 목적은 웹 서버로의 청크 전송을 최소화하는 것입니다.

  1. output_buffering= 설정이 도움이 될 수 있습니다. 최신 FPM / FastCGI 설정 에서 php.ini 또는 .htaccess 또는 .user.ini 를 통해 구성하십시오.
    활성화하면 PHP가 출력을 웹 서버로 즉시 전달하는 대신 버퍼링 할 수 있습니다. 따라서 PHP는 HTTP 헤더를 집계 할 수 있습니다.
  2. ob_start(); 대한 호출에 참여할 수 있습니다. 호출 스크립트 위에. 그러나 여러 가지 이유로 신뢰성이 떨어집니다.
    • <?php ob_start(); ?> 첫 번째 스크립트를 시작합니다. 공백이나 BOM이 이전에 섞여서 비효율적 일 수 있습니다.
    • HTML 출력을 위해 공백을 숨길 수 있습니다. 그러나 애플리케이션 로직이 바이너리 콘텐츠 (예 : 생성 된 이미지)를 보내려고하면 버퍼링 된 외부 출력이 문제가됩니다. (추가 해결 방법으로 ob_clean() 필요합니다.)
    • 버퍼는 크기가 제한되어 있으며 기본값으로두면 쉽게 오버런 될 수 있습니다. 그리고 그것은 드물게 발생하지 않으며, 그것이 발생했을 때 추적하기가 어렵습니다.

 

 

따라서 두 가지 방법 모두 신뢰할 수 없게 될 수 있습니다. 특히 개발 설정 및 / 또는 프로덕션 서버간에 전환 할 때 더욱 그렇습니다. 그렇기 때문에 출력 버퍼링이 단순한 문제 / 엄격한 해결 방법으로 널리 간주됩니다.

매뉴얼의 기본 사용 예제 와 더 많은 장단점을 참조하십시오.

이전에 헤더 경고를받지 못했다면 출력 버퍼링 php.ini 설정 이 변경된 것입니다. 현재 / 새 서버에서 구성되지 않은 것 같습니다.

항상 headers_sent() 를 사용하여 헤더를 보낼 수 있는지 여부를 조사 할 수 있습니다. 정보를 조건부로 인쇄하거나 다른 대체 논리를 적용하는 데 유용합니다.

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

유용한 대체 해결 방법은 다음과 같습니다.

  • HTML <meta> 태그
    • 애플리케이션이 구조적으로 수정하기 어려운 경우 리디렉션을 허용하는 쉬운 (그러나 다소 비전문적 인) 방법은 HTML <meta> 태그를 삽입하는 것입니다. 리디렉션은 다음을 통해 수행 할 수 있습니다.
       <meta http-equiv="Location" content="http://example.com/">
      또는 짧은 지연으로 :
       <meta http-equiv="Refresh" content="2; url=../target.html">
      <head> 섹션을지나 사용하면 잘못된 HTML이 생성됩니다. 대부분의 브라우저는 여전히 그것을 받아들입니다.
  • 자바 스크립트 리디렉션
    • 대안으로 자바 스크립트 리디렉션 을 페이지 리디렉션에 사용할 수 있습니다.
       <script> location.replace("target.html"); </script>
      <meta> 해결 방법보다 HTML을 더 많이 준수하지만 JavaScript 가능 클라이언트에 의존합니다.

 

 

그러나 두 방법 모두 진짜 HTTP header () 호출이 실패 할 때 허용 가능한 폴백을 만듭니다. 이상적으로는이를 최후의 수단으로 항상 사용자 친화적 인 메시지 및 클릭 가능한 링크와 결합하는 것이 좋습니다. (예를 들어 http_redirect () PECL 확장이 수행하는 작업입니다.)

setcookie() 와 session_start() 도 영향을 받는 이유

setcookie()session_start() 모두 Set-Cookie: HTTP 헤더를 보내야합니다. 따라서 동일한 조건이 적용되며 조기 출력 상황에 대해 유사한 오류 메시지가 생성됩니다.

(물론 브라우저에서 비활성화 된 쿠키 나 프록시 문제의 영향을받습니다. 세션 기능은 디스크 여유 공간 및 기타 php.ini 설정 등에 따라 달라집니다.)

출처 : https://stackoverflow.com/questions/8028957/how-to-fix-headers-already-sent-error-in-php
728x90
반응형