Při vývoji aplikace, která počítá s přepisováním adres pomocí mod_rewrite (Cool URL, přátelské adresy), je většinou nutné řešit problém s relativními a absolutními cestami. Projekt obvykle běží na vlastní doméně, např.
www.exaple.com. URL stránky potom může vypadat třeba takto:
www.example.com/clanek/adresa-clanku/. Všechny adresy ve stránce (cesty k obrázkům, CSS stylům, ...) potom musí být zapsané tak, aby ukazovaly do kořenového adresáře webu, jinak nebudou fungovat. To lze vyřešit více způsoby, nejoblíbenější je použití lomítka k určení absolutní cesty
(<img src="/obrazky/obrazek.jpg" alt="" />).
Problém nastává v případě, kdy se projekt vyvíjí na lokálním počítači. Na něm existuje více různých aplikací vedle sebe. Běžně jsou potom jednotlivé weby v oddělených adresářích, takže adresa potom vypadá nějak takto:
http://localhost/nazev-projektu/. Výše zmíněné lomítko potom ale bude ukazovat na adresu http://localhost/, což způsobí nefunkčnost aplikace.
Existuje více řešení popsané situace. Mě se osvědčilo využít spojení se šablonami SMARTY.
V každém projektu mám soubor settings.php, ve kterém definuji jeho základní nastavení. Mimo jiné je v něm i tento kód:if($_SERVER["HTTP_HOST"] == "127.0.0.1" || $_SERVER["HTTP_HOST"]== "localhost") {
//localhost - predpoklada cestu http://localhost/adresar/
$url = explode("/", $_SERVER["REQUEST_URI"]);
$rewrite = "/" . $url[1];
$smarty->register_outputfilter('f_rewrite');
}
else
$rewrite = false;
Pokud je podmínka platná, uloží se do proměnné $rewrite adresář projektu (včetně počátečního lomítka), v opačném případě se proměnná nastaví na false.
Nejdůležitější řádek je umístěn uvnitř podmínky -$smarty->register_outputfilter('f_rewrite');. Tento kód nastaví tzv. výstupní filtr. Znamená to, že před samotným zobrazením šablony (= HTML výstup stránky) se zavolá PHP funkce f_rewrite.
Ptáte se, k čemu je to dobré? V momentě, kdy se zavolá tato funkce, je již šablona kompletně zpracovaná, a funkce tak může modifikovat HTML kód. Toho lze s výhodou využít k převedení adres na požadovaný tvar:
function f_rewrite($tpl_source, &$smarty) {
$nahrada = $GLOBALS["rewrite"] . "/";
$vyrazy = array (
'~<(img)( [^>]*)? (src)="/([^"]+)"([^>]*)>~i',
'~<(a)( [^>]*)? (href)="/([^"]+)?"([^>]*)>~i',
'~<(link)( [^>]*)? (href)="/([^"]+)"([^>]*)>~i',
'~<(script)( [^>]*)? (src)="/([^"]+)"([^>]*)>~i',
'~<(form)( [^>]*)? (action)="/([^"]+)"([^>]*)>~i',
'~<(input)( [^>]*)? (src)="/([^"]+)"([^>]*)>~i'
);
$replace = "<\\1\\2 \\3=\"$nahrada\\4\"\\5>";
foreach ($vyrazy as $key=>$vyraz) {
$tpl_source = preg_replace($vyraz, $replace, $tpl_source);
}
return $tpl_source;
}
Funkce bere 2 parametry - $tpl_source je HTML kód šablony, $smarty potom objekt SMARTY. Samotné tělo se skládá z definice regulárních výrazů a jejich následným nahrazením v požadovaném formátu.
Pojďme si rozebrat třeba řádek'~<(img)( [^>]*)? (src)="/([^"]+)"([^>]*)>~i':
(img) je název HTML tagu. Závorky uloží obsah do proměnné k pozdějšímu použití (viz. dále),( [^>]*)? je trochu složitější výraz, ale ne moc :-) Rozebereme ho zevnitř:
[^>] znamená jakýkoli znak kromě >,* určuje možný vícenásobný výskyt předchozího, [^>]* tedy znamená žádný, nebo více znaků, neobsahující >,? značí, že celá sekvence je nepovinná (žádný nebo jeden výskyt předchozí sekvence),<img class="x"...>src, který se opět uloží do proměnné,="/), která nemá speciální význam, hledají se znaky rovnítka, uvozovek a lomítka,([^"]+) je podobné předchozímu výrazu:
[^"] znamená jakýkoli znak kromě ",+ určuje minimálně jeden výskyt, [^"]+ dohromady znamená alespoň jeden znak jiný, než uvozovky,<img src="/img/obrazek.jpg" /> (všimněte si, že nezachycuje první lomítko - o to se postará znak před touto sekvencí -, ani poslední uvozovku)," uzavírá atribut,([^>]*) je stejná jako ta výše, ukládá další atributy - například <img src="/img/obrazek.jpg" alt="" /> (včetně mezery a koncového lomítka),Pole $vyrazy obsahuje definice pro nejdůležitější HTML značky. Pokud by nějaká chyběla, není problém jí doplnit. Regulární výraz by se dal napsat i jednodušeji (jeden pro všechny značky), tento kód ale dává větší flexibilitu při určování, jaké všechny tagy se budou nahrazovat.
Za definicí pole následuje cyklus, který projde všechny jeho položky a použije je do následující konstrukce:$tpl_source = preg_replace($vyraz, $replace, $tpl_source);
Funkce preg_replace nahradí všechny výskyty vzoru (proměnná $vyraz) hodnotou (proměnná $replace) a vrátí takto upravený řetězec.
Hodnota je textový řetězec "<\\1\\2 \\3=\"$nahrada\\4\"\\5>". Nejzajmavější v něm jsou proměnné, např. \\1. V regulárním výrazu se určité sekvence uzavřely do závorek. Tyto části jsou přístupné právě přes proměnné - \\1 se tak nahradí obsahem první závorky, \\2 obsahem druhé závorky atd. Pokud tedy srovnáme regulární výraz'~<(img)( [^>]*)? (src)="/([^"]+)"([^>]*)>~i' a"<\\1\\2 \\3=\"$nahrada\\4\"\\5>" s konkrétním HTML tagem<img class="xx" src="/img/obrazek.jpg" alt="" />, dostaneme toto:
<,(img), což uloží img do proměnné \\1. V řetězci tak vznikne <img,( [^>]*)? zachytí atribut class, \\2 ho vloží do řetězce -<img class="xx",(src) a \\3 vloží do řetězce mezeru a atribur src -<img class="xx" src,=" (ve výrazu je znak uvozovky escapován zpětným lomítkem - to ruší jinak speciální význam uvozovky), ty se tedy přidají do řetězce - <img class="xx" src=",$nahrada. Ta obsahuje název adresáře včetně počátečního a koncového lomítka. Řetězec se tedy modifikuje takto:<img class="xx" src="/nazev-projektu/,\\4 přidá původní adresu:<img class="xx" src="/nazev-projektu/img/obrazek.jpg,\\5, ve které jsou další atributy -<img class="xx" src="/nazev-projektu/img/obrazek.jpg" alt="" /,<img class="xx" src="/nazev-projektu/img/obrazek.jpg" alt="" />.Jak je vidět, změnila se pouze cesta obrázku tak, že nyní již ukazuje do adresáře projektu a bude tedy fungovat i na lokálním počítači. Obdobně se převedou všechny cesty tagů, které jsou uvedené v poli $vyrazy.
V HTML šabloně se všechny adresy zapisují absolutní cestou -<img class="xx" src="/img/obrazek.jpg" /> a o nic víc se není třeba starat. Nahrazují se pouze absolutní cesty začínající /, adresy s http:// zůstanou v původním stavu.
Největší výhodou tohoto postupu je, že nahrazení se provádí pouze na lokálním počítači, při ostrém provozu na serveru tedy nedochází k žádné zátěži navíc. Kodér se také nemusí zdržovat psaním navíc, jednoduše vše píše s lomítky.
19.08.08 - Programování - 27760x -
Karma: 17.

Díky za postup, něco takového jsem docela dlouho hledal. Já jsem tenhle problém řešil pomocí
"<?php echo $dir ?>/odkaz". To je ale poměrně dost práce navíc a kód není přehlednej. Tenhle článek mě přesvědčil k používání šablon, který jsem už sice vyzkoušel, ale při práci nepoužil.Cau, ja tenhle problem resil pomoci direktivy VirtualHost v nastaveni Apache, viz google
Není mnohem jednodušší využívat standartního
<base href="http://domena.cz/ " />a pak všude používat jen relativní cesty vzhledem k výše uvedenému? ;-)
Odpověď na I.C. — #3 Značku base určitě není dobré používat, například některé vyhledávače s tím mohou mít problém. Pokud vím, důležité vyhledávače to podporují, ale rozhodně bych se na ni nespoléhal.