Mod_rewrite pro hezká URL – lomítka, adresáře, proměnné

19. srpna 2005

V naší exkurzi do hlubin mod_rewrite se již pomalu dostáváme od základů k řešení standardních situací. Tentokrát si ukážeme, jak vytvořit virtuální adresářovou strukturu webu a jak si pojistit adresářová Cool URIs proti omylným či zlomyslným uživatelům. Kromě toho si předvedeme jednoduchou metodu, jak dostat do PHP a jiných skriptovacích jazyků potřebné parametry pro správné generování stránky.

Automatické doplnění lomítek

Další z řady nekonečných problémů, které mohou hlavně při důkladné SEO kampani zamíchat kartami, jsou lomítka na konci URL. Jak už jsem psal v předchozím článku, je důležité zajistit jednotný tvar všech URL (používání variant s „www“ a bez) a tak i používání adres ukazujících na adresáře bez lomítka na konci může způsobit potíže.

Když generujeme Cool URIs dynamicky, není problém zajistit strojovou přesnost adres. Horší to ale je, když přijde pan člověk a nějaké to lomítko odmaže. Pak už je na nás zamezit šíření pirátské verze a důsledně podstrkávat lomítka.

RewriteEngine On
RewriteCond %{REQUEST_URI} !.[[:alnum:]]+$
RewriteRule ^(.+[^/])$ /$1/ [R=301]

Problém je v podstatě velice snadno řešitelný – za každé URL, které už lomítko neobsahuje, ale také není souborem (za soubory už lomítko nedáváme) jednu krásnou natočenou svislici přidáme.

Direktiva RewriteRule tedy přesměruje /cokoli na /cokoli/ (regulární výraz ale neodpovídá řetězci cokoli/!) a RewriteCond učiní tento příkaz platným, jen když adresa nemá příponu (tiše předpokládáme, že soubory nějakou koncovku mají).

Vytvoření adresářové struktury

Zatím jsme si uváděli pouze jednoduché příklady přesměrování, nyní si ukážeme, jak vytvořit umělou adresářovou strukturu webu, aneb zlatý klenot přepisování.

Proč se s takovou oblibou používají adresy typu http://www.example.com/zamestnanci/byvali/martin-bublan/? Je to hlavně kvůli vysoké přehlednosti, která je podpořena jednoznačným členěním webu do jakýchsi bloků – adresářů. Dalším důvodem je podstrčit vyhledávači URL s co největším množstvím důležitých hesel, a tím pádem si vylepšit v SEO. Spláchnou se tak dvě mouchy jednou ranou.

I návštěvníkům webu tento tvar vyhovuje. Lišácky odmazávají části adresy v očekávaní, že na nich vybafne seznam zaměstnanců firmy, popřípadě jen těch bývalých. Proto při tvorbě takovýchto adres nezapomínejte zajistit, aby byly funkční i jejich dílčí části. Běžní surfaři se tak na vašich stránkách budou tvářit chytře, protože „uhádli“ URL a v očích zkušenějších webtvůrců nebudete považováni za nováčky.

Při návrhu se musíme zamyslet nad tím, jak bude dynamický skript, řešící požadavek na konkrétní stránku, vědět, že chceme vidět zrovna osobní údaje „Martina Bublana“. Musíme si uvědomit, že skriptu můžeme předávat jako parametry jen části adresy, tudíž v tomto případě bychom mohli považovat za jednoznačný ukazatel na daný záznam v databázi řetězec bublan. Museli bychom ale při zjišťování odpovídajících dat odstranit nebezpečné znaky a diakritiku z příjmení v databázi.

Aby se programátoři vyhnuli v kódu různým konverzím předaných řetězců z adresy, je výhodnější použít v URL číselný údaj, se kterým není potřeba provádět žádné změny. Většinou jen někde jednoduše přidáme číselné ID, třeba takto: http://www.example.com/zamestnanci/byvali/6-martin-bublan/. Jak ale sami vidíte, adresa už není tak hezká a je také hůře zapamatovatelná. Uživatelé jsou však docela tolerantní, a když jde o dobrý web, vesele opisují i adresy s tunou zbytečných parametrů. Nicméně v dnešní elektronické době je už šíření webů na papírcích spíše výjimkou a tak přidání pár číslic do adresy většinou ani uživateli ani vyhledávači nepřitíží a vám ušetří pár řádek kódu.

Také je velmi důležité zajistit, aby naše smyšlená URL fungovala jak se zadaným, tak i nezadaným lomítkem na konci adresy. To už ale díky prvnímu příkladu tohoto článku víme.

