PHPでheader()を利用する際、既にechoやprintなどで出力が始まっているとエラー(Warning)が出る場合がある。header()の前に出力が始まってるかどうか判定したい思って調べた。
次のようにするとバッファされてるせいかエラーが出ない。
no_err.php
<?php
echo "start".PHP_EOL;
header('Content-Type: text/plain');
echo "end".PHP_EOL;
//結果
//start
//end
バッファをob_flush()するとヘッダが送信されるのでheader()でエラーが出る。
err.php
<?php
echo "start".PHP_EOL;
ob_flush();//出力開始
header('Content-Type: text/plain');
echo "end".PHP_EOL;
//結果
//start
//Warning: Cannot modify header information - headers already sent by
//(output started at /home/test/html/err.php:3) in /home/test/html/err.php
//on line 4
//end
出力が始まっていればヘッダも出力される筈なのでheaders_sent()を見れば良い。
headers_sent.php
<?php
echo "start".PHP_EOL;
ob_flush();//出力開始
if(headers_sent()){
echo "出力が始まってる!".PHP_EOL;
}else{
header('Content-Type: text/plain');
}
echo "end".PHP_EOL;
//結果
//start 出力が始まってる! end
出力が始まってるかどうか判定できました。めでたしめでたし😇
ではない!
gzipなどを利用する際にはheaders_sent()をチェックしてもブラウザ側でエラーが出る。
err_gz.php
<?php
echo "start".PHP_EOL;
if(headers_sent()){
echo "出力が始まってる!".PHP_EOL;
echo "end".PHP_EOL;
}else{
header('Content-Encoding: gzip');
echo gzencode("end".PHP_EOL);
}
出力される前にバッファされてるのでheaders_sent()時点ではまだヘッダが送信されない。ob_flush()を使えばヘッダが送信されてheaders_sent()は機能するがheader()は使えなくなる。
では、どうする?
バッファに入ってるデータの量が分かれば良いので、ob_get_contents()でバッファを調べる。
ob_get_contents_gz.php
<?php
echo "start".PHP_EOL;
if(headers_sent() || strlen(ob_get_contents())){
echo "出力が始まってる!".PHP_EOL;
echo "end".PHP_EOL;
}else{
header('Content-Encoding: gzip');
echo gzencode("end".PHP_EOL);
}
//結果
//start 出力が始まってる! end
"start"を取り除けば無事にgzipされた"end"だけ表示される。
ob_get_contents_gz_2.php
<?php
if(headers_sent() || strlen(ob_get_contents())){
echo "出力が始まってる!".PHP_EOL;
echo "end".PHP_EOL;
}else{
header('Content-Encoding: gzip');
echo gzencode("end".PHP_EOL);
}
//結果
//end
めでたしめでたし😇