PHP'de "Başlıklar zaten gönderildi" hatası nasıl düzeltilir. Hata kontrol operatörü

  • 03.11.2019

Programlamanın ayrılmaz bir parçası, koddaki hataların tanımlanmasıdır. Bir programcı alnında en az yedi açıklık olsun, yine de hatalar yapacak, hatta bazen banal olanlar. Bu, insanın doğası gereği kolaylaştırılmıştır. Bu nedenle, programcı zamanının çoğunu koddaki hataları ayıklamak ve tanımlamak için harcar. Buna göre, koddaki hataları tespit etmek için ne kadar esnek ve kullanışlı araçlar varsa ve programcı bunları ne kadar iyi bilirse, üretkenliği de o kadar yüksek olur.

PHP bir betik programlama dili olduğundan, kodda yapılan tüm hatalar kod yürütülürken algılanır. Bir PHP programcısı olarak, hem genel olarak programlamaya özgü standart hatalarla hem de değişkenleri adlandırmadaki yazım hataları gibi oldukça gizli hatalarla uğraşmanız gerekecek.

PHP dili, yürütülmesi sırasında komut dosyasındaki hataları algılamak için iki mekanizma sağlar: standart PHP hata mekanizması ve istisna mekanizması. PHP'de birçok işlevsellik standart hata mekanizmasını kullanır, bu yüzden bunu bilmemek imkansızdır. Bu nedenle, bu makalede bu mekanizmaya odaklanacağız.

Standart PHP hata mekanizması oldukça basittir - PHP yorumlayıcısı bir betiği çalıştırırken bir hatayla karşılaşırsa, programcıyı bu konuda bilgilendirmeye çalışır. Ancak, bu mekanizma için oldukça fazla ayar vardır, bu yüzden PHP bilen bir programcının bunları anlaması oldukça zordur.

Hatalar görüyoruz

Bu nedenle, PHP'nin hataları doğrudan sayfada göstermesi için kodda özel bir parametre ayarlamanız gerekir:

ini_set("display_errors", 1); //display_errors, hataları doğrudan sayfada görüntülemekten sorumludur. 0 - hatalar görüntülenmiyorsa

Şimdi, komut dosyasında herhangi bir hata oluşursa, yorumlayıcı sayfada bununla ilgili bilgileri görüntüler. Örneğin, var olmayan bir işleve sahip bir komut dosyası çalıştırırsanız:

ini_set("display_errors", 1);
Eko "

Görüntülenecek dize

";
yankı abrakadabra();
Eko "

Bir hata nedeniyle görüntülenmeyecek satır

";

sayfa aşağıdaki hatayı gösterecektir:

Ölümcül hata. Bu tür bir hata, betiğin çalışmasını kesintiye uğrattığı ve aşağıdaki kodun yürütülmeyeceği anlamına gelir.

Sayfadaki komut dosyası hatalarının görüntülenmesi yalnızca komut dosyasının hatalarını ayıklamak için kullanılır, bu nedenle kodu bir üretim ortamında çalıştırırken display_errors parametresi 0 olarak ayarlanır.

Genel olarak, PHP'nin farklı önemli kategorilerde hataları vardır: bazıları kodun daha fazla yürütülmesini kesintiye uğratır - diğerleri yapmaz, bazıları yakalanabilir - diğerleri yapamaz. Hata kategorilerinin tam listesi aşağıda verilmiştir:

