Reklama

Stat4u

Stat4u

Prosty licznik w PHP i MySQL

Wiemy już jak stworzyć prosty licznik, odporny na przeładowania, który swoje dane gromadzi w pliku tekstowym. Najwyższa pora na stworzenie podobnego licznika, który swoje dane gromadzi w bazie danych.

Stworzenie pojedynczej tabeli tylko z jednym rekordem, w którym zapisana jest wartość licznika jest bezsensowne. Czy nie lepiej mieć w bazie danych informację na temat odwiedzin z każdego dnia oddzielnie i dopiero na podstawie tych danych wyliczać wartość licznika? Brzmi skomplikowanie, prawda? Ale takie rozwiązanie jest tylko trochę bardziej czasochłonne w wykonaniu niż rozwiązanie z jednym rekordem gromadzącym wszystko. Dodatkową zaletą takiego rozwiązania jest możliwość poznania sposobów na realizację niektórych czynności przez SQL, a nie przez PHP.

Struktura tabeli

Struktura wymaganej tabeli powinna być prosta. Powinniśmy móc w niej zapisać datę i ilość odwiedzin tego dnia. Do zapisu daty możemy swobodnie wykorzystać typ date, który ułatwi nam również późniejsze operacje na bazie. Wartość licznika to oczywiście liczba całkowita, więc najrozsądniejszym wyborem będzie tutaj typ int.

Pełne zapytanie SQL tworzące tabelę wygląda tak:

create table `licznik` (
  `data` date not null default '0000-00-00',
  `licznik` int(11) not null default '1',
);

Zostanie utworzona tabela o nazwie licznik, w której będą dwa pola: data oraz licznik. Oba pola nie mogą być puste (NULL), więc dla każdego ustawiana jest domyślna wartość (default).

Wartością domyślną, która ustawiana jest w chwili tworzenia rekordu, dla pola licznik jest jeden. Dzięki temu, po stworzeniu nowego rekordu (co będzie równoznaczne z pierwszym wywołaniem danego dnia) nie trzeba już wywoływać kolejnego zapytania, które zwiększa wartość licznika.

Zliczanie

Liczenie odwiedzin nie powinno następować za każdym razem, kiedy otwierana jest jakakolwiek podstrona, ale tylko wtedy gdy osoba, która odwiedza naszą stronę robi to po raz pierwszy (od jakiegoś czasu). Dlatego konieczne jest zastosowanie jakiegoś prostego mechanizmu zabezpieczającego przed przeładowaniem. Najwygodniejszy tutaj jest tandem: ciasteczka i adres referencyjny.

Samo dodawanie wartości do licznika jest, można powiedzieć, banalne. Wszystko dzięki możliwościom języka SQL. Najlepiej wykorzystać tutaj rekurencję w zapytaniach oraz funkcję MySQL curdate(), która generuję aktualną datę w formacie akceptowanym przez typ date.

W przypadku, gdy odwiedzający jest pierwszą osobą wywołującą stronę danego dnia, należy utworzyć nowy rekord w tabeli. W przypadku jego braku baza zgłosi błąd po próbie wykonania zapytania dopisującego. Ale to zachowanie można wykorzystać. Jeśli baza zgłosi błąd to wtedy można wywołać zapytanie tworzące nowy rekord. Oczywiście należy tutaj założyć, że nie wystąpią inne błędy. Inkrementować wartości już nie trzeba, ponieważ wartość domyślna to jeden. Ponieważ znamy strukturę tabeli (i wiemy, że nie będziemy jej zmieniać), można skorzystać z uproszczonej wersji zapytania insert.

Kod

Najwyższa pora na napisanie kodu. Na początek należy sprawdzić, czy to jest pierwsze wejście użytkownika. Następnie wykonujemy próbę zwiększenia wartości licznika, jeśli to się nie uda, a założyliśmy, że nie występują nieznane błędy, to dodajemy nowy rekord.

