Šablona z databáze spustí a komponenty + open_basedir

mrazek85
Člen | 9
+
0
-

Ahoj, mám presenter ve kterém se z databáze načte HTML obsah do $content – v tomto HTML potřebuji nahradit nějaké znaky za volání a spuštění komponenty a posléze tento obsah poslat do renderu presenteru (aby se komponenty vykonaly).
V současnosti mi funguje toto (zjednodušeně):

public function actionDetail($id) {
	$article = $this->database->table('clanek')->get($id);
    $this->template->content = $this->decodeText($article->text);
}

function decodeText($text) {
	$template = $this->createTemplate();
    $template->getLatte()->setLoader(new \Latte\Loaders\StringLoader);
    $content = $text;
    $content = preg_replace_callback("/*****/", function($matches) {
		return "{control " . $matches[1] . "}";
	}, $content);
	return $template->getLatte()->renderToString($content, $template->getParameters());
}

toto fyzicky funguje, ale v případě, že to nahraju na hosting, kde je zaplé open_basedir, píše mi Tracy (v oblasti „latte templates“).
1× Rendered Templates
a druhá je chyba:
Error: Latte\Bridges\Tracy\LattePanel-2
ErrorException: is_file(): open_basedir restriction in effect. File(<div class=„col-sm-5“ sty…html kod

Na localhostu s XAMPP, kde jej mám vyplé vše běhá v pořádku a zobrazí se v Tracy panelu 2× vedle sebe Rendered Templates :

renderToString zjevně vyžaduje cestu k souboru s latte, nicméně zde žádná šablona není (HTML je generován z db) – zřejmě funkci používám blbě, lze nějak opravit tento kód ?

m.brecher
Generous Backer | 763
+
0
-

@mrazek85

V dokumentaci je metoda renderToString() popsaná jako nástroj k vykreslení šablony latte která je v souboru do proměnné jako string, který se později vykreslí do jiné šablony – metoda je určena spíš pro použití Latte bez Nette, protože v Nette se šablony vykreslují přímo bez nutnosti šablonu vykreslit do proměnné:

https://latte.nette.org/cs/develop#…

Ty ale máš HTML již z databáze jako string rovnou a tak metodu renderToString() možná vůbec nepotřebuješ !!

Co na to jít jednodušeji nějak takto:

public function actionDetail($id) {
	$article = $this->database->table('clanek')->get($id);
    $this->template->content = $this->decodeText($article->text);
}

function decodeText($text) {
	    return preg_replace_callback("/*****/", function($matches) {
		return "{control " . $matches[1] . "}";
	}, $text);
}
dakur
Člen | 493
+
0
-

renderToString() je v pořádku, pokud používáš StringLoader, soubor to neřeší, ale bere právě ten první parametr jako vstup (viz docs). Nemáš pak v tý komponentě, kterou to má parsovat, nějaký include? Tam je evidentně problém s oprávněním na hostingu při vkládání souboru.

m.brecher
Generous Backer | 763
+
0
-

@dakur

renderToString() je v pořádku, pokud používáš StringLoader, soubor to neřeší, ale bere právě ten první parametr jako vstup

v dokumentaci, jsem nikde poznámku, že metoda renderToString() soubor neřeší neviděl, třeba jsem se ale jenom díval na nesprávná místa:

https://latte.nette.org/cs/develop#…
https://latte.nette.org/…ending-latte#…

Pokud je skutečně možné, že StringLoader modifikuje první parametr metody renderToString(), bylo by vhodné to do dokumentace srozumitelně doplnit – pokud to tam už někde není. Popř. doplnit poznámku přímo do odstavce o StringLoader.

Klidně PR do dokumentace podám, ale rád bych znal názor zkušenějších ;).

jeremy
Člen | 50
+
+1
-

@m.brecher

v dokumentaci, jsem nikde poznámku, že metoda renderToString() soubor neřeší neviděl

renderToString() je v pořádku, pokud používáš StringLoader, soubor to neřeší

Myslim, ze to bylo mysleno tak, ze to soubor neresi pouze pokud se pouziva StringLoader. Je jedno jestli se pouzije metoda render() nebo renderToString(), plati to pro oboje. V takovem pripade je primo ten string sablona a nehleda se zadny soubor.

