| この記事の要点 |
|
エラー内容
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/config.php:15) in /var/www/html/login.php on line 22
「ヘッダー情報を変更できません。ヘッダーは既に送信されています(出力は config.php の 15 行目で始まりました)」という意味です。in ... on line 22 は失敗した header() の場所、output started at は先に何かを出力してしまった場所です。直すべきなのは後者です。
原因: HTTP ヘッダーは本文より先に送られる
HTTP のレスポンスは「ヘッダー → 空行 → 本文」の順でブラウザに送られます。PHP は、スクリプトが最初に 1 バイトでも本文を出力した時点でヘッダーを確定して送信します。その後で header() を呼んでも、送信済みのヘッダーは変更できないため、この警告が出てリダイレクトや Cookie の設定が効きません。
同じ理由で、setcookie() や session_start()(セッション Cookie を送るため)も、出力の後に呼ぶと同種の警告になります。
よくある出力の犯人
| 犯人 | 例 |
|---|---|
| echo / print / var_dump | デバッグ用に書いた var_dump($user); が残っている |
| PHP タグの外の HTML | ファイル冒頭に <!DOCTYPE html> があり、その後で header() を呼んでいる |
<?php より前の空白・改行 | ファイル 1 行目が空行になっている |
?> より後ろの空白・改行 | require した設定ファイルの末尾に改行が残っている |
| UTF-8 の BOM | エディタが保存時にファイル先頭へ不可視の 3 バイトを付けた |
| エラーメッセージ | display_errors が有効で、Notice や Deprecated が先に画面に出た |
対処法
1. header() を出力より前に移動する
リダイレクトや Cookie の判定処理は、HTML を出力し始める前に済ませます。
<?php
// NG: 先に HTML を出してから header()
// echo '<p>ログイン中...</p>';
// header('Location: /mypage.php');
// OK: 判定とリダイレクトを先に行う
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: /login.php');
exit; // リダイレクト後は必ず処理を止める
}
?>
<!DOCTYPE html>
<html>
...
2. 閉じタグ ?> を書かない
関数定義や設定だけの PHP ファイルでは、末尾の ?> を省略します。PHP は閉じタグがなくても問題なく動き、閉じタグの後ろに紛れ込んだ改行が出力される事故を防げます。PSR-12 などのコーディング規約でも、PHP だけのファイルでは閉じタグを省略するよう定めています。
3. BOM を取り除く
エディタの保存形式を「UTF-8(BOM なし)」にして保存し直します。VS Code ならステータスバーの文字コード表示から「エンコード付きで保存」→「UTF-8」を選びます。Linux では次のコマンドで BOM 付きファイルを探せます。
# BOM (EF BB BF) で始まる .php ファイルを一覧表示
grep -rl $'^\xEF\xBB\xBF' --include='*.php' .
# 1 ファイルの先頭 3 バイトを確認(efbbbf なら BOM あり)
head -c 3 config.php | xxd -p
4. エラー表示を画面に出さない
本番環境では display_errors = Off にしてエラーはログに出します。ただし、Notice が出ていること自体が不具合のサインなので、その原因も直しておきます。
最終手段: 出力バッファリング
スクリプト冒頭で ob_start(); を呼ぶか、php.ini の output_buffering を有効にすると、出力がいったんバッファに溜まるため警告は出なくなります。しかし原因の出力(余計な空白やデバッグ表示)はそのまま残り、JSON や画像のダウンロードが壊れる原因にもなります。既存システムの応急処置にとどめ、上の 1〜3 で根本から直すのがおすすめです。
確認方法
どこで出力が始まったかをコードから調べるには headers_sent() が便利です。
<?php
if (headers_sent($file, $line)) {
error_log("出力開始: {$file} の {$line} 行目");
} else {
header('Location: /mypage.php');
exit;
}
修正後はブラウザの開発者ツール(ネットワークタブ)でレスポンスを確認し、リダイレクトなら 302 などのステータスと Location ヘッダーが返っていれば解決です。
よくある質問
ローカルでは出ないのにサーバーでだけ出る
php.ini の output_buffering の設定が環境によって違うことが多い原因です。ローカルで出力バッファリングが有効だと、余計な出力があってもバッファに溜まって警告になりません。サーバーで無効になっていると、同じコードで警告が出ます。php -i | grep output_buffering や phpinfo() で両方の値を見比べてください。どちらの環境でも動くよう、コード側で出力の順序を直すのが確実です。
WordPress で突然出るようになった
テーマの functions.php やプラグインのファイルを編集した後に出る場合は、編集したファイルの末尾にある ?> の後ろの空行や、ファイル先頭の BOM が典型的な原因です。エラーメッセージの output started at に、そのファイル名が表示されているはずです。
関連
- PHP リダイレクト (header Location) 完全ガイド
- TXT(.txt)完全ガイド — 文字コード・改行・BOM
- PHPログ出力完全ガイド(error_log/Monolog/PSR-3/Laravel/logrotate)
- PHP 外部ファイル呼び出し (include/require/autoload) 完全ガイド
子ページはありません
- Fatal error: Maximum execution time of 30 seconds exceeded in...
- Fatal error: Uncaught Error: Cannot use object of type stdClass as array in ...
- Warning: Use of undefined constant ... - assumed '...' (this will throw an Error)
- ERROR: Call to undefined method Maatwebsite\Excel\Excel::load()
- Maximum execution time of 30 seconds exceeded
- Your requirements could not be resolved to an installable set of packages. ... To enable extensions, verify that they are enabled in your .ini files:
- could not find driver
- the requested PHP extension mbstring is missing from your system.
- the requested PHP extension dom is missing from your system.
- A non well formed numeric value encountered
- Warning: Cannot modify header information - headers already sent by ...
- php_network_getaddresses: getaddrinfo failed: Name or service not known
- XMLWriter::openUri(): Unable to resolve file path
- Object of class stdClass could not be converted to string
- Class 'Google_Service_Youtube' not found
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09