CodingBison

In addition to using cookies, we can also use PHP sessions to store temporary user-information and use it later when the same user revisits the page or when user navigates to some other page that also requires the same information.

However, unlike cookies that are stored at the client, session data is stored at the server. The location where the server stores session data can be specified in the PHP config file ("php.ini") file using the "session.save_path" parameter. From a client's perspective, the client has little control over storage of session data, except for modifying the session values by providing new input.

PHP Session: Getting Started

For sessions to work, each PHP page must call session_start() before doing any session-related task; it is a good idea to keep session_start() at the top of the page.

The function, session_start() is not limited to only those pages that "start" a session and store session variables, but it should also be added to pages that wish to access existing session variables or to add new session variables. The reason for this behavior is that session_start() activates session variables for a given page. On the other hand, if a page does not need any session variables, then it can skip specifying session_start().

For each session, PHP assigns a unique session ID number; we can use session_id() function to retrieve the value of a given session. Further, PHP uses $_SESSION array to hold session variables. Note that $_SESSION is not an alias for $HTTP_SESSION_VARS and PHP handles them as two different variables. In fact, with introduction of $_SESSION, use of $HTTP_SESSION_VARS is now deprecated.

Let us go through a quick demonstration of PHP sessions! This example (provided below) provides a simple login page; we name it "session_form_login.html". We make its action method point to a file ("session_login.php") that creates a new session and stores session data.

 <!doctype html>
 <html> 
 <head> <h3>A Trivial Login Form </h3></head> 
 <body> 

 <form name="input_form" method="POST" action="session_login.php"> 
 <br> Username: <input type="text" name="textUsername">
 <br> Password: <input type="password" name="passwordPassword">
 <br> <input type="submit" name="submitButton" value="Login">
 <br><br><br>Feedback/Comments:<br>
 <textarea name="textareaComments"> We appreciate your comments.  </textarea>
 </form> 

 </body></html>

Next, let us describe the action file ("session_login.php").

The action file starts with session_start() to activate PHP session. Next, it prints $_SESSION to confirm that variables $username and $password do not exist in the global session array. After that, we save both $username and $password variables in the $_SESSION array and then reprints $_SESSION array to verify that these session variables are indeed part of the global session array.

 <?php session_start(); ?>

 <!doctype html>
 <html><body>
 <?php
 echo "Let us print the _SESSION array <br>";
 var_dump($_SESSION);
 $sess_id = session_id();
 echo "<br>Let us print the session id: $sess_id <br>";

 $username = $_POST["textUsername"];
 $password = $_POST["passwordPassword"];
 $comments = $_POST["textareaComments"];
 $_SESSION['username'] = $username;
 $_SESSION['password'] = $password;

 echo "<br>The passed username is: $username <br>";
 echo "The passed password is: $password <br>";
 echo "The passed comments are: $comments <br>";

 echo "<br>After updating the _SESSION array, let us print it again <br>";
 var_dump($_SESSION);

 echo "<br><a href=session_view.php> View your profile </a>";
 ?>
 </body></html>

If we were to login as "user1001" and with password as "password1001" in the "session_form_login.html" page, then here is how the "session_login.php" page would look:



Figure: Action Method: PHP Login page (using Session)

The output confirms that $_SESSION array is NULL before we add any session variables to it.

To show continuity of the session data, we provide a "View your profile" link on "session_login.php" page such that the user can go to a new page (we call it "session_view.php") and see if the session variables are still accessible. With this, the HTML flow includes three different files.

Here is the flow:

 	HTML Form 			  Form Action File 	            Page Link
   --------------------------- 	        -----------------------          ---------------------
   |"session_form_login.html"|  ----->  | "session_login.php" |  ----->  | "session_view.php"|
   --------------------------- 	        -----------------------          ---------------------
 			     Submit the Form.			Click the  
 			    Form data is passed 	    "View your profile"
 			     as $_POST array.

 	Figure: HTML Flow when submitting a Form and viewing user-data using HTML Sessions.  

Let us now describe the last page in the above flow: "session_view.php". To confirm that the current session is persistent, "session_view.php" prints both $_SESSION and the session ID. The main task of this page is to merely print the values of $username and $password!

