Thursday 13 October 2016

Cookies in PHP

Introduction to Cookies

Cookies are one of the most widely misunderstood concepts of Internet surfing to both users and developers. Many people think that cookies are dangerous, insecure 'things' that let people get your credit card details and what not. This is, for most cases, completely untrue. To the experienced web developer, cookies present a medium for allowing quicker and more user friendly access to your website.

Cookies are simply files stored in a special temporary location determined by your web browser (like Internet Explorer) which allow public information to be stored for your benefit usually. By public information, this can entail any information that you have entered into forms on websites, or certain non-identifying information such as your IP address or user agent.

What makes cookies so special is that, sites can set cookies holding your username and password so that you don't have to log in again. Or perhaps they will store your email address and favourite colour so that a website can change its colour so that it is more appealing to you. Most importantly though, is that other websites and people cannot access your cookies, hence making them fairly secure.

Having a secure method to store user information doesn't mean that you can store anything in cookies though. It is widely accepted that you never store a user's credit card number in a cookie, or a password that will give access to a highly secure area (such as online banking). For areas that require less security like forums, web-mail and unimportant user accounts, it is acceptable to store passwords in encrypted form. The topic of encrypting passwords will be discussed later.


How to Set Cookies


PHP has a very handy function for us called setcookie(), which does exactly as it says; sets a cookie. The function contains many different parameters, of which almost all are optional, however, a majority are quite important.

bool setcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure]]]]] )


This function definition shows us that only the name parameter is actually required, however, to do anything useful, we will be using value, expire and sometimes path and domain.

When you set a cookie, you must give it a name and you should give it a value, unless you are removing it. Cookies are also generally set to expire at a certain time (measured in seconds from 1972). This means, after a certain amount of time, a cookie will be deleted and the information lost. This is a means to remove redundant information from your system and to keep everything up to date. A cookie also has to be set for a particular domain and path. This means you can set cookies to only work in certain directories or sub-domains which can provide added security.

We will now create a very simple example of cookie usage. This is one of the most common methods of using cookies, so this should be quite useful.

First Cookie
<?php
$username 
'jonny4';

setcookie('username'$username);
?>


What we do here, is set a cookie called username containing the username jonny4. Now this cookie will exist in the domain and folder that the script is run in. So we are going to assume you run this script in www.example.com. If you wanted to access it from admin.example.com it would not work, and you will find that the cookie does not exist. However, it is possible to access the cookie from www.example.com/test/cookies/ as this is still in the correct domain.

As this cookie does not have an expiry time, then the cookie will be deleted once the user closes their browser. This can be very useful for keeping a user logged in for an indefinite amount of time, however, as soon as they close their browser (hence, have left the site), the cookie is removed.

There are two very important things to abide by when using cookies. Firstly, there are can be no HTML, text or white-space output before calling the setcookie() function. This is due to a 'protocol restriction' and you will find that header() and session_start() functions must also follow this rule.
The second rule that you must follow, is that cookie will not become available until the next page has loaded. So you cannot set a cookie, and then immediately access it. You must always first refresh or go to another page to get access to the cookie. This is usually a source of many beginner errors when using cookies, but it is simple to follow.

Accessing the Cookie


Naturally you will want to access the cookie that you have set. With PHP, this is extremely easy and intuitive. Assuming that we have used the above code to set the cookie, and we are now on a new page, we can access the data as follows:

Access the cookie data
<?php

/* Prints the value stored in the username cookie */
echo $_COOKIE['username'];

?>


This code uses the $_COOKIE superglobal to access any cookies set in the current domain. If we were to run this script, it would output jonny4.

It is essential to note that you cannot modify the $_COOKIE superglobal and expect it to update the value in the cookie. If you want to update the cookie, you must manually do it again using setcookie(), again remembering that there can be no output before calling this function.


Practical Cookies : User Logon

To give a more detailed look into how to use cookies, I am going to show you how to create a little login form so that you can store the username and password in a cookie. We will use more complicated cookies now so that you can learn the full use of setcookie().

<html>
<head>
<title>User Logon</title>
</head>
<body>
  <h2>User Login </h2>
  <form name="login" method="post" action="login.php">
   Username: <input type="text" name="username"><br>
   Password: <input type="password" name="password"><br>
   Remember Me: <input type="checkbox" name="rememberme" value="1"><br>
   <input type="submit" name="submit" value="Login!">
  </form>
</body>
</html>


This is the code for our login form, which will produce the following (CSS excluded):



Now that we have our form, we will create our login script. We must decide what restrictions we are going to place on the cookie. I have decided that this will only run on the www.example.com domain and in the /account directory only. Hence,

Login Code
<?php
/* These are our valid username and passwords */
$user 'jonny4';
$pass 'delafoo';

