你是不是也遇到过这个经典报错:
vbnet
Warning: Cannot modify header information - headers already sent by...
中文名就叫:
"还没来得及发 HTTP 头,你就先输出东西了"
别慌,这绝对不是大问题,但也是 PHP 新手最容易踩的坑。
今天我用最简单的方式,带你把这个问题彻底讲懂。
1⃣ 这个错误到底什么意思?
一句话解释:
你调用
header()、setcookie()、session_start()之前,代码里已经"悄悄输出了一些东西"。
这些"输出"可能是:
- 一个看不见的空格
- 一个回车符
- 隐藏的 BOM 字节
- 你自己 echo/var_dump 的内容
- 引入文件里的输出
只要有一点点输出,header 就会报错。
2⃣ 最常见的罪魁祸首:UTF-8 BOM
很多编辑器默认保存为"UTF-8 BOM",而 PHP 最怕 BOM。
BOM 会在文件最开头偷偷输出三个字节:
EF BB BF
你看不见,但服务器能看到。
于是服务器说:
"啊你已经输出了,我就不能设置 header 了。"
✔ 如何判断文件是不是 BOM?
症状明显:
- 中文突然乱码
- header 报错特别早
- 新建文件使用过 Windows 记事本 / Dreamweaver
✔ 如何去掉 BOM?
VSCode
右下角 → 点击"UTF-8" → 选择 UTF-8(无 BOM) 保存即可。
Notepad++
菜单 → 格式 → 选择 UTF-8(无 BOM)
宝塔面板编辑器 / PHPStorm
默认不会带 BOM,比较安全。
3⃣ 第二大元凶:文件顶部的空格 + 回车
PHP 文件头部常见两种错误:
❌ 错误写法 1:
php
(空格)(空格)
<?php
❌ 错误写法 2:
php
<?php
// 顶部多了一行空行
这两个都会导致 header 报错。
✔ 正确写法
php
<?php
第一行第一列必须是 <?php,上面不能有任何内容。
记住:
空格也算输出!回车也算输出!
4⃣ 第三类:你自己输出的调试信息
最容易忘的情况:
scss
var_dump($data);
header("Location: /index.php");
你调试一下忘记删了,header 直接挂掉。
其它输出包括:
- echo
- print_r
- die
- exit
都要检查一遍。
5⃣ include/require 的文件里也可能有输出
主文件可能没问题,但你这样写:
javascript
require 'config.php';
header("Location: xxx.php");
只要 config.php 有:
- BOM
- 空格
- echo
- HTML
都会导致 header 报错。
记得 所有被引入的文件也要检查。
6⃣ 万能解决方案:输出缓冲(最稳)
如果你实在搞不清哪里输出了,可以直接使用:
scss
ob_start();
把它放在所有代码最上方。
PHP 会把所有输出暂存,
等你把 header / cookie / session 都设置完,
再统一输出。
7⃣ 最稳定推荐写法(复制就能用)
php
<?php
ob_start();
session_start();
header("Content-Type: text/html; charset=utf-8");
// 你的逻辑...
这套写法能避免 99% 的 "header already sent"。
9⃣ 最后给你一个超实用排查顺序(收藏版)
- 检查文件顶部是否有空格/空行
- 转成 UTF-8 无 BOM
- 搜索所有 output(echo/print/var_dump)
- 检查 include 的文件
- 统一加
ob_start() - 不行再检查 CDN 或 gzip(非常少见)
按这顺序查,10 分钟必解决。