Poznámka: články jsou již mnoho let staré, doba se posunula, mnoho věcí v nich doporučovaných je již dnes překonané - berte s rezervou!


Jak na SEO-friendly URL (a další věci) pomocí mod_rewrite pro Apache a PHP

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…pod­minka… 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/clan­ky.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_FILE­NAME} – 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:

  1. 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í
  2. 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.
  3. 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&t­itulek=$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&t­itulek=$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




48
 
62
 
55
 
26
 
10
 
 
Vložit komentář:
 

 



 

 

Nepoužívejte žádné html ani texy značky, odřádkování se zachová. Pokud uvádíte zdrojový kód, můžete ho vložit mezi značky
<syntax jazyk="PHP">...</syntax>,
bude potom zformátován. Jako atribut můžete uvést PHP, C#, HTML, CSS a mnoho dalších.


opiste cislo Opište číslo:

 

18. 3. 2007 14:33:37
[1] (Petr Stříbný (petrstribny(at)gmail.com)) www
Nemám rád povinné titulky odpovědět
Článek jsem nečet, ale co se týká generování CoolURI, tak používám jen jedno pravidlo pro .htaccess, které mi prostě jakoukoliv URL přesměruje na skript a parsování/validaci URL nechávám na PHP. V .htaccess pak nemusím vymýšlet složitá pravidla a navíc mám v PHP neomezené možnosti jak s URL naložit.
19. 3. 2007 16:51:41
[2] (Trupík (jakub.maly(at)atlas.cz)) www
Re: Nemám rád povinné titulky odpovědět
[1]: Taky možnost. Pravidla v .htaccess nebývají nijak složitá (podle mne), prostě regulární výrazy, které v tom skriptu nakonec asi používáte skoro stejně, ne? Ale zajímalo by mne, jak děláte ono "tiché" přesměrování ("podstrkávání") - tedy obdoba toho, kdy v .htaccessu neuvedete přepínač [R]
23. 3. 2007 9:29:20
[3] (jb) www
když už je v titulku "SEO" odpovědět
Přijde mi docela nešťastné přesměrovávat pomocí R=301 nebo R=302 protože to vyhledávače opravdu nemají rádi. Jediný vyhledávač, který si s tím podle mé zkušenosti poradil a nevyřadil na čas mé stránky z vyhledávání, byl jyxo.cz.

Osobně používám následující univerzální .htaccess a celou logiku řeším až v obsluha_seo.php.

RewriteEngine on RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*) obsluha_seo.php
26. 3. 2007 20:23:32
[4] (Trupik (jakub.maly(at)atlas.cz)) www
Re: když už je v titulku "SEO" odpovědět
[3]: Vyhledávače ale v ideálním případě žádné odkazy na staré URL, které se budou přesměrovávat pomocí 301 a 302, neuvidí.
3. 4. 2007 0:30:39
[5] (kapčus)
odstranit parametr odpovědět
pokud chcete odstranit napr parametr ID, pouzijte toto
RewriteCond %{QUERY_STRING} ^ID=
RewriteRule ^(.*)$ http://www.adresa.cz? [R=301,L]

dulezity je ? na konci
pisu to protoze to nikde neni napsane, tak treba to nekomu pomuze
3. 2. 2008 11:21:17
[6] (Jenda (uschovna(at)centrum.cz))
přesměrování s novými proměnnými odpovědět
Dobrý den, chtěl bych se zeptat, je-li možné nějak vyřešit situaci, kdy mám fungující skript neco.php?id=123 a chtel bych jej nechat presmerovat trvale na retezec neco.php?id=123&jmeno=abc&prijmeni=def , pričemž v databázi mám tabulku obsahující samozřejmě jak id (primární klíč), tak jmeno a prijmeni. Je mi jasné, že to asi pouze pomocí .htaccess nepůjde, ale nevím, jak si pro ty proměnné jmeno a prijmeni sahnout do databaze a natlacit je do url. Díky moc.
3. 2. 2008 12:02:57
[7] (Trupik (jakub.maly(at)atlas.cz)) www
Re: přesměrování s novými proměnnými odpovědět
[6] Viz část článku "Oprava špatného titulku".
3. 2. 2008 14:54:07
[8] (Jenda (uschovna(at)centrum.cz))
Re: Re: přesměrování s novými proměnnými odpovědět
[7] Díky za rychlou odpověď. Přesto bych se chtěl ještě zeptat, která část kódu z celkového výsledného řeší právě to přidání dalších proměnných do url. Moc s tím ještě neumím, a tak mi není jasné, jestli pro to přesměrování na url s více proměnnými potřebuji celý ten výsledný kód, který uvádíte na konci a nebo jestli stačí jen některá z jeho částí.

