JustPaste.it

Logi serwera w PHP

W systemach typu UNIX oraz ogólnie na serwerach ważną rolę odgrywają tzw. logi, czyli dziennik systemowy. Taki "dziennik" zawiera dane dotyczące przebiegu działań użytkownika np. - na serwerze. W przypadku serwera Apache takie logi dostarczają informację o użytkowniku oglądającym Twoją stronę (wchodzącym na serwer HTTP ) jak np. adres IP , przeglądarkę, czas wizyty itp. Podstawowym pytaniem jest: do czego tak właściwie służą logi?

Podstawową kwestią jest kwestia bezpieczeństwa. W razie próby włamania na serwer, administrator ma możliwość zlokalizowania adresu IP z którego korzystał włamywacz i jeżeli jest to możliwe (czyt. jeżeli włamywacz takie informacje po sobie zostawił) - zgłosić przestępstwo do odpowiednich organów. Drugą kwestią są statystyki które dostarczają informacji na temat ilości wizyt, wywołań itp. Takie statystyki są właśnie sporządzane na podstawie logów serwera. Pomijam tu oczywiście takie darmowe systemy statystyk jak np. STAT4U, które jednak nie są tak wiarygodne jak statystyki na podstawie logów.

Logi to w rzeczywistości plik tekstowy (najczęściej z rozszerzeniem *.log), którego każda linia stanowi osobne wywołanie. Istnieją także logi, w których zapisane są błędy spowodowane przez aplikację (najczęściej nazwa takiego pliku to error.log). Dzięki temu np. autorzy owej aplikacji oraz administrator mają większe szanse na zlokalizowanie przyczyny.

Budowanie systemu logów


Większość providerów nie udostępnia logów do wglądu dla użytkownika (klienta). Jedną przyczyną jest to, że takie pliki tekstowe zajmują wiele miejsca (szczególnie przy popularniejszych serwisach) i najczęściej są kasowane po pewnym okresie czasu (np. tygodniu). Tematem tego artykułu jest zbudowanie własnego systemu logowania w PHP. Oczywiście nie będzie on tak wiarygodny i dokładny jak ten z Apache'a lecz może być jako takim "zabezpieczeniem" w razie jakiś ataków, próby spamu (np. na forach dyskusyjnych) itp. Co będzie Ci potrzebne? Zakładam, że Twój serwis WWW działa w oparciu o technologię PHP. Podczas budowania serwisów dynamicznych najlepiej mieć jakiś centralny, główny plik, w którym znajdują się najczęściej używane funkcje - np. plik functions.php. Może on np. wyglądać tak:

<?php

/* przykładowo - dołączenie do naszego pliku "głównego" innych modułów */
include 'config.inc';
include 'include/plik.php';

?>


Teraz każdy inny plik PHP w serwisie powinien dołączać, właśnie - plik functions.php. Przykładowo jeżeli posiadasz skrypt do rejestracji użytkownika (nazwijmy go newuser.php) to powinien on wyglądać tak:

<?php

include 'functions.php'; // dołączenie "głównego modułu"

/* dalsza część skryptu */
?>


Czemu o tym mówię? Otóż nasz skrypt prowadzący dziennik musi być wywoływany za każdym razem, gdy użytkownik wejdzie na stronę. Umieszczając kod takiego skryptu w pliku functions.php mamy pewność, że będzie on wykonywany za każdym razem.

Założenia


Należy sobie zadać pytanie: jakie informację od użytkownika ma zbierać nasz skrypt? Powiedzmy, że ma to być:


  •  
  • IP użytkownika
     
  • czas wywołania strony
     
  • IP wewnętrzny użytkownika
     
  • host użytkownika
     
  • URL jaki użytkownik odwiedził
     
  • nazwę przeglądarki z jakiej korzystał użytkownik
     
  • ID użytkownika 1


Wszystkie dane będą gromadzone w pliku acccess.log, który zostanie utworzony na serwerze; dane będą zapisywane w takiej postaci:

80.51.77.0 ( 10.1.1.153 ), ID: 0 piotrkow1.zzz.pl - [10-11-2003 18:31:42] /java/index.html
  

Pierwszy człon zawiera IP zew.; w nawiasie znajduje się IP wew. dalej ID użytkownika, jego host, data wystąpienia zdarzenia oraz plik, jaki próbował odczytać - w tym wypadku /java/index.html. Oczywiście to tylko przykład - celowo pomiąłem tutaj informację, np. na temat przeglądarki.

Kod źródłowy skryptu


<?php
/****************************************************************************
*                                log.php
*                         -------------------------
*                      rozpoczety    : 28.07.2003 r.
*                      wersja        : $Revision: 1.1 $
*                      zmiana        : $Date: 2003/07/28 11:12:09 $
*
****************************************************************************/


  $log_dir = '/sciezka_na_serwerze/do_naszego_serwisu';

  // proba otwarcie pliku access.log lub - w przypadku gdy zrodlowy nie istnieje - utworzenia go
  $file = @fopen($log_dir . '/access.log', 'a');
  @flock($file, 2); // blokowanie pliku - wylacznosc na zapis i odczyt
 
  $string = '%remote_ip% ( %forwarded_for% ), ID: %user% %host% - [%time%] %url%'; // z konfiguracji odczytanie formatu zapisu logu
 
  $string = str_replace('%remote_ip%', getenv('REMOTE_ADDR'), $string);
  $string = str_replace('%host%', gethostbyaddr(getenv('REMOTE_ADDR')), $string);
  $string = str_replace('%forwarded_for%', getenv('HTTP_X_FORWARDED_FOR'), $string);
  $string = str_replace('%time%', date('d-m-Y H:i:s'), $string);
  $string = str_replace('%url%', getenv('REQUEST_URI'), $string);
  $string = str_replace('%user%', (isset($cookie) ? $cookie['id'] : 0), $string); // te linie możesz usunąć - obowiązuje jedynie w projekcie Coyote
  $string = str_replace('%user_agent%', getenv('HTTP_USER_AGENT'), $string);

/* poczwszy od wersji 4.0.1 funkcja str_replace() moze przybierac wartosci ktore sa tablica */
 
  @fwrite($file, $string . "n"); // zapisanie linii
  @flock($file, 3); // odblokowanie pliku
  @fclose($file);
 
// $Id: log.php,v 1.1 2003/07/28 11:12:09 Adam Exp $

?>


Powyższy fragment kodu pochodzi z projektu OpenSource o nazwie Coyote który obsługuje serwis 4programmers.net
Ważnym fragmentem tego skryptu jest zmienna $string do której przypisywany jest tekst - tzw. format logu. Miejsce rozpoczynające się
i kończące znakiem % zostanie zastąpione odpowiednimi wartościami (danymi na temat użytkownika) za pomocą funkcji str_replace. Oczywiście format
logu (zmienna $string) możesz ustalać sam wedle własnego uznania. Jeżeli potrzebujesz jedynie IP użytkownika oraz nazwy przeglądarki z jakiej korzystał,
możesz napisać tak:

$string = '%remote_ip% %user_agent%';


Nie zapomnij do zmiennej $log_dir przypisać ścieżki, gdzie ma zostać zapisany plik access.log. To praktycznie wszystko. Cała budowa skryptu jest bardzo prosta.
Za każdym razem gdy skrypt jest wywoływany otwierany zosaje plik access.log i zostaje dopisana do niego kolejna linia. Znak @ przed instrukcjami PHP
gwarantuje to, iż nawet w razie wystąpienia błędu, użytkownik tego nie odczytuje.

Dołączenie skryptu


Powyżej przedstawiłem całą zawartość skryptu, skopiuj ten tekst i zapisz do pliku - np. log.php, a następnie umieść owy plik na serwerze. Następnie otwórz
plik functions.php i dopisz do niego linię:

include 'log.php';


Dzięki temu do skryptu functions.php dodana zostanie zawartość pliku log.php, który dokona zapisu w dzienniku.

Kwestie bezpieczeństwa



Jeżeli nasz plik - access.log jest zapisany w katalogu do którego ma dostęp serwer, niesie to za sobą pewne niebezpieczeństwo, iż zwykły użytkownik znając
lokalizację pliku access.log będzie mógł zobaczyć nasz dziennik, zobaczyć wszystkie adresy IP itp. Dlatego możemy w sprytny sposób zablokować możliwość
podglądu pliku access.log z poziomu przeglądarki (do pliku wgląd będziesz miał jedynie Ty poprzez program FTP lub shella ).
Wystarczy, iż Twój Apache obsługuje pliki .htaccess (kropka na początku). W takim wypadku możesz na serwerze, w katalogu, gdzie znajduje się
plik access.log umieścić plik .htaccess z następującą zawartością:

<FilesMatch "access.log">
deny from all
allow from ...
</FilesMatch>


