Nhiều khi chúng ta làm những việc hết sức đơn giản, và trong thâm tâm, mặc nhiên chúng ta đã được "lập trình" rằng việc đó dĩ nhiên là bình thường!
Trong lập trinh cũng vậy, ví dụ bạn viết một đoạn code rất bình thường, hay bạn luôn mặc định đoạn code đó là "bình thường":
<?php
header("Location: index.php");
?>Ý tưởng: redirect sang trang khác, ví dụ Home, About Us...Nói chung là...bình thường! Bạn bấm chạy…
Và…
Warning: Cannot modify header information - headers already sent
Bạn nhìn màn hình…
"Header gì? Gửi lúc nào??? Không hiểu??"
Chúc mừng, bạn vừa gặp một trong những lỗi "bình thường" của PHP
Lỗi "header already sent" trong PHP xảy ra khi bạn gửi output (echo, HTML, khoảng trắng…) trước khi gọi hàm header().
Hiểu đơn giản
PHP có một "luật ngầm":
Phải gửi header trước, rồi mới gửi nội dung
Nhưng bạn lại làm:
- gửi nội dung trước
- rồi mới gửi header
"Giám sát viên" PHP lạnh lùng phán: "Không được! Header phải đầu tiên!"
Ví dụ thực tế
Bạn gửi bưu kiện, thông thường mọi người sẽ:
- Ghi địa chỉ (header)
- Gửi hàng (data)
Nhưng bạn lại:
- gửi hàng trước
- rồi mới ghi địa chỉ
Bưu điện...ngơ ngác: "Ơ kìa???"
PHP cũng vậy
Lỗi kinh điển
Case 1: echo trước header
<?php
echo "Hello";
header("Location: index.php");
?>Bạn đã "in ra" màn hình Hello rồi
Vì vậy header không gửi được nữa
Case 2: có khoảng trắng trước <?php
<?php
header("Location: index.php");3 dấu cách đó… cũng tính là output
Đây là lỗi:
"nhìn không thấy nhưng phá banh chương trình"
Case 3: HTML trước PHP
<h1>Hello</h1>
<?php
header("Location: index.php");
?>HTML = output
Dẫn tới header fail
Case 4: file include gây lỗi
include "config.php";
header("Location: home.php");Nếu config.php có:
- echo
- hoặc khoảng trắng
Kết quả cũng lỗi vì "liên quan"
Cách fix
Cách 1: Đặt header trước mọi thứ
<?php
header("Location: index.php");
exit;
?>Không echo trước đó
Cách 2: Không có khoảng trắng
File phải bắt đầu như này:
<?php
Không có:
- space
- dòng trống
- BOM
Cách 3: Dùng output buffering (hơi xịn một chút)
<?php
ob_start();
echo "Hello";
header("Location: index.php");
ob_end_flush();
?>PHP sẽ "giữ lại" output
Kết quả là cho phép header chạy trước, kiểu như header có vé VIP.
Nhưng:
Lính mới nên hạn chế dùng cách này
Test thử (rất nên làm, làm rồi sẽ hiểu)
Tạo file:
<?php
echo "Test";
header("Location: https://google.com");
?>Mở lên sẽ nhận món quà...lỗi
Sửa lại:
<?php
header("Location: https://google.com");
exit;
?>Kết quả là redirect OK
Debug kiểu dev "xịn sò"
Khi gặp lỗi này:
- Xem có echo không
- Xem có HTML trước PHP không
- Xem có khoảng trắng không
- Check file include
90% lỗi nằm ở đây
Một sự thật hơi "đau"
Lỗi này:
- không khó
- nhưng rất "khó chịu"
Vì:
Bạn nhìn code… thấy đúng hết, chẳng có gì phải "lăn tăn"
Nhưng thực tế:
sai 1 dấu cách
Tổng kết
"header already sent" không phải lỗi phức tạp
Nó chỉ là: bạn đã gửi output trước
Nhớ:
- header phải đứng đầu
- không echo trước
- không có khoảng trắng
FAQ nhanh
Có thể echo rồi redirect không?
Không (trừ khi dùng ob_start)
Tại sao lỗi vẫn xảy ra dù không thấy echo?
Có thể do khoảng trắng hoặc file include
exit có cần không?
Có, để dừng script sau khi redirect
Bạn có thể cũng đang gặp:
PHP không nhận dữ liệu từ form