A druhý můj dotaz je, jak mám napsat ten první řádek (který máte hned po rewriteengine on), když současný skript nemám v samostatném adresáři (vy ho máte v adresáři clanky/), ale v rootu a jmenuje se vypis.php.

Moc moc díky, budu Vám vděčen za pomoc.
3. 2. 2008 15:31:10
[9] (Trupik (jakub.maly(at)atlas.cz)) www
Re: Re: Re: přesměrování s novými proměnnými odpovědět
[8] jestli tomu rozumím správně, tak do neco.php přidat
header("Location: http://www.example.com/neco.php". "id=".$id. "jmeno=".$jmeno. "prijmeni=".$prijmeni);


Co se týče druhého dotazu, tak zase nevím, jestli vám rozumím správně, ale snad logicky do toho pravidla nepsat řetězec "clanky/".
3. 2. 2008 15:42:51
[10] (Jenda (uschovna(at)centrum.cz))
Re: Re: přesměrování s novými proměnnými odpovědět
[7] Díky za rychlou odpověď. Přesto bych se chtěl ještě zeptat, která část kódu z celkového výsledného řeší právě to přidání dalších proměnných do url. Moc s tím ještě neumím, a tak mi není jasné, jestli pro to přesměrování na url s více proměnnými potřebuji celý ten výsledný kód, který uvádíte na konci a nebo jestli stačí jen některá z jeho částí.

A druhý můj dotaz je, jak mám napsat ten první řádek (který máte hned po rewriteengine on), když současný skript nemám v samostatném adresáři (vy ho máte v adresáři clanky/), ale v rootu a jmenuje se vypis.php.

Moc moc díky, budu Vám vděčen za pomoc.
3. 2. 2008 17:05:13
[11] (Jenda (uschovna(at)centrum.cz))
Re: Re: Re: Re: přesměrování s novými proměnnými odpovědět
[8] U toho druhého dotazu mi šlo o to, že vy máte skript v adresáři clanky/, takže pravidlem stanovíte, že vše v tomto adresáři chcete přesměrovávat - tomu odpovídá tento zápis:
RewriteRule ^clanky/([0–9]+)-?(.*) /clanek.php?id=$1&t­itulek=$2&xxx=1 [R=301] - to je jasné a pochopitelné.


No a mě šlo o to, jak byste to pravidlo zapsal, pokud byste soubor neměl umístěn takto:
www.example.com/clanky/1234-titulek-clanku
ale takto:
www.example.com/1234-titulek-clanku

U toho prvního dotazu mi šlo o to, která ta část v tom výsledném zápisu .htaccess "komunikuje" s tím php skriptem - tj. jestli je to pouze první řádek

RewriteRule ^clanky/([0–9]+)-?(.*) /clanek.php?id=$1&t­itulek=$2&xxx=1 [R=301

nebo i ty následující.

Snad jsem to napsal srozumitelně :)

Ještě jednou díky za pomoc.

3. 2. 2008 17:28:42
[12] (Trupik (jakub.maly(at)atlas.cz)) www
Re: Re: Re: Re: Re: přesměrování s novými proměnnými odpovědět
[11]: Tak myslím, že už jsem na všechno předtím odpověděl a víc už asi pomoct nedokážu. Pokud něco není jasné, doporučuji si přečíst všechno znova případně se podívat do nějakého obsáhlejšího návodu.
19. 10. 2011 12:30:28
[13] (Simba (simba112(at)gmail.com))
parametr xxx=1 odpovědět
Chtěl bych se zeptat, příjde mi ale že pokud použiješ pro odstranění cyklení přepisování ten parametr xxx=1, tak pokud ti na něj někdo příjde, je stránka opět přístupná ze dvou adres z :

clanky/1234-nadpis

clanek.php?id=$1&t­itulek=$2&xxx=1

nebo ne?
25. 11. 2012 2:49:26
[14] (killy kat (killykat(at)yahoo.com)) www
longchamp handbags odpovědět
Great! Thanks for your documents, its been very helpful. Thanks again for sharing your information.