Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

Translate to English… Ins Deutsche übersetzen…

Zrádné regulární výrazy v PHP

V PHP jsou k dispozici tři knihovny pro regulární výrazy: PCRE, Oniguruma a POSIX Regex. Druhá jmenovaná nemusí být vždy k dispozici a třetí je zavržená, proto byste měli používat výhradně šikovnější a rychlejší knihovnu PCRE. Bohužel implementace trpí docela nepříjemnými nedostatky, a to ve všech verzích PHP.

Činnost jednotlivých funkcí preg_* lze rozdělit do dvou kroků:

  1. kompilace regulárního výrazu
  2. exekuce (hledání, záměna, filtrování, …)

Sympatické je, že PHP zkompilovanou podobu regulárních výrazů udržuje v cache a tudíž se kompilují vždy jen jednou. Proto je vhodné používat statické regulární výrazy, tj. negenerovat je parametricky.

Teď k těm nepříjemným záležitostem. Pokud se během kompilace odhalí chyba, PHP na ni upozorní chybou úrovně E_WARNING, avšak návratová hodnota funkce je nejednotná:

  • preg_filter, preg_replace_callback, preg_replace vrací NULL
  • preg_grep, preg_match_all, preg_match, preg_split vrací FALSE

Dobré je vědět, že funkce vracející skrze referenci pole $matches (tj. preg_match_all a preg_match) při kompilační chybě argument nevynulují, tudíž testovat návratovou hodnotu má opodstatnění.

PHP od verze 5.2.0 disponuje funkcí preg_last_error vracející kód poslední chyby. Avšak pozor, týká se to pouze chyb vzniklých během exekuce! Pokud dojde k chybě během kompilace, hodnota preg_last_error se nevynuluje a vrací předchozí hodnotu. Pokud tedy návratová hodnota preg_* funkce není NULL resp. FALSE (viz výše), rozhodně nepřihlížejte k tomu, co preg_last_error vrací.

K jakým chybám může dojít během exekuce? Nejčastějším případem je překročení pcre.backtrack_limit nebo nevalidní UTF-8 vstup při použití modifikátoru u. (Poznámka: neplatné UTF-8 v samotném regulárním výrazu se odhalí již při kompilaci.) Nicméně způsob, jak PHP s takovou chybou naloží, je naprosto neadekvátní:

  • nevygeneruje žádnou zprávu (silent error)
  • návratová hodnota funkce může naznačovat, že je vše v pořádku
  • chybu lze zjistit až následným zavoláním preg_last_error

Zastavím se u té návratové hodnoty, což je asi největší zrada. Proces se totiž vykonává do chvíle, než se chyba objeví a poté se vrátí částečně zpracovaný výsledek. A to v naprosté tichosti. Jenže ani tohle neplatí vždy, třeba trojice funkcí preg_filter, preg_replace_callback, preg_replace umí i při exekutivních chybách vracet NULL.

Zda došlo během exekuce k chybě lze zjistit jedině voláním preg_last_error. Ale jak už víte, tato funkce vrací nesmyslný výsledek v případě, že došlo naopak k chybě kompilace, musíme tedy obě situace rozlišit přihlédnutím k návratové hodnotě funkce, zda-li je NULL resp. FALSE. A jelikož funkce vracející NULL při chybě kompilace umí vracet NULL i při chybě exekuce, lze konstatovat asi jen tolik, že PHP je nadevší pochybnost zkurvený jazyk.

Jak by vypadalo korektní a bezpečné použití PCRE funkcí? Například takto:

function safeReplaceCallback($pattern, $callback, $subject)
{
        // callback musíme ověřit sami
        if (!is_callable($callback)) {
                throw new Exception('Neplatny callback.');
        }

        // vynulujeme preg_last_error
        preg_match('##', '');

        // zavoláme PCRE
        $result = preg_replace_callback($pattern, $callback, $subject);

        // chyba exekuce?
        if (preg_last_error()) {
                throw new Exception('Chyba zpracovani regularniho vyrazu.', preg_last_error());

        } elseif ($result === NULL) { // chyba kompilace?
                $error = error_get_last();
                throw new Exception($error['message']);
        }

        return $result;
}

