URL Rewriting (Webdevelopment)

URL Rewriting houdt het herschrijven (to rewrite) van de URL's van een website in. Url rewriting zie je voornamelijk terug op blogs, nieuwssites en ook in dit woordenboek. Er kunnen verschillende redenen zijn om URL rewriting toe te passen.


Het doel van URL Rewrite


Tot 2005 konden spiders niet overweg met dynamische urls en dus bood URL rewriting een uitkomst om webpagina's beter indexeerbaar te maken. De URL's die hieruit voort kwamen, worden zoekmachine vriendelijke URL's genoemd. Door de titel van een pagina ofwel nieuwsbericht terug te laten komen in de URL, kun je meer belang geven aan de betreffende woorden. Het is dan ook van belang dat je juiste titels toekent aan pagina's.

Sinds 2005 kunnen de grotere zoekmachines, waaronder Google, ook dynamische webpagina's indexeren die op te roepen zijn door middel van een query string. Indien deze echter te complex worden, zullen spiders hier meer moeite mee krijgen.

Behalve dat de urls zoekmachine vriendelijker worden, ogen ze natuurlijk ook beter.
Bij dynamische content, opgeroepen met behulp van een query string, is dit in mindere mate het geval:
www.domein.com/index.php?pagina=autos&merkid=3&autoid=381
Door URL rewriting toe te passen, kun je naast de nodige identificatienummers door te geven, ook eenvoudig namen of titels in de URL verwerken:
www.domein.com/autos/3/opel/381/vectra_gts.html

Indien dit soort URL's terug komen in de zoekresultaten, kan men direct overzien of ze op een pagina binnen zouden komen die overeenkomt met waar ze naar zoeken, de inhoud is namelijk voorspelbaar (want het zal hoogstwaarschijnlijk over een Opel Vectra GTS gaan, waarbij het daadwerkelijk om een auto gaat). De URL bevat daarnaast geen query's of rare leestekens, het is leesbaarder en begrijpelijker voor je bezoeker, waardoor men een betere indruk kan krijgen van de opbouw en misschien zelfs omvang van een website.


Het idee achter URL Rewrite


Bij het toepassen van URL Rewrite, creeer je paden of mappen die niet daadwerkelijk aanwezig zijn op de server, zogenaamde virtuele paden. De inhoud van een pagina wordt in deze gevallen namelijk uit een database gehaald aan de hand van de informatie die in de URL verwerkt zit. Zowel in het geval van het voorbeeld met de query string, als de zogenaamde nette URL, zal er het volgende gebeuren:
  1. Er wordt gecontroleerd of de paginanaam bestaat, in dit geval autos.
  2. Het merkid en autoid worden uit de URL gefilterd (respectievelijk 3 en 381)
  3. Gecontroleerd wordt of het merkid voorkomt in de database, zo ja, dan kan de merknaam opgehaald worden, in het ander geval kan er een passende melding worden getoond dat het merk niet bestaat, denk aan een aangepaste 404-pagina.
  4. Als het merk bestaat, haal je aan de hand van het autoid de autodetails uit de database om deze weer te kunnen geven, afhandeling (bijvoorbeeld als het autoid niet voor komt), kan op eenzelfde manier als in het geval van het ophalen van het merk


Met andere woorden, er is geen bestand genaamd vectra_gts.html aanwezig op de server. Dit kan in de URL worden geplaatst om het geheel leesbaarder voor bezoekers en spiders te maken.


De achterliggende techniek: PHP en Mod Rewrite / .htaccess


Er zijn verschillende manieren om nette URL's in handen te krijgen. In elk geval zal er een serverside taal aan te pas moeten komen, zoals PHP of ASP. Voor ondersteuning van URL rewriting heb je een rewrite engine nodig, een bekend voorbeeld is de mod rewrite-module van Apache.

De rewrite engine moet dus ingeschakeld zijn. Vaak is dit niet standaard het geval, je kunt dit op Apache dan alsnog doen middels een .htaccess bestand door hierin de volgende code op te nemen:
RewriteEngine On
De plaats waar je dit bestand op de server moet plaatsen, is afhankelijk van het deel van de website waarop je URL Rewrite toe wilt passen. Vaak wordt dit bestand geplaatst in de root van de server.

