Marc Reichelt: Schönere URLs mit mod_rewrite des Apache

Hallo an alle,

ich möchte für ein Projekt von mir nun mit mod_rewrite für schönere URLs sorgen. Dazu habe ich beispielsweise folgende Konfiguration:

<VirtualHost *:80>  
    ServerName testing.example.net  
    ServerAdmin admin@testing.example.net  
  
    LogLevel warn  
    DocumentRoot "/var/www/testing.example.net/htdocs"  
    CustomLog "/var/www/testing.example.net/logs/access_log" combined  
    ErrorLog "/var/www/testing.example.net/logs/error_log"  
  
    <Directory "/var/www/testing.example.net/htdocs">  
        Options SymLinksIfOwnerMatch  
        AllowOverride All  
  
        Order allow,deny  
        allow from all  
  
        AddHandler type-map .var  
        DirectoryIndex index.var  
  
        RewriteEngine On  
        RewriteRule ^/chooselanguage(\?.*)?$ /chooselanguage.php$1  
   </Directory>  
  
</VirtualHost>

Im Beispiel möchte ich nun die URL http://testing.example.net/chooselanguage auf die Datei chooselanguage.php weiterleiten. Wenn Parameter vorhanden sind, sollen diese ebenfalls weitergeleitet werden.
Das funktioniert mit der oben genannten Regel auch gut.
Jetzt möchte ich aber noch einen Zugriff auf die URL /chooselanguage.php von außen verhindern. Die Inhalte von chooselanguage.php sollen nur über die URL /chooselanguage erreicht werden können, und nicht direkt.
Wie realisiere ich das?

Vielen Dank im Voraus & Grüße

Marc Reichelt || http://www.marcreichelt.de/

