【PHP8.x】headers_sent関数の使い方

作成日: 更新日:

headers_sent関数は、HTTPヘッダーが既に送信されたかどうかを確認する関数です。具体的には、HTTPレスポンスヘッダーがクライアントに送信されたかどうかを調べ、その結果をboolean型(真偽値)で返します。ヘッダーが送信済みであればtrueを、まだ送信されていなければfalseを返します。

この関数は、スクリプトの特定の部分でヘッダーを送信する前に、ヘッダーが既に送信されていないかを確認する際に役立ちます。例えば、header()関数などを使用してヘッダーを送信する前に、headers_sent()関数を使用して、予期せぬエラーや警告を防ぐことができます。

headers_sent()関数は、引数を省略することも、ファイル名と行番号を受け取ることもできます。引数を省略した場合、関数は単にヘッダーが送信されたかどうかを返します。ファイル名と行番号を引数として指定した場合、ヘッダーが最初に送信されたファイル名と行番号を、それぞれ引数で指定された変数に格納します。これにより、ヘッダーがどこで送信されたかを特定し、デバッグに役立てることができます。

この関数の戻り値は次のとおりです。

  • true: HTTPヘッダーが既に送信されている場合。
  • false: HTTPヘッダーがまだ送信されていない場合。

headers_sent()関数を使用することで、HTTPヘッダーの送信に関する問題を効率的に管理し、より安定したWebアプリケーションを開発できます。

基本的な使い方

構文(syntax)

headers_sent(string &$file = null, int &$line = null): bool

引数(parameters)

string|null $filename = null, int|null $line = null

  • string|null $filename = null: ヘッダー送信が検出されたファイル名を格納するための文字列。デフォルトは null。
  • int|null $line = null: ヘッダー送信が検出された行番号を格納するための整数。デフォルトは null。

戻り値(return)

bool

HTTPヘッダーが既に送信されているか、または送信が中断された場合に true を返します。それ以外の場合は false を返します。

サンプルコード

PHP headers_sent() でヘッダー送信状況を確認する

<?php

// headers_sent() 関数の動作を示すサンプルコードです。
// このスクリプトは、Webサーバー経由で実行することを想定しています。

// ヘッダーが送信されたファイル名と行番号を格納するための変数を初期化します。
$filename = null;
$line = null;

// --------------------------------------------------------------------------
// 1. ヘッダー送信前の状態を確認
// --------------------------------------------------------------------------
// この時点では、まだどのHTTPヘッダーもブラウザに送信されていません。
// headers_sent() は false を返すはずです。
if (headers_sent()) {
    echo "エラー: 予期せずHTTPヘッダーが既に送信されています。<br>";
} else {
    echo "OK: まだHTTPヘッダーは送信されていません。<br>";
}

echo "<hr>";

// --------------------------------------------------------------------------
// 2. 意図的にヘッダーとコンテンツを送信する
// --------------------------------------------------------------------------
// HTTPヘッダーを設定します。これはすぐには送信されず、メモリ上にキューイングされます。
header('Content-Type: text/html; charset=UTF-8');
echo "Content-Type ヘッダーを設定しました。<br>";

// ここで何らかのコンテンツを出力します。
// PHPは、出力バッファリングがオフの場合、またはバッファがいっぱいになった場合に、
// 最初に出力があった時点で、キューイングされた全てのヘッダーを送信します。
// この `echo` 文がヘッダー送信のトリガーになります。
echo "最初のコンテンツ出力。<br>";

echo "<hr>";

// --------------------------------------------------------------------------
// 3. ヘッダー送信後の状態を確認
// --------------------------------------------------------------------------
// この時点では、上記の `echo` 文によってHTTPヘッダーが既に送信されているはずです。
// headers_sent() は true を返し、参照渡しで指定した `$filename` と `$line` に情報が格納されます。
if (headers_sent($filename, $line)) {
    echo "成功: HTTPヘッダーは既に送信されています。<br>";
    echo "ヘッダーが送信されたファイル: " . $filename . "<br>";
    echo "ヘッダーが送信された行番号: " . $line . "<br>";
} else {
    echo "エラー: ヘッダーが送信されていません。<br>";
}

