PHP: Pozor na zákeřnou funkci filter_var() a FILTER_VALIDATE_INT. Provádíte validaci nulových hodnot (a nejen těch) správně?
Chceme ověřit, jestli vstup od uživatele je opravdu jakákoliv hodnota integer. Očekáváme tedy celé záporné číslo, celé kladné číslo nebo nulu. Pokud pro validaci celočíselných hodnot (FILTER_VALIDATE_INT) používáme PHP funkci filter_var(), můžeme se při nevhodně použité podmínce dostat do problémů s nulou.
Mějme následující vlastní validační funkci (předem upozorňuji, že je chybná, takže ji NEPOUŽÍVEJTE):
function valid_integer($number) { if (filter_var($number, FILTER_VALIDATE_INT)) { return 1; } else { return 0; } }
Když funkci filter_var() předáme vstupní hodnotu, očekáváme, že nám vrátí hodnotu 1, pokud bude hodnota celé číslo a ve všech ostatních případech vrátí hodnotu 0.
Podívejme se, co vypíše u jednotlivých volání s různými hodnotami:
echo valid_integer(2020); // 1 echo valid_integer(1); // 1 echo valid_integer(0); // 0, což je špatně, protože nula je integer echo valid_integer(10.5); // 0 echo valid_integer('2020'); // 1 echo valid_integer('1'); // 1 echo valid_integer('0'); // 0, což je špatně, protože nula je integer echo valid_integer('10.5'); // 0 echo valid_integer('ahoj'); // 0
Funkce filter_var() vrací filtrovaná data, nebo FALSE, když filtr selže. Problém je tedy v naší podmínce. Upravme ji proto takto:
function valid_integer($value) { if (filter_var($value, FILTER_VALIDATE_INT) !== false) { return 1; } else { return 0; } }
Nyní již funkce vrátí očekávané výsledky:
echo valid_integer(2020); // 1 echo valid_integer(1); // 1 echo valid_integer(0); // 1 echo valid_integer(10.5); // 0 echo valid_integer('2020'); // 1 echo valid_integer('1'); // 1 echo valid_integer('0'); // 1 echo valid_integer('10.5'); // 0 echo valid_integer('ahoj'); // 0
Validační funkce filter_var() respektuje netypovost PHP jazyka
Pokud se k nám dostane hodnota z odeslaného formuláře, číslo může být jako součást řetězce. Nebo proměnnou ořezáváme pomocí funkce trim(). V zápisu kódu je to ekvivalentní tomuto:
$value = "10";
Což je trochu něco jiného než následující čistě číselná hodnota:
$value = 10;
PHP je netypový jazyk, takže nerozlišuje mezi výše uvedenými zápisy. Se všemi výhodami a nevýhodami s tím spojenými.
Pokud pro validace použijeme filter_var(), netypovost je dle očekávání dodržena a obě hodnoty jsou vyhodnoceny jako celé číslo.
Kdybychom ale pro validaci použili funkce is_int() nebo is_float(), tak v případě číselné hodnoty předané jako řetězec máme problém. Obě funkce totiž kontrolují datový typ.
Vedle toho funkce is_numeric() ověřuje, jestli je hodnota jakékoliv číslo (celé, desetinné atd.), ale dodržuje netypovost jazyka, takže ji můžete použít jak pro ověření čistě číselných hodnot, tak i číselných řetězců.
Validační funkce filter_var() je tu s námi již od PHP 5.2.0, tedy téměř čtrnáct let, přesto se jí spousta programátorů vyhýbá. Což je škoda.