Co se tyce dokumentace, tak mi to prijde celkem jasne popsany prave v sekci o StringLoaderhttps://latte.nette.org/…ending-latte#…

mrazek85
Člen | 9
+
0
-

@m.brecher
Pokud by se to řešilo takto, tak šablona (samozřejmě při |noescape) textově vypíše <p>text z db... {control.. }</p> → komponenta se nevykoná

@dakur
Nevím o tom, v komponentě používám klasické render metody. Teď jsem zjistil, že chybu Tracy hlásí, i když string žádnou komponentu neobsahuje, je to např. jen :

public function actionDetail() {
    $this->template->content = $this->decodeText("<p>jen text</p>");
}

function decodeText($text) {
	$template = $this->createTemplate();
    $template->getLatte()->setLoader(new \Latte\Loaders\StringLoader);
	return $template->getLatte()->renderToString($text, $template->getParameters());
}

v latte je jen {$content|noescape}

Náhled na Tracy : link

V případě, že to pošlu bez toho StringLoaderu, renderToString tak to funguje samozřejmě bez chyb v Tracy, ale potřebuju zpracovat případné komponenty ještě před tím, než to dám do hlavní šablony (aby to nepsalo „{control formular }“ ale vypsalo HTML té komponenty <form>…</form> ).

Marek Bartoš
Nette Blogger | 1177
+
0
-

A které volání is_file() ti padá? is_file rozlišuje mezi souborem a složkou a nejspíš je tam kvůli tomu. Case, kdy se do volání dostane html by se nejspíš v kódu měl ošetřit. Ideálně poslat odkaz na konkrétní řádek na GitHubu

Editoval Marek Bartoš (18. 9. 2023 16:40)

dakur
Člen | 493
+
0
-

Jojo, je potřeba zjistit, co to je za is_file(), na kterém to padá.

stepos2
Člen | 51
+
0
-

Bez StringLoaderu by to mohlo jít takhle:

public function actionDetail($id)
{
	$article = $this->database->table('clanek')->get($id);
	$content = $this->decodeText($article->text);
    $this->template->content = preg_replace_callback(
		'/\{control ([a-zA-Z0-9_-]+)}/',
		fn(array $m) => $this->renderComponent($m[1]),
		$content
	);
}

function decodeText($text)
{
	return preg_replace_callback("/*****/", function($matches) {
		return "{control " . $matches[1] . "}";
	}, $text);
}

function renderComponent(string $name)
{
	ob_start();
	$this->getComponent($name)->render();
	return ob_get_clean();
}
m.brecher
Generous Backer | 763
+
0
-

@jeremy

Co se tyce dokumentace, tak mi to prijde celkem jasne popsany prave v sekci o StringLoader: https://latte.nette.org/…ending-latte#…

Když se v tom hrabeš delší dobu, tak to jasné je, ale mě jako nově příchozímu do problematiky StringLoaderu v dokumentaci chybí popis funkce u druhého příkladu:

Zjednodušené použití:

$template = '{if true} {$var} {/if}';
$latte->setLoader(new Latte\Loaders\StringLoader);
$latte->render($template);

Člověk tak nějak odhadne, že se asi Latte dovtípí, že soubor šablony ‚{if true} {$var} {/if}‘ neexistuje a tedy bude jméno souboru považovat za kód šablony, co ale jiné šablony, které existují, bude je Latte načítat ze souboru i když je nastaven StringLoader?? To už z dokumentace nevyčtu a musím to v reálu otestovat. Myslím, že podrobnější vysvětlení v dokumentaci k StringLoaderu by bylo ku prospěchu celé komunitě.

A co se stane, když PHP vyhodnotí ‚{if true} {$var} {/if}‘ jako cestu, která vede mimo base restriction oblast ?? Zřejmě vyhodí Exception o které je tady řeč. Asi by se toto mělo v Latte nějak fixnout, aby k tomu nedocházelo.

m.brecher
Generous Backer | 763
+
-2
-

@mrazek85

Teď jsem zjistil, že chybu Tracy hlásí, i když string žádnou komponentu neobsahuje

Vzpomněl sem si, že před časem jsem s podobnoiu exception zápasil také. PHP prostě zjistí, že ‚<div…‘ není v cestě uvedené v base restriction. Nepozná, že je to HTML !!! Latte zřejmě magicky načte šablonu ze stringu pokud je nastaven StringLoader a pokud první parametr není cesta k šabloně – což testuje pomocí is_file(). Jenže base restriction se bezpochyby testuje dříve než se zavolá is_file() takže se vyhodí výjimka porušení base restriction.