echo "<hr>";

// --------------------------------------------------------------------------
// 4. ヘッダー送信後に再度ヘッダーを設定しようとする
// --------------------------------------------------------------------------
// 既にヘッダーが送信されているため、この `header()` 関数は警告 (Warning) を発生させ、
// 新しいヘッダーを送信できません。
// 実際のアプリケーションでは、`headers_sent()` でこの状態を事前にチェックすることで警告を防ぎます。
if (!headers_sent()) {
    header('X-Custom-Header: Value');
    echo "別のヘッダーを設定しました。<br>"; // このメッセージは通常、表示されません。
} else {
    echo "注意: HTTPヘッダーが既に送信されているため、これ以上ヘッダーを設定することはできません。<br>";
    // 次の行を有効にすると「Warning: Cannot modify header information - headers already sent by...」
    // といった警告がブラウザに出力されます。
    // header('X-Custom-Header: Value'); 
    echo "試みに `header('X-Custom-Header: Value')` を実行した場合、PHPは警告を出力します。<br>";
}

?>

PHPのheaders_sent()関数は、HTTPヘッダーがWebブラウザに既に送信されたかどうかを真偽値(trueまたはfalse)で確認します。オプションの引数$filename$lineを指定すると、ヘッダーが送信されたソースファイル名と行番号がそれぞれ格納されます。

このサンプルコードでは、まずheaders_sent()falseを返す、まだヘッダーが送信されていない状態を示します。次に、header()関数でContent-Typeヘッダーを設定し、その後にecho文でコンテンツを出力します。PHPは、最初のコンテンツ出力があった時点で、それまでにキューに貯められていた全てのHTTPヘッダーをブラウザに送信するため、このechoがヘッダー送信のトリガーとなります。

ヘッダー送信後、再度headers_sent($filename, $line)を実行すると、関数はtrueを返し、$filename$lineにはヘッダーが送信されたコードの場所が格納されます。一度ヘッダーが送信されると、それ以降にheader()関数を使って新たなヘッダーを設定しようとすると、PHPは警告(Warning)を発生させ、そのヘッダーは送信されません。headers_sent()を事前に利用することで、このような予期せぬエラーを防ぎ、堅牢なWebアプリケーション開発に役立てることができます。

headers_sent()は、HTTPヘッダーがクライアントに送信済みかを確認する関数です。PHPスクリプトからの最初のコンテンツ出力(例: echo)があった時点で、ヘッダーは自動的に送信されます。一度ヘッダーが送信されると、それ以降はheader()関数で新しいヘッダーを設定できません。設定しようとすると「headers already sent」といった警告が発生します。この警告を避けるため、header()関数を呼び出す前にheaders_sent()で送信済みかを必ず確認してください。引数に変数を与えると、ヘッダーが送信されたファイル名と行番号を取得できます。本関数はWebサーバー上で実行することを前提としています。

PHPでヘッダー送信前にリダイレクトする

<?php

/**
 * 指定されたURLに安全にリダイレクトを試みます。
 * ヘッダーが既に送信されているかを確認し、リダイレクトが可能であれば実行します。
 *
 * @param string $url リダイレクト先の完全なURL。
 * @return void
 */
function safeRedirect(string $url): void
{
    // headers_sent() 関数は、HTTP ヘッダーが既にクライアント(ブラウザなど)に送信されているかどうかをチェックします。
    // スクリプトが何らかの出力(HTMLタグ、echo、空白文字など)を行うと、ヘッダーが送信されます。
    // header() 関数はヘッダーが送信される前にのみ機能するため、このチェックは重要です。
    if (!headers_sent()) {
        // ヘッダーがまだ送信されていない場合、Location ヘッダーを設定してリダイレクトを実行します。
        header('Location: ' . $url);
        // header() でリダイレクトを設定した後、スクリプトの残りの部分が実行されないように exit() を呼び出すことが重要です。
        exit;
    } else {
        // ヘッダーが既に送信されている場合、header() 関数によるリダイレクトはできません。
        // この状況では、ユーザーにリダイレクトできなかったことを伝えるか、
        // JavaScript など別の方法でリダイレクトを試みる必要があります。
        echo '<p style="color: red;">エラー: 既に何らかのコンテンツが出力されているため、リダイレクトできませんでした。</p>';
        echo '<p>本来は <a href="' . htmlspecialchars($url) . '">' . htmlspecialchars($url) . '</a> へリダイレクトされる予定でした。</p>';
        echo '<p>このメッセージは、リダイレクトが失敗した場合にのみ表示されます。</p>';
    }
}