if (isset(
$_POST['username']) && isset($_POST['password')) {
   
    if ((
$_POST['username'] == $user) && ($_POST['password'] == $pass)) {   
       
        if (isset(
$_POST['rememberme'])) {
            
/* Set cookie to last 1 year */
            
setcookie('username'$_POST['username'], time()+60*60*24*365'/account''www.example.com');
            
setcookie('password'md5($_POST['password']), time()+60*60*24*365'/account''www.example.com');
       
        } else {
            
/* Cookie expires when browser closes */
            
setcookie('username'$_POST['username'], false'/account''www.example.com');
            
setcookie('password'md5($_POST['password']), false'/account''www.example.com');
        }
        
header('Location: index.php');
       
    } else {
        echo 
'Username/Password Invalid';
    }
   
} else {
    echo 
'You must supply a username and password.';
}
?>


This code is fairly simple if you break it into parts. First, we have our valid username and password defined so that we can check if the user has entered the correct values. We then check if the user has actually submitted the form and the required values using isset($_POST['username']). If they haven't, a nice error message is displayed.

We then do the important check of if the entered values are equal to the preset username and password. If they aren't we display an error message, however, if they are, the cookie will be set. As you can see we set the cookie using two different methods. If the user has checked the Remember Me box, then the cookie is set to expire at the time of time()+60*60*24*365 which is equal to one years time. The time() function returns the seconds since the start of Unix operating system (1972).

We have used the domain and path parameters of setcookie() to restrict the domain to www.example.com/account as we have specified. If the user has not checked the Remember Me box, then the cookie does not have an expiry time (we have set it to false), hence it will be deleted when the user closes their browser.

You should have also noticed how we have set the password cookie. Instead of just saving the password to a cookie, we have encrypted or hashed it using the md5() function. This function hashes a string so that the original data cannot be recovered. This increases the security of storing the password, but doesn't make it much more difficult for us to deal with.

This script also utilises the header() function to redirect to the index.php page once the cookie has been set. It is important to note that this function can't have any HTML output before calling it, the same as setcookie(). Note: If you are using IIS and not Apache, then you have to use a HTML redirect (META tags) as header() will not work.


Accessing the Data


We currently have a form which submits a username and password, and a login script which sets the cookie on the user's machine. Now we need to access this data, so that it can be used. We are going to access it so that we can validate that the user viewing index.php has actually logged in.

Validating
<?php
/* These are our valid username and passwords */
$user 'jonny4';
$pass 'delafoo';

if (isset(
$_COOKIE[['username']) && isset($_COOKIE['password')) {
   
    if ((
$_POST['username'] != $user) || ($_POST['password'] != md5($pass))) {   
        
header('Location: login.html');
    } else {
        echo 
'Welcome back ' $_COOKIE['username'];
    }
   
} else {
    
header('Location: login.html');
}
?>


In this script, we just check that the cookie exists and is valid. If they aren't, then the user is redirected back to the login form. Otherwise a welcome message is included. The only important thing to notice is how we have validated the password. Before on the login.php script, we have encrypted our password using md5() and as this encryption cannot be undone, we must compare encrypted versions. Hence, we encrypt our preset value and compare it to the already hashed cookie value. This way, there is no chance of the original password becoming available.

Deleting Cookies

Cookies as very picky about how they are deleted and usually require that they be removed, using the same values as they were set with. Hence, if we have a domain or path specified, then we must specify this domain/path when deleting the cookie.

To delete a cookie, you simply set the value of the cookie to null, and also set the expiring time of the cookie in the past. Ideally, one would set the expiry time to about a year in the past, so that if the system time is off by a few minutes or days even, then the cookie will still delete correctly.

Let's dive right in:

<?php

setcookie
('username'''time()-60*60*24*365);

?>


The above script would delete a cookie called username that was in the domain and path that the script is run in. Notice how to expiry time has been set to a year in the past. This will ensure correct deletion of the cookie.

User Logout


Going back to our user logon system, we can now create a very simple logout script. This will mean, that the user will have to re-login on the next access attempt to index.php, even if the Remember Me option was set.

Logout
<?php

setcookie
('username'''time()-60*60*24*365'/account''www.example.com');
setcookie('password'''time()-60*60*24*365'/account''www.example.com');

header('Location: login.html');

?>


See how simple that was? All we had to do, is use the setcookie() function in the same way as before, except setting the value to being empty and the expiry in the past. It is important to set the path and domain otherwise there is a large chance that the cookie will not be deleted.

After our cookies are deleted, the script will redirect back to the login form so that the user can login again. Previously I had mentioned that IIS will not set cookies properly if the header() function is used to redirect. Here is how we could get around this problem:

<?php

setcookie
('username'''time()-60*60*24*365'/account''www.example.com');
setcookie('password'''time()-60*60*24*365'/account''www.example.com');

?>

<html>
<head>
<meta http-equiv="refresh" content="0;URL=login.html">
</head>
<body>
Redirecting...
</body>
</html>


All that we have done is use the meta refresh HTML tag to do the redirect. Using this method, IIS will work perfectly. So, if you are on a IIS server, then I recommend you replace all the previous header() redirects with this HTML code, replacing the page to be redirected to, to the page needed.

This is all there is to cookies for the majority of thinkable uses. They should provide a mechanism in increasing your sites usability and making it easier for you to manage users.

0 comments:

Post a Comment