Anlam
Devamlı
Tanım
Olasılık
1
E_ERROR
ölümcül hata
Değil
2
E_UYARI
düzeltilebilir hata
Evet
4
E_PARSE
Ayrıştırıcı hata
Değil
8
E_NOTICE
potansiyel hata
Evet
16
E_CORE_ERROR
E_ERROR'a benzer, ancak PHP çekirdeği tarafından oluşturulur
Değil
32
E_CORE_WARNING
E_WARNING'e benzer, ancak PHP çekirdeği tarafından oluşturulurDeğil
64
E_COMPILE_ERROR
E_ERROR'a benzer, ancak Zend Engine tarafından oluşturulur
Değil
128
E_COMPILE_UYARI
E_WARNING'e benzer ancak Zend Engine tarafından üretilmiştirDeğil
256
E_USER_ERROR
E_ERROR'a benzer, ancak trigger_error() tarafından tetiklenir
Evet
512
E_USER_WARNING
E_WARNING'e benzer, ancak trigger_error() tarafından tetiklenirEvet
1024
E_USER_NOTICE
E_NOTICE'a benzer, ancak trigger_error() tarafından tetiklenirEvet
2048
E_STRICT
Kod kalitesini iyileştirme önerileriyle çalışma zamanından mesaj (PHP5'ten beri)
-
4096
E_RECOVERABLE_ERROR
Tehlikeli ancak önemli olmayan hata (ör. tür uyuşmazlığı)
Evet
8192
E_ KULLANIMDAN KALDIRILDI
Kullanımdan kaldırılan özellik veya özellik uyarısı
Evet
16384
E_USER_DEPRECATED
Kullanımdan kaldırılan özellik veya kodda belirtilen özellik kullanım uyarısı
Evet
32767
E_ALL
Tüm hatalar
Değil

Kolaylık sağlamak için, bir bit maskesi oluşturarak hata işleme düzeyini belirlemek için kullanılan sabitler sağlanmıştır. Sabitlerin "konuşan" adları vardır. Sabite baktığımızda - sözdizimi hatası durumunda E_PARSE düzeyinde bir hata oluştuğunu söyleyebiliriz, E_NOTICE programcıya PHP programlamanın "iyi stilini" bozmanın bir hatırlatıcısıdır.

Varsayılan olarak, hata mesajı oluşturma modunun değeri E_ALL & ~E_NOTICE şeklindedir ve bu, E_NOTICE kategorisine ait olmayan tüm mesajların çıktısına karşılık gelir. Programcı, sayfada hangi hata kategorilerini görmesi gerektiğini esnek bir şekilde yapılandırabilir. Hata oluşturma modunu değiştirmek için, error_reporting yapılandırma parametresini değiştirmeniz gerekir. Herhangi bir hatanın görüntülenmesini etkinleştirmek için bu parametreyi E_ALL olarak ayarlamalısınız:

Örneğin, aşağıdaki kodu çalıştırırsanız:

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

Aynı anda iki kategoride hata alacağız (uyarı ve uyarı):

Bildirilmemiş bir değişken kullanıldığında, bir E_NOTICE hatası oluşur. MySQL (veya başka bir) veritabanına bağlantı başarısız olduğunda, PHP yorumlayıcısı E_WARNING düzeyinde bir hata bildirir.

Günlük hataları

display_errors yapılandırma parametresi 0 olarak ayarlansa bile, komut dosyası yürütme sırasında meydana gelen hataların varlığının görüntülenmesi yine de mümkün olmalıdır. Bu nedenle, bir hata meydana gelirse, nerede ve neden olduğunu bilmeliyiz. Bu amaçlar için PHP, hata günlüğü ayarlarına sahiptir.

Varsayılan olarak, PHP hiçbir yerde hataları günlüğe kaydetmez. Bunu değiştirmek için log_errors yapılandırma parametresini 0'dan 1'e değiştirmeniz gerekir:

ini_set("log_hataları", 1);

Bu durumda, hatalar otomatik olarak error_log yapılandırma parametresinde belirtilen dosyaya kaydedilir. error_log parametresi, hataların günlüğe kaydedileceği istenen dosyanın yolu belirtilerek de değiştirilebilir:

ini_set("error_log", "/var/log/php_errors.log");

Yani, kod için:

ini_set("display_errors", 1);
ini_set("hata_raporlama", E_ALL);
ini_set("log_hataları", 1);
ini_set("hata_log", __DIR__ . "/log.txt");
$db = mysql_connect($db_host, "kullanıcı", "şifre");

Benzer bilgiler günlük dosyasına yazılır ve sayfada görüntülenir:

PHP Uyarısı: Tanımsız değişken: 7. satırda Z:\home\test\www\index.php içindeki db_host
PHP Uyarı: mysql_connect(): 7. satırda Z:\home\test\www\index.php içindeki "user"@"localhost" kullanıcısı (şifre kullanılarak: YES) için erişim reddedildi

İşleme Hataları

Hatalar, yakalanabilir ve engellenemez olarak ikiye ayrılır. Kritik olmayan hatalar özel kod tarafından yakalanabilir. Hata kategorisi açıklama özet tablosu, hangi hata kategorilerinin yakalanabileceği hakkında bilgi verir.

Kodda kritik olmayan hataları yakalamak için kendi fonksiyonunuzu gerçekleyip ilan etmeniz ve set_error_handler fonksiyonuna ismini iletmeniz yeterlidir. Aynı zamanda, uygulanan fonksiyona 5 parametre iletilir:

  • bir tamsayı olarak hata seviyesi;
  • bir dize olarak hata mesajı;
  • dize olarak hatanın oluştuğu dosyanın adı;
  • tamsayı olarak hatanın oluştuğu satır numarası;
  • hatanın oluştuğu kapsamda bulunan tüm değişkenlerin bir dizisi. Ayrıca, global değişkenler de dahil edilecektir.
,

Çıktı

PHP, standart hata yayılımını işlemek ve yönetmek için güçlü araçlara sahiptir. Bu nedenle, komut dosyasının doğru yapılandırılması şartıyla, şu veya bu hatayı yakalamak zor olmayacaktır. Birçok kod yukarıda açıklanan mekanizmayı kullandığından, bu alan bilgisi herhangi bir PHP programcısı için çok önemlidir.

PHP bir hata işleme operatörünü destekler: @ işareti. PHP kodundaki herhangi bir ifadeden önce gelmesi durumunda, bu ifade tarafından oluşturulan herhangi bir hata mesajı yok sayılır.

ile kendi hata işleme işlevinizi ayarlarsanız set_error_handler(), o zaman yine de çağrılır, ancak bu işlevin içindeyse işlev error_reporting(), hataya neden olan işlev @ ile bastırılmışsa 0 döndürür.

Seçenek ayarlanmışsa track_errors, oluşturulan tüm hata mesajları $php_errormsg değişkeninde saklanacaktır. Her yeni hatada bu değişkenin üzerine yazılacaktır, bu nedenle gerekirse hemen kontrol edin.

// Dosyalarla çalışırken kasıtlı hata
$my_file = @file("non_existent_file" ) veya
ölmek( "Dosya açılırken hata oluştu: Hata mesajı şuydu: "$php_errormsg "" );

// sadece işlevler için değil, herhangi bir ifade için çalışır
$değer = @ $önbellek [ $anahtar ];
// $key anahtarı yoksa, hata mesajı (uyarı) görüntülenmez

?>

Yorum: @ operatörü yalnızca ifadelerle çalışır. Basit bir kural vardır: Bir şey bir değer döndürürse, önünde @ operatörünü kullanabilirsiniz. Örneğin, bir değişken adından, rastgele bir işlevden veya bir çağrıdan önce @ kullanabilirsiniz. Dahil etmek, bir sabit vb. Aynı zamanda, bu operatörü bir fonksiyon veya sınıf tanımından önce kullanamazsınız, aşağıdaki gibi koşullu yapılar Eğer, foreach vb.

Ayrıca işlevin açıklamasına bakın error_reporting() ve manuel bölüm Hata İşleme ve Günlüğe Kaydetme İşlevleri.

Dikkat

Bugün, "@" operatörü, komut dosyasını kesintiye uğratan kritik hatalar hakkında bile mesajların çıktısını bastırır. Diğer şeylerin yanı sıra, bu, herhangi bir işlevin çalışması sırasında meydana gelen hataları bastırmak için "@" kullandıysanız, mevcut değilse veya yanlış yazılmışsa, herhangi bir bildirimde bulunmaksızın daha fazla komut dosyası çalışmasının durdurulacağı anlamına gelir.

12 yıl önce

Yeni bir sınıf/nesne için hataları bastırmak için:

// Test edildi: PHP 5.1.2 ~ 2006-10-13

// Tipik örnek
$var = @some_function();

// Sınıf/Nesne Örneği
$var = @new bazı_class();

// Çalışmıyor!
//$var = yeni @some_class(); // sözdizimi hatası
?>

Bunu en çok bir ağa bağlanırken faydalı buldum.
hataları kontrol etmek istediğim veritabanı
ve müşteriye görüntülenen uyarılar, hala
sınıf erişim stilini kullanma.

14 yıl önce

trigger_error()() işlevini kullanmak daha iyi
tanımlı uyarıları, uyarıları ve hataları görüntülemek için hata seviyesini kendiniz kontrol edin. bu, php.ini'de tanımlanmışsa günlük dosyalarına mesaj yazmanıza izin verir, çıktı
error_reporting() düzeyine bağlı olarak mesajlar ve @-işaretini kullanarak çıktıyı bastırır.

8 yıl önce

Birleştirilmiş bir hata yönetimine sahip olmak için ErrorException istisnasını kullanırsanız, error_reporting istisna işleyicisine iletilmeyebileceğinden boş sayfalar gibi bazı baş ağrılarıyla karşılaşabileceğiniz için istisna işleyicide değil, hata işleyicide error_reporting'e karşı test yapmanızı tavsiye ederim. .


{
}

function catchException ($e )
{
{
dönüş;
}

// Bir şeyler yap
}

?>

Bunu yapmak daha iyi olurdu:

FunctionException_error_handler ($errno , $errstr , $errfile , $errline )
{
if (error_reporting() === 0 )
{
dönüş;
}

Yeni ErrorException ($errstr , 0 , $errno , $errfile , $errline );
}

set_error_handler("exception_error_handler");

function catchException ($e )
{
// Bir şeyler yap
}

set_exception_handler("catchException");

?>

4 yıl önce

@ operatörü konusunda kesinlikle çok liberal olmamanız gerekirken, bunun günah olduğunu iddia eden nihai insanlara da katılmıyorum.

Örneğin, .ini dosyasının eksik olabileceğini biliyorsanız, parse_ini_file() tarafından oluşturulan uyarı düzeyindeki hatayı bastırmak çok makul bir kullanımdır.
Benim durumumda YANLIŞ dönüş değerini almak bu durumu halletmek için yeterliydi, ancak API'm tarafından verilen hataların fark edilmesini istemedim.

TL; DR: Kullanın, ancak yalnızca neyi bastırdığınızı ve nedenini biliyorsanız.

2 yıl önce

İfade bir hatayla karşılaştığında, Hata Kontrol Operatörü tarafından korunan bir ifadenin dönüş değeri atanan bir değişken için PHP'nin davranışı nedir?

Aşağıdaki koda göre sonuç NULL'dur (ancak bunun her durumda doğru olduğu onaylansaydı iyi olurdu).

$var = 3 ;
$dizi = dizi();

$var = @$dizi["x"]; // bu atamadan sonraki $var değeri nedir?

// atama hiç gerçekleşmemiş gibi önceki değeri (3) mü?
// YANLIŞ mı yoksa NULL mu?
// bir tür istisna mı yoksa hata mesajı mı yoksa hata numarası mı?

Var_dump($var); // "NULL" yazdırır

?>

5 yıl önce

Herhangi birinin (başkasının) hata operatörünü devre dışı bırakmak/etkinleştirmek için bir yönerge bulup bulamayacağını merak ediyordum. Yani, (bazı kodlarda birkaç yerde gördüğüm) gibi bir şey yerine:

if (tanımlı(ÜRETİM) )) {
@işlev();
}
Başka(
işlev();
}