404


404 oznacza błąd jaki zostaje zwracany przez serwer, w przypadku, gdy plik, który próbuje wczytać użytkownik - nie istnieje. Na wielu serwerach istnieje
możliwość wyświetlania w takim wypadku własnego komunikatu. Wystarczy możliwość obsłużenia plików .htaccess, który powinien mieć taką zawartość:

ErrorDocument 404 /404.php


Dzięki temu w razie wystąpienia błędu 404, zostanie wczytany plik 404.php. Dlaczego o tym piszę? Otóż dzięki temu w naszych logach można
umieścić także informację o niedzaiałających plikach. Wystarczy, że plik 404.php będzie miał taką zawartość:

<?php
// plik 404.php
include 'functions.php';
echo 'Taki plik nie istnieje';
?>


Dzięki temu oprócz wyświetlenia standardowego komunikatu, w logach zostanie odnotowana próba załadowania pliku, który nie istnieje.

Czyszczenie logu


Wiadomo - z dnia na dzień plik logu zajmuje coraz więcej miejsca na serwerze. Warto więc czyścić go co jakiś czas (ew. kopię zapisywać na np. miesiąc na innych partycji). Aby zbytnio się nie przemęczać, warto może pomyśleć o programowanie cron, który w środowisku UNIX służy do okresowego uruchamiania. Hmm... może niezbyt wyraźnie się wyraziłem. Dzięki tej aplikacji można zaprogramować czasowe uruchamianie swojego np. skryptu - raz w tygodniu. Program cron "budzi się" co 1 min. i czyta pliki konfiguracji. Tak więc możesz zaplanować uruchamianie jakiś poleceń co minutę, co 5 min., raz w tygodniu, raz w miesiącu, w określone dni tygodnia, albo nawet raz w roku. Uwaga! To czy posiadasz dostęp do crona, zależy od Twojego administratora. W każdym razie wymagane będzie posiadanie na serwerze konta shell.

W naszym przykładzie posłużymy się skryptem napisanym w Perlu , który będzie czyścił zawartość naszego dziennika. Taki skrypt należy umieścić na serwerze - najlepiej w miejscu do którego nie ma dostęp Apache. Przykładowo u mnie na serwerze pliki, do których ma dostęp Apache, nalezy umieszczać w katalogu 'public_html'. Tak więc taki skrypcik można umieścić katalog wyżej w stosunku do 'public_html'. Dzięki temu użytkownik nie mający dostęp do Twojego konta shell nie będzie w stanie uruchomic tego skryptu.

Skrypt powinien wyglądać mniej więcej tak:

#!/usr/bin/perl

  $url = 'public_html';


  open (FILE_HANDLE, '&gt;' . $url . '/access.log');
  close (FILE_HANDLE);

# $Id: empty.pl,v 1.1 2003/07/29 16:23:54 Adam Exp $
 


Skrypt ma prostą budowę - jego zadaniem jest otwieranie pliku access.log z parametrem '&gt;', który powoduje czyszczenie pliku.

Nie zapomnij w zmiennej $url przypisać prawidłowej ścieżki (nazwy katalogu), w którym znajduje się plik access.log.

Teraz należy ustawić odpowiednie parametry crona. Zaloguj się na swoje konto i w konsoli wpisz polecenie:

crontab -e
Jeżeli uruchomi się domyślny edytor to znaczy, że wszystko jest ok. W edytorze tym wpisz taką linię:


01 0 * * 0 (cd /home/sciezka_do_serwera; perl empty.pl)


Taka instrukcja spowoduje przejście do katalogu /home/sciezka_do_serwera oraz uruchomienie skryptu Perla - empty.pl, który wyczyści plik access.log. Cała ta operacja zostanie wykonana o 1.00 rano w niedziele.

Uwaga!  Pamiętaj aby skryptowi Perla nadać prawa wykonywania - 0775.  

Więcej informacji na temat crontab'a możesz znaleźć w pomocy systemowej - polecenie man crontab.
Dodatkowe linki:

  •  
  • http://httpd.apache.org


    1 w tym przykładzie ID użytkownika odnosi się do projektu Coyote i do serwisu 4programmers.net, gdzie ID zarejestrowanego użytkownika znajduje się w cookie .


Źródło: 4programmers.net. Treść udostępniona na zasadach licencji Creative Commons Attribution

 

Autor: 4programmers.net

Licencja: Creative Commons - bez utworów zależnych