Our ability to enter the poll as many times as we want has been very useful while testing, but it makes it trivial for anyone to skew our poll to whichever answer they want. All they have to do is keep hitting “reload”, or write a script of their own to keep reloading the page.
We can use “cookies” to keep track of individual visitors. PHP can handle this tracking for us almost automatically.
At the top of our page, below $pollchoices, add:
session_start();
IF ($existingchoice = $_SESSION["choice"]):
$alreadychose = true;
ELSE:
$alreadychose = false;
ENDIF;
This starts a session. When you start a session in PHP, PHP automatically checks to see if there is already an existing session on the client. You can store data in the session, using $_SESSION. So here, after we start the session, we check to see if the session data already includes a choice having been made. If it is, we set our container $alreadychose to true. Otherwise, we set it to false. We’ll use this later to display either the form or the thanks for voting message.
Change the line that says:
IF ($choice = $_POST["imagine"]):
to
IF (!$alreadychose && $choice = $_POST["imagine"]):
//make sure that they sent us a valid choice
IF ($pollchoices[$choice]):
//yes, this choice exists
$_SESSION["choice"] = $choice;
$alreadychose = true;
$existingchoice = $choice;
So far we have only checked one thing to see if we should use the PHP inside our “if” areas. Here we are checking two things: first, have they already chosen? The exclamation point reverses that check, so what we’re checking is if they have not already chosen. Then, if they have not already chosen, we check to see if they have just made a choice. If so, we add that choice to their session. We also have to set $alreadychose and $existingchoice here, so that we thank them rather than show them the form again--remember that they don’t get the cookie until we give it to them, and since we only just now gave it to them, $alreadychose and $existingchoice are still blank. We have to set them here.
We now can remember if they have made a choice and what the choice was. Anything we put into $_SESSION will be remembered whenever they return to our page. We aren’t going to do it now, but you might remember the last time they visited, for example.
In front of the <form...> line, add:
<?IF ($alreadychose):?>
<p>Thanks for voting for <?echo $pollchoices[$existingchoice]?>!</p>
<?ELSE:?>
And, after the </form> line, add:
<?ENDIF?>
When you try to load this page now, you might see something like:
Warning : session_start() [ function.session-start ]: Cannot send session cache limiter - headers already sent (output started at /home/jerry/public_html/php/poll.php:2) in /home/jerry/public_html/php/poll.php on line 4
This means that you did not put the PHP code at the very top of your web page. Cookies are not part of your web page’s document area. They are part of the “headers” that you rarely see as a user. The headers must be sent before the document is sent. Once you start sending the document, even if it is just a space or a carriage return, you can no longer send any headers. Make sure that the “<?” that starts your PHP code is at the very top of your file.
It’s still pretty easy to “beat” our poll. All anyone has to do is turn off cookies in their browser. If they turn off cookies, they’ll never send the cookie back to us, and we’ll never know that they were already here. You can go ahead and check that right now: find our cookie in your web browser’s preferences, delete it, and you can vote once again.
Sessions are based on cookies. Cookies are fully under the control of the browser. No matter how much you try to secure your application from cookie manipulation, you cannot win. You cannot rely on cookies being kept.
There are a number of issues with cookies besides that as well. Our poll above will not let anyone vote who uses the same computer as someone who has already voted.