Uiteindelijk zijn er ook verschillende manieren om de verwerking van de URL's op te zetten. Kortom, er zijn vele combinaties mogelijk om dit concept op te zetten. Twee mogelijke uitwerkingen zullen hier worden weergegeven.

Met behulp van PHP kun je uiteindelijk de url ophalen en hier gegevens uithalen zoals in een eerdere voorbeeld is gedemonstreerd. In het .htaccess-bestand zul je reguliere expressies op moeten nemen, afhankelijk van de manier waarop je URL rewriting toe wilt passen. Dit kunnen erg complexe expressies tot eenvoudigere expressies zijn.


Url Rewriting voor bestaande websites


Indien je URL Rewriting toe wilt passen op een bestaande website, maar de al aanwezige software (bijvoorbeeld een CMS) hierop niet aan wilt passen, sta je minder flexibel tegenover het herschrijven van URL's. Wel geldt dat des te consequenter een eventueel CMS gegevens uit de database haalt, des te eenvoudiger het is om hiervoor nette url's te maken.

Stel dat je pagina's met querystrings hebt welke consequent zijn opgebouwd, zoals
domein.nl?pagina=paginanaam of
domein.nl?pagina=paginanaam&id=idnummer,
dan kun je enkele algemene expressies maken om te zorgen dat de parameters alsnog juist aankomen. Paginanaam zou bijvoorbeeld contact of vacatures kunnen zijn, in het laatste geval zul je een overzicht van vacatures krijgen waarbij je door kunt klikken naar een vacature voor meer details. Hiervoor zal een uniek identificatiecode meegestuurd moeten worden, om de juiste gegevens uit de database te halen, vaak zal dit in de database opgeslagen zijn in een kolom ofwel attribuut genaamd id. Deze kun je in de url meegeven, idnummer zal in dat geval het betreffende getal zijn.

Indien andere pagina's ook zo zijn opgebouwd (bijvoorbeeld een portfolio-pagina of een agenda, waarbij details voor een portfolioitem of een dag opgeroepen kan worden aan de hand van een id), kun je voor deze toepassingen een enkele expressie maken, die de url uiteindelijk herschrijft.

De algemene URL die je in de adresbalk wilt hebben is:
1. domein.nl/paginanaam
of indien er sprake is van een meegestuurde id:
2. domein.nl/paginanaam/23
Algemeen ziet het er dan zo uit:
1. domein.nl/(a-z+)
of
2. domein.nl/(a-z+)/(0-9+)

De delen tussen ronde haken moeten uit de url gefilterd worden om door te kunnen geven aan de url's waarnaar herschreven moet worden. Voor het eerste deel geldt dat er enkel alfabetische karakters in voor mogen komen, voor het tweede gedeelte, het id, mogen alleen getallen voor komen. De plus geeft aan dat het deel uit minstens 1 karakter moet bestaan.
Uiteraard kun je ook underscores, koppeltekens of andere karakters toestaan, hiervoor zul je de reguliere expressie iets uit moeten breiden. Je kunt ook een algemeen teken (meta-karakter) gebruiken die alles er uit filtert, namelijk de punt:
domein.nl/(.+)/(.+)

Daarna moeten de opgevangen waarden (de waarden tussen haken) door worden gegeven aan de url waarnaar achter de schermen herschreven moet worden. Deze waarden zijn nu variabelen geworden, welke we op kunnen vangen met de variabele-karakter in .htaccess, te weten $, en om de hoeveelste variabele het gaat. Met $1 vangen we bijvoorbeeld de paginanaam op:
index.php?pagina=$1&id=$2

De gehele .htaccess-bestand zou er op dit moment als volgt uit zien:
RewriteEngine On
RewriteRule ^(.+) index.php?pagina=$1 [L]
RewriteRule ^(.+)/(.+) index.php?pagina=$1&id=$2 [L]

Of, indien je de indruk wilt wekken dat het om html-bestanden gaat:
RewriteEngine On
RewriteRule ^(.+).html index.php?pagina=$1 [L]
RewriteRule ^(.+)/(.+).html index.php?pagina=$1&id=$2 [L]

