Prosím o fanfáry, na scénu přichází Latte
3. S kompletně přepsaným kompilátorem. Nová verze představuje
největší vývojový skok, jaký kdy v Nette nastal.
Proč vlastně Latte
Latte má překvapivou historii.
Původně totiž nebylo myšleno vážně. Mělo dokonce demonstrovat, že
žádný šablonovací systém není v PHP potřeba. Bylo pevně spjato
s presentery v Nette, kde však nebylo defaultně zapnuté a programátor jej
musel aktivovat přes tehdejší ošklivý název CurlyBracketsFilter.
Zvrat přišel až s nápadem, že šablonovací systém by mohl HTML
stránce rozumět. Vysvětlím. Pro ostatní šablonovací systémy je text
v okolí značek jen šumem bez jakéhokoliv významu. Je jedno, jestli jde
o HTML stránku, CSS styl nebo třeba text v Markdownu, šablonovací engine
vidí jen shluk bajtů. Latte naopak dokument chápe. Což přináší spoustu
zásadních výhod. Od komfortu v podobě vychytávek jako jsou třeba n:attributy, až po
ultimátní bezpečnost.
Latte tak ví, jakou použít escapovací funkci (což
většina programátorů neví, ale díky Latte to nevadí a nevytvoří
bezpečnostní díru Cross-site
scripting). Zabrání vypsání řetězce, který by v určitém místě byl nebezpečný. Dokonce
dokáže předejít dezinterpretaci mustache
závorek frontendovým frameworkem. A bezpečnostní experti nebudou mít
co žrát :)
Nečekal bych, že tímto nápadem přeběhne Latte ostatní systémy
o 10 let, protože dodneška vím pouze o dvou, co takto fungují. Krom Latte
je to ještě Soy od Google. Latte a Soy jsou jediné opravdu bezpečné
šablonovací systémy pro web. (Byť teda Soy ze zmíněných vychytávek má
pouze to escapování.)
Druhou klíčovou vlastností Latte je, že pro výrazy uvnitř značek
(někdy se říká maker) používá jazyk PHP. Tedy syntaxi programátorovi
důvěrně známou. Vývojář se tak nemusí učit nový jazyk. Nemusí
zkoumat, jak se to či ono v Latte píše. Prostě to napíše tak jak umí.
Naopak třeba populární šablonovací systém Twig používá syntaxi Pythonu,
kde se i zcela základní konstrukce píší odlišně. Například
foreach ($people as $person) se v Pythonu (a tedy i Twigu) píše
jako for person in people, což zcela zbytečně nutí mozek
přepínat mezi dvěma opačnými konvencemi.
Latte tedy má oproti konkurenci natolik podstatnou přidanou hodnotu, že
má smysl investovat úsilí do jeho údržby a vývoje.
Současný kompilátor
Latte a jeho syntax vznikla před 14 lety (rok 2008), současný kompilátor
o tři roky později. Uměl už tehdy vše podstatné, co se dodnes používá,
tedy i bloky, dědičnost, snippety atd.
Kompilátor fungoval jako jednoprůchodový, což znamená, že parsoval
šablonu a rovnou ji přetvářel do PHP kódu, který sestavil do výsledného
souboru. Jazyk PHP používaný ve značkách (tj. v makrech) se tokenizoval a
poté procházel několika procesy, které tokeny upravovaly. Jeden proces
doplňoval řetězcové uvozovky kolem identifikátorů, jiný přidával
syntaktické vychytávky, které PHP tehdy neznalo (například zápis polí
pomocí [] místo array(), nullsafe operátory
?->) nebo které nezná doposud (zkrácený ternární
operátor, filtry ($var|upper|truncate), atd).
Tyto procesy ale nijak nekontrolovaly PHP syntax nebo používané
konstrukce. Což se výrazně změnilo až před dvěma lety (rok 2020)
s příchodem sandbox režimu.
Sandbox hledá v tokenech možné volání funkcí a metod a upravuje je, což
není vůbec jednoduché. Přičemž případné selhání je vlastně
bezpečností chybou.
Nový kompilátor
Za jedenáct let vývoje Latte se našly situace, kdy jednoprůchodový
kompilátor nestačil (třeba při inkludování bloku, který ještě nebyl definován). Všechny
issue šlo sice vyřešit, ale ideální by bylo přejít na dvoukrokovou
kompilaci, tedy nejprve šablonu naparsovat do mezipodoby, do AST stromu, a pak
teprve z něj vygenerovat kód třídy.
Taktéž s postupným vylepšováním PHPlike jazyka používaného
ve značkách přestávala dostačovat reprezentace v tokenech a ideální by
bylo i jej naparsovat do AST stromu. Naprogramovat sandbox nad AST stromem je
výrazně snadnější a dá se garantovat, že bude skutečně
neprůstřelný.
Trvalo mi pět let se do přepsání kompilátoru pustit, protože jsem
věděl, že to bude extrémně náročné. Už samotná tokenizace
šablony představuje výzvu, neboť musí běžet paralelně s parsováním.
Parser totiž musí mít možnost ovlivňovat tokenizaci, když například
narazí na atribut n:syntax=off.
Podporu pro paralelní běh dvou kódů přináší až Fibers v PHP 8.1,
nicméně Latte je zatím nevyužívá, aby mohlo fungovat na PHP 8.0. Místo
toho používá obdobné coroutines (v dokumentaci PHP o nich nic nenajdete,
tak alespoň odkaz na Generator
RFC). Pod kapotou Latte se tedy odehrávají kouzla.
Nicméně jako ještě mnohem náročnější úkol mi připadalo napsat
lexer a parser pro tak komplexní jazyk, jako je dialekt PHP používaný ve
značkách. V podstatě to znamenalo vytvořit něco jako nikic/PHP-Parser pro
Latte. A zároveň i nutnost formalizovat gramatiku tohoto jazyka.
Dnes můžu říct, že se mi povedlo všechno dokončit. Latte má
kompilátor, jaký jsem si dlouhá léta přál. A z toho původního nezbyl
ani jediný řádek kódu 🙂
Zajímalo mě, který PHP framework má nejlepší dokumentaci.
A jak si v žebříčku stojí Nette. Jenže jak to zjistit?
Všichni víme, že nejhorší je žádná dokumentace. Pak následuje
nedostatečná dokumentace. Opakem je obsáhlá dokumentace. Tedy zdá se, že
důležitým vodítkem je samotný objem dokumentace. Pochopitelně obrovskou
roli hraje i její srozumitelnost a aktuálnost, dojem dělá čtivost a
bezchybnost. Tyto faktory se velmi těžko měří. Nicméně sám vím, kolik
částí dokumentace Nette jsem mnohokrát přepsal, aby byly jasnější, kolik
oprav jsem mergoval, a předpokládám, že se tak děje u každého letitého
frameworku. Že tedy postupně všechny dokumentace konvergují k podobné
vysoké kvalitě. Tudíž si jako vodítko dovolím brát čistě objem dat,
byť jde o zjednodušení.
Pochopitelně se objem dokumentace musí dát do poměru s velikostí té
které knihovny. Některé jsou i řádově větší než jiné a pak by měly
mít i řádově větší dokumentaci. Pro jednoduchost budu velikost knihovny
stanovovat podle objemu PHP kódu. S normalizovaným bílým místem, bez
komentářů.
Vytvořil jsem graf poměru anglické dokumentace ku kódu u známých
frameworků CakePHP (4.2), CodeIgniter (3.1), Laravel (8.62), Nette (3.1),
Symfony (5.4), YII (2.0) a Zend Framework (2.x, již nevyvíjený):
Jak z grafu vidíte, obsáhlost dokumentace vůči kódu je u všech
frameworků víceméně podobná.
Vyčnívá CodeIgniter. Smekám před CakePHP a YII, které se snaží
udržovat dokumentaci v celé řadě dalších jazyků. Obsáhlost dokumentace
Nette je nad průměrem. Zároveň Nette je jediný framework, který má 1:1
překlad i v naší mateřštině.
Smyslem grafu NENÍ ukázat, že ten či onen framework má o tolik procent
obsáhlejší dokumentaci než jiný. Na to je metrika příliš primitivní.
Smyslem je naopak ukázat, že obsáhlost dokumentace u jednotlivých
frameworků z velké míry srovnatelná. Vytvořil jsem jej hlavně pro sebe,
abych získal představu, jak je na tom dokumentace Nette ve srovnání
s konkurencí.
Původně vyšlo v srpnu 2019, údaje jsou aktualizované pro
říjen 2021.
Hurá, Nette už má první záznam v CVE! To znamená, že
v něm byla objevena první vážná zranitelnost. Co se vlastně stalo?
Na konci prázdnin mi napsal vývojář Cyku
Hong z malebného Taiwanu, že našel v Nette zranitelnost a
v následujícím e-mailu vysvětlil princip možného zneužití. Ověřil
jsem, že jde o uskutečnitelný útok. Dovoluje útočníkovi za určitých
okolností na některých webech pomocí speciálně sestaveného URL spustit
kód, tedy jde o zranitelnost Remote code execution (RCE). Cyku, díky!
Musím říct, že to bylo v 13leté historii frameworku Nette vlastně
poprvé, co někdo našel takto závažnou zranitelnost. Dříve byly
několikrát reportovány drobné záležitosti, např. letos v březnu Jan
Gocník odhalil možnou zranitelnost v případě, že by programátor
deserializoval a vypsal query proměnnou
echo unserialize($_GET['a']), což je samo o sobě principiálně
velmi nebezpečné, nicméně jeho nález jsem samozřejmě opravil. Také jsem
dostal řadu hlášení, které nebyly opodstatněné, například že
uploadovaný obrázek vyhovující testu isImage() může v sobě
obsahovat PHP kód. Což samozřejmě může, například v metadatech, ale
není to bezpečnostní problém Nette.
Ale zpět k chybě, o které je tento článek. Bezprostředně po
nahlášení jsem ji opravil a vydal nové verze balíčků
nette/application a nette/nette.
Nejstarší zasaženou verzí bylo Nette 2.0, které už sice není 6 let
udržované, ale protože Nette má bezpečnost jako jednu z priorit, vydal
jsem nové verze také u všech nepodporovaných verzí. Což je ve světě
opensource frameworků ojedinělý krok. Díky tomu mohou uživatelé snadno
a bez prodlení aktualizovat nejen projekty udržované a běžící na
současných verzích, ale i projekty s technologickým dluhem. Vlastně
se teď dá říci, že každá řada Nette je nejen Long-Term Support
Release (tedy podporovaná alespoň dva roky, viz tabulka), ale z pohledu
bezpečnostních fixů i Forever-Term Supported 🙂
Druhým krokem bylo o chybě informovat. Samotné zveřejnění chyby na
blogu by i bez podrobného popisu zneužití představovalo vodítko pro
darebáky, kteří by se o chybě dozvěděli a mohli se pokusit ji zneužít.
Proto mi připadalo fér nejprve informovat všechny podporovatele Nette, poté i další
uživatele na které mám kontakt a teprve s určitým časovým odstupem
publikovat oznámení veřejně na blogu,
GitHubu
a katalogu
CVE. Prostě dát partnerům určitý čas zaktualizovat všechny weby
dříve, než by se objevil první útočník. Původně jsem zamýšlel dát
odstup týden, ale pak jsem na základě diskusí pochopil, že to je doslova
šibeniční termín a vhodnější je dát alespoň 2–4 týdny.
Jak už jsem zmiňoval, šlo o mou první zkušenost s takovou situací,
ale chtěl jsem ji zvládnout příkladně. Abych se nedopustil žádného
přešlapu, napsat jsem Michalu
Špačkovi, kterého považuji za nejlepšího odborníka v této oblasti,
a všechno s ním konzultoval. Michal mi schválil postup, dal řadu
užitečných rad, připomínkoval emaily atd. Michale, moc děkuji!
Ačkoliv žádný z mnou provozovaných webů nebyl tímto způsobem
zranitelný, prohledal jsem jejich access logy za posledních 8 let (co díra
existuje) a zjistil, že tento typ útoku na ně historicky nikdo nezkusil.
Soudím, že na zranitelnost nikdo dříve nepřišel. Útočníci totiž
obvykle zkouší testovat také přímo web nette.org.
Nechci zveřejňovat přesný postup zneužití chyby a doufám, že to ani
nikdo jiný neudělá. Alespoň ne v dohledné době, protože by tím
způsobil ostatním nepříjemnosti a zpronevěřil se duchu open source.
Aktualizujte prosím co nejdříve na nejnovější
setinkové verze:
nette/application 3.0.6 (případně 3.0.2.1, 3.1.0-RC2 nebo dev)
nette/application 2.4.16
nette/application 2.3.14
nette/application 2.2.10
nette/nette 2.1.13
nette/nette 2.0.19
Nejrychlejší oprava
Michal připravil Linuxový
skript a já obdobu
v PHP, který automaticky aplikuje patch přímo do zdrojových kódů
Nette na disku. Hodí se v případě, že udržujete velké množství
projektů, které nemáte čas korektně aktualizovat pomocí Composeru.
Informaci o chybě rozeslal emailem svým klientům VSHosting, WEDOS nebo
HostingBB, zároveň některé hostingy přímo blogují problematickou URL,
případně rovnou aplikovaly výše uvedený fix. Díky!!!
Stránky Nette existují ve dvou jazykových verzích: české
a anglické. Udržovat tak obsáhlý projekt ve dvou mutacích vyžaduje dost
práce, ale vidím v tom smysl.
Plnohodnotná česká dokumentace a fórum je totiž výhodou pro zdejší
začínající programátory, protože žádný jiný framework ničím takovým
nedisponuje. Samozřejmě ideální by bylo, kdyby každý Čech už od
základní školy uměl plynně anglicky, ušetřilo by to hodně práce, ale
není úkolem frameworku tohle suplovat. Nicméně angličtina není
v žádném případě druhotným jazykem. Naopak. Posuďte sami:
Dokumentace. Její současná velikost
čítá 3 MB textů (pro srovnání celé
dílo Shakespeare má 5 MB). Anglická a česká jsou přitom zcela identické.
Nejsem si vědom, že by jeden jediný odstavec existoval třeba v české
verzi a anglické chyběl. Případně by se v jedné verzi objevil mnohem
dříve než v druhé. Obě verze jsou neustále synchronizované. Pokud byste
na nesoulad narazili, vytvořte prosím issue na GitHubu.
Anglické forum bylo spuštěno v roce
2008. Na českém až do minulého týdne svítila zpráva: „Chcete se
zdokonalovat v angličtině? Zkuste psát do anglického fóra. I když by to
bylo s chybami – těmi se člověk učí.“, takže i mnoho Čechů
používá anglické fórum.
Nette Blog v tuto chvíli čítá
34 článků v angličtině a 19 v češtině. Rozhodně doporučuji blog
sledovat, třeba přes RSS,
stává se z něj hlavní zdroj informací o novinkách.
Diskuse na GitHubu jsou výhradně v angličtině. Tuším od roku 2012 je
to oficiální podmínka. Jedinou výjimkou jsou diskuse o české dokumentaci,
což je snad pochopitelné.
V celém kódu se nikdy neobjevilo jediné české slovo. Kód je od
prapočátků pouze v angličtině, včetně všech chybových hlášek,
komentářů atd. Tuším jen jednou se v něm vyskytlo slovo fuck 🙂
Dále je tu oficiální Twitter
kanál, který je od počátku kompletně anglicky.
Co naopak anglicky není? Tak především jsou to videa z Posobot a
facebooková stránka Nette Framework
CZ/SK, která slouží zejména k informování o lokálních akcích,
jako je právě Posobota nebo NettePivo. A taky kanál na Slacku
Péhápkaři, což tedy není oficiální součást Nette.
Ještě pár technických záležitostí: pokud přijdete na úvodní
stránku webu, fóra či blogu, nejspíš vás to přesměruje na českou verzi.
Je to pouze proto, že máte v prohlížeči nastavený jako preferovaný jazyk
češtinu nebo jste se už někdy v minulosti do české mutace přepnuli.
Jinak samozřejmě přesměrovává na anglickou verzi.
Taktéž je určitý rozdíl mezi výpisem článků či příspěvků na
českém a anglickém fóru. Web zkrátka předpokládá, že český uživatel
anglicky číst umí, takže českým uživatelům se například u nejnovějších příspěvků
vypisují i ty anglické nebo na českém blogu i anglické články,
u který neexistuje českých překlad. Zahraniční uživatel tento mix
nevidí.
Česká verze je zkrátka přidaným komfortem. Ale rozhodně preferujeme
tvořit obsah v angličtině.
V tu-dů listu mi
už druhý týden visí: „Sepsat článek, proč podporovat Nette.“
A zatímco jsem to odkládal, tak kluci z Freelo mě předběhli a napsali to
tak moc dobře, že už nemá smysl se o něco pokoušet 🙂
Co přinesou příští verze Nette Frameworku a jaký je plán
pro další vývoj?
Nette je tvořeno řadou knihoven, z nichž některé patří mezi světovou
špičku: Latte je nejbezpečnější
šablonovací systém, Tracy je mnohými
považován za nejpřívětivější debugovací nástroj, Dependency Injection
Container patří mezi ty nejpohodlněji použitelné. Spousta konceptů vznikla
šťastnou rukou a fungují v prakticky nezměněné podobě už 10 let,
například formuláře nebo komponentový systém presenterů.
Nicméně ve všech oblastech je hodně příležitostí co vylepšovat a
inovovat. A nápadů je spousta.
Nette spouští nový
crowdfundingový program, jehož cílem je získat finanční prostředky
pro vývoj frameworku. Hlavní změnou je, že místo jednorázových
příspěvků je zaměřen na pravidelnou měsíční podporu. Ta může
přicházet jak od jednotlivců, tak od firem, kterým nabízí možnost
zviditelnit se na webu Nette a inzerovat na
fóru nebo přímo v dokumentaci, tedy na místech s nejlepším zásahem
cílové skupiny programátorů.
Každý, kdo staví na Nette, má zájem, aby se framework aktivně vyvíjel.
Aby podporoval nové verze PHP. Aby se opravovaly chyby. Aby přicházel s dalšími novinkami, které usnadní práci
nebo ušetří čas a peníze. Aby framework měl skvělou dokumentaci a
existoval kolem něj užitečný obsah, ať už ve formě článků, návodů
nebo videí.
Řada částí Nette představuje světovou špičku a chceme, aby tomu tak
bylo nadále.
Bez adekvátního financování se nic z toho nedá zajistit. Přitom abyste
se mohli spolehnout, že vyjdou další verze, stačí docela málo: abyste jej
každý měsíc podpořili byť jen malou finanční částkou.
Pokud pracujete ve firmě, které Nette vydělává peníze, vysvětlete
prosím svému šéfovi, že je dobrý nápad se stát partnerem a zajistit tak
zdravé fungování projektu, na který spoléháte. Zvýšíte prioritu
řešení vašich issues a zároveň zviditelníte svoji společnost
v komunitě a přilákáte k sobě vývojáře.
Partnerství totiž přichází s exkluzivními výhodami. Například
s uvedením vašeho loga na webu Nette, možností vkládat pracovní
nabídky,
inzerovat na fóru (ukázka)
nebo v dokumentaci (ukázka),
tedy na místech se zcela nejlepším zásahem do skupiny Nette
vývojářů.
Partnerům vystavujeme faktury, aby si mohli podporu dát do nákladů, a to
buď měsíčně, čtvrtletně, půlročně nebo ročně.
V tuto chvíli máme stanoveny tři cíle, kterých chceme dosáhnout.
Prvním cílem je 64.000 Kč měsíčně, které zajistí, že se vývoji
bude věnovat jeden programátor na půl úvazku. Další vývoj Nette tak bude
pokračovat, nicméně polovičním tempem než dosud, což není úplně
ideální. Při dosažení hranice 128.000 Kč získá framework full-time
vývojáře a nové verze mohou přicházet každý rok.
Náklady jsou tak nízké proto, že nepotřebujeme kanceláře a hlavně
pracujeme na něčem, co nás baví.
Při dosažení třetí mety 196.000 Kč měsíčně budeme moci přizvat
další spolupracovníky a vylepšovat tak web, dokumentaci, vytvářet nový
obsah a nechat jej překládat do angličtiny. A tak oslovit zahraniční
komunitu. Čtvrtá meta dává možnost zapojit druhého programátora, což by
vývoj a správu issues značně zrychlilo.
Jakmile se dosáhne tohoto milníku, připravíme další cíle, které by
počítaly s více programátory, mohly by vznikat nové užitečné nástroje
a knihovny. Pak třeba vznikne i kniha o Nette.
Web Nette prochází redesignem
a první vlaštovkou je zbrusu nová horní lišta.
Na ní podobně jako ve vysílání ČT 24 nebo CNN běží tipy na
zajímavé články, knihovny, videa, události atd. Díky ní by vám nemělo
uniknout nic zajímavého, co se kolem Nette děje.
Potřebujete aktualizovat projekt běžící na Nette 2.0 na
nejnovější verzi? Tady je pár tipů, jak na to.
Stoupejte po jednotlivých
verzích
Tj. nejprve aktualizujte na Nette 2.1, poté 2.2, a tak dále. Důvod je ten,
že pokud se v Nette nějaká vlastnost změní nebo odstraní, děje se tak
v postupných krocích trvajících i několik let. Nejprve je vlastnost jako
deprecated jen označena v kódu (silently deprecated), v další velké verzi
emituje hlášku E_USER_DEPRECATED, ale funkčnost je zachována, a
teprve ve třetí verzi je odstraněna.
Nette se snaží, aby ony hlášky byly maximálně srozumitelné a návodné
(např.
Syntax {!$var} is deprecated, use {$var|noescape} on line 123),
abyste mohli zastaralé věci snadno nahradit.
Pokud byste přeskočili několik verzí, mohli byste přijít o tuto
důležitou fázi.
Začínejte bez
E_USER_DEPRECATED
Před nasazováním nové verze je vhodné nejprve vypnout hlášení chyb
E_USER_DEPRECATED:
$configurator->enableDebugger();
error_reporting(~E_USER_DEPRECATED); // všimněte si ~
Nyní můžete vyzkoušet, zda vše funguje jak má, bez upozorňování na
zapovězené věci. Pokud vše funguje, hlášky zase povolte a upravte podle
nich kód.
Za pár týdnů vyjde nová verze Nette 2.4, nejnabušenější
Nette všech dob. Postupně budu přidávat články, kde se dozvíte o všech
novinkách, ale ještě předtím…
…by bylo skvělé, kdybyste otestovali, jestli pod ním běží vaše
aplikace. Na všech svých webech už mám testovací 2.4 nasazenou a
pochopitelně jsem přitom odhalil řadu chybiček, které bylo potřeba
opravit. Tak prosím ověřte, jak jsou na tom vaše weby, než vyjde
stable.
Verze 2.4 by měla být na 99 % kompatibilní s verzí 2.3. Zároveň
upozorňuje, pokud používáte konstrukce, se kterými se už nepočítá do
Nette 3.0. Může se stát, že něco z toho je pro vás důležité a chtěli
byste funkčnost zachovat. Stačí o tom dát vědět. Ale samozřejmě co
nejdříve.
Podrobné vysvětlení všech případů, kdy Nette generuje upozornění, a
několika nekompatibilit mezi 2.3 a 2.4 najdete v tomto
vláknu na fóru. A velmi stručný přehled novinek můžete zkouknout ve
videu z poslední
Poslední soboty.