“headers already sent by” hatası ve çözümü

PHP ile ilgilenen birçok kişinin başına gelmiştir.

Warning: Cannot modify header information – headers already sent by (output started at /home/***/cihanaksoy/headersalready.php:1) in /home/***/headersalready.php on line 38

Bu hatayla ilgili stackoverflowun şu sayfasında çok güzel bir açıklama var. Bende arkadaşın anlattıklarının hemen hemen aynısı anlatacağım. Öncelikle birçok blogda ve forumda gördüğüm “sayfanın başına ob_start() ekle” v.s gibi basit çözümleri sunarak makaleyi bitirmeyeceğim. Bu hata nedir ve neden olur mantığını anlayarak çözüme ulaşacağız.

Genelde aşağıda verdiğim fonksiyonlar ile bu hataları yaşarsınız

Peki neden bu fonksiyon diye soracak olursanız. Çünkü! bu fonksiyonlar HTTP header’da değişikliğe giderler. HTTP header html kodundan görünmesede php webserver’a bu headerı gönderirler. Şuna benzer;

HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Length: 99
Content-Type: text/html; charset=UTF-8
Date: Thu, 15 Oct 2015 08:37:29 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.7 (Win32) PHP/5.6.13
X-Powered-By: PHP/5.6.13

<html><head><title>PHP çıktı sayfası</title></head>
<body><h1>İçerik</h1> <p>İçerik yazısı</p></a>

Yukarda görmüş olduğunuz ilk 8 satır HTTP Header olarak adlandırılır. O zaman sırasıyla adımlarımız şu şekilde;

  1. Header oluşturulur
  2. Webserver’a gönderilir
  3. HTML çıktısı gönderilir

Aslında gayet mantıklı. Header gönderildikten sonra nasıl tekrar değiştirilsin ki değil mi ? PHP kodlarıyla bunu anlatmaya çalışalım. Aşağıdaki gibi bir kodumuz olsun.

header('Content-Type: text/html; charset=utf-8');

echo '<html><head><title>PHP çıktı sayfası</title></head>
<body><h1>İçerik</h1> <p>İçerik yazısı</p></a>';

Şimdi bu PHP çıktımızın HTTP header bölümü şu şekilde;

HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Length: 99
Content-Type: text/html; charset=utf-8
Date: Thu, 15 Oct 2015 08:39:01 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.7 (Win32) PHP/5.6.13
X-Powered-By: PHP/5.6.13

Peki şimdi bu kodumuza birde session_start ekleyerek deneyelim.

header('Content-Type: text/html; charset=utf-8');
session_start();

echo '<html><head><title>PHP çıktı sayfası</title></head>
<body><h1>İçerik</h1> <p>İçerik yazısı</p></a>';

HTTP header çıktımız şu şekilde olacak;

HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection: Keep-Alive
Content-Length: 99
Content-Type: text/html; charset=utf-8
Date: Thu, 15 Oct 2015 08:41:00 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive: timeout=5, max=100
Pragma: no-cache
Server: Apache/2.4.7 (Win32) PHP/5.6.13
X-Powered-By: PHP/5.6.13

Diğeriyle karşılaştırırsanız değişiklikleri görebilirsiniz. İlk başta header hazırlanıp sonra html çıktısı basıldığından dolayı ekrana herhangi bir çıktı verilmeden önce halletmemiz gerekiyor.

Şimdi bu hatanın nasıl meydana geldiğini öğrendik. İlk başta verdiğimiz stackoverflow linkinde ki arkadaşın “olası nedenler” listesini türkçeleştirerek yazalım;

1-) Print, Echo

Ekrana çıktı veren print, echo gibi fonksiyonları header oluşturulduktan sonra kullanmaya özen gösterin. Bir tema motoru kullanmanız bu tip sorunları aşmanızda size kolaylık sağlar. HTML çıktısı oluşturabilecek bazı fonksiyonlar;

  • print
  • echo
  • printf
  • vprintf
  • trigger_error
  • ob_flush
  • ob_end_flush
  • var_dump
  • print_r
  • readfile
  • passthru
  • flush
  • imagepng
  • imagejpeg

2-) Yalın olarak kullanılan HTML alanları

PHP ile çıktı verilmemiş yalın olarak kullanılan HTML tagları HEADER çıktısını önleyebilir. Örneğin;

<!DOCTYPE html>
<?php
    // Artık header oluşturamazsınız. Çok geç!

Bunun çözümüde yine tema motoru kullanmaktan geçiyor.

3-) <?php tagından önce “beyaz boşluk” olması

Eğer “phpdosyaniz.php line 1” gibi bir hata alıyorsanız. Yani PHP hatanın 1. satırda olduğunu söylüyor ama siz bir hata göremiyorsaız muhtemelen hatanız beyaz bir boşluktur. Sonuçda beyaz boşlukda bir çıktıdır ve sonrasında header oluşturmak mantıksız olur.

