Tidak ada output sebelum mengirim header!
Fungsi yang mengirim / memodifikasi header HTTP harus dipanggil sebelum output apa pun dibuat .
summary ⇊
Kalau tidak, panggilan gagal:
Peringatan: Tidak dapat mengubah informasi header - header sudah dikirim (output dimulai pada script: line )
Beberapa fungsi yang memodifikasi tajuk HTTP adalah:
Output dapat:
Tak disengaja:
- Spasi sebelum
<?php
atau sesudah?>
- Tanda Pesanan Byte UTF-8 secara khusus
- Pesan atau pemberitahuan kesalahan sebelumnya
Disengaja:
print
, echo
dan fungsi lainnya yang menghasilkan keluaran
<html>
Bagian mentah <?php
kode sebelumnya .
Mengapa itu terjadi?
Untuk memahami mengapa header harus dikirim sebelum output, perlu melihat
respons HTTP khas . Script PHP terutama menghasilkan konten HTML, tetapi juga meneruskan satu set header HTTP / CGI ke server web:
HTTP/1.1 200 OK
Powered-By: PHP/5.3.7
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
<html><head><title>PHP page output page</title></head>
<body><h1>Content</h1> <p>Some more output follows...</p>
and <a href="/"> <img src=internal-icon-delayed> </a>
Halaman / output selalu mengikuti header. PHP harus meneruskan header ke server web terlebih dahulu. Itu hanya bisa dilakukan sekali. Setelah double linebreak, mereka tidak akan pernah bisa mengubahnya lagi.
Ketika PHP menerima output pertama ( print
, echo
, <html>
) itu akan
menyiram semua header dikumpulkan. Setelah itu dapat mengirim semua output yang diinginkan. Tetapi mengirimkan tajuk HTTP lebih lanjut tidak mungkin dilakukan.
Bagaimana Anda bisa mengetahui di mana output prematur terjadi?
The header()
peringatan berisi semua informasi yang relevan untuk menemukan masalah penyebab:
Peringatan: Tidak dapat mengubah informasi header - header sudah dikirim oleh
(output dimulai pada / www / usr2345 / htdocs / auth.php: 52 ) di /www/usr2345/htdocs/index.php on line 100
Di sini "baris 100" merujuk ke skrip tempat header()
doa gagal.
Catatan " output dimulai pada " dalam kurung lebih signifikan. Ini menunjukkan sumber output sebelumnya. Dalam contoh ini itu auth.php
dan garis52
. Di situlah Anda harus mencari hasil prematur.
Penyebab khas:
Cetak, gema
Output print
dan echo
pernyataan yang disengaja akan menghentikan kesempatan untuk mengirim header HTTP. Alur aplikasi harus disusun ulang untuk menghindari itu. Gunakan fungsi
dan skema templating. Pastikan header()
panggilan terjadi sebelum pesan ditulis.
Fungsi yang menghasilkan keluaran termasuk
print
, echo
, printf
,vprintf
trigger_error
, ob_flush
, ob_end_flush
, var_dump
,print_r
readfile
, passthru
, flush
, imagepng
,imagejpeg
antara lain dan fungsi yang ditentukan pengguna.
Area HTML mentah
Bagian HTML yang tidak diurai dalam .php
file juga merupakan output langsung. Kondisi skrip yang akan memicu header()
panggilan harus dicatat sebelum ada<html>
blok mentah .
<!DOCTYPE html>
<?php
// Too late for headers already.
Gunakan skema templating untuk memisahkan pemrosesan dari logika output.
- Tempatkan kode pemrosesan formulir di atas skrip.
- Gunakan variabel string sementara untuk menunda pesan.
- Logika output aktual dan output HTML yang dicampurkan harus mengikuti yang terakhir.
Spasi sebelumnya <?php
untuk peringatan "script.php line 1 "
Jika peringatan mengacu pada keluaran sejalan 1
, maka sebagian besar mengarah spasi putih , teks atau HTML sebelum <?php
token pembuka .
<?php
# There's a SINGLE space/newline before <? - Which already seals it.
Demikian pula dapat terjadi untuk skrip yang ditambahkan atau bagian skrip:
?>
<?php
PHP sebenarnya memakan satu linebreak setelah tag penutup. Tapi itu tidak akan mengkompensasi beberapa baris baru atau tab atau spasi bergeser ke celah seperti itu.
UTF-8 BOM
Linebreak dan spasi saja bisa menjadi masalah. Tetapi ada juga urutan karakter "tidak terlihat" yang dapat menyebabkan ini. Paling terkenal adalah
UTF-8 BOM (Byte-Order-Mark)
yang tidak ditampilkan oleh kebanyakan editor teks. Ini urutan byte EF BB BF
, yang merupakan opsional dan berlebihan untuk dokumen yang disandikan UTF-8. Namun PHP harus memperlakukannya sebagai output mentah. Ini mungkin muncul sebagai karakter 
dalam output (jika klien menafsirkan dokumen sebagai Latin-1) atau "sampah" serupa.
Secara khusus editor grafis dan IDE berbasis Java tidak menyadari keberadaannya. Mereka tidak memvisualisasikannya (diwajibkan oleh standar Unicode). Namun sebagian besar programmer dan editor konsol melakukan:
Di sana mudah untuk mengenali masalah sejak dini. Editor lain dapat mengidentifikasi keberadaannya dalam menu file / pengaturan (Notepad ++ pada Windows dapat mengidentifikasi dan
memperbaiki masalah ), Pilihan lain untuk memeriksa keberadaan BOM adalah beralih ke hexeditor . Sistem On * nix hexdump
biasanya tersedia, jika bukan varian grafis yang menyederhanakan audit ini dan masalah lain:
Perbaikan yang mudah adalah dengan mengatur editor teks untuk menyimpan file sebagai "UTF-8 (tanpa BOM)" atau nomenklatur semacam itu. Seringkali pendatang baru sebaliknya membuat file baru dan hanya menyalin & menempel kembali kode sebelumnya.
Utilitas koreksi
Ada juga alat otomatis untuk memeriksa dan menulis ulang file teks ( sed
/awk
atau recode
). Khusus untuk PHP ada phptags
tag yang lebih rapi . Ini menulis ulang tag dekat dan terbuka ke dalam bentuk panjang dan pendek, tetapi juga dengan mudah memperbaiki spasi putih terkemuka, Unicode dan UTF-x BOM:
phptags --whitespace *.php
Itu wajar untuk digunakan pada keseluruhan termasuk atau direktori proyek.
Spasi setelah ?>
Jika sumber kesalahan disebutkan sebagai di balik
penutupan?>
maka ini adalah tempat spasi putih atau teks mentah ditulis. Penanda akhir PHP tidak menghentikan eksekusi skrip pada saat ini. Setiap karakter teks / spasi setelah itu akan ditulis sebagai konten halaman.
Biasanya disarankan, khususnya bagi para pendatang baru, agar ?>
tag dekat PHP harus dihilangkan. Ini menghindari sebagian kecil dari kasus-kasus ini. (Cukup umum include()d
skrip adalah pelakunya.)
Sumber kesalahan disebutkan sebagai "Tidak dikenal pada baris 0"
Ini biasanya merupakan ekstensi PHP atau pengaturan php.ini jika tidak ada sumber kesalahan yang dikonkretkan.
- Terkadang
gzip
pengaturan penyandian aliran
atauob_gzhandler
.
- Tetapi bisa juga berupa
extension=
modul berlipat ganda yang menghasilkan startup PHP / pesan peringatan implisit.
Pesan kesalahan sebelumnya
Jika pernyataan atau ekspresi PHP lain menyebabkan pesan peringatan atau pemberitahuan dicetak, itu juga dianggap sebagai hasil prematur.
Dalam hal ini Anda perlu menghindari kesalahan, menunda eksekusi pernyataan, atau menekan pesan dengan misalnya
isset()
atau @()
- ketika salah satu tidak menghalangi proses debug nanti.
Tidak ada pesan kesalahan
Jika Anda memiliki error_reporting
atau display_errors
menonaktifkan per php.ini
, maka tidak ada peringatan akan muncul. Tetapi mengabaikan kesalahan tidak akan membuat masalah hilang. Header masih tidak dapat dikirim setelah output prematur.
Jadi, ketika header("Location: ...")
pengalihan gagal secara diam-diam, sangat disarankan untuk memeriksa peringatan. Aktifkan kembali dengan dua perintah sederhana di atas skrip doa:
error_reporting(E_ALL);
ini_set("display_errors", 1);
Atau set_error_handler("var_dump");
jika semuanya gagal.
Berbicara tentang redirect header, Anda harus sering menggunakan idiom seperti ini untuk jalur kode akhir:
exit(header("Location: /finished.html"));
Lebih disukai bahkan fungsi utilitas, yang mencetak pesan pengguna dalam kasus header()
kegagalan.
Output buffering sebagai solusi
Output buffering PHPs
adalah solusi untuk mengatasi masalah ini. Ini sering bekerja dengan andal, tetapi seharusnya tidak menggantikan struktur aplikasi yang tepat dan memisahkan output dari logika kontrol. Tujuan sebenarnya adalah meminimalkan transfer chunked ke server web.
The output_buffering=
Pengaturan demikian dapat membantu. Konfigurasikan di php.ini
atau via .htaccess
atau bahkan .user.ini pada pengaturan FPM / FastCGI modern.
Mengaktifkannya akan memungkinkan PHP melakukan buffer output alih-alih meneruskannya ke server web secara instan. PHP dengan demikian dapat mengagregasi header HTTP.
Itu juga dapat digunakan dengan panggilan untuk ob_start();
di atas skrip doa. Namun yang kurang dapat diandalkan karena berbagai alasan:
Bahkan jika <?php ob_start(); ?>
memulai skrip pertama, spasi putih atau BOM mungkin akan dikocok sebelumnya, menjadikannya tidak efektif .
Itu dapat menyembunyikan spasi untuk output HTML. Tetapi begitu logika aplikasi mencoba untuk mengirim konten biner (gambar yang dihasilkan misalnya), output asing buffered menjadi masalah. (Diperlukan ob_clean()
sebagai solusi lebih jauh.)
Ukuran buffer terbatas, dan dapat dengan mudah dibanjiri ketika dibiarkan default. Dan itu juga bukan kejadian langka, sulit dilacak
ketika itu terjadi.
Kedua pendekatan karena itu dapat menjadi tidak dapat diandalkan - khususnya ketika beralih antara pengaturan pengembangan dan / atau server produksi. Itulah sebabnya output buffering secara luas dianggap hanya sebagai penopang / hanya solusi.
Lihat juga contoh penggunaan dasar
dalam manual, dan untuk lebih banyak pro dan kontra:
Tapi itu berhasil di server lain !?
Jika Anda tidak mendapatkan peringatan header sebelumnya, maka pengaturan buffer php.ini output
telah berubah. Kemungkinan tidak terkonfigurasi pada server saat ini / baru.
Memeriksa dengan headers_sent()
Anda selalu dapat menggunakan headers_sent()
untuk menyelidiki jika masih memungkinkan untuk ... mengirim header. Yang berguna untuk mencetak informasi secara kondisional atau menerapkan logika fallback lainnya.
if (headers_sent()) {
die("Redirect failed. Please click on this link: <a href=...>");
}
else{
exit(header("Location: /user.php"));
}
Solusi fallback yang berguna adalah:
<meta>
Tag HTML
Jika aplikasi Anda secara struktural sulit untuk diperbaiki, maka cara mudah (tapi agak tidak profesional) untuk memungkinkan pengalihan adalah menyuntikkan <meta>
tag HTML
. Pengalihan dapat dicapai dengan:
<meta http-equiv="Location" content="http://example.com/">
Atau dengan penundaan singkat:
<meta http-equiv="Refresh" content="2; url=../target.html">
Ini mengarah ke HTML yang tidak valid ketika digunakan melewati <head>
bagian. Sebagian besar browser masih menerimanya.
Pengalihan JavaScript
Sebagai alternatif, pengalihan JavaScript
dapat digunakan untuk pengalihan halaman:
<script> location.replace("target.html"); </script>
Meskipun ini sering lebih sesuai dengan HTML daripada <meta>
solusinya, ini menimbulkan ketergantungan pada klien yang berkemampuan JavaScript.
Namun kedua pendekatan membuat fallback yang dapat diterima ketika panggilan HTTP asli () gagal. Idealnya Anda akan selalu menggabungkan ini dengan pesan yang ramah pengguna dan tautan yang dapat diklik sebagai pilihan terakhir. (Yang misalnya adalah apa yang http_redirect ()
ekstensi PECL .)
Mengapa setcookie()
dan session_start()
juga terpengaruh
Keduanya setcookie()
dan session_start()
perlu mengirimSet-Cookie:
header HTTP. Karena itu, kondisi yang sama berlaku, dan pesan kesalahan serupa akan dihasilkan untuk situasi keluaran prematur.
(Tentu saja mereka lebih jauh dipengaruhi oleh cookie yang dinonaktifkan di browser, atau bahkan masalah proxy. Fungsi sesi jelas juga tergantung pada ruang disk kosong dan pengaturan php.ini lainnya, dll.)
Tautan selanjutnya