PHP + mod_rewrite


Caps-Lock is FULL OF AWESOME!!1!
Attribution-NonCommercial-ShareAlike License by catcubed

Jeder WordPress Benutzer kennt die schönen Permalinks. Ein Link auf einen Artikel sieht meist nicht so aus

blogname/index.php?p=139

sondern so:

blogname/2010/04/07/Heute-ist-mal-wieder-was-tolles-passiert.

Die Technik dahinter ist recht simpel. Zum einen benötigt man das Apache2 Modul mod_rewrite und eine .htaccess Datei. Mod_rewrite leitet nach den Regeln, die man in der .htaccess Datei festlegt an eine Datei um. In diesem Fall eine PHP Datei, in der das $_SERVER Array ausgewertet wird.

Falls mod_rewrite im Apache deaktiviert ist, kann man das ganze recht simpel per Softlink einschalten:

schmiddi@dasgrauen:/etc/apache2$ cd /etc/apache2/
schmiddi@dasgrauen:/etc/apache2$ ls mods-available/ |grep rewrite
rewrite.load
schmiddi@dasgrauen:/etc/apache2$ ls mods-enabled/ |grep rewrite
schmiddi@dasgrauen:/etc/apache2/mods-enabled$ sudo ln -s ../mods-available/rewrite.load

Nun wird noch die Datei /etc/apache2/sites-enabled/000-default angepasst.

Ich habe lokal einen Apache Server, der nur der Programmiererei dient. Ich gehe hier nicht auf virtuelle Server oder sonst was ein.

Interessant sind nur die folgenden Zeilen:

DocumentRoot /var/www
<Directory />
Options FollowSymLinks
AllowOverride All
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>

Ich habe das AllowOverride einfach auf All gestellt und dann den Apache neu gestartet. Nun die .htaccess Datei anlegen und befüllen:

schmiddi@dasgrauen:/var/www$ touch .htaccess
touch: kann „.htaccess“ nicht berühren: Permission denied
schmiddi@dasgrauen:/var/www$ sudo !!
sudo touch .htaccess

Um auf die index.php im Serverroot umzuleiten braucht man die folgenden Zeilen:

# BEGIN WRoot

<IfModule mod_rewrite.c>

RewriteEngine On

RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule . /index.php [L]

</IfModule>

Bemerkenswert ist noch, das man innerhalb von IfModule kein Hash, Teppich, Schlängeli, Nummer (#) schreiben sollte, da dies Internal Errors produziert.
Nun kann man Adressen auf dem Server aufrufen, die es gar nicht gibt und wird entsprechend an die index.php weitergeleitet. Zu den htaccess Dateien wäre noch zu sagen, dass sich das ganze rekursiv auswirkt und Hierarchien möglich sind. Wenn in einem Unterordner eine weitere Datei mit Rewrite Anweisungen liegt und dieses Verzeichniss oder ein tieferes aufgerufen wird, gilt die oberste Htaccess Datei.

Nun kann man sich die Sache unter PHP anschauen. An die Requesturl kommen wir wie gesagt mit dem $_SERVER Array:

$request = $_SERVER['REQUEST_URI'];

Wie so oft bei PHP bekommt man Probleme, wenn Sonderzeichen ins Spiel kommen:

Die Url:

http://localhost/Frühling/läßt/sein/blaues/Band

verwandelt sich in:

/Fr%C3%BChling/l%C3%A4%C3%9Ft/sein/blaues/Band

Um auswertbare Zeichenketten zu bekommen,  muß die Url dekodiert werden und der String nach UTF-8 gewandelt werden:

echo utf8_decode(urldecode($request));

Nun wird noch ein Array daraus gebastelt um die Urls bequem verarbeiten zu können:

function get_url(){
	$request = $_SERVER['REQUEST_URI'];
	$crumbs = explode('/' , utf8_decode(urldecode($request)));
	$retval=array();
	foreach ($crumbs as $crumb){
		if ( trim($crumb) !='')
			array_push($retval, $crumb);

	}//each
	return $retval;
}//function

Seehr schön. Um nun sinnvoll mit Permalinks zu arbeiten, muß man sich noch Gedanken über das Erstellen und Auswerten machen. Zuerst sollte man sich Gedanken über den Aufbau machen. Hier schauts so aus:

Jahr/Monat/Tag/Titel

Das erzeugen der Adresse erledigt die Funktion generate_url mit den Argumenten Titel und gewünschtem Format:

function generate_url($title, $format){
	$d= getdate();
	$year = $d["year"];
	$month = $d['month'];
	$day = $d['mday'];
	$msg = $format;

	$msg = str_replace ('%y', $year.'/', $msg);
	$msg = str_replace ('%m', $month.'/', $msg);
	$msg = str_replace ('%d', $day.'/', $msg);
	$msg = str_replace ('%t', $title.'/', $msg);

	return "http://" . $_SERVER['SERVER_NAME']."//$msg";
}//function

Nicht sehr elegant ist der 4fache Aufruf von str_replace. Ich habe auf die Schnelle nicht herausbekommen, wie ich das eleganter hinbekomme. Über sachdienliche Hinweise zur Aufklärung würde ich mich sehr freuen

Nun kann man das ganze mal ausprobieren:

//test generate_url
$format_string='%y%m%d%t';

$url= generate_url("PHP + mod_rewrite", $format_string);
echo "$url";

Der nächste Schritt ist nun die Auswertung. Dafür werden wir wieder den Formatstring benutzen, da er uns beschreibt, was wie aus der Persistenzschicht rausgeschaufelt werden muß. Wenn z.b nur 2010 angegeben ist, bekommt man jegliche Inhalte aus diesem Jahr, bei April den Inhalt aus Jahr und Monat, wenn der Artikel angegben ist, nur der Artikel:

function get_the_content($url_array, $format) {
	$n = count ($url_array);

	/*den Formatstring in ein Array wandeln, null values entfernen
	und den Index neu aufbauen :)*/

	$f_arr = explode('%', $format);
	$empty_element = array_keys($f_arr, "");

	foreach ($empty_element as $e)
		unset ($f_arr[$e]);
	$f_arr = array_values($f_arr);

	//titel in url vorhanden?
	$t_pos =  array_search('t', $f_arr);
	if ( $url_array[$t_pos] !="")
		return  "Select Artikel: ". $url_array[$t_pos];

	//Datum Basteln
	$year = $month = $day = 0;
 	$year = $url_array[array_search('y', $f_arr)];
	$month = $url_array[array_search('m', $f_arr)];
	$day = $url_array[ array_search('d', $f_arr)];
	//Monatsname nach Zahl
	$month_number = "";
	for($i=1;$i<=12;$i++){
		if(date("F", mktime(0, 0, 0, $i, 1, 0)) == $month){
			$month_number = $i;
			break;
		}
	}//for

	if ($month_number=="")
		return "nichts gefunden";
	//Unixtimestamp erzeugen
	$d = date('c', mktime(0, 0, 0, $month_number, $day, $year));
	return "SELECT Artikel in Datumsbereich $d";
}//function

Exemplarisch habe ich einfach mal einen Unixtimestamp erzeugt und zurückgegeben. Wenn jemand das ernsthaft verwenden will, sollte er sich ein paar Gedanken über Oo machen und manches schöner schreiben.

Advertisements
Dieser Beitrag wurde unter Allgemein, php, programmieren, webkrams abgelegt und mit , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s