RewriteEngine On
RewriteCond %{REQUEST_URI} !.[[:alnum:]]+$
RewriteRule ^(.+[^/])$ /$1/ [R=301]
RewriteRule ^([^/]+)/([^/]+)/([0-9]+)-[^/]+/?$ %{DOCUMENT_ROOT}/index.php?stranka=$1&oddeleni=$2&IDzamestnanec=$3 [L,QSA]

První dva řádky jsou vám jistě známy ze začátku tohoto článku, pojďme tedy dále. Uzávorkované výrazy ([^/]+) odpovídají neprázdným řetězcům, které neobsahují lomítko – tedy v našem případě znamenají jednotlivé řetězce mezi lomítky. Všimněte si dvou znaků /? na konci regulárního výrazu. Toto je právě ošetření adresy, aby fungovala jak se zadaným lomítkem na konci, tak i bez něj. Otazník znamená, že výraz před ním nemusí být zadán. V tomto případě je to ale zbytečné, protože díky předcházejícímu kroku budeme mít adresy končící lomítkem vždy. Další výraz ([0-9]+) znamená, že chceme jen číselné hodnoty – zjišťujeme konkrétní ID pracovníka.

A nyní si představme situaci, kterou jsem zmiňoval v úvodu. Uživatel bude postupně odmazávat různé části URL a bude čekat, že se mu místo stránky s chybou 404 (dokument nenalezen) zobrazí něco lepšího.

Řešení tkví, jak vám asi již došlo, v poněkud lepším regulárním výrazu. Pokud si ale netroufáte, můžete využít několika různých direktiv RewriteRule, přičemž každá bude reagovat na dílčí část adresy. Nicméně, proč dělat věci složitějšími…

RewriteEngine On
RewriteCond %{REQUEST_URI} !.[[:alnum:]]+$
RewriteRule ^(.+[^/])$ /$1/ [R]
RewriteRule ^([^/]+)/([^/]+)?/?([0-9]+)?(-[^/]+)?/?$ index.php?stranka=$1&oddeleni=$2&IDzamestnanec=$3&ctyrka=$4&a=%{REQUEST_URI} [L,QSA]

V podstatě je tento regulární výraz identický s předchozím, jen jsme doplnili otazníky za nepovinné části.

Direktiva RewriteRule je zapsána, vyzkoušena, ze škaredé URL máme hezkou Cool URI, ale obrázky nefungují, styly nenačteny, copak se děje? Snadná odpověď, veškeré relativně zadané cesty k dalším souborům by musely existovat i v námi vytvořeném pseudoadresáři.

Řešení není nikterak složité, stačí zadávat veškeré odkazy absolutně. Ovšem nemusíte psát celou adresu, tedy <a href="http://www.example.com/o-nas/firma.html">example</a>, stačí se nastavit do rootu (kořene webu) lomítkem na začátku: <a href="/o-nas/firma.html">example</a>.

Dalším řešením je použít trochu HTML, konkrétně element BASE.

Inicializace proměnných

Když jsme už u toho, neodpustím si menší vložku z PHP. Když máte zapnuté zobrazování chyb včetně typu „notice“ (error_reporting(E_ALL);), určitě vás nebaví dělat něco podobného, jako v příkladu (předem upozorňuji, že každý programátor tuto situaci řeší po svém, toto berte pouze jako možnou alternativu):

if (isSet($_GET[‚id‘]) && (validNumber($_GET[‚id‘]))
if (isSet($_GET[‚action‘]) && ($_GET[‚action‘]==’delete‘))

Psaním rozšířených RewriteRule se dá provést lehká inicializace proměnných a ušetřit nějaký ten isSet(), či případně další funkce:

RewriteRule ^/produkty/([0-9])+$ /produkty.php?id=$1&action= [L,QSA]

I když nám to samozřejmě nebude k ničemu platné, když k nám přijde uživatel se starým ošklivým URL…

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Štítky: Články

Mohlo by vás také zajímat

Nejnovější

3 komentářů

  1. Tomek

    Srp 6, 2009 v 17:33

    No nevím jak Vám, ale mně to tam teda lomítka nepodstrkává..

    Odpovědět
  2. Radek

    Srp 19, 2009 v 16:20

    Zalezi na konfiguraci serveru,

    tj. jestli tam nejsou uz pripraveny nejaky podminky, co ten prikaz ovlivni…

    kazdopadne ty lomitky by si zaslouzili predelat na:

    RewriteRule ^(.*[^/])$ /$1/ [R=301]

    presto, coz jen znamena, ze se ti lomitka doplni i za jedinnym znakem :)

    Odpovědět
  3. Mirek

    Říj 13, 2009 v 0:00

    Me to funguje jenom na podadresarich, tzn. treba na http://www.domena.cz/adresar/strana, ale nefunguje to na http://www.domena.cz/strana.

    Odpovědět

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *