V první řadě lze kontrolovat cookie:
<?php
if (isset($_COOKIE["hlasoval"])) {
echo "Váš hlas byl již dříve započten.\n";
} else {
setcookie("hlasoval", $_POST["hlas"], strtotime("+1 month"));
mysql_query("UPDATE anketa_odpovedi SET hlasy = hlasy + 1 WHERE id = '$_POST[hlas]'");
}
?>
Pokud má návštěvník cookies povolené, jedná se asi o nejspolehlivější způsob. Pokud si ale cookies zakáže, je tato kontrola k ničemu. V tom případě je možné kontrolovat ještě IP adresu. Ze dvou důvodů se nevyplatí spoléhat jenom na ni – jednak se adresa jednoho návštěvníka může v čase měnit (často je dynamicky přidělovaná) a jednak může jednu adresu používat víc lidí (při NAT zároveň, u dynamicky přidělovaných adres postupně). Doplňkové pravidlo je tedy vhodné nastavit např. tak, že z jedné IP adresy bude možné poslat pouze jeden hlas za hodinu:
<?php
if (isset($_COOKIE["hlasoval"])) {
echo "Váš hlas byl již dříve započten.\n";
} else {
setcookie("hlasoval", $_POST["hlas"], strtotime("+1 month"));
if (mysql_result(mysql_query("SELECT COUNT(*) FROM anketa_hlasy WHERE ip = '$_SERVER[REMOTE_ADDR]' AND datum + INTERVAL 1 HOUR > NOW()"), 0)) {
echo "Hlas z této adresy byl již dříve započten.\n";
} else {
mysql_query("INSERT INTO anketa_hlasy (hlas, ip, datum) VALUES ('$_POST[hlas]', '$_SERVER[REMOTE_ADDR]', NOW())");
}
}
?>
Pokud provoz prochází přes proxy server, bývá doplněna hlavička X-Forwarded-For a mohlo by nás to svádět, abychom ji kontrolovali. Protože jde ale tato hlavička snadno podvrhnout, nevyplatí se na ni spoléhat a je možné ji použít jen jako doplněk, např. takto:
- Pokud je přítomna cookie, hlas nezapočíst.
- Pokud z této kombinace IP adresa + X-Forwarded-For bylo již tuto hodinu hlasováno, hlas nezapočíst.
- Pokud již z této IP adresy v uplynulé hodině přišlo alespoň 5 hlasů, hlas nezapočíst.
<?php
if (isset($_COOKIE["hlasoval"])) {
echo "Váš hlas byl již dříve započten.\n";
} else {
setcookie("hlasoval", $_POST["hlas"], strtotime("+1 month"));
$forwarded_for = addslashes(preg_replace('~.*,\\s*~', '', $_SERVER["HTTP_X_FORWARDED_FOR"]));
if (mysql_result(mysql_query("SELECT COUNT(*) FROM anketa_hlasy WHERE ip = '$_SERVER[REMOTE_ADDR]' AND forwarded_for = '$forwarded_for' AND datum + INTERVAL 1 HOUR > NOW()"), 0)
|| mysql_result(mysql_query("SELECT COUNT(*) FROM anketa_hlasy WHERE ip = '$_SERVER[REMOTE_ADDR]' AND datum + INTERVAL 1 HOUR > NOW()"), 0) >= 5) {
echo "Hlas z této adresy byl již dříve započten.\n";
} else {
mysql_query("INSERT INTO anketa_hlasy (hlas, ip, forwarded_for, datum) VALUES ('$_POST[hlas]', '$_SERVER[REMOTE_ADDR]', '$forwarded_for', NOW())");
}
}
?>
Takto nastavená ochrana je již poměrně spolehlivá a v omezené míře je zranitelná pouze u lidí, kterým se mění IP adresa. U obvyklých kontrol jde ale hlavně o to možnost opakovaného provádění akce co nejvíc znepříjemnit. Pokud uživatel může s vyvinutím nemalého úsilí provést akci párkrát navíc, nejedná se o velký problém.