?>

Bunun gibi bir şey olabilir:

If (tanımlanmış (ÜRETİM )) (
ini_set("hata.silent", DOĞRU);
}
Başka(
ini_set("hata.silent", YANLIŞ);
}

?>

12 yıl önce

Bir oturumdan bir php betiği için tüm hata mesajlarını günlüğe kaydetmek istiyorsanız, şöyle bir şey kullanabilirsiniz:
oturum_başlangıç();
işlev hatası ($hata, $dönüş = YANLIŞ) (
global $php_errormsg ;
if(isset($_SESSION [ "php_errors" ])) (
$_SESSION[ "php_errors" ] = dizi();
}
$_SESSION["php_errors"] = $hata; // Belki $php_errormsg kullan
if($dönüş == DOĞRU ) (
$mesaj = "" ;
foreach($_SESSION ["php_errors"] as $php_error ) (
$mesajlar .= $php_error . "\n" ;
}
$mesajları döndür ; // Veya $_SESSION["php_errors"] kullanabilirsiniz
}
}
?>
Umarım bu birine yardımcı olur ...

PHP, meydana gelen hataları kontrol etmek için harika bir yol sağlar. Burada bir hatanın nasıl ele alınacağı hakkında konuşacağız - gerekirse olayı kullanıcıya bildirin (veya rapor etmeyin) - yöneticiyi e-posta ile bilgilendirin, olayla ilgili bilgileri günlük dosyasına yazın.

