Andü: String anhand von Muster auslesen

Hallo!

Ich will die Log-Dateien meines Servers in einen Array einlesen. Das klappt auch soweit. Mein Problem ist bloß, dass ich jede Zeile der Log Datei in ihre Bestandteile aufteilen will. Dazu hab ich mir ein "Muster" angelegt, nach welchem die Inhalte ausgelesen werden sollen. Aber das Auslesem nach dem Muster bekomm ich nicht hin...

Auszug aus der Log-Datei:
www.irgendwas.de 194.97.107.174 - - [14/Sep/2005:00:00:41 +0200] "GET /style.php?frame=true HTTP/1.0" 200 95 "-"

Dazu das Auslese-Muster:
%ServerAddress% %IP% - - [%Date%] "%Method% %Request% %Protocol%" %ServerCode% %Bytes% "%Referer%"

Danke schon im Voraus!
Andü

  1. Hello,

    Ich will die Log-Dateien meines Servers in einen Array einlesen. Das klappt auch soweit. Mein Problem ist bloß, dass ich jede Zeile der Log Datei in ihre Bestandteile aufteilen will. Dazu hab ich mir ein "Muster" angelegt, nach welchem die Inhalte ausgelesen werden sollen. Aber das Auslesem nach dem Muster bekomm ich nicht hin...

    Leider hast Du vergessen zu erzählen, was nicht klappt.

    www.irgendwas.de 194.97.107.174 - - [14/Sep/2005:00:00:41 +0200] "GET /style.php?frame=true HTTP/1.0" 200 95 "-"

    |              | | |                     |      |    |                     |         |   |  |

    Schau doch mal, ob Du mit dieser Teilung nicht weiter können könntet, und vielleicht nun nur noch einzelne Zeichen retuschieren musst.

    • Domain          -
    • IP              -
    • User            einzelnen Strich entfernen
    • PW              einzelnen Strich entfernen
    • Datum, Zeit     führende linke eckige Klammer entfernen, splitten
    • Zeitzone        anhängende rechte eckige Klammer entfernen
    • Method          Führendes Anführungszeichen entfernen
    • URi             -
    • Sheme, Version  anhängende rechte Klammer entfernen, splitten
    • Status          -
    • Bytes sent      -
    • Referer         umschließende Anführungszeichen entfernen

    Und wenn sich das Format mal ändern muss, beziehst Du die Aktionen immer noch namentliche auf die Arrayelemente. Damit musst Du die Auswertefunktionen nur ergänzen, aber nicht grundlegend ändern.

    Harzliche Grüße vom Berg
    esst mehr http://www.harte-harzer.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
    1. Leider hast Du vergessen zu erzählen, was nicht klappt.

      Hab ich nicht! Ich hab gesagt, dass ich das nicht hinbekomm! Heißt für mich: Ich weiß nicht wie ich das hinbekomm! (nagut vielleicht bisschen weit hergeholt)

      Wenn ich das anhand der Leerzeichen splite, bekomm ich aber nicht ganz eindeutige Werte. Ich will, falls sich das LogFormat mal ändert, ich einfach nur das Muster anpassen muss und es funktioniert wie vorher.
      Gibt es da keine Möglichkeit?

      Mit ereg oder preg_match kann man die entsprechende Einzelstrings ja bloß ersetzten oder täusch ich mich da?
      Quasi will ich eine Funktion, welche wie ereg/preg_match einen String nach einen Muster durchsucht und dann nicht ersetzt sondern die einzelnen Werte in einen Array liefert!

      Das gewünschte Ergebnis soll dann folgendes sein:
      Array
      (
        [ServerAddress] => www.irgendwas.de
        [IP] => 194.97.107.174
        [Date] => 14/Sep/2005:00:00:41 +0200
        [Method] => GET
        [Request] => /style.php?frame=true
        [Protocol] => HTTP/1.0
        [ServerCode] => 200
        [Bytes] => 95
        [Referer] => -
      )

      1. hi,

        Mit ereg oder preg_match kann man die entsprechende Einzelstrings ja bloß ersetzten oder täusch ich mich da?

        Ja, du täuschst dich :-)

        Quasi will ich eine Funktion, welche wie ereg/preg_match einen String nach einen Muster durchsucht und dann nicht ersetzt sondern die einzelnen Werte in einen Array liefert!

        preg_match_all() oder preg_split() helfen dir dabei weiter.

        gruß,
        wahsaga

        --
        /voodoo.css:
        #GeorgeWBush { position:absolute; bottom:-6ft; }
        1. Danke, ich hab das Problem wie folgt gelöst:

          $string = 'www.ec-hasslau.de 66.196.91.121 - - [01/Sep/2005:04:20:39 +0200] "GET /robots.txt HTTP/1.0" 200 49 "-"';
          $muster = 'www.ec-hasslau.de %IP% - - [%Date%] "%Method% %Request% %Protocol%" %ServerCode% %Bytes% "%Referer%"';

          preg_match_all ("|%(.+)%|U", $muster, $muster_teile);
          $muster_neu = preg_replace ("|%(.+)%|U", "(.+)", $muster);
          preg_match ("|" . $muster_neu . "|", $string, $string_teile);
          foreach ($muster_teile[1] as $key => $value)
          {
            $abschluss[$value] = $string_teile[($key + 1)];
          }

          ...ist das schon die optimale Methode oder gibt es da was schnelleres/kürzeres?
          Außerdem ist auch die eckige Klamme im Muster noch ein kleines Problem, da sie ja bei Suchmustern eine funktionale Bedeutung hat. Kann man das anders als mit den \ umgehen (am besten so, dass das Muster wirklich so wie der String aussehen kann)?

          1. Mir ist außerdem gerade noch aufgefallen, dass die Verwendung von % auch nicht unbedingt optimal ist, weil diese ja auch als Dateiname verwendet werden kann. Welches Zeichen wäre als Ersatz geeignet?

      2. Hello,

        Das gewünschte Ergebnis soll dann folgendes sein:
        Array
        (
          [ServerAddress] => www.irgendwas.de
          [IP] => 194.97.107.174
          [Date] => 14/Sep/2005:00:00:41 +0200
          [Method] => GET
          [Request] => /style.php?frame=true
          [Protocol] => HTTP/1.0
          [ServerCode] => 200
          [Bytes] => 95
          [Referer] => -
        )

        Warum schaust Du Dir dann nicht die Stringfunktionen von PHP an?
        Und wie fanelf.de schon schrieb, ist explode() für das erste Auseinandernehmen an den Leerzeichen die passende Funktion.

        $_datenfelder = explode(' ',rtrim($zeile));

        Dann umstapeln in ein assoziatives Array.

        • Domain          -
        • IP              -
        • User            einzelnen Strich entfernen
        • PW              einzelnen Strich entfernen
        • Datum, Zeit     führende linke eckige Klammer entfernen, splitten
        • Zeitzone        anhängende rechte eckige Klammer entfernen
        • Method          Führendes Anführungszeichen entfernen
        • URi             -
        • Sheme, Version  anhängende rechte Klammer entfernen, splitten
        • Status          -
        • Bytes sent      -
        • Referer         umschließende Anführungszeichen entfernen

        Das geht zum Besipiel mit http://de2.php.net/manual/de/function.array-combine.php, wenn man sich die Spaltenbezeichnungen einmal als Array festgelegt hat.

        Und dann mittels der Stringfunktionen die empfohlenen Korrekturen über die Feldnamen durchführen.

        foreach($_spalten as $spaltenname => $wert)
        {
          $func = 'f_'.$spaltenname;
          if (function_exists($func))
          {
            $_spalten($spaltenname) = $func($wert);
          }
        }

        Nun brauchst Du nur noch die Korrekturfunktionen zu definieren:

        #----------------------------------
          function f_User($wert)
          {
            if ($wert == '-') return '';
          }
        #----------------------------------
          function f_Datum($wert)
          {
            if (substr($wert,0,1) == '[')
            {
              $date = substr($wert,1,-8);
              $time = substr($wert,-8);

        $date_split = explode('/',$date);
              $time_split = explode(':',$time);

        $ret = array('date' => $date_split, 'time' => $time_split);
            }
            else
            {
              return false;
            }

        return $ret;
          }
        #----------------------------------

        usw.

        Das ist eine gut Übung für Dich, um die String- und Arrayfunktionen kennenzulernen, bevor Du dich an Regular Expressions heranwagst.

        Harzliche Grüße vom Berg
        esst mehr http://www.harte-harzer.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau
        1. Du hast nicht verstanden was ich will! Ich will das jetzt nicht an dieses eine Logformat alles anpassen, sondern eine allgemeine Funktion, die auf Basis des Musters flexsibel ist.
          Wenn die Funktion so ist, wie ich mir das vorstelle kann man sie auf alle möglichen Strings anwenden.

          Anderes Beispiele:
          blabla@web.de --> %Name%@%Provider%.%Land% --> Array ( [Name] => blabla [Provider] => web [Land] => de )

  2. offensichtlich sind die einzelnen teile durch leerstellen getrennt. daher wäre es am einfachsten mit split oder explode bei blanks in ein array zu trennen.

  3. Hallo Andü,

    Mein Problem ist bloß, dass ich jede Zeile der Log Datei in ihre Bestandteile aufteilen will.

    Aus meinem Perl-Kochbuch:

    while(<LOGDATEI>){  
      my ($client, $identuser, $authuser, $date, $time, $tz, $methode, $url, $protocol, $status, $bytes) =  
      /^(\S+) (\S+) (\S+) \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] "(\S+) (.*?) (\S+)" (\S+) (\S+)$/;  
      # ...  
    }
    

    In PHP übersetzten darfst du es selbst (preg_match_all() mit dem regulären Ausdruck (ggf. den noch etwas modifizieren) als ersten Parameter, der Inhalt des Logfiles als zweiten Parameter und einer Variablen als dritten (hier liegt dann das Ergebnis drin) - so würde ich das zumindest angehen :-)).

    Grüße aus Nürnberg
    Tobias