Harry: Apache / ErrorDocument / LogFiles

Holladiewaldfee,

wie schon öfters mal angeführt arbeite ich zur Zeit an einem CM-
System mit allerlei Schnickschnack. Ich würde ja gerne den Thread
verlinken, wo ich das schonmal alles erklärt habe, find ihn aber ums
Verrecken nicht mehr. Ist aber auch nicht so wichtig.

Als Server verwende ich Apache2.

Eines der Module in meinem Framework ist dafür zuständig, blöde URLs
wie z.B. bla.php?module=news&id=42&unwichtiges=zeug in "merkbare"
und "suchmaschinenverträgliche" umzuwandeln, also /news/42.

Da das ganze dynamisch gehen muß, möchte ich (auch aus
Portierungsgründen) nur ungerne mod_rewrite verwenden. Stattdessen
habe ich eine htaccess-Datei erstellt mit

ErrorDocument 404 /index.php?action=rewrite

Soll heißen: Immer wenn eine Seite nicht gefunden wird versucht das
rewrite-Modul die URL so umzuschreiben, daß was (aus Sicht des
Scriptes) sinnvolles rauskommt.

Beispiel:
Ein User fordert /news/43 an.
Apache stellt fest, daß das Verzeichnis nicht existiert und ruft
index.php?action=rewrite auf. Die PHP Seite isoliert den Querystring
aus $_SERVER['REDIRECT_QUERY_STRING'] und den ursprünglichen Pfad
aus $_SERVER['REDIRECT_URL'] und versucht, was sinnvolles draus zu
basteln. Anschliessend schaut sie in einer Datenbank nach, ob diesem
neuen String eine Seite zugeordnet ist.

Wenn nein wird eine Fehlermeldung ausgegeben und der Käse ist
gegessen.

Wenn ja schicke ich ein "HTTP/1.0 200 Ok" hinterher und gebe die
richtige Seite aus. Das Problem ist aber: Der Apache lässt sich
durch den zusätzlichen Header nicht beeindrucken und müllt mir
fröhlich mein LogFile zu.

Wie also bringe ich den Apachen dazu, wenn ein 200er-Header gesendet
wurde, keinen Eintrag ins LogFile zu schreiben?

Mir ist vollkommen klar, daß ich damit die Fehlerbehandlung des
Apachen mißbrauche und damit etwas anstelle, für das sie nie gedacht
war. Gibt es vielleicht noch einen anderen Weg (außer mod_rewrite),
auf dem ich das Geschilderte verwirklichen kann? Oder renne ich
dauernd mit dem Kopf an die Wand am Ende der Einbahnstraße?

Vielen Dank schonmal.

Ciao,

Harry