Omdat er twee verschillende situaties zijn (query string met en zonder een id), zul je ook twee verschillende reguliere expressies op moeten nemen.
Voor de punt staat in dit geval een backslash, een punt is namelijk een zogenaamde meta-karakter als het om reguliere expressies gaat, deze hebben een speciale betekenis. Om te zorgen dat de punt dus daadwerkelijk als een aanwezige punt wordt gezien, zul je hem moeten backslashen.
De L geeft aan dat als de url overeenkomt met de reguliere expressie, de betreffende rewrite-regel de laatste moet zijn die uitgevoerd wordt. Dit zorgt ervoor dat de tweede regel niet meer wordt uitgevoerd indien de url al overeen kwam met de voorgaande expressie.

Indien je nu domein.nl/contact.html invoert in de adresbalk van je browser, zul je de contactpagina zien, mits de contactpagina ook op te roepen is via domein.nl/index.php?pagina=contact. Het principe is dus hetzelfde, met behulp van de mod rewrite module van Apache kun je URL rewriting ongezien toepassen en kun je met dezelfde parameters in PHP blijven werken. Deze parameters worden in de GET-methode verstuurd. Ze worden in een array geplaatst, die je als volgt kan tonen op het scherm:
<?php
print_r( $_GET );
?>
Het resultaat zal zijn:
Array
(
[pagina] => 'contact'
);
Of, indien er een id is meegestuurd in de url:
Array
(
[pagina] => 'vacatures',
[id] => 23
);

Een bijkomend voordeel is dat, indien men externe koppelingen vanaf hun site hebben opgenomen die verwijzen naar jouw site, de pagina nog gewoon opgeroepen kan worden.


Om te zorgen dat de url's met query strings niet meer worden gebruikt, kun je op eenzelfde manier reguliere expressies opzetten voor redirects. Hieraan zul je een 301 statuscode moeten koppelen om te zorgen dat bijvoorbeeld spiders geen dubbele content gaan zien (door /contact.html en ?pagina=contact heb je namelijk twee pagina's met dezelfde inhoud), maar dat ze weten dat de pagina permanent verplaatst is:
RewriteRule index.php?pagina=(a-z0-9+)&id=(0-9+) /$1/$2 [R=301, L]
Htaccess:
RewriteEngine On

RewriteRule ^(.+) index.php?pagina=$1 [L]
RewriteRule ^(.+)/(.+) index.php?pagina=$1&id=$2 [L]

RewriteRule ?pagina=(a-z0-9+)$ /$1 [R=301, L]
RewriteRule ?pagina=(a-z0-9+)&id=(0-9+)$ /$1/$2 [R=301, L]

Het dollar-teken in de reguliere expressie is, net als een punt en het plus-teken, ook een meta-karakter. Deze geeft aan dat het het einde van de expressie is.

Wanneer je interne links hebt geplaatst binnen je eigen website, kun je alle links handmatig bij langs of je kunt met behulp van de php-functie preg_replace op dezelfde manier een reguliere expressie maken zodat url's met query strings om worden gezet naar nette url's.

Wanneer je website pagina's heeft die onregelmatige query strings bevatten, kun je op eenzelfde wijze meerdere reguliere expressies maken en opnemen in het .htaccess-bestand.


URL Rewriting in combinatie met OO


Indien je een nieuwe website of webshop ontwerpt, kun je achter de schermen flexibeler te werk gaan en kun je voor het .htaccess-bestand genoegen nemen met een enkele reguliere expressie:
RewriteRule ^(.*) index.php [L]
In deze situatie zal alles (.*) dat achter het domeinnaam komt, worden genegeerd. Je kunt deze waarde opvangen en als variabele doorgeven aan bijvoorbeeld index.php. Alles wordt volgens bovenstaande regel namelijk herschreven naar index.php.

Dit woordenboek werkt ook volgens deze URL rewrite principe. Omdat de url uiteindelijk op te vragen is met behulp van server-variabelen, wordt de variabele niet doorgegeven als parameter aan index.php maar wordt de letterlijke url achterhaald aan de hand van waarden van de server variabelen.

