헤더를 보내기 전에 출력이 없습니다!
HTTP 헤더를 전송 / 수정하는 기능은 출력하기 전에 호출해야합니다 .
summary ⇊
그렇지 않으면 호출이 실패합니다.
경고 : 헤더 정보를 수정할 수 없습니다-헤더가 이미 전송되었습니다 ( 스크립트 에서 출력이 시작되었습니다 : line )
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가 제 1 출력을 수신하면 ( print
, echo
, <html>
)는 것이다
플러시 모든 수집 헤더. 나중에 원하는 모든 출력을 보낼 수 있습니다. 그러나 추가 HTTP 헤더를 보내는 것은 불가능합니다.
조기 출력이 발생한 위치를 어떻게 알 수 있습니까?
header()
경고는 문제의 원인을 찾기 위해 모든 관련 정보를 포함합니다 :
경고 : 헤더 정보를 수정할 수 없습니다 - 헤더가 이미 의해 전송
(에서 시작 출력 / www /에서 usr2345 / htdocs에 / auth.php : 52 ) 라인 (100)에 /www/usr2345/htdocs/index.php에서
여기서 "라인 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 영역
.php
파일의 구문 분석되지 않은 HTML 섹션 도 직접 출력됩니다. 트리거됩니다 스크립트 조건을 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는이를 원시 출력으로 취급해야합니다. 
출력 에서 문자 (클라이언트가 문서를 Latin-1로 해석하는 경우) 또는 유사한 "쓰레기"로 표시 될 수 있습니다.
특히 그래픽 편집기와 Java 기반 IDE는 존재하지 않습니다. 그들은 그것을 시각화하지 않습니다 (유니 코드 표준에 의해 의무화 됨). 그러나 대부분의 프로그래머와 콘솔 편집기는 다음을 수행합니다.
초기에 문제를 쉽게 식별 할 수 있습니다. 다른 편집기는 파일 / 설정 메뉴에서 해당 존재를 식별 할 수 있습니다 (Windows의 메모장 ++에서 문제점을 식별하고 해결할 수 있음
). BOM 존재를 검사하는 또 다른 옵션은 hexeditor 를 사용하는 것 입니다. * nix 시스템 hexdump
은 일반적으로 이러한 변형 및 기타 문제 감사를 단순화하는 그래픽 변형이 아닌 경우에 사용 가능합니다.
쉬운 수정 방법은 파일을 "UTF-8 (BOM 없음)"또는 이와 유사한 명명법으로 저장하도록 텍스트 편집기를 설정하는 것입니다. 그렇지 않은 경우 종종 새로운 이민자가 새 파일을 만들고 이전 코드를 복사하여 붙여 넣는 것에 의존합니다.
수정 유틸리티
텍스트 파일 ( sed
/awk
또는 recode
) 을 검사하고 다시 쓰는 자동화 된 도구도 있습니다 . PHP의 경우 구체적으로 phptags
태그 tidier가 있습니다. 닫고 열린 태그를 길고 짧은 형식으로 다시 작성하지만 선행 및 후행 공백, 유니 코드 및 UTF-x BOM 문제를 쉽게 수정합니다.
phptags --whitespace *.php
전체 include 또는 프로젝트 디렉토리에서 사용하는 것이 좋습니다.
공백 ?>
오류 소스가 닫힘?>
뒤에 언급 된 경우
공백 또는 원시 텍스트가 작성된 위치입니다. 이 시점에서 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()
오류 발생시 사용자 메시지를 인쇄하는 유틸리티 기능이 바람직합니다 .
해결 방법으로 출력 버퍼링
PHP 출력 버퍼링
은이 문제를 완화하는 해결 방법입니다. 종종 안정적으로 작동하지만 제어 논리에서 출력을 구성하고 분리하는 적절한 응용 프로그램을 대신해서는 안됩니다. 실제 목적은 웹 서버로의 청크 전송을 최소화하는 것입니다.
output_buffering=
설정은 그럼에도 불구하고 도움이 될 수 있습니다. 최신 FPM / FastCGI 설정 에서 php.ini
또는 .htaccess
또는 .user.ini 를 통해 구성하십시오 .
이를 사용하면 PHP가 출력을 웹 서버에 즉시 전달하는 대신 출력을 버퍼링 할 수 있습니다. 따라서 PHP는 HTTP 헤더를 집계 할 수 있습니다.
마찬가지로 ob_start();
호출 스크립트를 호출하기위한 호출에 참여할 수 있습니다 . 그러나 여러 가지 이유로 신뢰성이 떨어집니다.
<?php ob_start(); ?>
첫 번째 스크립트를 시작 하더라도 공백이나 BOM이 전에 섞여서 비효율적 일 수 있습니다.
HTML 출력을위한 공백을 숨길 수 있습니다. 그러나 응용 프로그램 논리가 이진 콘텐츠 (예 : 생성 된 이미지)를 보내려고하면 버퍼 외부 출력이 문제가됩니다. ( ob_clean()
추가 해결 방법이 필요합니다.)
버퍼는 크기가 제한되어 있으며 기본값으로두면 쉽게 오버런 될 수 있습니다. 그리고 그것은 드문 일이 아니며,
일어날 때 추적하기가 어렵습니다 .
따라서 특히 개발 설정 및 / 또는 프로덕션 서버 간을 전환 할 때 두 방법 모두 신뢰할 수 없게 될 수 있습니다. 출력 버퍼링이 목발 / 엄격히 해결 방법으로 널리 간주되는 이유입니다.
매뉴얼 의 기본 사용법 예제 와 더 많은 장단점을 참조하십시오.
그러나 다른 서버에서 작동했습니다!?
이전에 헤더 경고를받지 못한 경우 출력 버퍼링 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"));
}
유용한 대체 해결 방법은 다음과 같습니다.
HTML <meta>
태그
응용 프로그램이 구조적으로 수정하기 어려운 경우 리디렉션을 허용하는 쉬운 방법이지만 다소 비전문적 인 방법으로 HTML <meta>
태그를 삽입하는 것
입니다. 다음을 통해 리디렉션을 수행 할 수 있습니다.
<meta http-equiv="Location" content="http://example.com/">
또는 짧은 지연 시간 :
<meta http-equiv="Refresh" content="2; url=../target.html">
이는 <head>
섹션을 지나서 사용할 때 유효하지 않은 HTML로 이어집니다 . 대부분의 브라우저는 여전히이를 수락합니다.
자바 스크립트 리디렉션
대안으로
페이지 리디렉션에 JavaScript 리디렉션을 사용할 수 있습니다.
<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 설정 등에 따라 달라집니다)
추가 링크