Über mich

Startseite arrow Tipps & Tricks arrow PHP und .htaccess: Aus statisch, mach dynamisch

PHP und .htaccess: Aus statisch, mach dynamisch

Donnerstag, 18. Juni 2009
Geschrieben von Armin Vieweg
Mit zwei kleinen Dateien auf dem Webspace kann man aus einer Website die z.B. auf statischen HTML-Dateien basiert, die Dynamik und Flexibilität von PHP rausholen. Hier erfahrt Ihr wie.

Zwei Dateien. Eine PHP- und eine htaccess-Datei. Mehr ist nicht nötig um die Funktionalität einer Website zu erhöhen und dadurch mehr Flexibilität und Dynamik in die Seite zu bringen.



Das Grundprinzip
Jede ASCII-Datei (also z.B. PHP, HTML, XML, etc.) auf dem Webspace wird bevor sie an den Browser des Besuchers geschickt wird vorher durch einen zentralen Kanal geschickt, in dem wir die Datei nach Belieben ändern können.


Die Vorteile
Durch diesen Tunnel ist es praktisch egal, wie die Website vorher aufgebaut war, wir können sie an einer Stelle mit immer dem gleichen PHP-Quellcode bearbeiten. Das spart Zeit und schafft neue Möglichkeiten.


Zur Praxis
Als erstes brauchen wir eine .htaccess Datei in der steht, dass alle Anfragen in eine bestimmte PHP-Datei geleitet werden. Das sieht dann z.B. so aus.

.htaccess Datei:

RewriteEngine On
RewriteRule (.*\.htm) tunnel.php



Die .htaccess Datei und die tunnel.php müssen bei diesem Beispiel im Document-Root-Verzeichnis der Internetseite liegen. Diese Regel besagt nun, dass jede Datei, die mit .htm endet auf die tunnel.php Datei weitergeleitet wird.

Wir erhalten dann erst mal eine weiße Seite, da in der tunnel.php ja noch nichts steht und diese leer ist.


tunnel.php Datei:

<?php
  ob_start();
      if(substr($_SERVER[REQUEST_URI],-1) == "/") { $_SERVER[REQUEST_URI] = "/index.htm"; }
      include_once($_SERVER[DOCUMENT_ROOT] . preg_replace("/(.*?)\?.*/i", "", $_SERVER[REQUEST_URI]));
      $inhalte = ob_get_contents();
  ob_end_clean();

  //...

  echo $inhalte;
?>



So sieht das Herz unseres neuen Features aus. Im Wesentlichen wird hier die eigentlich aufgerufene Datei includiert (also eingebunden). Anstatt die eingebundene Datei jedoch direkt auszugeben, was der Webserver bei einem normalen Aufruf machen würde, leeren wir den PHP-Ausgabepuffer und schreiben dessen Inhalt in eine Variable. In diesem Beispiel die Variable $inhalte.

Erst bei dem letzten Befehl "echo $inhalte;" geben wir dann die vorher gespeicherten Inhalte aus. Das bedeutet, dass wir zwischen Pufferung und Ausgabe alles mit dem Quellcode machen können, was wir wollen.

Wir sind hier in PHP, wie können also, da ja noch keine Ausgabe gemacht wurde, auch noch den HTTP-Header ändern oder andere PHP-Dateien includieren, die weitere Funktionen aufrufen.



Praktisches Anwendungsgebiet
Ich habe diese Lösung entwickelt und verwendet als ich für eine statische Website ein "Mini"-CMS geschrieben habe. Man kann sich anmelden und erhält dann eine Sitzungs-ID. Ist die ID gültig wird die Website mit zusätzlichen Funktionen angezeigt um deren Inhalte ändern zu können.

Und die Basis für das komplette CMS sind die beiden oben erläuterten Dateien. Recht einfach, was? :)


Kurze Anmerkung zur tunnel.php
Eine Sache in der Datei will ich noch kurz erklären.

if(substr($_SERVER[REQUEST_URI],-1) == "/") { $_SERVER[REQUEST_URI] = "/index.htm"; }