4-) UTF-8 BOM

Beyaz boşluklar, html çıktıları bunların hepsi gözle görebildiğimiz problemler ve halledilmesi kolay. Peki ya dosyamızın içinde göremediğimiz karakterler ? Bu genelde “UTF-8 BOM (Byte-order-Mark)” dil seçeneğini kullandığımız zaman başımıza gelen bir sorundur. Bunun sebebi birçok text editor BOM’un başlangıçta ürettiği Byteları varsayılan olarak gizliyor olması.

Eğer dosyanızı bir hex editor ile açacak olursanız bu byteları görebilirsiniz.

Hex Editör Örnek

Bunun kolay çözümü editörünüzden kodlama seçeneğini “UTF-8 BOMsuz” olarak ayarlamaktır. Notepad++ kullananlar için şu şekilde değiştirmelisiniz;

Notepad++ utf-8 bomsuz seçeneği

5-) Kapatma tagından (?>) sonra beyaz boşluk olması

Bazen kapatma taglarından sonra istemsiz olarak beyaz boşluk bırakabiliyoruz. Özellikle PHP’ye yeni başlayanlar “include()” fonksiyonunu kullanırken hatalar yapabiliyor.  Sayfanın başında bazı kontrol fonksiyonları için include edildikten sonra kapatma tagından sonra bir boşluk bırakmadığınıza emin olun.

6-) “Unknown on line 0” bilinmeyen hatası

Bu hata genellikle php.ini ayarlarınızda ki bir hata mesajının çıktı vermesinden dolayı gerçekleşir.

  1. Gzip encoding ayarlarından yada ob_gzhandler’dan kaynaklanabilir.
  2. PHP.ini’de bir eklentiyi iki kere yazmışsanız bu problem yaşanabilir.

7-) Hata mesajlarından dolayı hata vermesi

HTTP header işlemleri bitmeden önce bir hata verdiyse hata mesajı ile birlikte header already sent by hatası verecektir. Burda asıl önemli olan ilk verdiği hatayı düzeltmektir. Çünkü bir hata meydana gelip çıktı verildiği için already sent by hatası almanız çok muhtemel.

Hata mesajları kapalı olabilir!

Bazı durumlarda hiçbir hata almıyorsanız ama “header(‘Location: error.php’);” gibi bir yönlendirme fonksiyonunuz çalışmıyor ise büyük ihtimalle php.ini’den hata mesajlarınızı kapatmışsınız demektir. Debug modunda çalışırken hata mesajlarını ek etmeyin.

Hata mesajlarını açmak için;

error_reporting(E_ALL);
ini_set("display_errors", 1);

kodlarını sayfanızın başında kullanabilirsiniz.

Çözüm

Her hata mesajının çözümünü tek tek açıkladık. Ancak bazen çok geç olabiliyor. Localhost’da çalışan bir sistem sunucuda bu tip hatalara neden olabiliyor. Peki hal böyleyken nasıl bir çözüm üretebiliriz. Output Buffering türkçe adıyla Çıktı tamponlama!

PHP.ini yada htaccess ile aktif edebileceğim Output Buffering ile header already sent hatasından kurtulmuş oluruz.

Output buffering nasıl aktif edilir?

  1. php.ini ‘den değişiklik yaparak aktif edebilir.
    Output Buffering php.ini
    Resimde gördüğünüz ayarı 4096 yapıyoruz ve hatadan kurtulmuş oluruz.
  2. Htaccess ile output bufferingi aktif etmek
    php_flag output_buffering On

    kodumuzu .htaccess dosyamıza ekleyerek çıktı tamponlamayı açmış oluruz.

ÇÖZÜM 2

Kodunuzun en başına ob_start koyabilirsiniz. Bu hatayı engelleyecektir ancak header(‘Location: ‘); gibi header komutlarında sıkıntılar yaratabilir. Bunun için ilk çözüm yolunu yapmanız en mantıklısı olacaktır.

Farklı yönlendirme methodları

İkinci çözüm yolu size daha cazip geldiyse ve yönlendirme komutunuz (header(‘Location: cihanaksoy.php’)) çalışmıyor ise 2 farklı şekilde yönlendirme yapabilirsiniz.

  1. HTML Meta tagını kullanarak
    <meta http-equiv="Location" content="http://cihanaksoy.com/">

    yada süreli bir yönlendirme yapmak istiyorsanız

    <meta http-equiv="Refresh" content="2; url=../cihanaksoy.html">

    olarak kullanabilirsiniz.

  2. Javascript kullanarak
    <script> location.href("cihanaksoy.html"); </script>

    kodunu kullanarak Javascript ile yönlendirme yapabilirsiniz.

Bugünlük bu kadar. Bir sonrakki makalemizde görüşmek üzere.

2 Yorum

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

This site uses Akismet to reduce spam. Learn how your comment data is processed.