Uvedený kód transformuje chyby do výjimek, nesnaží se však potlačit výpis varování.

Bezpečné zpracování regulárních výrazů je implementováno ve třídě Nette\String.

napsáno 21. 5. 2010 | karma 21. líbil se vám článek? | shlédnuto 3552x | nahoru

Komentáře RSS 2.0 komentářů » přidat

avatar

#1 Ondřej Mirtes http://ondrej.mirtes.cz/ nový

Jak by řekl klasik – „peklíčko!“

Posláno 21. 5. 2010 ve 22.42 | Odpovědět
avatar

#2 K. http://k47.cz nový

Že by počátek \Nette\Regex?

Posláno 21. 5. 2010 ve 22.51 | Odpovědět
avatar

#3 Dušan Janošík dusan@djanosik.cz nový

A teď tu, jak pejsek s kočičkou pekli dort :)

Posláno 21. 5. 2010 ve 23.26 | Odpovědět

#4 PHX nový

Ale jaký jiný jazyk, ketrý je jednoduchý na nasazení do Apache, široce dostupný na hostingu a podporovaný na Linuxu? Osobne to vidím na Javu, ale zatím jsem neměl čas se do ni pořádně ponořit a v uvedených požadavcích si nevede extra dobře.

Posláno 21. 5. 2010 ve 23.35 | Odpovědět
Na komentář reagoval [6] Majkl578
avatar

#5 Jan Tichý http://www.medio.cz nový

Díky za zajímavý článek, i když byl určitě napsán jen a pouze kvůli té google bombě ;-)

Posláno 22. 5. 2010 v 0.09 | Odpovědět

#6 Majkl578 nový

#4 PHX: Spíš než na Javu bych to viděl na Python. :)

Posláno 22. 5. 2010 v 0.38 | Odpovědět
Na komentář reagoval [7] Aichi [8] IDDQD
avatar

#7 Aichi http://www.czechdesign.cz/blogs/aichi nový

#6 Majkl578: Spíš než Python nebo Javu bych viděl JavaScript

Posláno 22. 5. 2010 v 11.58 | Odpovědět
avatar

#8 IDDQD jakub.v.maly@gmail.com nový

#6 Majkl578: Sorry, ale budoucnost není v Pythonu, ani v Javě, ani v Javascriptu, natož v PHP, ale v ASP.NET a .NET Frameworku… Samozřejmě na IIS a Windows Serveru.

Posláno 22. 5. 2010 ve 13.26 | Odpovědět
Na komentář reagoval [9] Rychta [10] Majkl578 [18] vedouci
avatar

#9 Rychta lukas.rychtecky@gmail.com nový

#8 IDDQD: To chce celkem dost kuráže tvrdit, že budoucnost je v .NETu. Souhlasím, že to není PHP ani Python. Viděl bych to na boj mezi Javou a .NETem;o)

Posláno 22. 5. 2010 v 15.49 | Odpovědět

#10 Majkl578 nový

#8 IDDQD: Možná by bylo vhodné, kdyby sis přestal léčit komplexy. Tvé nepodložené názory nejsou vhodné. Dvanáctiletý bývalý spolužáku.

Posláno 22. 5. 2010 v 17.18 | Odpovědět
avatar

#11 makrobiotik koukam@nikde.nic nový

S těmi neléčenými komplexy má Majkl578 pravdu, ale platí to bohužel i na autora článku. Bez těch dem… by totiž nebylo ani nette ani samozvaný institut školení php a mnoho dalšího, autor by si na php nemohl postavit svou živnost atd.

Další věc je, že p. Grudl se v afektu spletl (nebo to možná vůbec neví?), že jsou v php minimálně tři extenze nad knihovnami pro regexp. Ta třetí je mbstring.

Doporučuji dietnější stravu, ty mraky indie v kombinaci s nutelou evidentně dráždí ta nepravá místa.

Posláno 23. 5. 2010 ve 12.11 | Odpovědět
Na komentář reagoval [15] David Grudl
avatar