Basis des Include ist die REQUEST_URI - also das was im Browser hinter der Domain steht. Gibt man aber nur die Domain ein ist der REQUEST_URI nur ein Slash (/). Ein Include in PHP benötigt aber eine gültig und physisch vorhandene Datei, das wäre also das "Directory-File", meist index.htm, index.html oder index.php. Nur Slash (/) ist also keine vorhandene Datei, daher die IF-Abfrage die aus einem / ein /index.htm macht.



Fazit
Ich hatte schon in zwei vollkommen unterschiedlichen Anwendungen verwendung für diesen Trick, weshalb ich ihn nun auch veröffentliche. Der Artikel ist keine Komplett-Lösung, aber eine Anregung.

Es gibt natürlich noch einfachere Möglichkeiten in einer HTML-Datei PHP-Code ausführbar zu machen, jedoch ist dies hier etwas komplexer und bietet noch mehr Möglichkeiten, als reiner PHP-Code.

Natürlich muss auf dem Webserver PHP und htaccess vorhanden und aktiviert sein. Dies ist aber schon bei günstigen Angeboten meist der Fall.

Für Fragen oder Anregungen stehe ich Euch wie immer in den Kommentaren oder per Mail gerne zur Verfügung.


  Kommentare (4)
 1 Geschrieben von: Christoph, am 14.08.2009 um 11:19
Bist du dir sicher, dass der Code oben ausreichend gegen das Ausspähen von höheren gelegenen Verzeichnissen geschützt ist?  
Dein Script enthält keine Eingabevalidierung, was es Angreifern ermöglichen würde, so ziemlich jede Datei zu includen, die im Dateisystem lesbar ist.  
Eine fehlerhafte rewrite Regel könnte zu dem dafür sorgen, dass die tunnel.php sich u.U. immer wieder selbst included, wenn man diese direkt abruft. Auch sollte man sich nicht darauf verlassen, dass das includen von remote Dateien unmöglich ist. 
Eingabevalidierung ist das A und O. Mir wurde vor einiger Zeit empfohlen, per vorher erstellter Whitelist zu überprüfen, welche Dateinamen/Pfade für Dateien als Eingabe akzeptiert werden und welche nicht.  
Sofern man sich vorher nicht eingehend mit Zeichenkodierungen und anderen Themen der PHP Sicherheit beschäftigt hat, sollte man lieber auf Nummer sicher gehen
 2 Geschrieben von: Armin Vieweg, am 14.08.2009 um 11:55
Hi Christoph, 
vielen Dank für Deine Einwände. Ich finde es gut, dass Du Dich mit den sicherheitstechnischen Aspekten befasst. 
 
Also außerhalb der des DOCUMENT_ROOT kann man - würde ich sagen - nicht zugreifen, da das Root ja im Include-Befehl vorgegeben ist. Sprich egal welche Datei man versucht aufzurufen, es wird immer der DOCUMENT_ROOT vorangestellt. Daher würde ich auch Remote-Dateien ausschließen. 
 
Das man die engine.php im Script ausschließt ist eine gute Idee! Und ich gebe Dir recht, dass eine Whitelist maximale Sicherheit bietet. 
 
Aber irgendwie glaube ich doch (ohne absolute PHP-Security-Professional) zu sein, dass diese Lösung schon sehr wenig Angriffsfläche bietet. 
 
Korrigiere mich, wenn ich mich irre! 
 
Gruß 
Armin
 3 Geschrieben von: Christoph, am 14.08.2009 um 15:04
Hi Armin, 
 
entschuldige bitte, bei den Remote Dateien habe ich das vorangestellte Document_Root wohl überlesen. 
Das Problem mit dem Verzeichniswechsel ist, dass man mit '..' in das übergeordnete Verzeichnis wechseln kann. Dies funktioniert auch innerhalb von Pfaden und nicht nur am Anfang. Das würde damit das vorangegangene Document_Root unwirksam machen. 
 
Bsp.: http://host/foo/../../../../etc/passwd
 4 Geschrieben von: Armin Vieweg, am 14.08.2009 um 17:35
Hi Christoph, 
 
danke für den Hinweis! Da war ich mir nicht sicher ob man tatsächlich ../ mitten im Link nutzen kann. Gut zu wissen! 
 
Gruß 
Armin
Letzte Aktualisierung ( Samstag, 20. Juni 2009 )
 
< Zurück   Weiter >