<?php
	$baza = @mysql_connect("serwer", "uzytkownik", "haslo");
	if($baza) {
		mysql_select_db("baza");
		if((!isset($_COOKIE['licznikowe-ciacho'])) && (!strstr($_SERVER['HTTP_REFERER'], "strona.pl"))) {
			setcookie("licznikowe-ciacho", "zliczono", 0);
			$sql = "update `licznik` set `licznik` = `licznik` + 1 where `data` = curdate()";
			if(!mysql_query($sql)) {
				$sql = "insert into `licznik` values(curdate(), '')";
				mysql_query($sql);
			}

		}
	}
?>

Proste. Na początku należy połączyć się z serwerem baz danych. Wykonujemy to przy pomocy funkcji mysql_connect. Znak at (@) na początku powoduje, że w razie niepowodzenia, na stronie nie pojawi się małoestetyczny komunikat błędu. Jeśli udało się połączyć z serwerem, to należy wybrać bazę (mysql_select_db). Następnie należy sprawdzić czy użytkownik dopiero co wszedł na stronę. Sprawdzamy czy przeglądarka użytkownika ma ustawione nasze ciasteczko oraz czy użytkownik, nie przeszedł z jakiejś podstrony naszego serwisu (adres referencyjny). Jeśli oba warunki nie będą spełnione, to można przystąpić do liczenia i ustawić odpowiednie ciasteczko. Z powodu tego ciasteczka należy kod umieścić na początku całej strony, w miejscu w którym jeszcze nic nie zostało wysłane do przeglądarki poza nagłówkami.

Zapytanie jest proste. Inkrementujemy (zwiększamy o jeden) wartość pola licznik w tabeli o takiej samej nazwie, rekordu, w którym pole data zawiera dzisiejszą datę. Inkrementacja wykorzystuje rekurencję. Przypisujemy polu licznik jego aktualną wartość powiększoną o jeden.

Jeśli wykonanie tego zapytania się nie powiedzie, to tworzymy nowy rekord (założyliśmy, że to jest jedyną możliwą przyczyną wystąpienia błędu).

Główny licznik

Poporzedni kod powodował liczenie, ale typowy licznik na stronie internetowej nie tylko liczy, ale również pokazuje aktualnie zliczoną wartość. Liczenie tutaj jest wyjątkowo proste.

<?php
	if($baza) {
		$sql = "select sum(`licznik`) from `licznik`";
		$licznik = mysql_result(mysql_query($sql), 0, 0);
		echo("<p>Jesteś $licznik gościem na stronie.</p>");
	}
?>

W zapytaniu dodajemy wartości pól licznik wszystkich rekordów w tabeli. Do wydobycia tej sumy można wykorzystać funkcję mysql_result(), która jest idealna do takich zapytań, w których jest zwracane tylko jedno pole zamiast całych wierszy.

Inne rozwiązanie problemu nowego dnia

Zamiast tworzenia nowego rekordu w razie niepowodzenia inkrementacji można wcześniej sprawdzić czy rekord dla dzisiejszego dnia istnieje. Proponuję kod:

<?php
	if(mysql_num_rows(mysql_query("select count(*), `data` from `licznik` group by `data` having `data` = curdate()")) != 1) 
		mysql_query("insert into `licznik` values(curdate(), 0)");
?>

Dość skomplikowany, ale działa wyśmienicie. W tym zapytaniu liczymy ilość rekordów, które w polu data mają dzisiejszą datę. Oczywiście pożądaną wartością jest tutaj 1, więc jeśli jest inna (czyli 0), to tworzymy nowy rekord. Ważne jest tutaj żeby ustawić wartość 0 dla pola licznik nowoutworzonego rekordu, tak, żeby jego inkrementacja (wykonywana chwilę później) dała wartość jeden, a nie dwa (ponieważ w tabeli wartością domyślną jest jeden).

Indeksy

Po kilkudziesięciu dniach działania skryptu tabela będzie miała sporo rekordów. Aby przyspieszyć operacje wykonywane w tabeli można przypisać indeksy niektórym polom. W tym przypadku, najlepszym wyjściem jest dodanie indeksu unique dla pola data. Dzięki temu w tabeli nie będą mogły się powtórzyć rekordy z taką samą datą i przeszukiwanie tabeli będzie szybsze. W tym celu należy jednorazowo wykonać zapytanie SQL:

alter table `licznik` add unique (`data`)
© Krzysztof Sawicki