--
Linux is like a wigwam - no windows, no gates and an Apache inside!
Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
  1. echo $begrüßung;

    RewriteRule ^/chooselanguage(?.*)?$ /chooselanguage.php$1

    Das Umleiten auf /... brachte mir neulich eine Endlosschleife ein. Der umgeschriebene interne Request wird aus dem aktuellen Verzeichnis hinaus nach "absolut sonstwo" geschickt und der Rewrite-Prozess beginnt neu. Vielleicht ist das aber im virtuellen Host anders als bei mir in der .htaccess.

    RewriteRule wertet den Query-String nicht aus. Wenn du dich darauf beziehen möchtest musst du eine RewriteCond verwenden. Ansonsten gibt es das Flag [QSA], mit dem der QS an die umgeschriebene URL angehängt wird.

    Jetzt möchte ich aber noch einen Zugriff auf die URL /chooselanguage.php von außen verhindern. Die Inhalte von chooselanguage.php sollen nur über die URL /chooselanguage erreicht werden können, und nicht direkt.
    Wie realisiere ich das?

    Mit

    <Files *.php>
      deny from all
    </Files>

    geht es nicht, da diese Regel auch auf den internen Request wirkt, und auch /chooselanguage ein 403 bekommt. Meine einzige Idee ist, in /chooselanguage.php REQUEST_URI mit SCRIPT_FILENAME zu vergleichen *) und daraufhin einen 403er header() zurückzugeben.

    *) Dabei muss der QUERY_STRING beachtet werden. Am besten ist es wohl $_SERVER['SCRIPT_FILENAME'] mit parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) zu vergleichen.

    echo "$verabschiedung $name";

    1. Hi dedlfix,

      Das Umleiten auf /... brachte mir neulich eine Endlosschleife ein. Der umgeschriebene interne Request wird aus dem aktuellen Verzeichnis hinaus nach "absolut sonstwo" geschickt und der Rewrite-Prozess beginnt neu. Vielleicht ist das aber im virtuellen Host anders als bei mir in der .htaccess.

      Bislang habe ich keine Endlosschleife bekommen. Natürlich muss man hier immer genau darauf achten, was man eigentlich angibt, aber ein Rewrite von /url?parameter auf /andereurl?parameter dürfte ohne Probleme hinhauen. Tut es bei mir nun ja auch.

      RewriteRule wertet den Query-String nicht aus. Wenn du dich darauf beziehen möchtest musst du eine RewriteCond verwenden. Ansonsten gibt es das Flag [QSA], mit dem der QS an die umgeschriebene URL angehängt wird.

      Nun ja - RewriteRule reicht mir momentan sehr gut aus. :-)

      Mit

      <Files *.php>
        deny from all
      </Files>

      geht es nicht, da diese Regel auch auf den internen Request wirkt, und auch /chooselanguage ein 403 bekommt. Meine einzige Idee ist, in /chooselanguage.php REQUEST_URI mit SCRIPT_FILENAME zu vergleichen *) und daraufhin einen 403er header() zurückzugeben.

      Stimmt - die <Files>-Direktive ist hier eher weniger angebracht. <Location> funktioniert aber, das werde ich dann wohl auch verwenden. Nun möchte ich "nur noch" bei anderen URLs (siehe meinem anderen Post) einen 404er statt einen 403er zurückgeben. Geht das mit Apache-Mitteln?

      Grüße

      Marc Reichelt || http://www.marcreichelt.de/

      --
      Linux is like a wigwam - no windows, no gates and an Apache inside!
      Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
      1. hallo Marc,

        die <Files>-Direktive ist hier eher weniger angebracht.

        Doch, das würde schon funktionieren. Du mußt nur zwischen den Platzhaltern für den Dateinamen ("chooselanguage") und für die Extension ("php") differenzieren.

        <Location> funktioniert aber

        Hat jedoch andere Konsequenzen.

        das werde ich dann wohl auch verwenden. Nun möchte ich "nur noch" bei anderen URLs (siehe meinem anderen Post) einen 404er statt einen 403er zurückgeben. Geht das mit Apache-Mitteln?

        Ähm ... ja, das geht *g* [1]

        Grüße aus Berlin

        Christoph S.

        [1]künftig solltest du deine Frage eventuell auch noch so komplettieren, daß du wissen möchtest, _wie_ es nun geht *gg*

        --
        Visitenkarte
        ss:| zu:) ls:& fo:) va:) sh:| rl:|
        1. Hallo Christoph,

          die <Files>-Direktive ist hier eher weniger angebracht.

          Doch, das würde schon funktionieren. Du mußt nur zwischen den Platzhaltern für den Dateinamen ("chooselanguage") und für die Extension ("php") differenzieren.

          Werde ich gleich nachher austesten. :-)

          <Location> funktioniert aber

          Hat jedoch andere Konsequenzen.

          Ich hoffe, es sind keine negativen.

          das werde ich dann wohl auch verwenden. Nun möchte ich "nur noch" bei anderen URLs (siehe meinem anderen Post) einen 404er statt einen 403er zurückgeben. Geht das mit Apache-Mitteln?

          Ähm ... ja, das geht *g* [1]

          [1]künftig solltest du deine Frage eventuell auch noch so komplettieren, daß du wissen möchtest, _wie_ es nun geht *gg*

          Das ist ja wohl mal verselbstständlich. ;-)
          Natürlich würde ich das auch gerne wissen.

          Grüße

          Marc Reichelt || http://www.marcreichelt.de/

          --
          Linux is like a wigwam - no windows, no gates and an Apache inside!
          Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
  2. Hallo nochmals,

    Jetzt möchte ich aber noch einen Zugriff auf die URL /chooselanguage.php von außen verhindern. Die Inhalte von chooselanguage.php sollen nur über die URL /chooselanguage erreicht werden können, und nicht direkt.

    Das Problem habe ich vorerst behoben, indem ich folgenden Code in den <VirtualHost> eingefügt habe:

    <Location "/chooselanguage.php">  
        Order deny,allow  
        deny from all  
    </Location>
    

    Allerdings würde ich jetzt gerne eher so vorgehen, dass der Zugriff nicht nur "verboten" wird, sondern der Statuscode 404 gesendet wird. Ist das im Apache machbar, und wenn ja, mit welchem Befehl?

    Grüße

    Marc Reichelt || http://www.marcreichelt.de/

    --
    Linux is like a wigwam - no windows, no gates and an Apache inside!
    Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
    1. Hi,

      Allerdings würde ich jetzt gerne eher so vorgehen, dass der Zugriff nicht nur "verboten" wird, sondern der Statuscode 404 gesendet wird. Ist das im Apache machbar,

      wieso eigentlich im Apache? Wenn es Dir nur um diese eine Datei geht - was spricht dagegen, hierin den REQUEST_URI auszulesen und ggfls. 404 zu senden?

      freundliche Grüße
      Ingo

      1. Hallo Ingo,

        Allerdings würde ich jetzt gerne eher so vorgehen, dass der Zugriff nicht nur "verboten" wird, sondern der Statuscode 404 gesendet wird. Ist das im Apache machbar,
        wieso eigentlich im Apache? Wenn es Dir nur um diese eine Datei geht - was spricht dagegen, hierin den REQUEST_URI auszulesen und ggfls. 404 zu senden?

        Es geht mir ja gerade nicht nur um diese eine Datei, sondern um mehrere. :-)
        Christoph meinte ja, dass man mit Apache-eigenen Mitteln einen 404er anzeigen kann, hat aber immer noch nicht verraten wie.

        Grüße

        Marc Reichelt || http://www.marcreichelt.de/

        --
        Linux is like a wigwam - no windows, no gates and an Apache inside!
        Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
        1. Hi,

          Es geht mir ja gerade nicht nur um diese eine Datei, sondern um mehrere. :-)

          und die kannst Du alle mit einer einzigen Regel erwischen? Wenn nicht, spricht auch dann nichts dagegen, in jeder PHP-Datei dafür eine kleine Routine zu includieren.

          freundliche Grüße
          Ingo

          1. Hallo Ingo,

            Es geht mir ja gerade nicht nur um diese eine Datei, sondern um mehrere. :-)
            und die kannst Du alle mit einer einzigen Regel erwischen? Wenn nicht, spricht auch dann nichts dagegen, in jeder PHP-Datei dafür eine kleine Routine zu includieren.

            Aber natürlich geht das - reguläre Ausdrücke sind ja recht flexibel... :-)
            Allerdings brauche ich dazu einen Befehl, der in einem <Location>-Eintrag vorkommen darf, der an dieser Stelle einen 404 anzeigt. Ein "deny from all" tut es ja bereits mit einem 403. Allerdings hoffe ich immer noch auf Christoph, dass er mir den Befehl (den es anscheinend auch gibt) mitteilt. :-/

            Grüße

            Marc Reichelt || http://www.marcreichelt.de/

            --
            Linux is like a wigwam - no windows, no gates and an Apache inside!
            Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
            1. Hallo nochmals,

              Allerdings brauche ich dazu einen Befehl, der in einem <Location>-Eintrag vorkommen darf, der an dieser Stelle einen 404 anzeigt. Ein "deny from all" tut es ja bereits mit einem 403. Allerdings hoffe ich immer noch auf Christoph, dass er mir den Befehl (den es anscheinend auch gibt) mitteilt. :-/

              Ich habe jetzt eine gut funktionierende Lösung gefunden - ohne Christophs Hilfe.
              Und zwar habe ich <Location>-Eintrag entfernt, dafür sehen die Rewrite-Regeln im <VirtualHost> nun wie folgt aus:

              RewriteEngine On  
              RewriteRule ^/chooselanguage(\?.*)?$ /chooselanguage.php$1 [L]  
              RewriteRule ^/chooselanguage\.php(\?.*)?$ /404 [L]
              

              Und zwar wird die URL /chooselanguage.php (mit variablen Parametern) auf eine nicht existierende Adresse /404 weitergeleitet. Wichtig ist nun noch das [L] am Ende der zweiten Zeile, was dafür sorgt ("L" steht für "last"), dass keine erneute Umleitung von /chooselanguage.php nach /chooselanguage erfolgt.
              Das [L] in der dritten Zeile hat derzeit bei mir keine sonderliche Funktion - ist aber eine zusätzliche Absicherung gegen weitere RewriteRules.

              Grüße

              Marc Reichelt || http://www.marcreichelt.de/

              --
              Linux is like a wigwam - no windows, no gates and an Apache inside!
              Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
              1. Und nochmal hallo,

                RewriteEngine On

                RewriteRule ^/chooselanguage(?.)?$ /chooselanguage.php$1 [L]
                RewriteRule ^/chooselanguage.php(?.
                )?$ /404 [L]

                  
                Der Text "$1" an /chooselanguage.php ist offenbar nicht notwendig. Die Parameter, die an /chooselanguage angehängt werden, werden auch ohne "$1" übergeben.  
                Folgender Code ist simpler und funktioniert ebenso gut:  
                  
                ~~~apache
                RewriteEngine On  
                RewriteRule ^/((en|de)/)?(search|imprint|chooselanguage)$ /$3.php [L,E=lang:$2]  
                RewriteRule ^/(search|imprint|chooselanguage)\.php?$ /404 [L]
                

                Hinzugefügt habe ich noch weiteren Code für URLs, die auch auf die (über die URL angegebene) Sprache reagieren sollen.

                Grüße

                Marc Reichelt || http://www.marcreichelt.de/

                --
                Linux is like a wigwam - no windows, no gates and an Apache inside!
                Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
                1. Hi,

                  RewriteRule ^/((en|de)/)?(search|imprint|chooselanguage)$ /$3.php [L,E=lang:$2]

                  och nee... Du bist auch einer, der sich mit Schulenglisch versucht?
                  Was glaubst Du, warum die Hälfte aller von Google gefundenen Seiten zu "imprint" aus Deutschland stammen? ;-)

                  Abgesehen davon: ich habe übrigens auch gerade eine zweisprachige Seite erstellt und konnte hier ganz auf einen Sprachparameter verzichten, weil die Linktexte eindeutig der Sprache zuzuordnen sind.

                  freundliche Grüße
                  Ingo

                  1. Hallo Ingo,

                    RewriteRule ^/((en|de)/)?(search|imprint|chooselanguage)$ /$3.php [L,E=lang:$2]
                    och nee... Du bist auch einer, der sich mit Schulenglisch versucht?
                    Was glaubst Du, warum die Hälfte aller von Google gefundenen Seiten zu "imprint" aus Deutschland stammen? ;-)

                    Hmm, "Masthead" klingt aber sehr ungewöhnlich - und scheint auch eher für eine Zeitung gedacht zu sein. Ich werde die Seite dann wohl eher in "contact" umbenennen. ;-)
                    Ich dachte eigentlich, ich könnte "imprint" verwenden, weil der CCC das auch so macht. Ich nahm an, dass dort Leute sitzen, die des Englischen mehr mächtig sind als ich.
                    Ja, außer meinem Schulenglisch, den zwar zahlreichen aber kurzen Reisen in andere Länder und dem normalen Englisch, welches ich mir über das Internet "anlese", bleibt mir recht wenig übrig.
                    Nichtsdestotrotz ist mein Englisch nicht sooo schlecht - es hapert (wie üblich) an bestimmten Begriffen und natürlich der konstanten Übung, die ich nur hätte, wenn ich jeden Tag Englisch reden könnte bzw. müsste. Genau deshalb möchte ich gerne ein Jahr im Ausland machen. :-)

                    Abgesehen davon: ich habe übrigens auch gerade eine zweisprachige Seite erstellt und konnte hier ganz auf einen Sprachparameter verzichten, weil die Linktexte eindeutig der Sprache zuzuordnen sind.

                    Das steht bei zwei Sprachen noch in einem annehmbaren Verhältnis, aber bei dem Projekt, das wir derzeit planen ("Linux Hardware Datenbank" bzw. "Linux Drivers", siehe Archiv), haben wir wesentlich mehr Sprachen im Visier.
                    Nichtsdestotrotz finde ich das mit den Sprachcodes besser: Man befindet sich z. B. auf http://example.org/de/contact, und möchte die entsprechende Seite beispielsweise auf Englisch ansehen, so entfernt man einfach das "de/" und hat die englischsprachige Seite da. Nicht, dass man diese Funktionalität auch über von PHP generierte Links lösen könnte - aber ich finde, dass das System so einfacher ist.

                    Grüße

                    Marc Reichelt || http://www.marcreichelt.de/

                    --
                    Linux is like a wigwam - no windows, no gates and an Apache inside!
                    Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
                    1. Hi,

                      Hmm, "Masthead" klingt aber sehr ungewöhnlich - und scheint auch eher für eine Zeitung gedacht zu sein.

                      Imprint auf jeden Fall auch. Lies mal http://de.wikipedia.org/wiki/Imprint.
                      Auch wenn es in Amerika keine Pflicht zur Anbieterkennung gibt, findet man diese dort oft unter "legal notice" - sogar auf enigen englischsprachigen Seiten aus Deutschland wie http://www.mba.uni-mannheim.de/legal.html oder gar http://www.dresden-airport.de/en/suche/impressum.html.
                      Interessant ist http://europa.eu/ - hier wurde offenbar vom Englischen aus ins Deutsche mit "rechtlicher Hinweis" übersetzt.

                      Nichtsdestotrotz finde ich das mit den Sprachcodes besser: Man befindet sich z. B. auf http://example.org/de/contact

                      Wirklich nicht "kontakt"? Finde ich übrigen am passendsten für ein Impressum.

                      freundliche Grüße
                      Ingo

                  2. Hi,

                    Was glaubst Du, warum die Hälfte aller von Google gefundenen Seiten zu "imprint" aus Deutschland stammen? ;-)

                    Vermutlich weil diese Fachleute englischsprachige EDV-Literatur bevorzugen, und das Impressum in englischsprachigen Büchern nunmal imprint heißt?! =:-)

                    Und weil wir uns in Deutschland angewöhnt haben, ggf. existierende lat. Fachwörter auch im Internet sinnvoll weiterzunutzen - obwohl im Internet nix gepreßt wird (außer den unzähligen/unsäglichen AOL-CDs versteht sich! >;->).

                    Kriege ich jetzt 'nen Leuchtkeks? ;-)

                    Gruß, Cybaer

                    --
                    Hinweis an Fragesteller: Fremde haben ihre Freizeit geopfert, um Dir zu helfen. Helfe Du auch im Archiv Suchenden: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!
  3. hi,

    Jetzt möchte ich aber noch einen Zugriff auf die URL /chooselanguage.php von außen verhindern. Die Inhalte von chooselanguage.php sollen nur über die URL /chooselanguage erreicht werden können, und nicht direkt.
    Wie realisiere ich das?

    Oberhalb des Document Roots ablegen?

    Dein 404er bei aufruf von http://testing.example.net/chooselanguage.php kommt dann auch automatisch, weil es http://testing.example.net/chooselanguage.php schlicht und einfach nicht gibt (sofern da keine weitere Umschreibung eingreift).

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }