如何使用PHP中的正则表达式解析Apache日志

7

我正在尝试在PHP中拆分此字符串:

11.11.11.11 - - [25/Jan/2000:14:00:01 +0100] "GET /1986.js HTTP/1.1" 200 932 "http://domain.com/index.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"

如何将此拆分为IP地址、日期,HTTP方法,域名和浏览器?

1
这是一个更糟糕的问题版本,它需要进行完整的解析:https://dev59.com/ymsz5IYBdhLWcg3w3r0J - ftrotter
4个回答

14

这个日志格式似乎是Apache的合并日志格式。尝试使用以下正则表达式:

/^(\S+) \S+ \S+ \[([^\]]+)\] "([A-Z]+)[^"]*" \d+ \d+ "[^"]*" "([^"]*)"$/m

匹配的组如下:

  1. 远程IP地址
  2. 请求日期
  3. 请求HTTP方法
  4. User-Agent

但是域名在此处未列出。第二个引用字符串是Referer 值。


1
@streetparade:使用 preg_match_all 函数,你可以获取所有匹配项:preg_match_all('...', $str, $matches) - Gumbo
这个正则表达式编译不了... 缺少一个圆括号 ;) - The Surrican
这个有误,auth-user字段(第三个,%u)可以包含空格。 - Julien Palard
@JulienPalard,您能否提供一个更新的建议? - Gumbo
@Gumbo 在这里:https://dev59.com/ymsz5IYBdhLWcg3w3r0J - Julien Palard
这个正则表达式无法匹配带有转义双引号的URL或引用:"。也许可以使用"([^"]|\")"代替"[^"]"。 https://dev59.com/S3M_5IYBdhLWcg3wgjW2#1352140 - Matt Pennington

4

这里有一些Perl代码,不是PHP,但使用的正则表达式相同。这个正则表达式可以解析我见过的所有内容;客户端可能会发送一些奇怪的请求:

my ($ip, $date, $method, $url, $protocol, $alt_url, $code, $bytes,
        $referrer, $ua) = (m/
    ^(\S+)\s                    # IP
    \S+\s+                      # remote logname
    (?:\S+\s+)+                 # remote user
    \[([^]]+)\]\s               # date
    "(\S*)\s?                   # method
    (?:((?:[^"]*(?:\\")?)*)\s   # URL
    ([^"]*)"\s|                 # protocol
    ((?:[^"]*(?:\\")?)*)"\s)    # or, possibly URL with no protocol
    (\S+)\s                     # status code
    (\S+)\s                     # bytes
    "((?:[^"]*(?:\\")?)*)"\s    # referrer
    "(.*)"$                     # user agent
/x);
die "Couldn't match $_" unless $ip;
$alt_url ||= '';
$url ||= $alt_url;

4

您应该查看正则表达式教程。但是这里是答案:

if (preg_match('/^(\S+) \S+ \S+ \[(.*?)\] "(\S+).*?" \d+ \d+ "(.*?)" "(.*?)"/', $line, $m)) {
  $ip = $m[1];
  $date = $m[2];
  $method = $m[3];
  $referer = $m[4];
  $browser = $m[5];
}

请注意,日志中记录的不是域名,而是HTTP Referer。


2
// # Parses the NCSA Combined Log Format lines:
$pattern = '/^([^ ]+) ([^ ]+) ([^ ]+) (\[[^\]]+\]) "(.*) (.*) (.*)" ([0-9\-]+) ([0-9\-]+) "(.*)" "(.*)"$/';

使用方法:

if (preg_match($pattern,$yourstuff,$matches)) {

    //# puts each part of the match in a named variable

    list($whole_match, $remote_host, $logname, $user, $date_time, $method, $request, $protocol, $status, $bytes, $referer, $user_agent) = $matches;

}

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