Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Stringi i inne boxerki
Forum PHP.pl > Forum > Przedszkole
phpamator
Hej hej, witajcie przedszkolaki,
Po dość długiej przerwie wpadłem z pytaniem za które z pewnością zaraz dostanę po głowie ale niech tam smile.gif

Otóż chciałbym sobie wyciągać pewne dane z logów czytając linią po linii. Samo czytanie nie nastręcza żadnych problemów, jednak gdy przychodzi do dzielenia łańcucha ....

.... tu zaczynają się schodki, pewnie dlatego, że powinienem się za to wziąć już dawno temu ale jakoś tak wyszło .... że zajmowałem się innymi rzeczami a te ważne leżały "na półce".

Ale do rzeczy, w każdej linii mam różne sekcje, posłużę się przykładem:

2017-03-12 03:22:01,957 fail2ban.server [15071]: INFO rollover performed on /var/log/fail2ban.log
2017-03-18 12:42:38,575 fail2ban.filter [14691]: INFO [sshd] Found 95.68.146.94
2017-03-18 13:52:21,277 fail2ban.filter [14691]: INFO [sshd] Found 94.50.247.182
2017-03-18 13:52:23,864 fail2ban.filter [14691]: INFO [sshd] Found 94.50.247.182
2017-03-18 13:52:24,170 fail2ban.actions [14691]: NOTICE [sshd] Ban 94.50.247.182
2017-03-18 13:52:26,355 fail2ban.filter [14691]: INFO [sshd] Found 94.50.247.182
2017-03-18 14:07:57,173 fail2ban.filter [14691]: WARNING Determined IP using DNS Lookup: 1-34-200-253.hinet-ip.hinet.net = ['1.34.200.253']
2017-03-18 14:07:57,174 fail2ban.filter [14691]: INFO [sshd] Found 1.34.200.253
2017-03-18 14:07:59,521 fail2ban.filter [14691]: INFO [sshd] Found 1.34.200.253
2017-03-18 14:07:59,848 fail2ban.actions [14691]: NOTICE [sshd] Ban 1.34.200.253
2017-03-18 14:08:01,844 fail2ban.filter [14691]: INFO [sshd] Found 1.34.200.253
2017-03-18 16:35:53,379 fail2ban.filter [14691]: INFO [sshd] Found 123.169.205.199
2017-03-18 16:35:54,980 fail2ban.filter [14691]: INFO [sshd] Found 123.169.205.199
2017-03-18 16:35:55,618 fail2ban.actions [14691]: NOTICE [sshd] Ban 123.169.205.199
mniej więcej takie coś.
[edyta]Jak widać nie wszystkie linie są tak samo zorganizowane ale wybieram tylko te gdzie wykonana została akcja "Ban" i tylko te rozbijam po czym zapisuję do bazy.




Mógłbym sobie policzyć ile każdy segment średnio zajmuje i potem dzielić string na kawałki ale to chyba nie najlepszy pomysł szczególnie, że te "segmenty" nie są tej samej długości a co za tym idzie .... mogą się pojawić błędy. Chyba, że ustawię np pierwszych kilka których długość się nie zmienia a resztę ile wlezie do końca linii.

Nie sądzę jednak aby to miało sens, dlatego pytam, jak to zrobić, żeby za każdym razem linia była dzielona tak samo ?
Druga część pytania: mogę sobie wstaić jakiś delimiter (zamiast spacji) ale jak zauważyliście miejscami spacji jest kilka, nie byłoby problemu gdyby każdy segment oddzielony był jedną ....

Podpowiedzcie proszę, jak?


Pozdrawiam
amator
Pyton_000
preg_match i robisz sobie pattern. dla tego będzie to np:
Kod
(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d{3}) ([\w.]+?) \[(\d+)\]: (.+)
Tomplus
Tak jak napisał Python, ale dla podpowiedzi dalej... przetestuj sobie taki pattern np. tutaj: http://regex101.com

Dzięki takiemu narzędziu w prosty i szybki sposób przetestujesz kilka wierszy na raz, dodatkowo ucząc się co dana reguła powoduje w wyrażeniu.
phpamator
Dobrze, że nie pokazałem wam jak sobie poradziłem bo by "kupa" smiechu była i wstyd wink.gif

ale oczywiście chciałbym zrobić to w sposób optymalny i najbardziej poprawny. Dlatego dla porządku wyedytowałem pierwszy post i wkleiłem kilka linii przykładowych co by wszyscy widzieli o czym dokładnie mowa.
KsaR
preg_* by zapewnił poprawność, ale możesz spróbować w prostszy sposób czy działa ok:
  1. explode("\n", $logs);

Wynik testu - https://eval.in/756896
Pyton_000
Tak na szybko:
  1. <?php
  2.  
  3. $fileLog = 'path/to/log';
  4.  
  5. $lines = file($fileLog, FILE_IGNORE_NEW_LINES);
  6. $fail2ban = array_filter($lines, function($value) {
  7. return stripos($value, 'fail2ban') !== false;
  8. });
  9.  
  10. foreach ($fail2ban as $item) {
  11. preg_match('/(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d{3}) ([\w.]+?) \[(\d+)\]: (.+)/', $item, $match);
  12. var_dump($match);
  13. }
phpamator
Cytat(KsaR @ 19.03.2017, 02:13:27 ) *
preg_* by zapewnił poprawność, ale możesz spróbować w prostszy sposób czy działa ok:
  1. explode("\n", $logs);

Wynik testu - https://eval.in/756896


Działa, to najprostsza metoda na podzielenie i wrzucenie do tablicy.
Nie do końca jednak rozwiązuje to problem bo każdy element tablicy muszę ponownie dzielić. Dlatego regex będzie najlepszym rozwiążaniem ale tylko na okreslone linie.
Jak wspominałem nie wszystkie one są tak samo zbudowane, w niektórych jak widać na załączonym przykładzie układ elementów jest inny, część także zawiera dodatkowe dane.
Dlatego zrobiłem tak, że wybieram tylko te linie w których wystąpił string "Ban" i tylko te dzielę i wrzucam do tabeli.
ale ... w dalszej części mojego zadania muszę zrobić coś takiego:
najpierw zliczam ile linii znajduje się w pliku/logu, następnie odczytuję z tabeli ile linni było przy poprzednim sprawdzaniu, obliczam różnicę i sprawdzam tylko tyle linii ile zostało dopisanych od ostatniego sprawdzania.
I tu mam pytanie kolejne, jak byście to zrobili, czy puścili pętlę z ostatnio zanotowaną ilością linii i te poprostu pominęli a sprawdzanie zaczęli od ilości z poprzedniego sprawdzenia + 1? Mam nadzieję, że wiecie co mam na myśli /

... coś takiego $ostatnioLiniibylo więc
  1. foreach(file($linie as linia)){$i++;
  2. if($i >= $ostatnioLiniibylo){
  3. //wykonujemy sprawdzanie
  4. }
  5. }
  6.  

czy np obliczyć do której linii skoczyć i od tej kontynuować ?
Pyton_000
Przecież dałem CI gotowe rozwiązanie.
Jeśli chodzi o modyfikację tego to odczytujesz kolejne linie fgets() sprawdzasz czy data lini jest > od zapisaniej ostatniej daty parsowania (tak,powinieneś sobie to gdzieś zapisać) jeśli tak to lecisz dalej i parsujesz sobie jak chcesz...
phpamator
Ooops, dzięki, już "pacze" wink.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.