Hlavní navigace

PHP okénko: Escapování

Jakub Vrána

Dnešní PHP okénko připomíná nutnost správného escapování dat a popisuje funkce, které jsou k tomu účelu obsaženy v PHP.

V PHP jsou tři základní escapovací funkce, které se používají v různých situacích: addslashes, htmlspecialchars a urlencode.

Funkce addslashes se používá většinou při ukládání dat do databáze. Funkce doplní zpětné lomítko před apostrof, uvozovky a zpětné lomítko, takže text obsahující tyto znaky obalený apostrofy nebo uvozovkami může být bez obav použit v SQL dotazu. Při ukládání proměnných zvenku tuto funkci používejte pouze v případě, že není zapnutá direktiva magic_quotes_gpc, jinak dojde k dvojitému escapování. Některé databáze (např. MySQL) si vystačí s touto funkcí i při ukládání binárních dat, jiné pro escapování těchto dat potřebují použít vlastní funkci – např. SQLite používá funkci sqlite_escape_strin­g.

Funkce htmlspecialchars se používá při vypisování textu, ve kterém nechceme interpretovat HTML značky – řídící znaky <>"& se převedou na odpovídající HTML entity – tedy např. < na &lt;. Použití této funkce by mělo být samozřejmostí při vypisování neošetřeného textu a při používání proměnných v hodnotách atributů HTML značek, např. value.

<?php
// špatně - proměnná může obsahovat speciální HTML znaky
echo "<input name='search' value='$_GET[search]' />\n";

// špatně - proměnná může obsahovat apostrof
echo "<input name='search' value='" . htmlspecialchars($_GET["search"]) . "' />\n";

// správně - případné uvozovky jsou spolu s ostatními speciálními znaky defaultně escapovány
echo "<input name=\"search\" value=\"" . htmlspecialchars($_GET["search"]) . "\" />\n";

// správně - escapován bude i apostrof
echo "<input name='search' value='" . htmlspecialchars($_GET["search"], ENT_QUOTES) . "' />\n";
?> 

Funkci htmlspecialchars je zvykem používat na výstupu, i když by ji z výkonnostních důvodů bylo někdy lepší použít např. už při ukládání dat do databáze. Nedělá se to ze dvou důvodů – jednak by kvůli větší délce escapovaného textu mohl být zkrácen řetězec přesto, že uživatel maximální délku nepřekročil, a jednak by někdo do databáze mohl nestandardním způsobem vložit neošetřená data, která by při výpisu způsobila paseku.

Funkce urlencode se používá při ošetřování řetězce předávaného v URL. Funkce nahradí všechny nealfanumerické znaky kromě -_. jejich URL reprezentací – tedy znakem % následovaným dvojicí hexadecimálních číslic (mezera se převede na +). Pokud tedy chceme vytvořit přehled nejčastěji hledaných výrazů, měli bychom to udělat nějak takhle:

<?php
$result = mysql_query("SELECT search, pocet FROM searches ORDER BY pocet DESC LIMIT 10");
while ($row = mysql_fetch_assoc($result)) {
    echo "<li><a href='?search=" . urlencode($row["search"]) . "'>" . htmlspecialchars($row["search"]) . "</a> ($row[pocet])</li>\n";
}
mysql_free_result($result);
?> 

Kromě těchto základních escapovacích funkcí v PHP samozřejmě existují další, např. quotemeta nebo preg_quote. Vždycky jde o to zamyslet se nad tím, jestli v daném kontextu náhodou nejsou některé znaky speciální, a pokud ano, tak je správně ošetřit. Podle mého názoru je správné escapování jednou z vlastností, které odlišují kvalitní webové aplikace od těch ostatních.


Podobně laděné texty můžete najít i na autorově weblogu PHP triky.

Našli jste v článku chybu?
18. 4. 2005 0:50
Michal Kubeček (neregistrovaný)
Autor zapomněl na jeden, IMHO nejpodstatnější, důvod, proč htmlencodovat data až před tím, než se budou zobrazovat na web. Protože mnohdy s těmi daty potřebujeme provádět i něco jiného, než je rovnou zobrazit na web, (a nebo s nimi pracujeme i z jiných klientů než z PHP) a pak bychom si zbytečně přidělávali práci s jejich zpětným dekódováním. Ze stejných důvodů by bylo záhodno, aby berličky typu magic_quotes_gpc co nejdříve zmizely v propadlišti dějin spolu s dalšími hříchy nezralého mládí, jako…
18. 4. 2005 11:24
Pokud používáte magic_quotes_gpc, pak musíte vždy pamatovat na stripslashes pokud vstup například vypisujete, ukládáte do souboru, posíláte mailem apod. Zvlášť nepříjemný to je u formulářů, které po server-side validaci nabídnou zpátky formulář se vším co uživatel zadal, ale všechno \"vyslashovaný\". Je to sice lepší varianta, než kdybychom měli magic_quotes_gpc vypnutý a zapoměli addslashes, ale s tímto přístupem bychom mohli zavést i automatické htmlspecialchars a rawurlencode. Pros…