--
  Man weiß erst was man hatte, wenn man es verloren hat.
  Intelligenz ist nicht zwingend etwas positives.
  1. hi Harry ;-)

    Als Server verwende ich Apache2.

    Genauer bitte, und auch die Plattform angeben ...

    Wenn nein wird eine Fehlermeldung ausgegeben und der Käse ist gegessen.
    Wenn ja schicke ich ein "HTTP/1.0 200 Ok" hinterher und gebe die richtige Seite aus.
    Das Problem ist aber: Der Apache lässt sich durch den zusätzlichen Header nicht beeindrucken und müllt mir fröhlich mein LogFile zu.

    Glaub mir: so "fröhlich" ist er dabei gar nicht.

    Wie also bringe ich den Apachen dazu, wenn ein 200er-Header gesendet
    wurde, keinen Eintrag ins LogFile zu schreiben?

    Indem du ihm sagst, was er überhaupt und wie ins log schreiben soll? Wie hast du denn bisher deine logfiles in der httpd.conf konfiguriert?

    Mir ist vollkommen klar, daß ich damit die Fehlerbehandlung des Apachen mißbrauche

    Tut mir leid, wenn ich dir diese Klarheit wieder zumüllen/vernebeln/eintrüben muß. Gerade Apache 2.0.x sieht ziemlich konsequent vor, daß du logfiles und Error-Meldungen selber konfigurieren solltest/kannst/darfst.

    Grüße aus Berlin

    Christoph S.

    1. Holladiewaldfee,

      Als Server verwende ich Apache2.
      Genauer bitte, und auch die Plattform angeben ...

      Man FreeBSD, mal Linux, mal WinXP ... ;-)
      Apache 2.0.46.
      Sollte wenn möglich aber auch mit 1.3.2x laufen.

      Glaub mir: so "fröhlich" ist er dabei gar nicht.

      Och .. ich dachte ich mach ihm eine Freude, wenn er auch mal was
      sagen darf ;-)

      Indem du ihm sagst, was er überhaupt und wie ins log schreiben
      soll? Wie hast du denn bisher deine logfiles in der httpd.conf
      konfiguriert?

      Default. Prinzipell hat das ja auch nichts zu sagen, wenn, dann
      sollte sich die Sache über eine htaccess-Datei regeln lassen, ganz
      einfach aus dem Grund, daß nicht jeder, der das System nachher
      einsetzt (ich selbst eingeschlossen) auf dem Server, auf dem er es
      einsetzt, das Recht hat, in der httpd.conf rumzufummeln. Zu
      einem "AllowOverride FileInfo" lassen sich die meisten Admins dann
      ja grade noch überreden, aber zu "Änder mal bitte was am Log-
      Verhalten des Apachen" dann eher weniger.

      Mir ist vollkommen klar, daß ich damit die Fehlerbehandlung
      des Apachen mißbrauche
      Tut mir leid, wenn ich dir diese Klarheit wieder
      zumüllen/vernebeln/eintrüben muß. Gerade Apache 2.0.x sieht
      ziemlich konsequent vor, daß du logfiles und Error-Meldungen
      selber konfigurieren solltest/kannst/darfst.

      Schon klar (oder auch nicht).

      Das Problem ist: Der Apache sieht einen 404er und lässt dann auf
      Grund der ErrorDocument-Direktive meine PHP-Seite dran
      rumfuhrwerken. Die aber akzeptiert entweder den Fehler oder eben
      nicht. Wenn sie ihn nicht akzeptiert, weil sie es besser weiß,
      schickt sie einen 200er-Header los.

      Das Problem ist, daß der Apache in beiden Fällen einen Eintrag ins
      LogFile macht. Wenn der 200er Header aber geschickt wurde soll er
      eben das _nicht_ tun, da ja dann eigentlich kein Fehler vorlag.

      Also (graphisch):

      User Request:    /news/42
      Apache:          404
      Apache:          htaccess => ErrorDocument index.php
      index.php:       Umschreiben in module=news&id=42
      index.php:       Anfrage an DB: Existiert Seite, die
                       module=news&id=42 erwartet?

      (1) Ja
          index.php:   200 Ok
          index.php:   Angeforderte Seite abarbeiten
          Apache:      Eintrag LogFile: 404 NotFound /news/42 (*)

      (2) Nein
          index.php:   Fehlerseite ausgeben
          Apache:      Eintrag LogFile: 404 NotFound /news/42

      Der Fehler liegt bei (*): Eben diese Zeile soll _nicht_ ausgeführt
      werden!

      Ciao,

      Harry

      --
        Man weiß erst was man hatte, wenn man es verloren hat.
        Intelligenz ist nicht zwingend etwas positives.
      1. Wenn ich das richtig einschätze, dann schreibt der Apache den 404er schons ins Log-File, wenn die erste Anforderung kommt (also, wenn er auf index.php umleitet). Das kannst du wohl kaum beeinflussen, ausser, wenn du das Fehler-Logging ganz ausschaltest...

        mfg
        Michael

        1. Holladiewaldfee,

          Wenn ich das richtig einschätze, dann schreibt der Apache den

          404er schons ins Log-File, wenn die erste Anforderung kommt (also,
          wenn er auf index.php umleitet). Das kannst du wohl kaum
          beeinflussen, ausser, wenn du das Fehler-Logging ganz ausschaltest...

          Gnargh.
          Gut, angenommen, ich schalte den Käse ganz aus.
          Kann ich ihn dann dazu bewegen, doch noch einen Eintrag zu schreiben?

          Die einzige Methode, die mir dabei einfällt, ist in einem tieferen
          Verzeichnis die Fehlerbehandlung wieder zu aktivieren und dann dort
          einen (ähnlichen) 404er zu provozieren.

          Das ist aber nicht wirklich elegant, sondern eher eine
          Notbehelfslösung.

          Mit den Apache-Funktionen von PHP wird sich da wohl auch nix machen
          lassen (http://de3.php.net/manual/de/ref.apache.php).

          Also bliebe nur, ein anderes Konzept zu verwenden, d.h. Weg vom
          404er, hin zu ... (bitte nicht mod_rewrite)

          Leider bin ich nicht so der Apache-Konfigurations-Überflieger, so
          daß ich nicht alle Möglichkeiten kenne, die es hier geben könnte.

          Ciao,

          Harry

          --
            Man weiß erst was man hatte, wenn man es verloren hat.
            Intelligenz ist nicht zwingend etwas positives.
          1. jep.. denke auch, dass es anders gehen muss..

            es gibt da (soweit ich mich erinnern mag) eine Funktion des Apache die so weit in der Verzeichnisstruktur zurückgeht, bis sie eine index.php (oder andere Start-Datei) findet...

            aber wie die jetzt wieder heisst....

            werde mal kurz suchen gehen...

            1. Holladiewaldfee,

              werde mal kurz suchen gehen...

              Danke. Hat aber Zeit bis morgen ;-)
              Oder übermorgen. Oder irgendwann anders :)
              Hauptsache nicht "nie".

              Ciao,

              Harry

              --
                Man weiß erst was man hatte, wenn man es verloren hat.
                Intelligenz ist nicht zwingend etwas positives.
              1. Hab das Teil nicht mehr gefunden....

                aber hier im Forum wurde es vor rel. kurzer Zeit diskutiert.. hat also sicher Leute hier, die wissen wie es heisst...

                1. http://httpd.apache.org/docs/mod/directives.html. index-Datei -> "DirectoryIndex"

                  1. Thx aber das ist nicht das was ich gesucht habe...

                    es geht darum, dass sich der Apache selbst "nach oben" kämpft bis er eine index-Datei findet

          2. Hi Harry,

            Gut, angenommen, ich schalte den Käse ganz aus.

            und verzichtest auf sämtliche Warnmechanismen, die Dir sagen würden, daß Dein Webserver in Schwierigkeiten geraten ist? Das willst Du doch nicht ernsthaft tun.

            Die einzige Methode, die mir dabei einfällt, ist in einem tieferen
            Verzeichnis die Fehlerbehandlung wieder zu aktivieren und dann dort
            einen (ähnlichen) 404er zu provozieren.

            Die einzige Methode, die mir einfällt, ist, gar keinen 404er zu produzieren.

            Also bliebe nur, ein anderes Konzept zu verwenden, d.h. Weg vom
            404er, hin zu ... (bitte nicht mod_rewrite)

            Und warum nicht? Das, was Du bisher machst, ist genauso Apache-proprietär.

            Viele Grüße
                  Michael

            --
            T'Pol: I apologize if I acted inappropriately.
            V'Lar: Not at all. In fact, your bluntness made me reconsider some of my positions. Much as it has now.
            (sh:| fo:} ch:] rl:( br:^ n4:( ie:% mo:) va:| de:/ zu:| fl:( ss:) ls:~ js:|)
             => http://www.peter.in-berlin.de/projekte/selfcode/?code=sh%3A|+fo%3A}+ch%3A]+rl%3A(+br%3A^+n4%3A(+ie%3A%25+mo%3A)+va%3A|+de%3A%2F+zu%3A|+fl%3A(+ss%3A)+ls%3A~+js%3A|
            Auch diese Signatur wird an korrekt konfigurierte Browser gzip-komprimiert übertragen.
            1. Holladiewaldfee,

              Hi Harry,

              Gut, angenommen, ich schalte den Käse ganz aus.

              und verzichtest auf sämtliche Warnmechanismen, die Dir sagen

              würden, daß Dein Webserver in Schwierigkeiten geraten ist? Das
              willst Du doch nicht ernsthaft tun.

              Ja, stimmt, war'ne Schmarn-Idee. Ich hatte aber ja nie vor, das
              komplette Error-Logging auszuschalten sondern nur die 404er für ein
              bestimmtes Verzeichnis. Wäre dann doch ein echte 404er aufgetreten,
              hätte das PHP-Script ja einen Log-Eintrag gemacht (ja, ich weiß, das
              PHP-Script ist auch ein Schwachstelle).

              Die einzige Methode, die mir einfällt, ist, gar keinen 404er zu

              produzieren.

              Würde ich ja gerne.
              Ich weiß aber nicht wie. Ich könnte höchstens irgendein Script als
              Directory-Handler einspannen. Allerdings wäre ich dann halt damit
              geschlagen, jedesmal ein zusätzliches Unterverzeichnis angeben zu
              müssen (also domain.de/cms.php/bla/wurscht/laber, zur Not auch
              ohne ".php").

              Also bliebe nur, ein anderes Konzept zu verwenden, d.h. Weg vom
              404er, hin zu ... (bitte nicht mod_rewrite)

              Und warum nicht? Das, was Du bisher machst, ist genauso Apache-

              proprietär.

              Ja, aber viele Apachen haben halt kein mod_rewrite aktiviert. Und
              selbst wenn, so wüsste ich nicht, wie ich mod_rewrite mit einer
              Datenbank koppeln kann. Ich denke mal, ich müsste bei jeder Änderung
              die komplette Datei neu schreiben. Außerdem stehen da dann mit der
              Zeit ein echter Haufen Regeln drin, die abgearbeitet werden müssten,
              da ich die Namen für die Weiterleitungen nur ungern an irgendwelche
              Konventionen binden möchten (mal die für eine gültige URL abgesehen).

              Ich bin wie schon gesagt nicht so der Apache-Konfigurations-
              Überflieger. Und darunter fällt auch mod_rewrite ;-)

              Ciao & Danke,

              Harry

              --
                Man weiß erst was man hatte, wenn man es verloren hat.
                Intelligenz ist nicht zwingend etwas positives.
              1. Hallo Harry,

                Ja, aber viele Apachen haben halt kein mod_rewrite aktiviert. Und
                selbst wenn, so wüsste ich nicht, wie ich mod_rewrite mit einer
                Datenbank koppeln kann. Ich denke mal, ich müsste bei jeder Änderung
                die komplette Datei neu schreiben.

                Was für ein Käse verzapfst Du denn da?

                Du kannst Problemlos

                http://www.example.org/a/b/c/d/e/f/g/j

                nach

                http://www.example.org/index.php?path=a/b/c/d/e/f/g/j

                umschreiben:

                -----------------------------------------------------------
                RewriteEngine on

                RewriteBase /

                RewriteCond %{REQUEST_URI} !^index.php.*
                RewriteRule ^(.*) index.php?path=$1  [L,QSA]
                -----------------------------------------------------------

                Damit erschlägst Du _jeden_ Pfad. Absolut _jeden_. Wenn der Besucher

                http://www.example.org/alpha/beta/search?q=xyz

                aufruft, dann wird daraus ganz ordentlich ein

                http://www.example.org/index.php?path=alpha/beta/search&q=xyz

                Probier es aus!

                Viele Grüße,
                Christian

                1. Holladiewaldfee,

                  Was für ein Käse verzapfst Du denn da?

                  Käse.

                  http://www.example.org/a/b/c/d/e/f/g/j
                  nach
                  http://www.example.org/index.php?path=a/b/c/d/e/f/g/j
                  umschreiben:

                  Äh, ja, stimmt.
                  Denkfehler. Hargh. Ich muß ja nicht mod_rewrite selber an die Datenbank binden ... Ich sollte früher ins Bett gehn. Oder zumindest nicht mitten im Klausurstreß ein CMS schreiben wollen.

                  <insider>
                  [x] Dreht sich
                  </insider>

                  RewriteEngine on

                  RewriteBase /

                  RewriteCond %{REQUEST_URI} !^index.php.*
                  RewriteRule ^(.*) index.php?path=$1  [L,QSA]

                  Das ist schon klar, danke.
                  Mein Problem ist aber, wenn der Apache das Rewrite-Modul nicht geladen hat, ist der Ofen aus. Aber ich denke, da werde ich drüber hinwegsehen müssen, es geht wohl nicht ohne.

                  Damit erschlägst Du _jeden_ Pfad. Absolut _jeden_.

                  Das ist das Problem ;-)
                  Ich würde gerne dynamisch alle bereits bestehenden Dateien und Pfade ausnehmen.
                  Statisch könnte ich das ja (denke ich zumindest) mit !^index.php.* && !^img/.* && !^css/.* machen (vielleicht noch mit escape vor "/", probieren geht über studieren), aber dynamisch?

                  Naja, zur Not werde ich halt auf diese Dynamik verzichten, wenn's net anders geht.

                  Probier es aus!

                  Werd ich mal demnächst machen.
                  Nur noch 20 Seiten LinAlg, dann ist schluß für heute.
                  (He, es ist schönes Wetter, der Weiher, der Berg harrrrrrrr)

                  Ciao & Danke,

                  Harry
                   (dreht sich)

                  --
                    Man weiß erst was man hatte, wenn man es verloren hat.
                    Intelligenz ist nicht zwingend etwas positives.
                  1. Hallo Harry,

                    Statisch könnte ich das ja (denke ich zumindest) mit !^index.php.* && !^img/.* && !^css/.* machen (vielleicht noch mit escape vor "/", probieren geht über studieren), aber dynamisch?

                    Warum nicht:

                    ---------------------------------------------
                    RewriteEngine on

                    RewriteBase /

                    RewriteCond %{REQUEST_FILENAME} !-f
                    RewriteCond %{REQUEST_FILENAME} !-d
                    RewriteRule ^(.*) index.php?path=$1  [L,QSA]
                    ---------------------------------------------

                    Falls die Datei oder das Verzeichnis existiert, dann wird sie nicht von mod_rewrite angerührt, ansonsten wird index.php aufgerufen.

                    Du kannst zusätzlich noch ein

                    RewriteCond %{REQUEST_URI} ^/internal.*
                    RewriteRule ^(.*) -  [F]

                    einbauen, damit alles unterhalb von internal/ nicht von außen zugänglich ist. Die Fehlermeldung kannst Du dann mit ErrorDocument festlegen.

                    Viele Grüße,
                    Christian

                    1. Holladiewaldfee,

                      Warum nicht [...]

                      Vielleicht sollte ich doch morgen statt Schweinsbraten mal die mod_rewrite-Doku mampfen.

                      Herzlichen Dank, Du hast mir echt geholfen!

                      Ciao,

                      Harry

                      --
                        Man weiß erst was man hatte, wenn man es verloren hat.
                        Intelligenz ist nicht zwingend etwas positives.
                      1. Hallo Harry,

                        Vielleicht sollte ich doch morgen statt Schweinsbraten mal die
                        mod_rewrite-Doku mampfen.

                        *g*

                        Herzlichen Dank, Du hast mir echt geholfen!

                        Wobei mir auffällt, dass das /internal-Verbieten vor der anderen
                        Rewrite-Rule geschehen sollte, sonst kann man auf diese Weise zumindest die
                        Dateinamen herausfinden.

                        Viele Grüße,
                        Christian

      2. hallo Waldfee,

        Mal FreeBSD, mal Linux, mal WinXP ... ;-)
        Apache 2.0.46.

        Ja klar, warum frag ich auch nach :-( konnts mir ja denken.

        Default. Prinzipell hat das ja auch nichts zu sagen

        pah, Prinzipienreiter ...

        wenn, dann sollte sich die Sache über eine htaccess-Datei regeln lassen

        Richtig. Die Konfiguration für die Errormeldungen kannst du inne .htaccess schreiben, siehe http://httpd.apache.org/docs-2.0/mod/core.html#errordocument, das log-Format leider (noch) nicht.

        Das Problem ist: Der Apache sieht einen 404er und lässt dann auf
        Grund der ErrorDocument-Direktive meine PHP-Seite dran
        rumfuhrwerken. Die aber akzeptiert entweder den Fehler oder eben
        nicht. Wenn sie ihn nicht akzeptiert, weil sie es besser weiß,
        schickt sie einen 200er-Header los.

        So weit ist das meines Wissens tatsächlich "default".

        Das Problem ist, daß der Apache in beiden Fällen einen Eintrag ins
        LogFile macht.

        Ähm, wirklich?

        Wenn der 200er Header aber geschickt wurde soll er eben das _nicht_ tun, da ja dann eigentlich kein Fehler vorlag.

        Tut er auch nicht, jedenfalls nicht "default" (und nicht bei mir). Die 200 gehört allenfalls in die access.log

        Also (graphisch):

        äks ...

        User Request:    /news/42
        Apache:          404
        Apache:          htaccess => ErrorDocument index.php
        index.php:       Umschreiben in module=news&id=42
        index.php:       Anfrage an DB: Existiert Seite, die
                         module=news&id=42 erwartet?

        (1) Ja
            index.php:   200 Ok
            index.php:   Angeforderte Seite abarbeiten
            Apache:      Eintrag LogFile: 404 NotFound /news/42 (*)

        Da ist ein Denkfehler drin. Der Indianer hat ja bereits auf 404 reagiert. Daß du so gemein bist, da eine PHP-Seite zwischenzuspannen, ist ihm wurscht, und was die macht, ist ihm wohl auch wurscht. Wenn sie fertig ist, schreibt er einfach seinen Eintrag fertig, egal, was das PHP-Ding macht (ist ja möglicherweise ein neuer Prozeß).

        Der Fehler liegt bei (*): Eben diese Zeile soll _nicht_ ausgeführt werden!

        Jaja, ich habs kapiert, bloß dein Apache noch nicht. Es kann tatsächlich an den Einstellungen für die logfiles liegen, da müßte sich eine "Umleitung" zu einer Index-Seite (Standard-Dokument) irgendwo bei
        LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined
        einbauen lassen. Hab ich aber noch nie probiert. Schau mal nach, ob dein PHP-Script den "%(Referer)" oder den "%(Usewr-Agent)" (warum eigentlich den?) neu schreiben kann. Aber da fang ich auch an zu schwimmen.

        Grüße aus Berlin

        Christoph S.

  2. N'Abend Harry,

    Gibt es vielleicht noch einen anderen Weg (außer mod_rewrite),
    auf dem ich das Geschilderte verwirklichen kann?

    Die einfachste Methode wäre meiner Meinung nach, alle Zugriffe auf das Verzeichniss über ein Script laufen lassen, dass diese dann auswertet. Das müsste IMHO auch ohne mod_rewrite gehen.

    Warum willst du eigentlich mod_rewrite nicht verwenden? Ich denke mal, bei anderen Servern gibt es ähnliche, wenn vielleicht auch nicht so effektive alternativen.

    Oder renne ich dauernd mit dem Kopf an die Wand am Ende der Einbahnstraße?

    Also das kann ich dir nicht sagen, dass must du schon selber wissen *SCNR*

    Grüße Andres Freund (der übrigens auch am Entwickeln eines CMS ist. Allerdings nicht in PHP sondern in Perl)

    --
    ss:) zu:) ls:} fo:) de:] va:) ch:| n4:& rl:° br:^ js:( ie:% fl:( mo:|
  3. Holladiewaldfee! ;)

    Genau sowas versuche ich auch gerade zu basteln. :) Dabei wird zwar mod_rewrite verwendet aber nur um bei jeder Anfrage automatisch einen http-loader (.php) aufzurufen, also nicht für die eigentliche Umleitung. So ist man relativ flexibel.

    Irgendwie gibt es da aber noch ein Problem mit der Rewrite-Regel, weil der Loader sich selbst aufruft und damit eine endlose Rekursion auslöst. Jedenfalls wenn ich im PHP-Skript mit header location weiterleite. Um die Rekursion zu umgehen, könnten Umgebungs-Var nützlich sein, die man entweder mit der Rewrite-Regel behandelt oder am Anfang des Loaders. Was auch klappen könnte, ist statt header location mit fsockopen als Client zu fungieren und die URL direkt zu laden, so dass mod_rewrite davon nix mitbekommt.

    Dann gibt es noch Deine Möglichkeit mit den Error-Docs was aber das Log vollmüllt und sicher nicht im Sinne des Erfinders ist.

    Ich meine kürzlich über Apache gelesen zu haben, dass wenn die in der URL angegebene Datei nicht gefunden wird, man einstellen kann, dass durch die übergeordneten Verzeichnisse gelaufen, bzw. gesucht wird. Demnach würde doch bei /loader.php/foo/bar trotzdem der loader aufgerufen werden, oder?

    Viel Erfolg!

    MfG

    Danny