Jak tohle vyřešit netuším, je to ale problém, který by se měl řešit ! Latte by mělo umožnit striktně deklarovat, že chci načítat šablonu z proměnné a ne to řešit magicky pomocí is_file(). Tedy doplnit do metod ->render() a renderToString() parametr pro vynucení načítání z řetězce, kdy by se nevolalo is_file() a base restriction by nevadilo, třeba:

$latte->renderToString($code, $parameters, loadFromString: true);
$latte->render($code, $parameters, loadFromString: true);

Co na to ostatní ??

jeremy
Člen | 50
+
+1
-

@m.brecher

A co se stane, když PHP vyhodnotí ‚{if true} {$var} {/if}‘ jako cestu

Nestane, StringLoader bere vsechen text jako content sablony. Takze, pokud se napise cesta k souboru, napr: /path/to/template.latte, tak to i tak nevyhleda ten soubor, rovnou compilne ten text. is_file() se u StringLoader nepouziva, pouze pro nacteni cache. To, ale problem neni. Mam teorii popsanou dole.

Načítá šablony z řetězců.

Toto je hned prvni veta v dokumentaci o StringLoader. Mozna by to chtelo zmenit nebo vic vysvetlit co se tu mysli jako sablona, ale i tak mi to prijde celkem jasny.

Mozna bych zmenil v dokumentaci

$latte->setLoader(new Latte\Loaders\StringLoader([
	'main.file' => '{include other.file}',
	'other.file' => '{if true} {$var} {/if}',
]));

$latte->render('main.file');

na

$latte->setLoader(new Latte\Loaders\StringLoader([
	'main' => '{include other}',
	'other' => '{if true} {$var} {/if}',
]));

$latte->render('main');

Kdyz jsem to cetl po prvy tak me to taky trochu na chvili zmatlo.

Co se tyce te chyby s is_file(), podle screenshotu to vypada na chybu primo v tracy panelu, ne latte. Tracy panel pouziva is_file() na nekolika mistech, je mozny ze prave tam se snazi nacist html jako cestu k souboru.

@mrazek85 mozna by to chtelo ukazat celou tu chybu, cast je zakryta druhym panelem.

Editoval jeremy (19. 9. 2023 0:03)

jeremy
Člen | 50
+
0
-

@mrazek85 jakou verzi Tracy a Latte pouzivas?

V Tracy\Helpers v metode editorUri() se pouziva is_file() bez @. Je to jediny misto (ktere jsem nasel), kde by to pri chybe vyhodilo exception. is_file() se tu pouziva na vyhledani souboru pro vytvoreni odkazu na editor. V pripade sablony vyrenderovane pres StringLoader to tam hodi obsah ty sablony. Pouzivam nejaktualnejsi verze a v mem pripade to nejdriv z obsahu odstrani html.

Edit: verze je asi celkem jedno vzhledem k tomu ze na localu to funguje. Z nejakyho duvodu to vypada, ze se na produkci neodstrani html.

Duvod, proc myslim ze tam je problem je, ze chyba nastane v Rendered Templates panelu hned na zacatku. V druhem Latte panelu jsou normalne odkazy na latte soubory, ale tady je prave nazev sablony html text.

Editoval jeremy (19. 9. 2023 1:04)

m.brecher
Generous Backer | 763
+
0
-

@jeremy

Jestli StringLoader nepoužívá is_file() a rovnou natvrdo načítá ze stringu, tak je v Latte všechno OK a chyba by mohla být ve volání is_file() ve vkládané šabloně – což bylo vyloučeno, takže by to mohlo být voláním is_file() v Tracy.

V ukázce kódu ‚main.file‘ by bylo vhodnější použít jak navrhuješ ‚main‘, protože přípona .file může vyvolávat nejasnosti – mě to mátlo v tom smyslu, že jsem nejdřív myslel, že jenom ‚main.file‘ a ‚other.file‘ se načítá z řetězce a ostatní hodnoty ze souboru + přidat do komentáře, že to funguje pro metody render() i renderToString().

Podám do dokumentace PR.

Marek Bartoš
Nette Blogger | 1177
+
0
-

Aby se tu ve slohovkách neztratilo to relevantní – je to fixnutelné, stačí vědět kde.
https://forum.nette.org/…open-basedir#…

nightfish
Člen | 474
+
0
-

@MarekBartoš Odhaduji, že warning je vyhozen v https://github.com/…/Helpers.php#L61, který se volá z https://github.com/….panel.phtml#L83, do které propadá hodnota $item->phpFilehttps://github.com/…ttePanel.php#L106

OP teda používá mírně starší verzi, protože mu to chybu hlásí na řádku 60 a nikoliv 61.

mrazek85
Člen | 9
+
0
-

Díky za informace, jsem zase o trošku chytřejší.
Původní verze Tracy byla v2.9.0, pro sychr jsem to dnes přehrál na v2.10.3 – chyba vyskakuje stále, ale už ne na řádku 60, ale na řádku 61.

Kód na webu funguje v pořádku, chyba bude jen v té Tracy – zřejmě jak psal @nightfish link

ErrorException: is_file(): open_basedir restriction in effect. File(<div class="col-sm-5" style="decimal: LEFT;"></div>) is not within the allowed path(s): (/www/autoprep:/usr/share/pear:/usr/share/php:/www/test.cz:/php_sess_data/test.cz:/www/test.cz-tmpdir:/var/www/web5/test.cz:/var/www/web2/test.cz) in /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Helpers.php:61
Stack trace:
#0 [internal function]: Tracy\Bar->Tracy\{closure}(2, '...', '...', 61)
#1 /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Helpers.php(61): is_file('...')
#2 /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Helpers.php(26): Tracy\Helpers::editorUri('...', NULL)
#3 /www/test.cz/web.test.cz/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.panel.phtml(81): Tracy\Helpers::editorLink('...')
#4 /www/test.cz/web.test.cz/vendor/latte/latte/src/Bridges/Tracy/LattePanel.php(95): require('...')
#5 /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Helpers.php(364): Latte\Bridges\Tracy\LattePanel->Latte\Bridges\Tracy\{closure}()
#6 /www/test.cz/web.test.cz/vendor/latte/latte/src/Bridges/Tracy/LattePanel.php(96): Tracy\Helpers::capture(Object(Closure))
#7 /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Bar/Bar.php(143): Latte\Bridges\Tracy\LattePanel->getPanel()
#8 /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Bar/Bar.php(115): Tracy\Bar->renderPanels('')
#9 /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Bar/Bar.php(89): Tracy\Bar->renderPartial('...')
#10 /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Debugger/DevelopmentStrategy.php(123): Tracy\Bar->render(Object(Tracy\DeferredContent))
#11 /www/test.cz/web.test.cz/vendor/tracy/tracy/src/Tracy/Debugger/Debugger.php(292): Tracy\DevelopmentStrategy->renderBar()
#12 [internal function]: Tracy\Debugger::shutdownHandler()
#13 {main}
jeremy
Člen | 50
+
+3
-

Prave jsem si zapnul open_basedir a hazi mi to stejnou chybu pri pouziti StringLoader na nejaktualnejsi verzi Tracy. Je jasne, ze chyba je v Tracy\Helpers::editorUri(). Staci pridat ‚@‘ pred is_file().

Git issue: https://github.com/…y/issues/572

@DavidGrudl @mrazek85

m.brecher
Generous Backer | 763
+
0
-

@MarekBartoš

Aby se tu ve slohovkách neztratilo to relevantní – je to fixnutelné, stačí vědět kde.

Máš pravdu, z uvedených příkladů u StringLoaderu je skoro úplně jasné jak to funguje a detaily si člověk vyzkouší. Jenom ta přípona .file není jasné co se tím chce říci. Není to tak, že by tam mělo být třeba main.latte načtení standardní šablony které se StringLoaderem přesměruje jinam během testů ?? Jiné koncovky u latte šablon asi těžko někdo používá. Takže asi jediné co by se mohlo v dokumentaci poopravit je nahradit koncovku .file koncovkou .latte. Jak píše @jeremy koncovku úplně vynechat by mohlo být také matoucí, protože v kódu nebudeme mít:

$latte->render('main');

nýbrž:

$latte->render('main.latte');

Dává mě smysl přesměrovat ‚main.latte‘ na nějaký string aniž bych musel měnit kód.