PHP Sessions in Plain English
You might have read or heard someone say, “You need sessions because HTTP is a stateless protocol.” However, that technical jargon isn’t really useful to someone who’s just learning all this stuff, so let’s get away from all those techy words and just learn about sessions using simple, everyday words.
<?php session_start(); // Add to the top of every page that uses sessions $_SESSION["foo"] = "bar"; // Add or update a session variable named "foo" echo $_SESSION["foo"]; // Echo a session variable named "foo"
A Short Comparison
Imagine you want to play a video game. You start up the game, and after 30 minutes of playing, you say, “Okay, I’m done playing for now,” and you shut down the game.
Then a bit later you say, “I want to play again!” So you load up the game again, you play for another 30 minutes, and shut down the game again.
This is a LOT like how web applications work. Each time you hit a PHP web page, that request starts up the PHP engine, then the PHP engine generates the web page (which often takes less than 1 second), hands it back to the web browser, and shuts down. So it’s almost like playing that video game multiple times, for less than 1 second at a time.
Now imagine if you had to start from the beginning every time you played the game. You’d simply be playing the same first 30 minutes over and over again, right?
So instead, you save your game at the end of playing.
As you’re playing the game, the game keeps track of your progress, like the points you’ve gotten or the level you’re on. All of that information is called the state of the game, and it’s kept in the game’s memory while it’s running. When you shut down the game, the game loses that memory.
When you save your game, what you’re doing is copying that state into a file that can stick around when the game isn’t running.
Later when you run the game again and you load your save game file, the game reads the data from the file and uses it to reconstruct the game’s state in memory. The end result is that you pick up where you left off.
Sessions are like save games for web applications.
Cookies: Helpful but Not Secure
Unless you’ve been living under a rock, you’ve probably heard of cookies. Usually someone or something is suggesting you clear your cookies.
A cookie is just a tiny file (or piece of memory) that can hold some data for a web application, and gets sent along with every request you page to that application.
For example, if you visit a web site and on the first page you set your preferred language to Spanish, the site might give you a cookie named “preferred_language” with the value “spanish”. When you click a link to go to the second page, your browser makes the request for that second page AND it also passes along that “preferred_language” cookie. The server can see the cookie and make decisions about how to generate the second page based on that cookie (e.g. generate the page in Spanish instead of English).
For a long time, a lot of web sites just used nothing but cookies to “save” information about a user’s visit.
However, there are a few problems with using cookies for everything. The biggest problem is that they are stored ENTIRELY on the user’s computer and can thus be manipulated by an evil user.
For example, let’s say that you wanted your web application to recognize that someone was already logged in, so after they log in as “john.smith”, you set a cookie called “logged_in” and it has a value of “john.smith”. A malicious hacker might look at the cookies on their computer and simply change “john.smith” to “administrator” and then access the web site. Suddenly, the web site is saying, “Welcome back, Administrator!” and is giving you access to features that only the true administrator should have.
So there were many different scenarios where a web application wanted to track information about a user’s visit BUT in a way that didn’t give the user direct access to that data. That’s where sessions come in.
How Sessions Work
In a PHP application, you might do things like log in, or add items to a shopping cart. That information might go into the application’s state while the page is being generated (meaning the PHP engine is running and processing the current page request), but as soon as the page finishes generating on the server, the PHP engine shuts down again and it throws all of that data away.
When you choose to enable sessions for a PHP page by calling session_start(), the server saves some data (of your choosing) into a file that is stored on the server, and gives it a random long filename like “sess_j265ih8frhn28v8qecam604anj”.
Then it gives the end user a cookie called a “session ID cookie” that only has that really long, random ID “j265ih8frhn28v8qecam604anj” and nothing more.
The next time that the user visits another page on the web site, the browser sends that session ID cookie along with the request. When the PHP code calls session_start() again, this time it sees that there’s a session ID that has been passed in with the request. So it goes and looks for a file that corresponds to that session ID. It finds the file, opens it, and then loads all of that data so that your PHP code has access to it.
Now For Some Code…
Enabling sessions is easy. All you have to do is call session_start() on every page where you want sessions to be enabled, but you have to call it BEFORE you have any sort of output (even a blank line is considered output).
<?php session_start(); ?> Hello!
<?php session_start(); ?>
<?php $x = "World!"; session_start(); echo "Hi!";
Bad Examples (because they all have output before the session_start() is called):
Hello! <?php session_start();
<?php echo "Hi!"; $x = "World!"; session_start();
Once session_start() has been successfully called, you can then use the $_SESSION array to store and retrieve values between different page hits. For example if I start on page1.php and set a session variable, then go to page2.php and echo it:
<?php session_start(); $_SESSION["Hello"] = "World!";
<?php session_start(); echo $_SESSION["Hello"]; // OUTPUT: World!
Pretty easy and simple, right? Now let’s move onto the common questions!
Q: What happens if I call session_start() more than once?
This has no harmful effect, except that you’ll get a PHP warning that looks like this:
Notice: session_start(): A session had already been started - ignoring in <filename> on line <number>
NOTE: You’ll only see this on the screen if you have configured PHP (via php.ini or via ini_set() calls) to display warnings on the screen and have error_reporting set high enough.
Q: Why doesn’t my session work?
The most common root cause for this is that you have SOME kind of output before you’ve called session_start(). Normally, PHP will display an error, but in some environments, the display_errors setting is turned off so you won’t see the error on the screen (it would show up in the PHP error log if you have it enabled – and you should have it enabled). The end result is it looks like there are no errors but sessions just aren’t working.
So the first thing to do is to confirm that as the root cause. If that’s what is happening, then the warning will be:
Warning: session_start(): Cannot start session when headers already sent in <filename> on line <number>
Sometimes the output can be in a different included/required file, but the most devious cause is the UTF-8 Byte Order Mark (BOM) which are 3 invisible bytes that are SOMETIMES added to the very beginning of a UTF-8-encoded file. Not all editors will add this, but it does happen. A lot of editors will not show these bytes, so it looks like there’s nothing there. To confirm, use a hex editor / viewer to look at the first few bytes of the code. Example:
Those 3 bytes are outside the <?php … ?> block, so they count as output.
Q: Can I store any kind of data, like arrays, in $_SESSION?
Yes, you can! Just about any kind of data you can think of should be able to be stored. However, bear in mind that the server has to read the session data every time the visitor hits another page, so if you store 10 megabytes of data into a session, the server is going to read that 10 megabytes repeatedly – once per page hit. So to avoid performance problems, use sessions sparingly – only store what really needs to be stored.
Q: Could someone else steal my session if they knew my session ID?
Yes, they can. It’s called “session hijacking” and the server cannot tell the difference between two different people who are passing it the same session ID.
That said, session IDs are 26 characters long and each character can be “a” through “z” or a digit, so imagine a typical combination lock that has 3 dials that each go from 0 to 9, giving you a total of 1,000 possible combinations. Now imagine one that has 26 dials that each have 36 different values. That is 2,382,404,202,878,992,384 possible combinations. It’s pretty unlikely that anyone randomly guess a valid session ID (especially since they usually don’t last for too long and are randomized each time).
If session hijacking occurs, it’s usually because the session ID was exposed or copied somehow (e.g. a social engineering attack where someone calls and pretends to be the IT help desk and walks the user through viewing the session ID cookie).