mod_rewrite a hezké url díl III

Thu, 21 May 2015 21:16:57 +1100

Články o mod_rewrite pro hezké url mi dlouhodobě zaznamenávají velkou návštěvnost, což ale není ten důvod, proč jsem se rozhodl napsat díl už asi osmistý padesátý prvý. Některé věci je totiž nutné uvést po letech na pravou míru: předchozí díly měly v prvé řadě ukázat, že pomocí mod_rewrite lze dosáhnout cokoli, co si člověk jenom zamane. Každá aplikace, byť je sebehůř napsaná, má šanci na přátelská url.

Problém nastal v případě, kdy měli méně zkušení uživatelé tendence psát hromady zbytečně krkolomných pravidel nebo se je snažili nasadit na nevhodně navrženou strukturu url adres - namísto toho, aby začali s úpravami v PHP kódu. Sám jsem takovým uživatelem býval, ale dnes už vím, jaká je v jednoduchosti síla. Dnešní pokračování seriálu o mod_rewrite tedy vše zase zjednoduší. Představíme si 5 základních využití mod_rewrite, které vám vystačí téměř na jakkoli náročný projekt.

1. Obecné přesměrování

Zapsat do souboru .htaccess přesměrování je jedna z věcí, kterou potřebuje každý. Následující 3 případy by měly pokrýt většinu případů, kdy budeme přesměrování potřebovat:

1. Přesouváme celý web na novou doménu.

2. Změnila se url článků a nemáme v PHP naprogramovaný modul, který by redirectoval automaticky.

3. Změnila se url kategorie a je potřeba přesměrovat i vše, co je uvnitř.

# celý web na novou doménu
RewriteRule ^(.*)$ http://www.nova-domena.cz/$1 [L,R=301,QSA]

# konkrétní url na jinou konkrétní url
RewriteRule ^clanek/?$ jiny-clanek/ [L,R=301]

# stará kategorie a vše uvnitř na novou kategorii
RewriteRule ^stara-kategorie/(.*)$ nova-kategorie/$1 [L,R=301]

2. Přidání nebo umazání www před doménovým jménem

Pro domény druhého řádu chceme www přidávat, u domén třetího řádu zase odmazávat. Toto by mělo být zpravidla vyřešeno už na úrovni hostingu, ale ne vždy tomu tak bývá. Proto druhý typ přepisů, které člověk využije, je právě přidávání respektive umazávání "www".

# umazání www
RewriteCond %{HTTP_HOST} ^www.mujweb.cz$
RewriteRule (.*) http://mujweb.cz/$1 [R=301,QSA,L]

# přidání www
RewriteCond %{HTTP_HOST} ^mujweb.cz$
RewriteRule (.*) http://www.mujweb.cz/$1 [R=301,QSA,L]

3. Hezké url pro jednoduchý web

Pokud máme vytvořený jednoduchý web, který využívá include podle GET proměnné nebo je vše rozházeno v souborech *.php v kořenovém adresáři webu, bude vždy stačit jedno z následujících pravidel. Víc opravdu není nutné. Jakmile začneme mít potřebu složitějších rewritů, máme tu už jedno obecné pravidlo, které vystačí jak na miniaturní webík tak na monstrózní aplikaci.

# index.php?page=neco => neco/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?page=$1 [L]

# stranka.php => stranka/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ $1.php [L]

4. Hezké url pro web libovolné náročnosti

Všechno na index.php. Víc není potřeba. Bude existovat jedna GET proměnná, kterou rozbijeme podle lomítka a necháme už PHP, aby si zpracovalo řetězec podle své potřeby. Ve chvíli, kdy pocítíme potřebu dalších GET proměnných, rewritovat je už nebudeme, protože to prostě není potřeba. Jestl i tak máme stále nutkání tyto proměnné rewritovat, bude možná lepší se nejdřív zamyslet nad architekturou aplikace.

# vše na index.php a proměnnou $_GET[path]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?path=$1 [L,QSA]

5. Výjimka z předchozího příkladu

Zase tak jednoduché to nakonec nebude, abychom všechno pokryli jedním pravidlem :o) Občas potřebujeme určité url adresy nasměrovat na jiný soubor, než index.php: například proto, aby se zbytečně nenačítalo celé jádro systému a všechny knihovny, když chceme udělat jenom jednoduchý AJAX request. Nebo nabídnout soubor ke stažení tak, aby nebyla vidět ani url souboru ani skutečná url skriptu, který soubor ke stažení nabídne. Přidáme tedy pravidlo druhé, které musí být uvedeno před tím prvním: pokud regulární výraz nebude splněn, server aplikuje pravidlo druhé.

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^simple_module/(.*)?$ index_simple.php?path=$1 [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?path=$1 [L,QSA]

6. HTTP na HTTPS

SSL certifikát je dnes už téměř samozřejmostí a občas potřebujeme na celé doméně přidat to "s" do protokolu. To nám umožní následující zápis.

RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.treba.cz/$1 [R=301,L]

Čtvrtý bod bych měl ještě asi trochu více rozvést. Kdykoli bude výsledná url stránky například "www.treba.cz/hlavni-kategorie/dalsi-kategorie/", proměnná $_GET["path"] bude mít hodnotu "hlavni-kategorie/dalsi-kategorie/". Proměnnou rozbijeme podle lomítka (funkcí explode) a šáhneme do databáze pro "Další kategorii" která má nad sebou "Hlavní kategorii". Tedy namísto vícenásobných identifikátorů pro strukturu stránek pracujeme s polem hodnot.

Jestliže chceme přidat ještě i nějaké stránkování (které mimochodem opravdu nemusí mít "pěkné" url), stačí otestovat poslední hodnotu pole na celé číslo. Tím rozlišíme, že "hlavni-kategorie/2/" je pouze druhá stránka výpisu příspěvků, nikoli kategorie "2". Problém samozřejmě nastane ve chvíli, kdy budeme kategorii pojmenovanou "2" vlastně chtít: a jedno nám přebije druhé.

A to je vše dámy a pánové. V předchozích dílech seriálu jsem vás naučil, jak mod_rewrite funguje, co všechno dokáže a jak specifická pravidla umožňuje napsat. A díky tomu jsem dnes mohl ukázat, že dané vědomosti je dobré mít, ale v praxi je vždy využijeme na mnohem jednodušší úrovni.