Sonda w PHP
Na wielu stronach można znaleźć sondę. Autorzy pytają się o różne rzeczy, od oceny wyglądu strony po wojnę w Iraku (jeszcze :-/ ). W polskim Internecie istnieje kilka serwisów, które pozwalają na wstawienie na stronę prostych sond. Coraz więcej jednak serwisów udostępnia na własnych serwerach języki server-side, a w szczególności PHP. Poniżej postaram się zaprezentować prostą sondę napisaną w PHP.
Zaczynamy
Na samym początku należy stworzyć na stronie formularz z pytaniem i odpowiedziami. Na przykład:
<form action="glosuj.php" method="post"> <p>Co sądzisz o gotowanej marchewce?<br /> <input type="radio" name="glos" value="1" />Uwielbiam<br /> <input type="radio" name="glos" value="2" />Nienawidzę<br /> <input type="submit" value="Zagłosuj" /> </p> </form>
Tak stworzony formularz prześle skryptowi glosuj.php informację, którą odpowiedź zaznaczył użytkownik. Ta informacja zostanie wysłana przy pomocy metody post, czyli dane nie pojawią się w adresie (co praktycznie uniemożliwia podsyłanie specjalnie spreparowanego linku innym osobom, żeby zagłosowały bez znajomości pytania), ale w nagłówkach wysyłanych przez przeglądarkę do serwera. W formularzu znajdują się dwa elementy typu radio, czyli pola, z których zaznaczone może być tylko jedno. Jednak aby przeglądarka wiedziała, że należą one do jednego "pytania" i nie mogą być oba zaznaczone w jednym momencie, trzeba tym elementom nadać identyczny atrybut name. Wartość, na podstawie której skrypt będzie rozpoznawał odpowiedź to zawartość atrybutu value, czyli "1" dla entuzjastów i "2" przeciwników gotowanej marchewki. Ostatnim bardzo ważnym elementem, jest przycisk wysyłający, czyli element submit, bez którego nie możliwe jest zgłoszenie wyników. Zawartość atrybutu value tego elementu to tekst, który pojawi się na przycisku.
Zapisywanie głosów
Na początku musimy zdecydować o sposobie przechowywania wyników sondy. Najlepiej zapisywać dane w pliku tekstowym (lub w bazie danych, ale bazy danych nie są jeszcze zbyt popularne). Dość prostym formatem jest plik tekstowy zawierający na przykład taką zawartość:
32:42:
Taki sposób zapisu umożliwia łatwe rozdzielenie danych. Załóżmy, że pierwsza liczba to ilość głosów za marchewką, a druga liczba, to ilość głosów przeciw marchewce. Żeby rozdzielić te dane wystarczy użyć funkcji split(). Ale o tym później.
Na początku stwórzmy taki plik, ale zawierający zera zamiast liczb z przykładu. Dwukropek na końcu ubezpiecza przed odczytaniem znaku końca linii. Nadajmy plikowi nazwę na przykład wyniki.txt. Należy również się upewnić, że skrypty będą miały prawo do zapisu i odczytu! Czyli w systemach uniksowych musi mieć prawa 666. Prawa do wykonywania (777) nie są potrzebne.
Teraz należy zająć się skryptem. Na początku skrypt musi odczytać poprzedni stan, potem rozpoznać jaki głos został przed chwilą oddany, dodać do odpowiedniej wartości i zapisać plik ponownie.
<?php
/*Początek interpretowanego bloku */
$plik = fopen("wyniki.txt", "r");
/*otwarcie do odczytu pliku z wynikami*/
$dane = fread($plik, filesize("wyniki.txt"));
/*odczytanie z pliku z wynikami danych i zapisanie ich do
zmiennej $dane odczytanych zostanie tylko tyle znaków ile
istnieje w pliku, nie mniej, nie więcej*/
$wyniki = split(":", $dane);
/*wydzielenie dwóch wyników, rozdzielenie zawartości zmiennej
po znaku dwukropka*/
fclose($plik);
/*zamknięcie pliku*/
if($_POST['glos'] == 1)
$wyniki[0] += 1;
/*jeśli użytkownik głosował "za" marchewką,
czyli zmienna "glos" ma wartość jeden to do
wyników za dopisywany jest jeden głos*/
else if ($_POST['glos'] == 2)
$wyniki[1] += 1;
/*analogiczna operacja do poprzedniej, ale dodawany jest
głos "przeciw"*/
else
;
/*instrukcja dla reszty przypadków, które teoretycznie nie
powinny nastąpić*/
$plik = fopen("wyniki.txt", "w");
/*ponowne otwarcie pliku z wynikami, tym razem do zapisu, plik
jest wyzerowany*/
flock($plik, 2);
/*zablokowanie pliku przed innymi skryptami, które będą chciały
zapisywać*/
fwrite($plik, "$wyniki[0]:$wyniki[1]:", 200);
/*zapis wyników do pliku, 200 znaków z powodzeniem wystarczy*/
flock($plik, 3);
/*zdjęcie blokady z pliku*/
fclose($plik);
/*zamknięcie pliku*/
header("Location: pokaz.php");
/*przekierowanie przeglądarki do pliku pokaz.php*/
?>
/*koniec interpretowanego bloku*/
Ostatnim poleceniem w skrypcie jest przekierowanie przeglądarki do pliku pokaz.php, który będzie wyświetlał dotychczasowe wyniki. Skrypt, który tworzy te wyniki też nie jest zbyt skomplikowany.
<?php
$plik = fopen("wyniki.txt", "r");
/*otwarcie pliku z wynikami do odczytu*/
$dane = fread($plik, filesize("wyniki.txt"));
/*odczytanie wszystkich bajtów z pliku*/
fclose($plik);
/*zamknięcie pliku*/
$wyniki = split(":", $dane);
/*rozdzielenie wyników*/
$suma = $wyniki[0] + $wyniki[1];
/*zsumowanie wyników*/
?>
<table>
<tbody>
<tr><td>Lubiący gotowaną marchewkę:</td><td>
<?php
echo(round($wyniki[0]/$suma * 100));
/*wyświetlenie zaokrąglonej procentowej ilości głosów,
znak procenta jest w następnej linijce*/
?>
%</td><td>
<img src="pasek.gif" alt="pasek.gif"
title="Za marchewką!" height="10" width="
<?php
echo(round($wyniki[0]/$suma * 100));
/*podobnie jak wcześniej, tyle, że wyświetlona liczba będzie
szerokością graficznego paska, w tym wypadku liczba 100 jest
maksymalną szerokością paska */
?>
" /></td></tr>
<tr><td>Nienawidzący gotowanej marchewki:</td><td>
<?php
echo(round($wyniki[1]/$suma * 100));
?>
%</td><td>
<img src="pasek.gif" alt="pasek.gif"
title="Przeciw marchewce!" height="10" width="
<?php
echo(round($wyniki[1]/$suma * 100));
?>
" /></td></tr>
</tbody>
</table>
<p>Ogołem oddano głosów: <?php echo($suma); ?>.</p>
Oczywiście potrzebny jest jeszcze malutki obrazek (np. wysokość - 10 pikseli, a szerokośc - 1 piksel), który będzie służył za pasek procentowy.
Niedogodności
Podstawową niedogodnością przedstawionego wyżej rozwiązania, jest brak jakiegokolwiek mechanizmu zabezpieczającego przed wielokrotnym głosowaniem. Najprostszym i dośc skutecznym sposobem na zapewnienie sobie tej ochrony są ciasteczka (ang. cookies). Są łatwe w użyciu i mają spore możliwości, jednak ochrona przez nie zapewniana nie jest stuprocentowa. Wystarczy jednak do tego, żeby "zwykły śmiertelnik" głosował tylko raz na określony czas. Konieczne są następujące zmiany w pliku glosuj.php:
<?php
if (isset($_COOKIE['mojasonda'])) {
echo("Już głosowałeś!");
/*warunek sprawdza czy istnieje w przeglądarce ciasteczko o nazwie
"mojasonda", jeśli tak to nie pozwala na ponowne oddanie głosu*/
}
else {
/*tutaj dotychczasowa zawartość pliku głosuj.php,
ale bez przekierowania, a za nią... */
setcookie("mojasonda", "glosowalem", time()+ 604800);
/*to polecenie wysyła do przeglądarki ciasteczko o nazwie "mojasonda"
i zawartości "glosowalem", ciasteczko będzie ważne 604800 sekund,
czyli równy tydzień, po tygodniu będzie można znowu glosować*/
header("Location: pokaz.php");
}
?>
Ciasteczko ustrzeże przed zagłosowaniem przez tego samego użytkownika, z tej samej przeglądarki przez tydzień, pod warunkiem, że użytkownik nie wyłączył akceptacji ciasteczek w przegladarce oraz nie usunął ciasteczka.