Once our task is done, we unset all the session variables and destroy the session. If we were to print the $_SESSION array beyond this point, then it would neither show any of these variables nor the earlier session id. Destroying the session also means that if we were to reload this page, then we would see that the $_SESSION array is NULL.

Here is the "session_view.php" file":

 <?php session_start(); ?>

 <!doctype html>
 <html>
 <?php
 echo "Let us print the _SESSION array <br>";
 var_dump($_SESSION);

 $sess_id = session_id();
 echo "<br>Let us print the session id: $sess_id <br>";

 if (isset($_SESSION['username']) and isset($_SESSION['password'])) { 
     $Username = $_SESSION['username'];
     $password = $_SESSION['password'];
     echo "<br>From the session array: <br>"; 
     echo "The passed username is: $username <br>";
     echo "The passed password is: $password <br>";

     unset($_SESSION['username']);
     unset($_SESSION['password']);
     session_destroy();

     echo "<br>After destroying, the session: <br>"; 

     echo "Let us print the _SESSION array <br>";
     var_dump($_SESSION);
 } else {
     echo "<br>The session does not have username/password variables";
 }

 ?>
 </html>

When we click the "View your profile" link on the session_login.php page, then it takes us to session_view.php page with the following output. Please note that the session ID is same on both the pages.



Figure: Form Login

Let us also show the case of reloading the page. Since this page has already destroyed the session, reloading the page would fail to find the session variables. Note that even though we destroy the session, the session id is still the same. To get rid of session id, we need to regenerate it once we have destroyed the session using session_regenerate_id(true).



Figure: Action Method: PHP View page (using Sessions)

Similar to HTML cookies, it is not necessary that we explicitly pass a link from one page to another to use session data! We can randomly navigate from one page to another page and still see the session variables, as long as the pages are from the same server and as long as they start with session_start(). Thus, in the above example, if we were to go to a new page, let us say session_view2.php, instead of session_view.php, even then, all the session variables would still be visible.

Lastly, we should note that an earlier form of registering session variables was to use session_register() instead of the global $_SESSION array; use of this function is now deprecated and we should prefer to use $_SESSION array instead.

PHP Session Timeout

Sometimes, a user can walk away from her (public) computer without logging out or without closing the browser. For such cases, we can use session timeout to detect user-inactivity and thereupon, delete the session data. This is an important security measure, since the session data should not be available when the user has left the workstation; if the data were to fall in wrong hands, then it can potentially compromise user's information.

We describe two methods for providing session timeout.

First Method: Using garbage collection

The first method is to use PHP's inbuilt session-based garbage collection. Setting an appropriate timeout for garbage collection would mean that for cases of inactivity, the garbage collection would automatically clear the session data.

To demonstrate session timeout using these two methods, we begin by modifying the earlier "session_login.php" file.

In the first method, we set the value of garbage collection "session.gc_maxlifetime" parameter (defined in php.ini file) to a smaller value, let us say, 60 seconds. The parameter "session.gc_maxlifetime" represents the time after which garbage collection kicks in and clears the existing sessions. Setting this parameter to a smaller (application-appropriate) timeout means that the garbage collection can happen at the right time and then, it would automatically clear the session data.

Here is the modified "session_login.php" file that sets the value of 'session.gc_maxlifetime' to 60 seconds. We use ini_get() to get the value of initial PHP variables (defined in php.ini config file) and ini_set() to set the value of these variables.

 <?php
 $session_timeout_value = ini_get('session.gc_maxlifetime'); /* stored in seconds */
 $session_timeout_value /= 60; /* Convert into minutes */
 echo "Session timeout value (in minutes) is : $session_timeout_value <br>";

 ini_set('session.gc_maxlifetime', 60); /* make it 1 minute */

 session_start();
 ?>

 <!doctype html>
 <html><body>
 <?php
 $username = $_POST["textUsername"];
 $password = $_POST["passwordPassword"];
 $comments = $_POST["textareaComments"];
 $_SESSION['username'] = $username;
 $_SESSION['password'] = $password;

 echo "<br>The passed username is: $username <br>";
 echo "The passed password is: $password <br>";
 echo "The passed comments are: $comments <br>";

 echo "<br>After updating the _SESSION array, let us print it again <br>";
 var_dump($_SESSION);

 echo "<br><a href=session_update.php> Update your profile </a>";
 ?>
 </body></html>

