Jak na SEO-friendly URL (a další věci) pomocí mod_rewrite pro Apache a PHP
- Vložil Trupík 2/8/2007 10:34:43 AM
-
Pro obecný úvod do problematiky URL a implementaci SEO-friendly URL pro ASP.NET a ISS doporučuji předešlý článek
Jak na SEO-friendly URL v ASP.NET
Na serveru Apache lze SEO-friendly URL implementovat pomocí modulu
mod_rewrite a souborů .htaccess. Tento modul je použit na
většině placených hostingů, na freehostinzích být nemusí. To, jestli
váš hosting mod_rewrite podporuje zjistíte buďto přímo od poskytovatele
nebo prostě nahráním a vyzkoušením souboru .htaccess. Některé hostingy
použití .htaccess omezují např. jen na některé adresáře.
Soubory .htaccess
Soubory .htaccess jsou soubory, kterým můžete ovlivnit chování webového
serveru při poskytování požadované adresy. Fungují hierarchicky –
soubor .htaccess můžete vytvořit v libovolném adresáři a pravidla
v něm se pak budou vztahovat na daný adresář a jeho podadresáře.
Pokud nějaké pravidlo definujete víckrát v různých .htaccess
souborech (tedy v různých adresářích), použije se vždy to, které
je nejblíž danému souboru (tedy nejvíc zanořené, nejvyšší prioritu má
.htaccess v daném adresáři, po něm v adresáři o úroveň
výš atd.)
Kombinaci mod_rewrite a .htaccess můžete použít k různým věcem
(ne jen pro SEO-friendly URL. To si nechám na konec, protože je to
nejnáročnější.
Vlastní chybová stránka
Velmi jednoduchým pravidlem můžete předefinovat chybovou stránku 404
– tedy stránku, kterou prohlížeč zobrazí, pokud soubor na serveru
neexistuje.
ErrorDocument 404 /fnf.php
Zákaz / povolení adresáře
Pravidlem deny znepřístupníte daný adresář (+ podadresáře). To se
hodí třeba pro adresáře, kde máte uložené skripty, které includujete do
jiných stárnek.
# radka zacinajici krizkem je komentar a nezpracovava se
# deny from all zakaze pristup vsem deny from all
# deny from + IP adresa (nebo jeji cast) zakaze pristup
# konkretnim pocitacum (skupinam pocitacu)
deny from 224.123
# opakem deny je prikaz allow– povoleni
allow from 127.0.0.1
Pravidla pro přesměrování – redirect
Přesměrování je nejspíš ta nejsilnější zbraň. Existují dva
druhy
- viditelné přesměrování – při zpracování URL
server zjistí, že je
adresa přesměrovaná, tak u tom informuje prohlížeč klienta HTTP
hlavičkou
-- 301 – Moved Permanently (trvale přesunuto)
-- 302 – Moved Temporarily (dočasně přesunuto)
viditelné přesměrování použijete např. pokud změníte vnitřní
strukturu serveru, změníte adresu nějakého dokumentu, přesunete stránky
na jinou doménu apod. Server pouze zašle příslušnou hlavičku,
o nahrání stránky z nové adresy se musí postarat klient
(prohlížeč) – ten typicky okamžitě nahraje stránku z nového
umístění. V adresním řádku prohlížeče se také objeví nová
adresa.
- skryté přesměrování – toto přesměrování se
děje pouze na serveru. Klient
o přesměrování neví a myslí si, že dokument se nachází na
původní URL. Toto přesměrování použijete typicky při přesměrování
z adres nezačínající „www“ na adresy, které zažínají
„www“ (tím se zamezí duplicitám). Dalším typickým použitím
je přesměrování ze statických adres (SEO-friendly) na dynamické.
Mod_rewrite defaultně provádí skryté přesměrování. Pokud chcete
provést viditelné přesměrování, je potřeba za dané pravidlo doplnit
modifikátor
- [R=301] pro trvalé přesunutí
- [R=302] pro dočasné přesunutí
Základní syntaxe přesměrování
základní syntaxe je
# zapne presmerovavani – staci jednou na zacatku souboru
Rewrite engine on RewriteCond…podminka…
RewriteRule pravidlo(regularni vyraz) novaadresa [modifikatory]
Jednoduchá viditelná přesměrování
Přesměrování jednoho souboru na jiný:
RewriteRule stara-url\.html nova-url.html
všimněte si sekvence \. – tečka je totiž speciálním znakem
v regulárních výrazech, které mouhou být součástí pravidla, a
proto je nutné jí escapovat.
Přesměrování adresy bez www na adresu s www :
RewriteCond %{HTTP_HOST} ^example.com [NC] RewriteRule (.*) http://www.example.com/$1 [R=301,QSA]
tady je už situace o něco zajímavější. První řádek je
podmínka. %{HTTP_HOST} je proměnná, která obsahuje část host z URL.
Znak ^ značí začátek url. Pokud tedy URL začíná na
„example.com“ (tedy nezačíná na http://www.example.com), provede se následující
pravidlo.
(.*) znamená přesměrování všech URL na novou adresu. $1 připojí za
adresu první skupinu (tedy celou adresu) modifikátor QSA připojí za adresu
také query string (parametry) takže z adresy
example.com/clanky.php?id=12 se přesměruje na www.example.com/clanky.php?id=12
Přesměrování celého webu na jinou doménu
RewriteCond %{HTTP_HOST} ^wwww.example.com [NC] RewriteRule ^(.*)$ http://www.new-example.com/$1 [R=301,QSA]
podobná situace jako minule
Co všechno lze v pravidlech použít
Užitečné proměnné pro podmínky RewriteCond
- %{HTTP_HOST} – část host z URL (z http://www.example.com/index.php
je to http://www.example.com)
- %{REQUEST_FILENAME} – jméno požadovaného
souboru
- %{REQUEST_URI} – URL požadovaného souboru
- %{QUERY_STRING} – query string adresy (parametry)
– velmi užitečné – (z http://www.example.com/clanky.php?id=1
je to id=1)
Modifikátory pravidel (je jich víc, ale já si vždy vystačil
s těmito)
- [NC] – pravidlo nebere v úvahu malá/velká
písmena
- [R=301], [R=302] – provede se viditelné
přesměrování
- [QSA] – za novou url se přidá také původní query
string (parametry)
- [L] – žádná další přepisovací pravidla se po
tomto pravidle už provádět nebudou
- [F] – URL vrátí klientovi kód 403 –
zakázano. Moc nepoužívám (radši někam přesměruji).
SEO-friendly URL
Nejnáročnější ale jistě také nejužitečnější část jsem si nechal
na konec. Budu uvažovat web s nějakými články, které jsou
jednoznačně určené svým číslem (parametr id) Co tedy bude mým
cílem:
- přesměrování statických adres na dynamické tedy přesměrování
www.example.com/clanky/1234-titulek-clanku
=> www.example.com/clanek.php?id=1234
To se provede jako skryté přesměrování
- přesměrování statických adres se špatným titulkem na adresu se
spravnym titulkem
www.example.com/clanky/1234-spatny-titulek
=> www.example.com/clanky/1234-titulek-clanku
To se provede jako viditelné přesměrování (a po něm proběhne
neviditelné přesměrování v prvním bodě).
Tato část se může zdát zbytečná, ale není. Zamezí se tak
duplicitám.
- propagování statických URL
www.example.com/clanek.php?id=1234;
=> www.example.com/clanky/1234-titulek-clanku
Toto je tedy opak bodu 1), ale opět není zbytečný – zase se
zabrání duplicitám. Bez tohoto bodu by totiž obě adresy vracely stejný obsah.
Přesměrování statických adres
stačí celkem jednoduché pravidlo
RewriteRule ^clanky/([0–9]+)(.*) /clanek.php?id=$1
Oprava špatného titulku
protože je potřeba na nové adrese znát původní titulek, je potřeba ho
nějak dostat i na novou adresu. Takže nejprve upravíme původní
pravidlo:
RewriteRule ^clanky/([0–9]+)-(.*) /clanek.php?id=$1&titulek=$2
Teď už budeme ve skriptu clanky.php znát i požadovaný titulek.
Opravu titulku nelze provést v .htaccess souboru, ale musí se sáhnout do
clanek.php. Tam vložíme takovýto kód.
$urltitulek = $_GET['titulek']
$urlid = $_GET['id']
// najdeme clanek v databazi podle id
$sql = "SELECT * FROM clanky WHERE id = '".addslashes($urlid)."'";
$clanek = mysql_fetch_object(mysql_query($sql));
// id nemusi vubec existovat - vracime chybu 404
if ($clanek == NULL)
{
header("HTTP/1.1 404 Not Found");
header("Location: http://www.example.com/clanek-nenalezen.php");
header("Connection: close");
}
else
{
//porovnani spravneho titulku. Predpokladam, ze sloupec titulek
//obsahuje presne ten retezec, ktery ma byt v URL
if ($clanek->titulek != $urltitulek)
{
header("HTTP/1.1 301 Moved Permanently");
header("Location: http://www.example.com/clanky/".$clanek->id."-".$clanek->titulek);
header("Connection: close");
}
}
Propagace statických adres
Nechceme, aby byly zvenčí „vidět“ dynamické adresy
s parametry. Zdálo by se, že stačí doplnit následující
pravidlo:
RewriteCond %{QUERY_STRING} id=([0–9]+)
RewriteRule ^clanek\.php$ /clanky/%1 [R=301,L]
Pravidlo sice dělá to, co chceme, ale je tu jeden problém. Toto pravidlo
přesměruje na ten tvar adresy, který očekává zase první pravidlo a tak
se tyto dvě pravidla zacyklí. Je potřeba tomuto zacyklení zabránit.
Já osobně to dělám tak, že při prvním přepisu přidám jako další
parametr příznak, že už se podruhé přepisovat nemá. Takže celkově by
to mohlo vypadat nějak takhle:
RewriteEngine on
RewriteRule ^clanky/([0–9]+)-?(.*) /clanek.php?id=$1&titulek=$2&xxx=1 [R=301]
# pouziuju dve podminky – druha testuje, jestli uz se URL jednou neprepsala
# vykricnik pred podminkou znamena klasickou negaci RewriteCond
%{QUERY_STRING} id=([0–9]+) RewriteCond %{QUERY_STRING} !xxx=1
RewriteRule ^clanek\.php$ /clanky/%1? [R=301,L]
Ohodnoťte prosím užitečnost článku