| この記事の要点 |
|
エラー内容
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 / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- プロジェクトをTomcatプロジェクトとして認識させる方法 2026-10-07 22:32:50
- MySQLの1366 Incorrect string value|Laravelの文字コード・絵文字エラー 2026-10-07 21:54:03
- curlの証明書ホスト名不一致|旧エラー51・現行60の確認と対処 2026-10-07 21:54:03
- LaravelのMassAssignmentException|fillableの原因と安全な対処 2026-10-07 21:54:03
- Eclipse で Tomcat の起動ログがコンソールに出ない時の確認手順 2026-10-07 21:54:02
- MySQLにおける中央値(Median)の導き方(バージョン8未満) 2026-10-07 13:49:45
- getInputForward 2026-10-07 13:41:15
- JSONから配列に変換 2026-10-07 13:41:15
- ビューから値をモデルに格納しコントローラーで受け取る方法 2026-10-07 13:23:41
- Laravelのテーブル作成と定義変更|マイグレーション・up/down・注意点 2026-10-07 13:23:41
- NumPy 配列に要素を追加する方法 (append / concatenate) 2026-10-07 13:23:41
- MariaDB・MySQLで現在日時を取得する方法|NOW・タイムゾーン・保存型 2026-10-07 13:13:36
- 【django】テンプレートで定数を使用する方法 2026-10-07 13:10:15
- Spring BootにおけるApplication.propertiesの環境依存設定の分割方法 2026-10-07 12:09:35
- Not supported for DML operations【Springエラー】 2026-10-07 11:09:38