İlk önce PHP'de hangi hataların olduğunu tanımlayalım.

PHP aşağıdaki hata düzeylerini destekler:

E_ERROR
E_UYARI
E_PARSE
E_NOTICE
E_CORE_ERROR
E_CORE_WARNING
E_COMPILE_ERROR
E_COMPILE_UYARI
E_USER_ERROR
E_USER_WARNING
E_USER_NOTICE
E_ALL
E_STRICT

Aslında, bunlar sadece bir bit maskesi oluşturarak hata işleme düzeyini belirlemek için kullanılan sabitlerdir. Sabitlerin "konuşan" adları vardır. Sabite baktığımızda - bir sözdizimi hatası durumunda E_PARSE düzeyinde bir hata oluştuğunu söyleyebiliriz, E_NOTICE programcıya PHP programlamanın "iyi stilini" bozma konusunda bir hatırlatmadır.

Birkaç örnek:

MySQL (veya başka bir) veritabanına bağlantı başarısız olduğunda - PHP yorumlayıcısı E_WARNING düzeyinde bir hata bildirir

Uyarı: mysql_connect(): Kullanıcı için erişim reddedildi: " [e-posta korumalı]" (Şifre kullanarak: EVET) /home/mysite/index.php'de (satır 83)

Not: PHP yorumlayıcısının hataları bildirebilmesi için PHP'nin uygun şekilde yapılandırılması gerekir: display_errors bayrağı etkinleştirilmelidir - 1, error_reporting yönergesi E_WARNING düzeyindeki hataları (tercihen diğerleri, elbette) görüntülemenin gerekli olduğunu belirtmelidir. . Bu yönergelerin değerleri gereksinimlerinizi karşılamıyorsa, aşağıdaki içeriğin bulunduğu .htaccess dosyasını (adın başındaki nokta gereklidir) komut dosyasının bulunduğu klasöre yerleştirerek kendiniz yüklemeyi deneyebilirsiniz:

php_flag display_errors açık
php_value error_reporting "E_ALL & ~E_NOTICE"

Bu, hata mesajlarının ve E_NOTICE dışındaki tüm seviyelerin gösterileceği anlamına gelir.
Bir programcı sözdizimi hatası yaptığında, PHP yorumlayıcısı E_PARSE düzeyinde bir hata bildirir.

Ayrıştırma hatası: ayrıştırma hatası, beklenmeyen '(', 150. satırda /home/mysite/index.php dosyasında T_STRING bekleniyor

Ama bizim için en ilginç hata seviyeleri E_USER_ERROR ve E_USER_WARNING. Adından da anlaşılacağı gibi, bunlar kullanıcının ayarlayabileceği hata seviyeleridir. Bunun için bir trigger_error() işlevi vardır - onun yardımıyla, PHP'nin yaptığı gibi kullanıcıyı olay hakkında bilgilendirebilirsiniz.

PHP kılavuzundan bildiğiniz gibi, trigger_error() işlevi iki parametre alır.

void trigger_error(string error_msg[, int error_type])

İlk parametre, "dosya bulunamadı" gibi metinsel bir hata mesajıdır. İkinci parametre hata seviyesini belirtir. trigger_error() işlevi yalnızca E_USER hata ailesiyle çalışır; bu, bir E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE düzeyinde hata ayarlayabileceğiniz ve E_WARNING düzeyinde bir hata ayarlayamayacağınız anlamına gelir. İkinci parametre isteğe bağlıdır ve varsayılan olarak E_USER_NOTICE şeklindedir.

Hadi deneyelim:

Diyelim ki haber akışı için verilerimiz news.txt dosyasında saklanıyor ve dosya bulunamazsa bir hata bildirmemiz gerekiyor. Programın metni şöyle görünecek:

if (!file_exists('/home/mysite/news.txt')) (
trigger_error('Haber dosyası bulunamadı');
}

Sonuç olarak, PHP yorumlayıcısı E_USER_NOTICE düzeyinde bir hata bildirecektir.

Uyarı: Haber dosyası 47. satırda /home/mysite/index.php içinde bulunamadı
Ama bize ne veriyor? Yeni başlayanlar için, yönergeler php.ini veya .htaccess dosyasında ayarlanmışsa

php_value log_errors "1"
php_value log_errors_max_len "1024"
php_value error_log "/home/mysite/my.log"
Ardından, /home/mysite/my.log dosyasına olayla ilgili bir giriş otomatik olarak eklenecektir.

PHP Uyarısı: 47. satırda /home/mysite/index.php içinde haber dosyası bulunamadı
Ayrıca set_error_handler() işlevini kullanarak, bir PHP betiğinin yürütülmesi sırasında oluşan kendi hata işleyicimizi ayarlayabiliriz.

Kılavuzdan bildiğiniz gibi - PHP 4'te, işlev tek bir dize parametresi alır - her hata oluştuğunda yürütülecek işlevin adı. PHP 5, bir parametre daha ayarlamayı mümkün kılar - işleyicimiz kullanılarak işlenecek hataların türü. İşlev, bu noktaya kadar ayarlanmış işleyici işlevinin adı olan bir dize döndürür.

string set_error_handler(geri arama error_handler[, int error_types])

böyle ayarla

set_error_handler("my_error_handler");
Hataları işleyecek özel bir işlev aşağıdaki giriş parametrelerini alabilir:

— hata seviyesi kodu
- hatanın dize yorumu
- hatanın oluştuğu dosyanın adı
- hatanın oluştuğu satır