The output of this page would display the current default value of 'session.gc_maxlifetime' parameter (in our case, 24 minutes). Since we set it to 1 minute, after 1 minute of inactivity, the session should get cleared.

However, there is one catch with this method! PHP also specifies a probability with which garbage collection happens. PHP achieves this by using two additional initial parameters, "session.gc_probability" and "session.gc_divisor". And, the probability that the garbage collection process would be started is calculated using "session.gc_probability/session.gc_divisor". Thus, there is no certainty (since the above probability is not 1.0) that the session would timeout after gc_maxlifetime interval expires and hence, the session may not always expire on the timeout specified!

First Method: Using session timestamp

The second method is to add a timestamp key in the $_SESSION array. We can use this timestamp to detect a period of inactivity. When an activity happens after a long time, then we simply delete the session data.

This method makes session timeout more deterministic as compared to using garbage collection. Here, we add a field "lastTimeStamp" to the $_SESSION array and store the current time in that field. After that, whenever user does anything (e.g. clicking the session_view.php link), then we look at the new current time and check if it is greater than the lastTimeStamp plus the specified timeout value; if it is, then we simply clear the session.

Here is the modified "session_login.php" page that contains the second method:

 <!doctype html>
 <html><body>
 <?php

 session_start();
 $username = $_POST["textUsername"];
 $password = $_POST["passwordPassword"];
 $comments = $_POST["textareaComments"];
 $_SESSION['username'] = $username;
 $_SESSION['password'] = $password;

 $_SESSION['lastTimeStamp'] = time();

 echo "<br>The passed username is: $username <br>";
 echo "The passed password is: $password <br>";
 echo "The passed comments are: $comments <br>";

 echo "<br>After updating the _SESSION array, let us print it again <br>";
 var_dump($_SESSION);

 echo "<br><a href=session_view.php> View your profile </a>";
 ?>
 </body></html>

For this second method to work, we also need to modify the "session_view.php" page; let us call it "session_timeout_view.php". Here, we check if the current time (time()) has become more than the earlier time stamp (stored as $_SESSION['lastTimeStamp']) plus the specified timeout (60 seconds in this case). If current time is greater then that means sufficient time (more than 60 seconds) has expired and we unset session data and destroy the session. Otherwise, if sufficient time has not expired, then we simply reset the time stamp value stored in $_SESSION['lastTimeStamp'].

 <?php session_start(); ?>

 <!doctype html>
 <html>
 <?php
 echo "Let us print the _SESSION array <br>";
 var_dump($_SESSION);

 $sess_id = session_id();
 echo "<br>Let us print the session id: $sess_id <br>";

 if (isset($_SESSION['username']) and isset($_SESSION['password'])) { 
     if (isset($_SESSION['lastTimeStamp']) &&  ((time()- 
     $_SESSION['lastTimeStamp']) > 60)  ) {
         echo "<br>Your session has expired <br>";
     } else { 
         $_SESSION['lastTimeStamp'] = time();
         $username = $_SESSION['username'];
         $password = $_SESSION['password'];
         echo "<br>From the session array: <br>"; 
         echo "The passed username is: $username <br>";
         echo "The passed password is: $password <br>";
     }

     unset($_SESSION['username']);
     unset($_SESSION['password']);
     unset($_SESSION['lastTimeStamp']);
     session_destroy();

     echo "<br>After destroying, the session: <br>"; 

     echo "Let us print the _SESSION array <br>";
     var_dump($_SESSION);
 } else {
     echo "<br>The session does not have username/password variables";
 }

 ?>
 </html>

We first provide the output of the modified "session_login.php" page. We would reach this page from "session_form_login.php" by entering "user1001" as username and "password1001" as password.



Figure: Action Method: PHP Login page (using Session)

Next, if we were to keep the above page idle for more than 60 seconds and then click on "View the profile", then we would reach the "session_timeout_view.php" page and would see the following:



Figure: Action Method: PHP View page (after session timeout)





comments powered by Disqus