// --- 以下はサンプルコードの実行部分です ---

// リダイレクトしたいURLを指定します。
$targetUrl = 'https://www.php.net/manual/ja/function.headers-sent.php';

// ★この下の行のコメントを外すと、"Hello!" が出力され、その結果ヘッダーが送信されます。
// ★これにより、safeRedirect() 関数内で headers_sent() が true を返し、リダイレクトに失敗する状況を再現できます。
// echo "Hello! ";

// safeRedirect 関数を呼び出して、リダイレクトを試みます。
safeRedirect($targetUrl);

// もしリダイレクトが成功すれば、この下の行は実行されず、ブラウザは $targetUrl へ移動します。
// もしリダイレクトが失敗すれば(上記の `echo` のコメントを外した場合など)、
// この下の行が実行され、エラーメッセージと共に表示されます。
echo '<p>この行は、リダイレクトが成功した場合には表示されません。</p>';
echo '<p>通常、リダイレクト後にこのページの内容が表示されることはありません。</p>';

?>

PHPのheaders_sent関数は、HTTPヘッダーが既にクライアント(ウェブブラウザなど)に送信されたかどうかを確認する際に使用します。これは、header()関数を使ったリダイレクトやクッキーの設定といった処理が、ヘッダーが送信される前に行われる必要があるため、非常に重要なチェック機能です。スクリプトが何らかの出力(HTMLタグ、空白文字、echo文など)を行うと、ヘッダーは自動的に送信されます。

この関数は、オプションで$filename$lineという引数を受け取ります。これらは、ヘッダーが送信済みだった場合に、どのファイル名と行番号で出力が行われたかを確認したいときに指定します。戻り値はブール型で、ヘッダーが既に送信済みならtrue、まだ送信されていないならfalseを返します。

サンプルコードでは、safeRedirect関数がheaders_sent()を使って安全なリダイレクトを試みています。if (!headers_sent())でヘッダーが未送信であることを確認できた場合、header('Location: ' . $url);でリダイレクト指示を出し、exit;でスクリプトの処理を終了させます。これにより、ブラウザは指定されたURLへ遷移します。一方、もしheaders_sent()trueを返してヘッダーが既に送信されていた場合、header()関数によるリダイレクトは機能しないため、リダイレクト失敗のメッセージをユーザーに表示します。サンプルコード中のコメントアウトされたecho "Hello! ";を有効にすると、意図的にヘッダーを送信させ、リダイレクトが失敗する状況を再現できます。このように、headers_sent()はPHPスクリプトでヘッダー関連の処理を行う際に、適切なタイミングを判断するために役立ちます。

headers_sent() 関数は、PHPがブラウザにHTTPヘッダーを既に送信済みかを確認します。echo やHTMLタグ、空白文字など、スクリプトからの何らかの出力があった時点でヘッダーは送信され、一度送信されると header() 関数によるリダイレクトは機能しなくなります。

リダイレクトを行う header('Location: ...') を使用する際は、必ずその直後に exit; を記述して、それ以降のスクリプトの実行を停止することが重要です。これを怠ると、意図しない処理が実行されたり、コンテンツが表示されたりする可能性があります。ヘッダー送信後にリダイレクトが必要な場合は、JavaScriptによるリダイレクトなどの代替手段を検討してください。また、画面にURLなどを表示する際には、XSS対策として htmlspecialchars() で適切にエスケープすることを忘れないでください。

【PHP8.x】headers_sent関数の使い方 | いっしー@Webエンジニア