Ayrıca bu fonksiyonun E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING seviyelerindeki hataları işleyemeyeceğine dikkat edilmelidir.

Bunun nedeni, listelenen hata düzeylerinin, yorumlayıcı özel hata işleyici hakkında herhangi bir bilgiye sahip olmadan önce ortaya çıkmasıdır.

O halde fonksiyonumuzu ilan edelim.

function my_error_handler($kod, $msg, $dosya, $satır) (
}

Not: Her bir az ya da çok hacimli komut dosyası, onunla çalışmanın rahatlığı için genellikle birkaç dosyaya bölünür. Programın modülerliğinin nasıl organize edileceği ayrı bir konuşma konusudur. Şimdi size sadece genel ayarları ayrı bir dosyaya ayırmanızı tavsiye etmek istiyorum, bu dosya programın başında include deyimini kullanarak veya auto_prepend_file yönergesini kullanarak bağlanacak. İşleyicimiz de bu dosyaya yerleştirilebilir. Hata işleyicinin kurulumu, programın başlangıcına mümkün olduğunca yakın, tercihen en başında yapılmalıdır.
Bunun gerçekten çalıştığından emin olmak için yeni bir PHP dosyası oluşturalım ve onu çalıştırmayı deneyelim.

myerrortest.php dosyasının içeriği

n"; echo "$file ($satır)"; ) set_error_handler("my_error_handler"); if (!file_exists("/home/mysite/news.txt")) ( trigger_error("Haber dosyası bulunamadı"); ) ?>

Bu dosyanın işlenmesinin sonucu aşağıdaki gibi olacaktır:

Bir hata oluştu Haber dosyası bulunamadı (1024)
/home/mysite/myerrortest.php (12)
Artık oluşan tüm hatalar hakkında veri alan bir fonksiyonumuz var. Bunu nasıl kullanabileceğimizi düşünelim.

Seviye hatalarını ele alacağız
E_ERROR
E_UYARI
E_NOTICE
E_USER_ERROR
E_USER_NOTICE

İyi bitmiş bir programda ilk üç hata hiç oluşmamalıdır, bu yüzden bunları sadece hata metnini ekranda göstererek kullanıcıya bildireceğiz. Bu, komut dosyası geliştirme durumundayken çalışabilir, ardından bunlarla ilgili mesajlar devre dışı bırakılabilir veya bir günlük dosyasına yazılabilir.

Diğer ikisine gelince - tahmin ettiniz - orada işe yarayabilirler. Gerekirse kendimiz bu seviyelerin hatalarına neden olacağız. Diyelim ki - E_USER_ERROR seviyesindeki hatalar - hata mesajının günlük dosyasına girmesi ve yöneticinin e-postasına gönderilmesi gerektiğinde (örneğin, bir SQL sorgusu yürütülürken bir hata veya erişim eksikliği) durumunda arayacağız. gerekli dosyaya). E_USER_NOTICE düzeyindeki hatalar, "hafif" hatalar oluştuğunda (örneğin, kullanıcı formu yanlış doldurduğunda veya veritabanından var olmayan bir kayıt talep ettiğinde) ortaya çıkar.

Şimdi hata işleme fonksiyonumuz şöyle görünecek:

// Bazı ön ayarlar // hata görüntüleme modunu // E_NOTICE error_reporting (E_ALL & ~E_NOTICE) dışındaki tüm hataları gösterecek şekilde ayarlayın; // bu sabit // hata ayıklama modunu etkinleştirmek/devre dışı bırakmaktan // hata ayıklama sırasında sorumludur - mesajlar // posta ile gönderilmez, sadece ekrana yazdırılır define("DEBUG", 0); // bu, // kullanıcının görmek istediği mesajı saklayacak olan global bir değişkendir // $MSG = ""; // geliştiricinin hataların nereye gönderileceği e-postası define("ADM_EMAIL"," [e-posta korumalı]"); // günlük dosyası define("LOGFILE","/home/mysite/mylog.log"); // sunucu ile zaman farkı (saniye cinsinden) define("TIMEOFFSET", 0); // fonksiyonun kendi fonksiyonu my_error_handler($kod, $msg, $dosya, $satır) ( // hata mesajının yazılacağı // global değişken. global $MSG; // E_NOTICE düzeyindeki hataları yoksay // ve mesaj modu hata raporlaması varsa hataları yoksay (($code == E_NOTICE) veya (error_reporting() == 0)) ( dönüş; ) // eğer E_USER_NOTICE düzeyinde bir hataya neden olduysak - // hata metnini $MSG global değişkenine yazmanız yeterlidir // ve if ($code == E_USER_NOTICE) ( $MSG = $msg; Return; ) // eğer hata E_ERROR ise - hata metnini yazdırın // ve eğer ($code == E_ERROR) ( die ("
HATA:".$mesaj."
".$file." (satır ".$satır.")
"); ) // E_WARNING seviyesinde bir hata varsa - hatanın metnini yazdırın // ve if ($code == E_WARNING) ( echo "
UYARI:".$mesaj."
".$file." (satır ".$satır.")
"; Return; ) // E_USER_ERROR düzeyinde bir hata varsa if ($code == E_USER_ERROR) ( // $MSG değişkenine hatanın oluştuğu metni yazın, // nedenlerini bildirmeyeceğiz, sadece ayrıntıların // e-postaya gönderildiğini bildir $MSG = "Önemli Hata: Eylem başarısız oldu.
Geliştiriciye bir hata mesajı gönderildi."; // ayrıntıları $metin değişkenine $metin = $msg yazın."
"."Dosya: ".$dosya." ("".$line.")"; // DEBUG sabiti 1 olarak ayarlanmışsa - // ekrandaki hata hakkındaki bilgileri yazdır, değilse - hata metnini postayla gönder // error_mail() işlevi ve günlüğe yaz - error_writelog() işlevi if (DEBUG == 1) ( error_print($text); ) else ( error_mail($text); error_writelog($text); ) Return; ) ) // işleyiciyi ayarla set_error_handler ("my_error_handler"); Şimdi yardımcı fonksiyonları tanımlıyoruz // f-i ekrana hatayı yazdırır function error_print($text) ( echo $text."

"; ) // fonksiyon mail ile hata gönderiyor fonksiyon error_mail($metin) ( $metin = str_replace("
", "n", $text); $info = "Zaman: ".get_datetime()."nUzak IP:".get_ip()."n"; mail(ADM_EMAIL, "Hata raporlama", $info.$text ); ) // işlev, günlük işlevine bir hata yazar error_writelog($metin) ( $metin = str_replace("
", "t", $metin); if (@$fh = fopen(LOGFILE, "a+")) ( fputs($fh, get_datetime()."t".get_ip()."t".$metin. "n"); fclose($fh); ) ) // zaman farkını dikkate alarak zamanı alın function get_time() ( return(date("H:i", time () + TIMEOFFSET)); ) / / get_date() zaman farkı fonksiyonunu dikkate alarak tarih al ( return(date("Ymd", time() + TIMEOFFSET)); ) // saat farkı fonksiyonunu dikkate alarak tarih ve saati al get_datetime() ( return get_date() ." ".get_time(); ) // IP alma işlevi get_ip() ( return($_SERVER["REMOTE_ADDR"]); ) Ve son olarak, // işlevini kullanma örneği bir dosyaya haber yazar function write_news($başlık, $metin) ( $news_file = "/home/mysite/news.txt"; // başlık olup olmadığını kontrol edin - kritik olmayan hata if (!trim($title)) ( // içinde fonksiyonun hatayla bittiğini belirlemek için // - gereklidir - false döndürmek Fonksiyon // trigger_error() - true döndürür, // ters çevrilmiş sonucunu döndürürüz st"); ) // haber metninin olup olmadığını kontrol edin - hata kritik değildir if (!trim($text)) ( return !trigger_error("Haberin metnini belirtmek gereklidir"); ) // // yazacağımız dosyanın bulunup bulunmadığını kontrol edin eğer dosya bulunamazsa - (!file_exists($news_file)) ise kritik bir hata oluşur ( return !trigger_error("Haber veritabanı dosyası bulunamadı!", E_USER_ERROR) ; ) // ...veri burada ön işleniyor... // haber kaydı $fh = fopen ($news_file, "a+"); fputs($fh, $başlık."t".$metin."n"); fclose($fh); // her şey yolundaysa - işlev true değerini döndürür; ) // haber yazmaya çalışıyorum // bu veri bir web formundan gelebilir $res = write_news("Haberim", "Haberimin metni"); if ($res === false) ( // if false döndürülür - bir hata yazdırılır echo $MSG; ) else ( // her şey yolundaysa - rapor edebilirsiniz // veya daha iyisi, kullanıcıyı bir yere yönlendirin. echo "Haber eklendi" ; )

Örneğin çalışması için önceki üç kod bloğunu bir PHP dosyasına kopyalamanız yeterlidir. Komut dosyasının çalışabilmesi için 777 günlük dosyasında izinleri ayarlamayı, doğru yolları ayarlamayı ve e-postanızı belirtmeyi unutmayın. DEBUG değişkenini 1 olarak ayarlayarak hata ayıklama modunu etkinleştirebilirsiniz.

    kasıtlı:

    • çıktı üreten print , echo ve diğer işlevler
    • Çiğ önceki bölümler

Bu neden oluyor?

Başlıkların ayrılmadan önce neden gönderilmesi gerektiğini anlamak için tipik bir HTTP yanıtına bakmanız gerekir. PHP betikleri çoğunlukla HTML içeriği oluşturur, ancak aynı zamanda bir dizi HTTP/CGI başlığını web sunucusuna iletir:

HTTP/1.1 200 Tamam Destekleyen: PHP/5.3.7 Değişken: Kabul Et-Kodlama İçerik Türü: text/html; karakter kümesi=utf-8 PHP sayfası çıktı sayfası

içerik

Biraz daha çıktı izler ...

ve

Sayfa/çıktı her zaman başlıkları takip eder. PHP, önce web sunucusunda üstbilgileri oluşturmayı geçmelidir. Bu sadece bir kez yapılabilir. Çift çizgiden sonra onları asla değiştiremez.

PHP ilk çıktıyı aldığında (print , echo , ), toplanan tüm başlıkları temizleyecektir. Daha sonra istediği tüm çıktıları gönderebilir. Ancak sonraki HTTP başlıklarını göndermek mümkün değildir.

Erken çıkışın nerede gerçekleştiğini nasıl öğrenebilirim?

header() uyarısı, sorunun nedenini bulmak için gerekli tüm bilgileri içerir:

Uyarı: Başlık bilgileri değiştirilemiyor - başlıklar zaten gönderildi (çıktı ile başlar/www/usr2345/htdocs/ yetki.php: 52) 100. satırda /www/usr 2345/htdocs/index.php içinde

Burada "satır 100", header() çağrısının başarısız olduğu betiği ifade eder.

Parantez içindeki "çıktı ile başlayan" notasyonu daha önemlidir. Önceki çıktının kaynağını belirtir. Bu örnekte, auth.php'dir ve 52. satır. Erken bir çıkış aramanız gereken yer burasıdır.

