Å ablony jsou běžnou souÄástà dynamických webů. Nenà proto divu, že dosud vzniklo nemalé množstvà šablonovacÃch systémů, vÃce Äi ménÄ› vydaÅ™ených. Smarty osobnÄ› Å™adÃm do té druhé skupiny, myslÃm, že se jedná o nepraktický molouch spatlaných regulárnÃch výrazů. MÃsto dalÅ¡Ãho hanobenà Smarty zneužiji jeho nestydaté velikosti a dám ji do kontrastu se svým skromným Å¡ablonovacÃm uzlÃÄkem o cca 70 řádcÃch.
Žádná odlehÄená syntaxe, nic se nekompiluje, Å¡ablonu pÅ™edstavujà běžné PHP soubory, které bych se koderovi bez znalosti PHP zdráhal svěřit. Neznà to pÅ™ÃliÅ¡ pÅ™esvÄ›dÄivÄ›, že? PÅ™inejmenÅ¡Ãm pro vlastnà projekty je to ale bájeÄná vÄ›c. Ono to totiž má i výhody.
Ten šablonovacà skript jestli chcete vidět. Ano? Tak tady je (pro PHP5).
A tuhle je ukázka, jak se s nÃm bezva pracuje:
require_once('Template.inc.php');
$doc = new Template('tpl/'); // šablony jsou v adresáři tpl/
$doc->nazev = 'Hudebnà nástroje'; // nastavÃme nadpis stránky
$nastroje[] = array('nazev'=>'Harmonika', 'ladeni'=>'C#');
$nastroje[] = array('nazev'=>'PÅ™ÃÄná flétna', 'ladeni'=>'F');
// zparsujeme seznam nástrojů
foreach($nastroje as $nastroj) {
$doc->parse('nastroj.php', '.NASTROJE', $nastroj);
}
// tisknout šablonu stranka.php
$doc->parse('stranka.php', Template::dstPrint);
Neboli:
$doc. Potom můžeme nastavit jejà vlastnosti – Å™Ãkejme jim z pohledu Å¡ablony globálnà promÄ›nné, i když tento termÃn má obecnÄ› jiný význam. Globálnà proto, že jsou pÅ™Ãstupné ve vÅ¡ech Å¡ablonách parsovaných tÃmto objektem.foreach dvakrát zparsujeme Å¡ablonu tpl/nastroj.php. Výsledek se pÅ™ipojà do promÄ›nné $doc->NASTROJE (PÅ™ipojà se dÃky té teÄce na zaÄátku, kdyby tam nebyla, tak tu promÄ›nnou pÅ™epÃÅ¡eme.)Template::dstPrint namÃsto uloženà tiskneme. NÄ›kdy se může hodit Template::dstReturn, ÄÃmž, jak jistÄ› tuÅ¡Ãte, obdržÃme výsledek návratovou hodnotou.
<html>
<head>
<title><?=htmlspecialchars($nazev)?></title>
</head>
<body>
<h1><?=htmlspecialchars($nazev)?></h1>
<ul>
<?=$NASTROJE?>
</ul>
</body>
</html>
<li><strong><?=htmlspecialchars($nazev)?></strong> - laděnà <?=$ladeni?></li>
V obou šablonách jsem záměrně použil stejnou proměnnou $nazev, aby bylo vidět, že lokálnà proměnné majà přednost.
$res = mysql_query('SELECT jmeno, prijmeni FROM uzivatele');
while($row = mysql_fetch_assoc($res)) {
$doc->parse('uzivatel.php', '.UZIVATELE', $row);
}
Metodu Template::init() voláme na zaÄátku Å¡ablony, když je tÅ™eba urÄit, které rozÅ¡iÅ™ujÃcà funkce Å¡ablona použÃvá (tÅ™eba pro práci s URL). NedÄ›lá nic jiného než require_once vÅ¡ech skriptů, které jsou uvedeny jako parametry. Hledá je ve stejném adresáři, kde je umÃstÄ›na tÅ™Ãda a na konec automaticky doplňuje koncovku .inc.php. Je-li napÅ™. tÅ™Ãda umÃstÄ›na v adresáři lib/, pak Template::init('string') provede require_once('lib/string.inc.php')
Template->check() ověřuje dostupnost Å¡ablony. Vracà TRUE pokud daná Å¡ablona existuje a lze ji pÅ™eÄÃst.
Template->clear() Äistà vÅ¡echny nastavené vlastnosti objektu.
Zpracovánà šablon je pekelnÄ› rychlé (hlavnÄ› proto, že se nemusejà kompilovat). Dále, spousta Å¡ablonovacÃch systémů použÃvá k nastavenà promÄ›nných nÄ›jakou funkci, nejÄastÄ›ji assign(). Nemohou tak dÄ›lat psà kusy jako tÅ™eba list($doc->id, $doc->nazev) = mysql_fetch_row($res), což tady možné je.
Zde popsaný bastl nepovažuji za průlomové dÃlo, ostatnÄ› pár hodnÄ› podobných jsem už vidÄ›l. Na svou jednoduchost mi ale pÅ™ijde nesmÃrnÄ› efektivnà a jistÄ› bude pro nÄ›koho alespoň inspiracÃ.
U administrace je tÅ™eba ve vÄ›tÅ¡inÄ› pÅ™Ãpadů poÄÃtat s tÃm, že ji může použÃvat i vÃce uživatelů naráz. Je zÅ™ejmé, že provedou-li zmÄ›nu stejné databázové buňky souÄasnÄ›, poslednà zápis pÅ™episuje ostatnÃ. O tomhle problému se v souvislosti s PHP rozepsal Jakub Vrána.
Jsou ale situace, kdy pravidlo poslednà vyhrává je tÃm nejmenÅ¡Ãm zlem. Jednou takovou je triviálnà pÅ™evrácenà boolean sloupce. MÄ›jme napÅ™Ãklad výpis Älánků u nichž je tlaÄÃtko publikovat, které se kliknutÃm pÅ™epÃná na nepublikovat a zase zpÄ›t. URL takového tlaÄÃtka může vypadat takto:
?clanek=70&akce=prohodPublik?clanek=70&akce=publikovat pro nepublikovaný Älánek?clanek=70&akce=nepublikovat pro publikovaný ÄlánekPrvnà zápis je jednoduchý a univerzálnÃ, protože ve výpisu mÄ›nÃme jenom ID Älánku a akce zůstává stejná. PÅ™evrátit boolean sloupec v databázi je také snadné. PÅ™esto takové Å™eÅ¡enà nelze doporuÄit, protože pÅ™evracejÃ-li uživatelé A a B hodnotu souÄasnÄ›, vÅ¡e se takhle zamotá:
Druhý zápis si ve stejné situaci vede znamenitě. Uplatňuje ono pravidlo poslednà vyhrává:
Neboli PHP, dost! Možná to bude pro nÄ›koho novinka, ale PHP se dá taky vypnout. V takovém pÅ™ÃpadÄ› server odeÅ¡le skripty tak jak ležà a běžÃ. Jde mimochodem o skvÄ›lý způsob, jak zajistit bezpeÄnost pÅ™i uploadovánà souborů formulářem. DoteÄ, když jsme se chtÄ›li vyhnout spuÅ¡tÄ›nà cizÃho PHP skriptu na serveru, museli jsme (nÄ›kteÅ™Ã) preciznÄ› kontrolovat koncovku Äi vyhodnocovat obsah. Ale ono staÄà udÄ›lat v daném adresáři soubor .htaccess obsahujÃcÃ:
php_flag engine off
VÅ¡echny PHP skripty kolem takového .htaccess (vÄetnÄ› podadresářů) ztrácejà na své skriptovitosti. Stávajà se z nich obyÄejné textové soubory které nikomu ani v nejmenÅ¡Ãm nevadÃ. TÅ™i vÄ›ci je tÅ™eba mÃt na zÅ™eteli:
To jsem jednou potÅ™eboval udÄ›lat barevný pÅ™echod. Ale ne GIMPárnu na jedno použitÃ, nóbrž pÅ™echod dynamický, nÄ›co jako že by se zavolal soubor a vono se to vygenerovalo a tvářilo jako obrázek. S PHP a knihovnou GD je vÄ›c snadná a pÅ™idá-li se i mod_rewrite, pak i velmi sluÅ¡ivá. LaÅ¥ku jsem si nastavil zhruba do téhle výše:
Co se týÄe bodu 1, skript dostane seznam klÃÄových barev a velikosti mezer které má mezi nimi proložit pÅ™echodem. Jako oddÄ›lovaÄ takového seznamu jsem zvolil znak VaÅ¡e komentáře mÄ› pÅ™imÄ›ly zmÄ›nit oddÄ›lovaÄ na spojovnÃk "-" KlÃÄové barvy se zapisujà šesti velkými hexadecimálnÃmi ÄÃslicemi, mezery desÃtkovÄ›. Aby se mezera odliÅ¡ila od barvy, může mÃt maximálnÄ› pÄ›t cifer – v praxi se použijà nanejvýš ÄtyÅ™i. Zbývá jeÅ¡tÄ› rozliÅ¡it orientaci (bod 2). Tak co tÅ™eba jednÃm malým pÃsmenem na zaÄátku? A bude to buÄ + který asi nejlépe znázorňuje spojovánÃ.x pro horizontálnÄ› se opakujÃcà pÅ™echod nebo y pro pÅ™echod s opakovánÃm vertikálnÃm.
Bod 3: Skript na konci, pokud je to možné, uložà výsledek do souboru. Název souboru má stejný tvar s jakým pracuje mod_rewrite, takže pÅ™i pÅ™ÃÅ¡tÃm požadavku už soubor fyzicky existuje a má pÅ™ednost. Když vÃm, že obrázek potÅ™ebuju jenom jednou a je zbyteÄné ho cachovat (tÅ™eba jako v testovacÃm rámeÄku nÞ), pÅ™idám na konec parametr ?tmp. Jelikož parametry nejsou souÄástà názvu souboru, majà cachované soubory opÄ›t pÅ™ednost. A proÄ je to cachovánà tak nechutnÄ› důmyslné? Protože pÅ™episovánà URL je nastaveno case-sensitive, takže v cache nevzniknou duplicity – každý pÅ™echod je jednoznaÄnÄ› identifikován. Nuže a bod 4 vyÅ™eÅ¡Ãme omezenÃm délky celého pÅ™echodu – dejme tomu na 5000px?
Jak je popsáno výše, na zaÄátku musà být malé pÃsmeno x/y, za nÃmž následujà klÃÄové barvy a ÄÃselnÄ› vyjádÅ™ené mezery mezi nimi. Pokud mezi barvami prolnutà být nemá (tedy nulová mezera), pak se zapÃÅ¡e ihned dalšà barva, napÅ™. yFF00FF-00FF00 jsou fialový a zelený pixel vedle sebe. Jednoduchý gradient pro svislé opakovánà (y) zÃskáme tÅ™eba pod tÃmhle názvem:

Délku celého pruhu spoÄÃtáme souÄtem klÃÄových barev (3) a mezer mezi nimi (5+2). Pruh je tedy dlouhý 10px.
gradient/ si zkopÃrujete kam je pohodlnogradient/y00FF00-300-0000FF.png je 302px dlouhý pÅ™echod od zelené k modréKdo náhodou nemá k dispozici mod_rewrite, může skript volat pÅ™Ãmo: gradient/gradient.php?repeat=y&grad=00FF00-300-0000FF
… když by staÄil 1px? TuÄňákům nestaÄÃ. A možná i tygrům, pÅ™iznám se, že jsem po tom pÅ™ÃliÅ¡ nepátral. Problém je v hladkosti pÅ™echodu. ZatÃmco pod Windows je opakovaný pÅ™echod stejný pÅ™i jakékoli Å¡ÃÅ™ce pruhu, FF/Linux ukáže 1px proužek pÅ™i nižšà barevné hloubce jako nekoukatelnÄ› ohyzdné Äáry. ZjevnÄ› nejprve obrázek proložà a teprve potom ho opakuje. Je tedy jasné, že jednorozmÄ›rný pÅ™echod nemůže proložit nikterak rozmanitÄ›, ovÅ¡em dostane-li vÄ›tšà plochu, stane se s nÃm pÅ™ibližnÄ› tohle:

Opakovaný ÄernobÃlý pÅ™echod pÅ™i 8-bitové hloubce (FF/Linux)
K pÄ›ti pixelům jsem doÅ¡el po sáhodlouhém zkouÅ¡enÃ. VÅ¡e do 3px je bÃda, 4px zaÄÃnajà být pÅ™ijatelné a pÄ›t – bingo! Vyššà hodnoty samosebou pÅ™inášejà výsledek o Å¡petku lepÅ¡Ã, ale to už je pÅ™ÃliÅ¡ na úkor velikosti souboru (aÄkoli nijak drasticky, PNG komprese se celkem vytáhla). A protože tÄ›ch 5px je krásná a vždy použitelná hodnota, dal jsem ji na pevno do hlaviÄky skriptu namÃsto do URL, které je tÃm jednoduššÃ. PÅ™ipomÃnám, že fujtajblproužkový problém se týká jen nÞšÃch barevných hloubek (do 16 bitů).
body {
background:url('gradient/x664477-600-CC99FF.png') left top repeat-x fixed #CC99FF;
}
Teda, ne úplnÄ›, protože jak administrátoÅ™i WebZdarma tvrdÃ, skryjete-li reklamu, máte po ptákách.
Chci se zaměřit na následujÃcà situaci:
config.php s citlivými údaji, jako je login k MySQL apod.Nejprve nÄ›co k bezpeÄnosti. Nejlepšà řeÅ¡enà je samozÅ™ejmÄ› umÃstit citlivé soubory mimo DocumentRoot, to ale na WZ nejde. Je tedy nanejvýš vhodné, aby config.php mÄ›l koncovku .php, protože koncovka jiná, tÅ™eba .inc, by staÄila k tomu, aby kdokoli zadal do prohlÞeÄe http://superstranky.wz.cz/config.inc a hesla vidÄ›l v celé jejich kráse (server nepozná, že soubor má prohnat skrz PHP a běžnÄ› ho odeÅ¡le). Pro vÅ¡echny pÅ™Ãpady nenà od vÄ›ci takovému souboru jeÅ¡tÄ› zakázat pÅ™Ãstup zvenÄà pomocà .htaccess. Jistota je jistota.
V Äem je problém? Protože jeden podobný web spravuji, vÅ¡iml jsem si, že WebZdarma Å™ešà vkládánà reklamy pÅ™i uploadu PHP souboru – prostÄ› ji prasácky mrskne na konec (je to potom rychlé). Když do skriptu includujete 10 .php souborů a máte nastaveno zobrazovánà reklamy na stránce dole, uvidÃte ve výsledku celkem 11 reklam na jediné stránce. SamozÅ™ejmÄ›, každý soubor obsahoval reklamu. Jedno z Å™eÅ¡enà je použÃt funkce na Å™Ãzenà výstupu:
<?php
ob_start(); require_once('config.php'); ob_end_clean();
?>
Ale s mÃrou, protože tahle metoda zhltne veÅ¡kerý výstup skriptu, vÄetnÄ› pÅ™Ãpadných chyb. OstatnÃm vkládaným souborům které nemusejà být nutnÄ› skryté je lepšà dát koncovku .lib Äi podobnÄ›. TÃm se zamezà automatickému pÅ™ipojenà reklamy, proÄež nenà tÅ™eba je dál oÅ¡etÅ™ovat.
Tak, a teÄ jeÅ¡tÄ› jedna možnost. StaÄà dát na konec každého includovaného souboru return;, ÄÃmž se vkládánà ukonÄÃ. Dejte ale pozor, aby se jednalo skuteÄnÄ› o vkládané soubory, protože pokud půjde o opravdickou stránku, nezobrazà se reklama ani na nà a vystavujete se riziku, že vám web smažou. Sice nemohu ruÄit za to, že se to v ostatnÃch pÅ™Ãpadech nestane, ale podle mÄ› je tohle naprosto korektnà oÅ¡etÅ™enà závažného nedostatku. CÃlem pÅ™ece je, aby se na stránce zobrazovala právÄ› jedna reklama.
Jiřà PoÄta poznamenává, že staÄà zvolit v administraci ruÄnà vkládánà reklamy.
V knihovnÄ› mysqldump.php [ZIP] najdete dvÄ› funkce:
fmysqldump() – zapisovánà MySQL dumpu do souborumysqldump() – tisk MySQL dumpu na výstupbool fmysqldump ( resource $fp [, resource $link [, mixed $data_for [, mixed $struct_for]]] )
mixed mysqldump ( [ resource $link [, mixed $data_for [, mixed $struct_for [, bool $return ]]]] )
| $fp | ukazatel na otevřený soubor, do něhož se má dump zapisovat. |
|---|---|
| $link | otevÅ™ené MySQL spojenà s vybranou databázÃ. Pokud nenà uvedeno nebo je NULL, použije se poslednà spojenÃ. |
| $data_for | pole s názvy tabulek, jejichž data majà být dumpována. Např. array('tabulka1', 'tabulka2') Hodnota TRUE je výchozà a znamená všechny tabulky, array() pak znamená žádné tabulky. |
| $struct_for | pole s názvy tabulek, jejichž struktura má být dumpována. Hodnota TRUE je výchozà a znamená všechny tabulky, array() pak znamená žádné tabulky. |
| $return | namÃsto tisku na výstup vracet dump návratovou hodnotou. Pozor na pÅ™eteÄenà pamÄ›ti, dumpy bývajà veliké. |
Teoreticky by naráz nemÄ›lo být obsazeno o moc vÃc pamÄ›ti než je velikost nejvÄ›tÅ¡Ãho sloupce v dumpovaných tabulkách, ale ve skuteÄnosti jsem pro tabulky s plnÄ› obsazenými sloupci MEDIUMBLOB potÅ™eboval povolit 30 MiB, zÅ™ejmÄ› hlavnÄ› proto, že nÄ›které binárnà znaky se do mezipamÄ›ti ukládajà escapované.
<?php
require_once('mysqldump.php');
# připojit MySQL
mysql_connect('hostitel', 'uzivatel', 'heslo');
mysql_select_db('moje_databaze');
mysql_query('SET CHARACTER SET utf8');
# budeme posÃlat SQL soubor "zaloha_moji_databaze.sql"
# a chceme prohližeÄ rovnou vyzvat k uloženà (attachment)
header('Content-Type: text/x-sql');
header('Content-Disposition: attachment; filename="zaloha_moji_databaze.sql"');
# neukládat data do cache
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Thu, 30 Jun 1988 12:00:00 +0000 GMT');
# pro MEDIUMBLOB/MEDIUMTEXT sloupce je třeba navýšit paměť
ini_set('memory_limit', '32M');
# poslat dump na výstup
mysqldump();
?>
Tenhle skript umožnà klientovi stáhnout pÅ™es prohlÞeÄ dump vÅ¡ech tabulek v otevÅ™ené databázi.
Pozn.: Knihovna mysqldump je Å¡ÃÅ™ena v nadÄ›ji, že bude užiteÄná, avÅ¡ak bez jakékoli záruky.
<?php
$str = 'Ahoj <?php echo "světe!" ?>';
eval('?>'.$str.'<?php ');
?>
NormálnÄ› se eval() chová tak, že oÄekává PHP kód. Vtip je v tom, že ten se dá běžným způsobem uzavÅ™Ãt a na konci znovu otevÅ™Ãt, ÄÃmž uprostÅ™ed zÃskáváme prostor pro HTML Äi jiný Äistý text. A koneÄnÄ›, ten může znovu obsahovat PHP vsuvky, zkrátka se promÄ›nná zpracuje zrovinka jako by se includoval soubor. Pokud vám zmÃnÄ›ný trik fungovat nebude, budu vdÄ›Äný, když se v komentářÃch ozvete. Rád bych si udÄ›lal pÅ™ehled o kompatibilitÄ›. Já testoval na PHP 4.3.10-16 a 4.4.4.
Tempie jest GNU šablonový engine pro PHP. Odedneška jej naleznete na http://tempie.org.
At first, please overlook some language mistakes in the text, for although I do my best, this is the first time I have condescended to write an English article.
High-quality error logging is a powerful tool for debugging any sort of applications, even your PHP scripts. It gives you a control of their behavior, so if you provide a complex application, e.g. firm database, you can reveal errors rised during the live traffic. I want to show you my solution, consisting of one PHP class and additional MIME function. We'll be able to log errors and warnings to a file, send them via e-mail, and display them in cool colours as well.
Our class will be called by the trigger_error function. This is a standard PHP function as of PHP 4.0.1 and allows you to display a user-defined error message. It's possible to handle its calls, so first thing we have to do after the class setup is to call the set_error_handler function. Until PHP 5, it takes only one parameter, which must be a valid callback of user handling function. The handling function needs to accept two parameters - error number and error string. Additional three parameters may be supplied - the file where error occured, the line number, and the error context (array of variables present in the scope where error occured).
One important fact is that our function is not affected by the error_reporting settings and will be called every time the error occurs. We have to attend this selves inside the handling function. As of PHP 5, there is a optional parameter error_types directly in set_error_handler function.
We should also realize that the trigger_error outputs an error message even after setting the error handler function. Therefore, it's necessary to turn error_reporting off. Our function will still be called (see above). In practice, the only errors we'll be able to catch are E_WARNING, E_NOTICE, E_USER_ERROR, E_USER_WARNING and E_USER_NOTICE. When another error occurs (fatal, parsing, etc.), script won't be executed, not either set_error_handler function.
Finally, obvious facility is that if you throw up the class and set_error_handler function, application will still work properly, just depleted of error logging.
<?php
/*
* Error handling class
* --------------------
*
* @author Honza Odvárko <honza@odvarko.cz>
* @copyright Copyright 2006 Honza Odvárko
* @license GNU GENERAL PUBLIC LICENSE
*
* Thanks to http://www.faqs.org/rfcs/rfc2047.html
*/
# Outputs RFC 2047 encoded-word
# $encoding_method must be either 'b' (Base64 encoded) or 'q' (Quoted-Printable)
# $charset parameter only describes input encoding, there is no conversion involved
#
function mime_encoded_word($str, $encoding_method=null, $charset=null) {
if("$encoding_method" === '') $encoding_method = 'q';
if("$charset" === '') $charset = 'utf-8';
switch(strtolower($encoding_method)) {
case 'b':
$buf = "=?$charset$?B?".base64_encode($str).'?=';
break;
case 'q':
$buf = "=?$charset?Q?";
for($i=0,$c=strlen($str); $i<$c; $i++) {
$ch = $str{$i};
$ord = ord($ch);
if($ch == ' ') {
$buf .= '_';
} elseif($ord > 31 && $ord < 127 && $ch != '=' && $ch != '?' && $ch != '_') {
$buf .= $ch;
} else {
$buf .= '='.strtoupper(dechex($ord));
}
}
$buf .= '?=';
break;
default:
trigger_error("Invalid encoding method '$encoding_method' (must be either 'b' or 'q')", E_USER_WARNING);
return false;
}
return $buf;
}
class err {
# describes encoding of error string
var $encoding = 'utf-8';
# which errors will be displayed
var $reporting = E_ALL;
# which errors will be logged to a file
var $logfile_level = E_ALL;
# log file location
var $logfile;
# which errors will be sent via e-mail
var $logmail_level = E_ALL;
# comma-separated list of log-mail recipients
var $logmail;
function set_encoding($value) {
$this->encoding = $value;
}
function set_reporting($value) {
$this->reporting = $value;
}
function set_logfile_level($value) {
$this->logfile_level = $value;
}
function set_logfile($value) {
$this->logfile = $value;
}
function set_logmail_level($value) {
$this->logmail_level = $value;
}
function set_logmail($value) {
$this->logmail = $value;
}
function handler($errno, $errstr, $errfile, $errline, $errcontext) {
$use_reporting = 0!=($this->reporting & $errno);
$use_logfile = 0!=($this->logfile_level & $errno);
$use_logmail = 0!=($this->logmail_level & $errno);
switch($errno) {
case E_WARNING: $errtype='Warning'; $errcolor='orangered'; break;
case E_NOTICE: $errtype='Notice'; $errcolor='green'; break;
case E_USER_ERROR: $errtype='Error'; $errcolor='red'; break;
case E_USER_WARNING: $errtype='Warning'; $errcolor='orangered'; break;
case E_USER_NOTICE: $errtype='Notice'; $errcolor='green'; break;
default:
$errtype='Unknown error';
$errcolor='red';
}
if($use_reporting) {
header('Content-Type: text/html; charset='.$this->encoding);
echo "<br />\n<b style=\"color:$errcolor\">$errtype</b>: ".htmlspecialchars($errstr).
' in <b>'.htmlspecialchars($errfile)."</b> on line <b>$errline</b><br />\n";
}
if(!$use_logfile && !$use_logmail) return true;
$date = date('r');
$dump = wddx_serialize_vars('errcontext');
$dumpsize = strlen($dump);
$record =
"ERROR\n".
" no: $errno\n".
" type: $errtype\n".
" text: $errstr\n".
" file: $errfile\n".
" line: $errline\n".
" date: $date\n".
"\n".
"SERVER\n".
" http_host: {$_SERVER['HTTP_HOST']}\n".
" http_user_agent: {$_SERVER['HTTP_USER_AGENT']}\n".
" remote_addr: {$_SERVER['REMOTE_ADDR']}\n".
" script_filename: {$_SERVER['SCRIPT_FILENAME']}\n".
" request_method: {$_SERVER['REQUEST_METHOD']}\n".
" request_uri: {$_SERVER['REQUEST_URI']}\n".
"\n".
"CONTEXT DUMP [$dumpsize B]\n".
$dump;
$succeed = true;
if($use_logfile) {
if((string)$this->logfile !== '') {
if(($fp = fopen($this->logfile, 'a')) !== false) {
$write =
"\n\n\n--------------------------------------------------------------------------------\n".
$record;
fwrite($fp, $write);
fclose($fp);
} else {
$succeed = false;
$this->_internal_warning("Unable to open log file '{$this->logfile}' for writing", __FILE__, __LINE__);
}
} else {
$succeed = false;
$this->_internal_warning('Log file is not specified', __FILE__, __LINE__);
}
}
if($use_logmail) {
if((string)$this->logmail !== '') {
$to = $this->logmail;
$subject = "$errtype: $errstr";
$subject = mime_encoded_word($subject, null, $this->encoding);
$message = $record;
$message = str_replace("\n.", "\n..", $message); # SMTP workaround (Windows only)
$headers[] = 'Mime-Version: 1.0';
$headers[] = 'From: ERROR-HANDLER';
$headers[] = 'Content-Type: text/plain; charset='.$this->encoding;
$headers[] = 'Content-Transfer-Encoding: 8bit';
$headers[] = 'X-Mailer: PHP/'.phpversion();
if(!mail($to, $subject, $message, implode("\r\n", $headers))) {
$succeed = false;
$this->_internal_warning('Unable to send log mail', __FILE__, __LINE__);
}
} else {
$succeed = false;
$this->_internal_warning('Log mail recipients are not specified', __FILE__, __LINE__);
}
}
return $succeed;
}
function _internal_warning($errstr, $errfile, $errline) {
header('Content-Type: text/html; charset=utf-8');
echo "<br />\n<b style=\"color:orangered\">Error handler warning</b>: ".htmlspecialchars($errstr).
' in <b>'.htmlspecialchars($errfile)."</b> on line <b>$errline</b><br />\n";
}
}
?>
<?php
require_once('err.class.php');
$err = new err();
$err->set_reporting (E_ALL & ~E_NOTICE); # display all except notices
$err->set_logfile_level(E_ALL); # log all (default, may be omitted)
$err->set_logfile ('error_log.txt');
$err->set_logmail_level(E_ALL & ~E_NOTICE); # mail all except notices
$err->set_logmail ('webmaster@example.org');
# let the handling function take control
set_error_handler(array($err, 'handler'));
# hide errors which we can handle
error_reporting(E_ALL & ~E_WARNING & ~E_NOTICE & ~E_USER_ERROR & ~E_USER_WARNING & ~E_USER_NOTICE);
# sample user warning
trigger_error('This is my own warning message', E_USER_WARNING);
# this produces warning too
implode();
?>
Don't forget to allow the write permissions to the directory where a log file should be created. Now if you see the orange warnings, they were successfuly handled and logged by the handling class.
Thanks to Mrs. Matoušková for the semantic correction.
PÅ™esunul jsem svůj Älánek na server IT-MaX, aby tu nestraÅ¡il. Takhle rozsáhlé obludnosti už budu rovnou vystavovat na podobných serverech a tady na nÄ› jen odkážu nÄ›jakým pÄ›kným odkazem.