Um die Erkennung von doppeltem Content für die Suchmaschinen auszuschließen und um das ganze Webprojekt schön sauber zu halten, sollte man grundsätzlich auf Großschreibung in URLs verzichten. Da es auch passieren könnte, dass Links auf anderen Seiten mit falscher Groß-/Kleinschreibung hinterlegt sind, die trotzdem zum Ziel führen wenn das CMS oder das eigene PHP-Projekt nicht Case-sensitiv arbeitet. Dies ist auch bei Word Press der Fall und betrifft somit sehr viele Seiten.
Lösung mittels Apache
Die erste Idee war es, den Apache per Rewrite-Regeln in der htaccess-Datei dazu zu bewegen alle URLs automatisch klein zu schreiben. Das Problem ist, dass man den Apache anscheinend nur vernünftig dafür nutzen kann, wenn man Zugriff auf die Config-Dateien des Apaches hat, da man hier mit einer Rewrite Map arbeiten muss. Es gibt zwar auch einige Beiträge, in denen die Rewrite Map in der htaccess-Datei aktiviert wird, aber da ich dies damals bei Strato erfolglos ausprobiert hatte und mich damit dann nicht weiter beschäftigt habe, komme ich zu dem Schluss, dass diese Möglichkeit bei einem Shared Hosting meistens eher rausfällt.
Es gibt noch eine weitere Möglichkeit die htaccess-Datei für das Umschreiben der URLs zu nutzen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# Skip this entire section if no uppercase letters in requested URL RewriteRule ![A-Z] - [S=28] # Replace single occurance of CAP with cap, then process next Rule. RewriteRule ^([^A]*)A(.*)$ $1a$2 RewriteRule ^([^B]*)B(.*)$ $1b$2 RewriteRule ^([^C]*)C(.*)$ $1c$2 RewriteRule ^([^D]*)D(.*)$ $1d$2 RewriteRule ^([^E]*)E(.*)$ $1e$2 RewriteRule ^([^F]*)F(.*)$ $1f$2 RewriteRule ^([^G]*)G(.*)$ $1g$2 RewriteRule ^([^H]*)H(.*)$ $1h$2 RewriteRule ^([^I]*)I(.*)$ $1i$2 RewriteRule ^([^J]*)J(.*)$ $1j$2 RewriteRule ^([^K]*)K(.*)$ $1k$2 RewriteRule ^([^L]*)L(.*)$ $1l$2 RewriteRule ^([^M]*)M(.*)$ $1m$2 RewriteRule ^([^N]*)N(.*)$ $1n$2 RewriteRule ^([^O]*)O(.*)$ $1o$2 RewriteRule ^([^P]*)P(.*)$ $1p$2 RewriteRule ^([^Q]*)Q(.*)$ $1q$2 RewriteRule ^([^R]*)R(.*)$ $1r$2 RewriteRule ^([^S]*)S(.*)$ $1s$2 RewriteRule ^([^T]*)T(.*)$ $1t$2 RewriteRule ^([^U]*)U(.*)$ $1u$2 RewriteRule ^([^V]*)V(.*)$ $1v$2 RewriteRule ^([^W]*)W(.*)$ $1w$2 RewriteRule ^([^X]*)X(.*)$ $1x$2 RewriteRule ^([^Y]*)Y(.*)$ $1y$2 RewriteRule ^([^Z]*)Z(.*)$ $1z$2 # If there are any uppercase letters, restart at very first RewriteRule in file. RewriteRule [A-Z] - [N] RewriteCond %{ENV:HASCAPS} TRUE RewriteRule ^/?(.*) /$1 [R=301,L] |
Die Beschreibung dieser und auch der Rewrite Map-Methode gibt es hier. Der Apache ist mit dieser Methode allerdings zu stark ausgelastet und der Seitenaufruf wird unnötig in die Länge gezogen. Durch die Tatsache, dass die gleiche URL unter Umständen sehr oft durch Rewrite-Regeln läuft entsteht sehr viel Overhead.
Lösung mittels Skript
Da das ganze sowieso eher weniger an den eingesetzten Server-Typ gebunden sein sollte, macht die folgende Realisierung mittels eines Skripts in der Sprache in der die Seite betrieben wird meiner Meinung nach sowieso mehr Sinn. In diesem Fall mit PHP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php if(isset($_GET['rewrite-urltolower-url'])) { // get URL to rewrite and remove it from $_GET-params $url = $_GET['rewrite-urltolower-url']; unset($_GET['rewrite-urltolower-url']); // load remaining $_GET-params into an array $params = http_build_query($_GET); // build params-string if needed if(strlen($params)) { $params = '?' . $params; } // relocate header('Location: https://' . $_SERVER['HTTP_HOST'] . '/' . strtolower($url) . $params, true, 301); } else { header("HTTP/1.1 404 Not Found"); die('Unable to convert the URL to lowercase. You must supply a URL to work upon.'); } exit(); |
Der Else-Zweig kommt eigentlich nicht zum Einsatz, da eine als Parameter übergebene URL in jedem Fall umgeschrieben wird und danach vom eigentlichen PHP-Projekt verarbeitet wird. Die Fehlerausgabe erfolgt nur, wenn das Skript ohne Parameter aufgerufen wird. Das Skript stammt aus diesem Blogbeitrag.
Wenn das Webprojekt schon komplett auf SSL umgestellt ist, muss man die Rewrite-Anweisung entsprechend abändern auf https:
1 |
header('Location: https://' . $_SERVER['HTTP_HOST'] . '/' . strtolower($url) . $params, true, 301); |
Dadurch wird einer unnötigen weiteren Umleitung durch die Rewrite-Regel auf die https-Adresse vorgegriffen.
Nötige htaccess-Anpassung
In der htaccess-Datei benötigt man dann eine Regel die ungefähr wie folgt aussieht:
1 2 3 4 5 6 |
# force rewrite of url to lowercase if upper case letters are found: RewriteCond %{REQUEST_URI} [A-Z] RewriteCond %{REQUEST_FILENAME} !-f # exclude sites from this rule: RewriteCond %{REQUEST_URI} !^/(membership)(/.*)? RewriteRule (.*) lowercase.php?rewrite-urltolower-url=$1 [QSA,L] |
Die Regel sorgt dafür, dass alle URLs mit großen Buchstaben in der URL, die nicht innerhalb eines Mitgliederbereiches liegen und nicht auf eine auf dem Server liegende Datei verweisen, an das lowercase.php-Skript umgeleitet werden. Hierbei darf man keinesfalls eine 301-Umleitung verwenden! Die ursprüngliche URL wird als der Parameter rewrite-urltolower-url an das PHP-Skript weitergegeben. Durch den Zusatz QSA werden auch URL-Parameter mit übergeben.
Ausblick
Alternativ kann man wohl auch das Canonical-Tag nutzen, welches eine Original-URL im html-Header angibt, wodurch die Suchmaschine weiß, dass die Seite nicht als doppelter Content zu werten ist.
Da man PHP auch zur Abwicklung der 301-Rewrites nutzen kann, könnte es eventuell sinnvoll sein, wenn man sehr viele Rewrite-Regeln hat, diese grundsätzlich über PHP und nicht über die htaccess-Datei abzuwickeln. Die Abwicklung über PHP könnte schneller sein, als über den Apache selber. Bisher konnte ich aber bei rund 100 Rewrite-Regeln in der htaccess-Datei keine Performance-Probleme feststellen.
Wenn das Webprojekt allerdings nicht zu sehr an einen Server, z. B. Apache oder IIS, gebunden sein soll, macht es auch Sinn die 301-Regeln über PHP abzuwickeln um die Seite möglichst plattformunabhängig zu halten.