Tipik nedenler:

  • Yazdır, yankı

    print ve echo deyimlerinden kasıtlı çıktı, HTTP üstbilgileri gönderme yeteneğini durduracaktır. Bunu önlemek için uygulama akışı yeniden yapılandırılmalıdır. İşlevleri ve şablon şemalarını kullanın. Mesajlar yazılmadan önce header() çağrılarının yapıldığından emin olun.

    Çıktı üreten işlevler şunları içerir:

    • print , yankı , printf , vprintf
    • trigger_error , ob_flush , ob_end_flush , var_dump , print_r
    • readfile , passthru , floş , imagepng , imagejpeg

    vb. ve özel işlevler.

  • HTML ham alanları

    .php dosyasındaki ham HTML bölümleri de doğrudan çıktıdır. Komut dosyası, işlenmemiş herhangi bir bloktan önce header() öğesinin çağrılmasına neden olan koşullarla işaretlenmelidir. .

    İşlemeyi çıktı mantığından ayırmak için bir şablonlama şeması kullanın.

    • Form işleme kodunu üstteki komut dosyalarında işleyin.
    • İletileri geciktirmek için geçici dize değişkenlerini kullanın.
    • Gerçek çıktı mantığı ve karışık HTML çıktısı, ikincisiyle eşleşmelidir.
  • önce boşluklarsatır 1"uyarılar

    Uyarı satırdaki çıktıya atıfta bulunuyorsa 1 , o zaman temelde boşluklar, metin veya HTML açılış belirtecinden önce

    Benzer şekilde, bu, eklenen komut dosyaları veya komut dosyası bölümleri için olabilir:

    ?>

    PHP aslında etiketlerden sonra bir satır yer. Ancak, bu boşluklara itilen birden fazla yeni satırı veya sekmeyi veya boşluğu telafi etmeyecektir.

  • UTF-8 Malzeme Listesi

    Sorunlardan biri sadece tek yönlü hat ve boşluk olabilir. Ancak buna neden olabilecek "görünmez" karakter dizileri de vardır. En havalısı UTF-8 Malzeme Listesi(bayt-sıra-işareti) çoğu metin düzenleyicisi tarafından görüntülenmez. Bu, UTF-8 kodlu belgeler için isteğe bağlı ve gereksiz olan bayt dizisi EF BB BF'dir. Ancak, PHP bunu ham çıktı olarak değerlendirmelidir. Çıktıda  karakterleri (istemci belgeyi latin-1 olarak yorumlarsa) veya benzeri "çöp" olarak görünebilir.

    Özellikle grafik düzenleyiciler ve Java IDE'leri bunların varlığından habersizdir. Oluşturmazlar (Unicode standardı tarafından zorunludur). Ancak çoğu programcı ve konsol düzenleyicisi:

    Sorunu erken bir aşamada anlamak kolaydır. Diğer düzenleyiciler, dosya/ayarlar menüsünde varlığını belirleyebilir (Windows'ta Notepad++ sorunu tanımlayabilir ve çözebilir.) Bir Malzeme Listesinin varlığını kontrol etmenin başka bir yolu, altıgen. *nix sistemlerinde, grafiksel bir seçenek değilse de genellikle hexdump mevcuttur, bu da bu ve diğer sorunları kontrol etmeyi kolaylaştırır:

    Kolay bir düzeltme, metin düzenleyicinizi dosyaları "UTF-8 (BOM yok)" veya benzeri bir adlandırma olarak kaydedecek şekilde ayarlamaktır. Yeni başlayanlar genellikle yeni dosyalar oluşturmaya başvururlar ve önceki kodu tekrar kopyalayıp yapıştırırlar.

    Yardımcı Programları Düzelt

    Metin dosyalarını (sed/awk veya recode) kontrol etmek ve yeniden yazmak için otomatik araçlar da vardır. PHP için özel bir phptags etiketi tidier vardır. Kapalı ve açık etiketleri uzun ve kısa formlara yeniden yazar, ancak aynı zamanda baştaki ve sondaki boşlukları, Unicode ve UTF-x sorunlarını kolayca düzeltir:

    Phptag'ler --beyaz boşluk *.php

    Dahil etme veya proje dizininin tamamını kullanmak mantıklıdır.

  • ?>'den sonraki boşluklar

    Hatanın kaynağı kapanış?> olarak belirtilmişse, burada bir miktar eksik veya ham metin yazılır. PHP bitiş işareti, bu noktada komut dosyasının yürütülmesini sonlandırmaz. Şimdiye kadar sayfa içeriği olarak yazıldıktan sonra herhangi bir metin/boşluk karakteri.

    PHP'nin sonundaki ?> kapanış etiketlerinin atlanması, özellikle yeni başlayanlar tarafından genel olarak kabul edilir. Bu, bu vakaların küçük bir kısmını önler. (Çoğunlukla include()d betikleri suçludur.)

  • "0 satırında bilinmiyor" olarak listelenen hata kaynağı

    Bu genellikle bir PHP uzantısıdır veya hatanın kaynağı belirtilmişse php.ini'dir.

    • Bazen akış yapılandırma seçeneği gzip veya ob_gzhandler şeklindedir.
    • Ancak, örtük bir PHP başlatma/uyarı mesajı oluşturan herhangi bir çift yüklü extension= modülü olabilir.
  • Önceki hata mesajları

    Başka bir PHP ifadesi veya ifadesi bir uyarıya neden olursa veya bir bildirim yazdırılırsa, bu da iptal olarak kabul edilir.

    Bu durumda, örneğin hatayı önlemeniz, ifadenin yürütülmesini geciktirmeniz veya mesajı bastırmanız gerekir. isset() veya @() - daha sonra hata ayıklamayı asla engellemez.

Hata mesajı yok

php.ini'de error_reporting veya display_errors'ı devre dışı bıraktıysanız, hiçbir uyarı görünmez. Ancak hataları görmezden gelmek çok fazla soruna neden olmaz. Erken bir çıkıştan sonra başlıklar hala gönderilemez.

Bu nedenle header("Location: ..." sessizce yeniden yönlendirdiğinde, uyarıları kontrol etmek iyi bir fikirdir. Bunları komut dosyası çağrısı başına iki basit komutla atayın:

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

Veya set_error_handler("var_dump"); Eğer hepsi hataysa.

Başlık yönlendirmeleri hakkında konuşurken, son kod yolları için genellikle şöyle bir deyim kullanmalısınız:

Exit(header("Konum: /finished.html"));

Tercihen, header() arızaları durumunda kullanıcının mesajını yazdıran bir yardımcı fonksiyon bile.

Geçici bir çözüm olarak çıktı arabelleğe alma

HTML çıktısı için boşlukları gizleyebilir. Ancak uygulama mantıksal olarak ikili içerik (oluşturulmuş bir görüntü gibi) göndermeye çalıştığında, arabelleğe alınmış yabancı çıktı bir sorun haline gelir. (Önceki seçenek olarak ob_clean() ihtiyacı.)

Tamponun boyutu sınırlıdır ve varsayılan olarak bırakılırsa kolayca taşabilir. Ve bu nadir değildir, ne zaman olduğunu takip etmek zordur.

Özellikle geliştirme ve/veya üretim sunucuları arasında geçiş yaparken her iki yaklaşım da güvenilmez hale gelebilir. Bu nedenle çıktı arabelleğe alma, yaygın olarak yalnızca koltuk değneği/katı bir geçici çözüm olarak kabul edilir.

Bu hata mesajı, HTTP başlıkları (setcookie veya başlık ile) gönderilmeden önce herhangi bir şey gönderildiğinde tetiklenir. HTTP başlıklarından önce herhangi bir çıktının alınmasının yaygın nedenleri:

    Rastgele boşluklar, genellikle dosyaların başında veya sonunda, örneğin:

Bunu önlemek için, sadece bir kapatma bırakın?>

  • Php dosyasının başındaki bayt bayt değerleri. Durumun böyle olup olmadığını görmek için php dosyalarınızı bir hex düzenleyici ile inceleyin. Bayt 3F 3C ile başlamalıdırlar. EF BB BF Malzeme Listesini dosyaların başından güvenle kaldırabilirsiniz.
  • echo , printf , readfile , passthru , önce kod çağrıları gibi açık çıktılar
  • display_errors php.ini özelliği ayarlanmışsa php tarafından verilen uyarı. Programcı hatası üzerine çökmek yerine, php sessizce hatayı yakalar ve bir uyarı verir. display_errors veya error_reporting ayarlarını değiştirebilseniz de, sorunu çözebilmelisiniz.
    Yaygın nedenler, tanımsız bir dizinin öğelerine (örneğin, girdinin ayarlanıp ayarlanmadığını kontrol etmek için boş veya isset kullanmadan $_POST["input"]) erişmek veya bir dize değişmezi yerine tanımsız bir sabit kullanmaktır ($_POST örneğinde olduğu gibi, şunu not edin: eksik alıntılar).

Ancak, çıktı arabelleğe alma sorunları önlerken, uygulamanızın neden HTTP gövdesini HTTP başlığından önce verdiğini gerçekten belirlemelisiniz. Bu, arayana yanlış numarayı aradığını bildirmeden önce bir telefon görüşmesi yapmak ve gününüzü ve hava durumunuzu tartışmak gibidir.

Bu hatayı daha önce birçok kez aldım. Ve eminim tüm PHP programcıları bu hatayı en az bir kez almıştır. Bu sorunu çözmek için sorununuzun düzeyine göre çözümü kullanmaya karar verebilirsiniz:

Olası çözüm 1:

Önce veya sonra boşluk bırakmış olabilirsiniz (dosyanın sonunda ?>'den sonra), yani.

BURADA BOŞ ALANLAR OLMAMALIDIRBURADA DA BOŞ ALANLAR İÇİN KONTROL EDİNİZ; BU SATIR (boş satır) OLMAMALIDIR.

Çoğu zaman bu sorununuzu çözecektir.İhtiyacınız olan dosyayla ilişkili tüm dosyaları kontrol edin.

Not. Bazen gedit (standart Linux editörü) gibi bir EDİTÖR (IDE), kaydetme kaydına tek bir boş satır ekler. Olmamalı. Eğer linux kullanıyorsanız. sayfanın sonundaki ?> sonrasındaki boşlukları/satırları kaldırmak için VI düzenleyicisini kullanabilirsiniz.

Bu sizi ilgilendirmezse, aşağıda gösterildiği gibi çıktıyı tamponlamak için ob_start kullanabilirsiniz:

Olası çözüm 2:

Bu, çıktıyı arabelleğe alacak ve sayfa arabelleğe alındıktan sonra başlıklarınız oluşturulacaktır.

Aşağıdaki satır yerine

//header("Yer:".ADMIN_URL."/index.php");

yazı yazmak

Eko("");

?>

Bu kesinlikle sorununuzu çözecektir. Aynı problemle karşılaştım ama bu sorunu başlık yazarak çözmeye karar verdim.

Basit ipucu: betiğinizde ilk etiketten hemen önce düz boşluk (veya görünmez özel karakter)

Kodda öznitelikleri/değerleri ayarlayabilmem için HTML5 kodunu ayrıştırmaya çalışıyorum, ancak DOMDocument (PHP5.3) gibi etiketleri desteklemiyor gibi görünüyor.