#12 makrobiotik koukam@nikde.nic nový

A samozřejmě php není skur.. jazyk, je to především glue language s velmi svobodným (místy trochu anarchistickým) pojetím komunitního vývoje se všemi důsledky, s tím je nutné se smířit a uvědomit si to.

Posláno 23. 5. 2010 ve 12.21 | Odpovědět
avatar

#13 petr petr.match@gmail.com nový

díky, já jsem článek pochopil a pobavil se při neděli. teď ještě aby nám vyšel ten hokej!

Posláno 23. 5. 2010 v 16.19 | Odpovědět
avatar

#14 David Grudl http://davidgrudl.com nový

Jakub Vrána mě taktně upozornil, že odkaz „dementí čuráci“ vede na stránku, kde je i jeho jméno, takže jsem jej taktně odstranil. Tedy nikoliv Jakuba, ale odkaz :-)

Posláno 23. 5. 2010 v 16.50 | Odpovědět
avatar

#15 David Grudl http://davidgrudl.com nový

#11 makrobiotik: díky za upozornění, odkaz na třetí knihovnu jsem doplnil.

(a taktéž doporučuji krotit se v projevu)

Posláno 23. 5. 2010 v 16.54 | Odpovědět
avatar

#16 Dundee http://blog.milde.cz nový

Nemá být místo pcre_* napsáno preg_*? Jinak fakt dobrý článek. Díky!

Posláno 24. 5. 2010 v 7.58 | Odpovědět
avatar

#17 David Grudl http://davidgrudl.com nový

Naja

Posláno 24. 5. 2010 v 10.54 | Odpovědět
avatar

#18 vedouci http://tomsik.cz nový

#8 IDDQD: Java je zaprve sracka (vlastni zkusenost – klidne se o tom muzem pobavit nekde jinde a podrobneji, argumenty jsou) a zadruhe ma svuj okruh zakazniku – bankovni a provozni systemy (opet z vlastni zkusenosti) a na male projekty ji nikdo nikdy nenasadi (napsat jednoduchou aplikaci v j2ee resp. jeho subsetu je nesrovnatelne narocnejsi cinnost nez v php) – k zamysleni je treba fakt, ze jedine blogy o jave, ktere bezi na jave jsou ty od sunu.

k .netu ani pythonu se vyjadrovat nebudu – neznam…

javascript nic nenahradi, to by znamenalo rhino a rhino znamena jvm a jvm znamena aplikacni server a nebo minimalne web kontejner – tzn. opet vsechny ty kovadliny z j2ee

no a php – to zustane tam, kde je – protoze je tady spousta vyvojaru, co ho umi, jsou tady hostingy za hubicku a koncoveho zakaznika nezajima, na jake platforme to bezi – zajima ho jenom, aby to bezelo, vypadalo a krasne blikalo – a na to je zatim nejlepsi php a ror

ror par lidi a projektu prebralo jak z javy, tak z php, ale dal uz to podle me nepujde, protoze vetsina killer featur byla hbite zapracovanych do php frameworku…

tot muj skromny nazor – zcela irelevantni ke clanku :-)

Posláno 6. 6. 2010 v 7.10 | Odpovědět

Zanechat komentář

  • na jiné komentáře odkazujte zápisem např. [2]
  • vaše IP bude zaznamenána a zobrazena
  • můžete použít Texy! syntaxi. HTML značky nejsou povolené. Příklad syntaxe: "text odkazu":odkaz, **tučně**, *kurzíva*, `code`
  • můžeme si tykat
  • diskuse mohou být řešeny metodou Indiana Jones
Text komentáře
Kontakt (povinné)

(maskuje se)




Výtah na začátek článku na první komentář

Názory čtenářů v diskusích nejsou názory provozovatele webu, a ten za jejich obsah neodpovídá.

phpFashion © 2004, 2010 David Grudlo webu

Pokud není uvedeno jinak, podléhá obsah těchto stránek licenci Creative Commons BY-NC-ND Creative Commons License BY-NC-ND

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.