Hledání neinicializovaných proměnných
Školení, která pořádám
PHP nás při úrovni chyb E_NOTICE upozorňuje na práci s neinicializovanými proměnnými. Jsou s tím ale spojené dva problémy:
- Kontrola probíhá až v době spuštění, což může být pozdě. Pokud kód pracující s neinicializovanou proměnnou nespustíme při testování, tak se o chybě můžeme dozvědět např. až po tom, kdy ji využije útočník.
- PHP nás neupozorní na přidání prvku do neinicializovaného pole. Na druhou stranu nás informuje o práci s neexistujícími prvky správně inicializovaného pole, což z pohledu bezpečnosti nevadí.
Napsal jsem proto program, který zdrojový kód zkontroluje, aniž by se kód musel spouštět. Původně jsem ho chtěl umístit na tento blog, ale poněkud se rozrostl, proto jsem pro něj vytvořil samostatný projekt. Program rozebere kód funkcí token_get_all a hledá v něm jakoukoliv práci s neinicializovanými proměnnými zhruba tímto algoritmem:
<?php
$initialized = array();
$tokens = token_get_all($source);
foreach ($tokens as $i => $token) {
if ($token[0] === T_VARIABLE) {
if ($tokens[$i+1] === '=') {
$initialized[$token[1]] = true;
} elseif (!$initialized[$token[1]]) {
echo "Uninitialized variable $token[1] on line $token[2].\n";
}
}
}
?>
Jde samozřejmě o hrubé zjednodušení. Zohledňují se následující konstrukce:
Naopak některé konstrukce se kontrolují v rozporu s chováním jazyka:
- Nezohledňuje se přístup ke globálním proměnným přes $GLOBALS
- Protože se kód nevyhodnocuje, tak se nezpracovávají proměnné proměnné, proměnné funkce, vkládání nekonstantních souborů, eval ani konstrukce
${"a"}
- Funkce musí být definovaná před tím, než je použita
- Cyklus foreach musí mít tělo uzavřené do bloku
- Jako rozsah viditelnosti proměnných se chápe blok
K poslednímu bodu – přestože je tento přístup především jednodušší, tak se jedná spíše o záměrnou vlastnost než nedostatek programu. Porovnejte následující dva kódy:
<?php
if (auth()) {
$auth = true;
} else {
$auth = false;
}
$auth = false;
if (auth()) {
$auth = true;
}
?>
Přestože oba kódy proměnnou správně inicializují, tak je druhý kód lepší – pokud bych do prvního kódu doplnil nějakou další větev, tak se může stát, že na inicializaci v některém případě zapomenu.
Závěr
Vyzkoušejte si, jestli správně inicializujete všechny proměnné. Pokud ano a program vám přesto tvrdí opak, dejte mi prosím vědět.
Diskuse
Pekné, tuším ma predbehneš vo všetkých projektoch čo som si vymyslel... Asi by som ich mal prestať vymýšľať ale začať aj niečo realizovať...
Skúšal som si pustiť testy a:
1. prešli len testy 1, 5, 11, 15, 19, 24, 26, 28, ostatné generovali notice
2. po nastavení <?php error_reporting(E_ALL ^ E_NOTICE); ?>
aj tak neprešli testy 6, 8 a 20.
PHP 5.2.5 @ Apache 2.2.4 @ Windows XP Home
Díky za upozornění. Můj kód tradičně počítá s vypnutými E_NOTICE, do funkce jsem to doplnil.
Chybu způsobující neprůchodnost zmiňovaných testů jsem také opravil.
E_NOTICE - chápem. Ja mám radšej "E_NOTICE save" kód, preto ich mám zapnuté.
mata:
nahodou jsem dnes narazil na tuto stranku ... ja jsem byl vzdy ucen, ze takovato konstrukce by se mela psat takto:
$auth = auth();
pripadne
$auth = auth();
if ($auth) { ... }
Diskuse je zrušena z důvodu spamu.