Door je website modulair ofwel object georienteerd (OOP) op te bouwen, kun je een zogenaamde Model View Controller (MVC) pattern creeren. Dit kan, in combinatie met URL rewriting, als volgt worden uitgewerkt:
jeroen.com/woordenboek/thema
Het woordenboek zelf staat in de map woordenboek. De controller in dit CMS pakt vervolgens de volgende deel uit de url, in dit geval thema. Van de class thema wordt een object gemaakt. Indien er nog een pad aanwezig is, zoals
jeroen.com/woordenboek/thema/google
zal er binnen het object van thema een functie worden uitgevoerd die overeenkomende gegevens ophaalt uit de database ofwel model voor het woord google.

In het geval van de class woorden, zijn er verschillende functies die aangeroepen kunnen worden, bijvoorbeeld:
jeroen.com/woordenboek/woorden/nieuw
Nadat er een object van de class Woorden is aangemaakt, zal de lid-functie nieuw aangeroepen moeten worden, die er voor zorgt dat alle woorden uit de database worden gehaald, op volgorde van nieuwste naar oudste.

Omdat elk deel in de url zijn eigen betekenis heeft, wil je de woorden afzonderlijk van elkaar in handen krijgen. Dit kan in PHP door gebruik te maken van een server variabele en deze te ontleden op de slash die in de url voorkomt. Simpelweg vertaalt in PHP
<?php
$parts = implode('/', $_SERVER['REQUEST_URI']);
print_r($parts);
?>
De array zal dan de volgende elementen bevatten:
Array
(
[0] => 'woordenboek',
[1] => 'woorden',
[2] => 'nieuw'
);
Het eerste element (0) kan genegeerd worden in het geval van dit woordenboek. Dit staat namelijk voor de map waarin het woordenboek draait. Het tweede element staat voor de class en het derde element voor de functie die binnen de class opgeroepen moet worden.
In dit woordenboek is er overigens een uitzondering gemaakt voor de woorden zelf.

RewriteRule en RewriteCond


Bij zo een totale rewrite dient er rekening gehouden te worden met mappen en bestanden die wel bestaan. Paden of verwijzingen naar een stylesheet of afbeeldingen-map, zullen ook herschreven worden. Dit kan op verschillende manieren voorkomen worden. Een eerste is door in de reguliere expressie op te nemen welke overeenkomende delen juist genegeerd moeten worden. Dit kan met behulp van de meta-karakter (!), de uitroepteken. Dit karakter wordt ook in script-, programmeer- en querytalen gebruikt en kan gelezen worden als het Engelse woord not.
Voor dit woordenboek geldt dat alles herschreven moet worden, behalve de map naar afbeeldingen en de stylesheet en javascript bestand. Dit is als volgt gedaan:
RewriteEngine On
RewriteRule !^((style.css|javascript.js)|(img)(/.*)?)$ index.php [L]

Je kunt ook condities gebruiken, wat misschien leesbaarder is, maar wel meer regels omvat:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/(style.css|javascript.js)$ [NC]
RewriteCond %{REQUEST_URI} !^/(img)(/.*)?$ [NC]
RewriteRule .+ /index.php [L]
In dit geval wordt de rewrite regel alleen uitgevoerd, als er in de opgevraagde uri (REQUEST_URI) geen (let op de uitroepteken) van de volgende bestanden of mappen voorkomen. Op deze manier kun je dus eenvoudig uit te zonderen paden van herschrijving uitsluiten.

Een andere oplossing is een conditie maken die controleert of een url overeenkomt met een bestaande pad of bestand. Als dit niet het geval is, kun je de rewrite regel uit laten voeren.
Een voordeel van de eerdere oplossing is dat je bestanden op de server kunt zetten (zoals database-gegevens of templates) die niet opgevraagd kunnen worden van buitenaf, maar wel door je CMS. Hiermee kan voorkomen worden dat bestanden die nodig zijn voor de werking van het CMS, zoals bijvoorbeeld de classes voor het MVC pattern, niet via het bestand zelf opvraagbaar zijn.

Gerelateerde woorden

Meer over URL Rewriting (externe links)

Thema & categorieën