With the release of PHP4, session management was introduced as an extension to the PHP language. PHP provides several session-related functions, and developing applications that use PHP sessions is straightforward. The three important features of session management are mostly taken care of by the PHP scripting engine.
In this section, we present how to use PHP sessions, showing how sessions are started and ended and how session variables are used. We list the PHP functions for building session-based web applications. Because not all browsers support cookies, and some users actively disable them, we describe how to use PHP sessions without relying on cookies. Finally, we show how to configure PHP session management with a discussion on the garbage collection used to remove old sessions and other configuration parameters.
An overview of PHP session
management is shown in Figure 8-1. When a user
first enters the session-based application by making a request to a
page that starts a session, PHP generates a session ID and creates a
file that stores the session-related variables. PHP sets a cookie to
hold the session ID in the response the script generates. The browser
then records the cookie and includes it in subsequent requests. In
the example shown in Figure 8-1, the script
welcome.php
records session variables in the
session store, and a request to next.php
then
has access to those variables because of the session ID.
Figure 8-1. The interaction between the browser and the server when initial requests are made to a session-based application
The out-of-the-box configuration of PHP session management uses disk-based files to store session variables. Using files as the session store is adequate for most applications in which the numbers of concurrent sessions are limited. A more scalable solution that uses a MySQL database as a session store is provided in Appendix D.
PHP provides a session_start( )
function that creates a new
session
and subsequently identifies and establishes an existing one. Either
way, a call to the session_start(
)
function initializes a session.
The
first time a PHP script calls session_start( )
,
a session identifier is generated, and, by default, a
Set-Cookie
header field is included in the
response. The response sets up a session cookie in the browser with
the name PHPSESSID
and the value of the session
identifier. The PHP session management automatically includes the
cookie without the need to call to the setcookie( )
or
header( )
functions.
The session identifier (ID) is a random string of 32 hexadecimal
digits, such as fcc17f071bca9bf7f85ca281094390b4
.
As with other cookies, the value of the session ID is made available
to PHP scripts in the $HTTP_COOKIE_VARS
associative array and in the $PHPSESSID
variable.
When a new session is started, PHP creates a session file. With the
default configuration, session files are written in the
/tmp
directory using the session identifier, prefixed with
sess_
, for the filename. The filename associated
with our example session ID is
/tmp/sess_fcc17f071bca9bf7f85ca281094390b4
.
If a call is made to session_start( )
, and the
request contains the PHPSESSID
cookie, PHP
attempts to find the session file and initialize the associated
session variables as discussed in the next section. However, if the
identified session file can’t be found,
session_start( )
creates an empty session
file.
Variables
need to be registered with the session_register( )
function that’s used in a
session. If a session has not been initialized, the
session_register( )
function calls
session_start( )
to open the session file.
Variables can be registered—added to the session
file—with the session_register( )
call as
follows:
// Register the variable named "foo" session_register("foo"); $foo = "bar";
Note that it is the name of the variable that is passed to the
session_register( )
function, not the variable
itself. Once registered, session variables are made persistent and
are available to scripts that initialize the session. PHP tracks the
values of session variables and saves their values to the session
file: there is no need to explicitly save a session variable before a
script ends. In the previous example, the variable
$foo
is automatically saved in the session store
with its value bar
.
Variables can be removed from a session with the
session_unregister( )
function call; again, the name of the
variable is passed as the argument, not the variable itself. A
variable that is unregistered is no longer available to other scripts
that initialize the session. However, the variable is still available
to the rest of the script immediately after the
session_unregister( )
function call.
Scripts that initialize a session have access to the session
variables through the associative array
$HTTP_SESSION_VARS
, and PHP automatically
initializes the named session variables if
register_globals
is enabled.
Example 8-2 shows a simple script that registers two
variables: an integer $count
, which is incremented
each time the script is called, and $start
, which
is set to the current time from the library function time( )
when
the session is first initialized. The script tests if the variable
$count
has been registered to determine if a new
session has been created. If the variable $count
has been registered already, the script increments its value.
Do not use the existence of $PHPSESSID
as
indicative of a new session, or as a method to access the session ID.
The first time a script is called and the session is created, the
PHPSESSID
cookie may not be set. Only subsequent
requests are guaranteed to contain the PHPSESSID
cookie. PHP provides a session_id( )
function that returns the session ID for the initialized session.
The script shown in Example 8-2 displays both
variables: $count
shows how many times the script
has been called, and time( )
-
$start
shows how many seconds the session has
lasted.
Example 8-2. Simple PHP script that uses a session
<?php // Initialize a session. This call either creates // a new session or re-establishes an existing one. session_start( ); // If this is a new session, then the variable // $count will not be registered if (!session_is_registered("count")) { session_register("count"); session_register("start"); $count = 0; $start = time( ); } else { $count++; } $sessionId = session_id( ); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head><title>Sessions</title></head> <body> <p>This page points at a session (<?=$sessionId?>) <br>count = <?=$count?>. <br>start = <?=$start?>. <p>This session has lasted <?php $duration = time( ) - $start; echo "$duration"; ?> seconds. </body> </html>
Session variables can be of the type Boolean, integer, double, string, object, or arrays of those variable types. Care must be taken when using object session variables, because PHP needs access to the class definitions of registered objects when initializing an existing session. If objects are to be stored as session variables, you should include class definitions for those objects in all scripts that initialize sessions, whether the scripts use the class or not. Objects and classes are described in Chapter 2.
PHP stores session variables in the session file by serializing the values. The serialized representation of a variable includes the name, the type, and the value as a stream of characters suitable for writing to a file. Here’s an example of a file that was created when the script shown in Example 8-2 was run several times:
count|i:6;start|i:986096496;
A PHP developer need not worry how serialization occurs; PHP session management takes care of reading and writing session variables automatically.
At
some
point in an application, sessions may need to be destroyed. For
example, when a user logs out of an application, a call to the
session_destroy( )
function can be made. A call to
session_destroy( )
removes the session file from
the system but doesn’t remove the
PHPSESSID
cookie from the browser.
Example 8-3 shows how the session_destroy( )
function is called. A session must be initialized before
the session_destroy( )
call can be made. You
should also test to see if $PHPSESSID
is a set
variable before killing the session. This prevents the code from
creating a session, then immediately destroying it if the script is
called without identifying a session. However, if the user has
previously held a session cookie, PHP initializes the
$PHPSESSID
variable, and the code redundantly
creates and destroys a session.
Example 8-3. Ending a session
<?php // Only attempt to end the session if there // is a $PHPSESSID set by the request. if(isset($PHPSESSID)) { $message = "<p>End of session ($PHPSESSID)."; session_start( ); session_destroy( ); } else { $message = "<p>There was no session to destroy!"; } ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head><title>Sessions</title></head> <body> <?=$message?> </body> </html>
In this section we list the key
functions used to build
session-based applications in PHP. Greater control over sessions can
be achieved through the configuration of PHP—as we discuss in
the Section 8.3.8 section—or
by using GET
variables to encode the session ID,
as discussed in the next section.
Boolean session_start( )
Initializes a session by either creating a new session or using an
identified one. Checks for the variable $PHPSESSID
in the HTTP request. If a session identifier isn’t
included in the request, or an identified session
isn’t found, a new session is created. If a session
ID is included in the request, and a session isn’t
found, a new session is created with the PHPSESSID
encoded in the request. When an existing session is found, the
session variables are read from the session store and initialized.
Using PHP’s default settings, a new session is
created as a file in the /tmp
directory. This
function always returns true
.
string session_id([string
id
])
Can be used in two ways: to return the ID of an initialized session and to set the value of a session ID before a session is created. When used to return the session ID, the function must be called without arguments after a session has been initialized. When used to set the value of the session ID, the function must be called with the ID as the parameter before the session has been initialized.
Boolean session_register(mixed
name
[, mixed ...])
Registers one or more variables in the session store. Each argument
is the name of a variable, or an array of variable names, not the
variable itself. Once a variable is registered, it becomes available
to any script that identifies that session. This function calls the
session_start( )
code internally if a session has not been
initialized. The session_unregister( )
function is called to remove a variable from
the session. Returns true
when the variables are
successfully registered.
Boolean session_is_registered(string
variable_name
)
Returns true
if the named variable has been
registered with the current session and false
otherwise. Using this function to test if a variable is registered is
a useful way to determine if a script has created a new session or
initialized an existing one.
session_unregister(string
variable_name
)
Unregisters a variable with the initialized session. Like the
session_register( )
function, the argument is the name of the
variable, not the variable itself. Unlike the
session_register( )
function, the session needs
to be initialized before calling this function. Once a variable has
been removed from a session with this call, it is no longer available
to other scripts that initialize the session. However, the variable
is still available to the rest of the script that calls
session_unregister( )
.
session_unset( )
Unsets the values of all session variables. This function
doesn’t unregister the actual session variables. A
call to session_is_registered( )
still returns true
for the
session variables that have been unset.
Boolean session_destroy( )
Removes the session from the PHP session management. With
PHP’s default settings, a call to this function
removes the session file from the /tmp
directory. Returns true
if the session is
successfully destroyed and false
otherwise.
A change that
can be made to the default PHP session management is to encode the
$PHPSESSID
value as an attribute in a
GET
or POST
method request and
avoid the need to set a cookie.
A simple experiment that illustrates what happens when users disable
cookies is to request the script shown in Example 8-2 from a browser that has cookie support turned
off. When repeated requests are made, the counter
doesn’t increment, and the session duration remains
at zero seconds. Because a cookie isn’t sent from
the browser, the variable $PHPSESSID
is never set.
The other side effect is that each time the page is requested, a
session file is created in the /tmp
directory.
Many users configure their browsers to not accept cookies, and
session-based applications won’t work unless they
are written to handle the missing cookie.
The session identifier that would have been sent as a cookie in this
experiment can be transmitted in a GET
or
POST
method request. While the
session_start( )
function can use
$PHPSESSID
set by either a GET
or POST
method request, it is more practical to
use the GET
variable. Using the
POST
variable leads to the reload problem
described in Chapter 6. Continuing the experiment,
requests that don’t contain the cookie can identify
an existing session by setting an attribute in a
GET
method request with the name
PHPSESSID
and the value of the session ID. For
example, an initial request can be made to Example 8-1 with the URL:
http://localhost/example.8-1.php
This creates a session and an associated file such as:
/tmp/sess_be20081806199800da22e24081964000
Subsequent requests can be made that include the
PHPSESSID
:
http://localhost/example.8-1.php?PHPSESSID=be20081806199800da22e24081964000
The response shows the counter set to 1
and the
correct session duration. Repeated requests to this URL behave as
expected: the counter increments, and the calculated duration
increases.
If you write session-based applications to use the URL to identify sessions, the application doesn’t fail for users who don’t allow cookies. Applications can use a test cookie to see if cookies are supported by the browser or just not use cookies at all.
When register_globals
is enabled, and both a
cookie and GET
or POST
are used
to set the $PHPSESSID
, the cookie wins. A
GET
or
POST
attribute value is overwritten by the value
associated with the cookie because of the default order in which PHP
initializes those variables.
The safe way to read cookies and GET
and
POST
attributes that have name conflicts is to use
the $HTTP_COOKIE_VARS
,
$HTTP_GET_VARS
, and
$HTTP_POST_VARS
arrays.
Another advantage of avoiding cookies is that some browsers, such as Netscape and Internet Explorer, share cookies across all instances of the program running for a particular user on the same machine. This behavior prevents a user from having multiple sessions with a web database application.
Scripts that generate embedded links to pages that use session
variables need to include a GET
attribute named
PHPSESSID
in the URL. This can be done using the
basic PHP string support and calls to session_id( )
.
For example:
<?php // Initialize the session session_start( ); // Generate the embedded URL to link to // a page that processes an order $orderUrl = "/order.php?PHPSESSID=" . session_id( ); ?> <a href="<?=$orderUrl ?>">Create Order</a>
To aid the creation of URLs that link to session-based scripts, PHP
sets the constant SID
that contains the session ID
in the form suitable to use as a URL query string. If there is no
session initialized, PHP sets the value of SID
to
be a blank string. If a session is initialized, it sets the
SID
to a string containing the session ID in the
form:
PHPSESSID=be20081806199800da22e24081964000
By including the value of SID
when URLs are
constructed, the hypertext links correctly identify the session. A
link that points to a script that expects a session ID can be encoded
like this:
<?php // Initialize the session session_start( ); ?> <a href="/order.php?<?=SID?>">Create Order</a>
As an alternative to writing code to formulate the session ID into
the URL, PHP includes a URL rewrite feature
that automatically modifies reference URLs to include the session ID
as a GET
attribute. To activate this feature, PHP
needs to be configured with - -enable-trans-id
and
then recompiled. Once URL rewrite is activated, PHP parses the HTML
generated by scripts and automatically alters the embedded URLs to
include the PHPSESSID
query string. The URL
rewrite feature has the disadvantage that extra processing is
required to parse every generated page.
PHP session management can be instructed not to set the
PHPSESSID
cookie by changing the
session.use_cookies
parameter to 0
in
the php.ini
file. The session configuration
parameters in the php.ini
file are described in
the later section Section 8.3.8.
While it
is good practice to build applications that provide a way to end a
session—with a script that makes a call to
session_destroy( )
—there is no guarantee that a user will
log out by requesting the appropriate PHP script. PHP session
management has a built-in garbage collection mechanism that ensures
unused session files are eventually cleaned up. This is important for
two reasons: it prevents the directory from filling up with session
files that can cause performance to degrade and, more importantly, it
reduces the risk of someone guessing session IDs and hijacking an old
unused session.
There are two parameters that control garbage collection:
session.gc_maxlifetime
and
session.gc_probability
, both defined in the
php.ini
file. A garbage collection process is
run when a session is initialized, for example, when
session_start( )
is called. Each session is
examined by the garbage collection process, and any sessions that
have not been accessed for a specified period of time are removed.
This period is specified as seconds of inactivity in the
gc_maxlifetime
parameter—the default value
being 1,440 seconds. The file-based session management uses the
update time of the file to determine the last access. To prevent the
garbage collection process from removing active session files, PHP
must modify the update time of the file when session variables are
read, not just when they are written.
The garbage collection process can become expensive to run,
especially in sites with high numbers of users, because the
last-modified date of every session file must be examined. The second
parameter gc_probability
sets the percentage
probability that the garbage collection process will be activated. A
setting of 100% ensures that sessions are examined for garbage
collection with every session initialization. The default value of 1%
means that garbage collection occurs with a probability of 1 in
100.[10] Depending on
the requirements, some figure between these two extremes balances the
needs of the application and performance. Unless a site is receiving
less that 1,000 hits per day, the probability should be set quite
low. For example, an application that receives 1,000 hits in a
10-hour period with a gc_probability
setting of
10% runs the garbage collection function, on average, once every 6
minutes. Setting the gc_probability
too high adds
unnecessary processing load on the server.
When it is important to prevent users from accessing old sessions,
the gc_probability
should be increased. For
example, the default session configuration sets up a cookie in the
browser to be deleted when the browser program is terminated. This
prevents a user from accidentally reconnecting to an old session.
However, if the session ID is encoded into a URL, a bookmarked page
can find an old session if it still exists. If session IDs are passed
using the GET
method, you should increase the
probability of running garbage collection.
There
are several parameters that can be manipulated to change the behavior
of the PHP session management. These parameters are set in the
php.ini
file in the section headed
[Session]
.
session.save_handler
This parameter specifies the method used by PHP to store and retrieve
session variables. The default value is files
, to
indicate the use of session files, as described in the previous
sections. The other values that this parameter can have are:
mm
to store and retrieve variables from shared
memory, and user
to store and retrieve variables
with user-defined handlers. In Appendix D we
describe how to create user-defined handlers to store session
variables in a MySQL database.
session.save_path
This parameter specifies the directory in which session files are
saved when the session.save_handler
is set to
files
. The default value is
/tmp
. When implementing user-defined
save_handler
methods, the value of this parameter
is passed as an argument to the function that opens a session.
User-defined handlers are discussed in Appendix D.
session.use_cookies
This parameter determines if PHP sets a cookie to hold the session
ID. Setting this parameter to 0
stops PHP from
setting cookies and may be considered for the reasons discussed in
the previous section. The default value is 1
,
meaning that a cookie stores the session ID.
session.name
This parameter controls the name of the cookie,
GET
attribute, or POST
attribute that is used to hold the session ID. The default is
PHPSESSID
, and there is no reason to change this
setting unless there is a name collision with another variable.
session.auto_start
With the default value of 0
for this setting, PHP
initializes a session only when a session call such as
session_start( )
or session_register( )
is made. If this parameter is set to
1
, sessions are automatically initialized if a
session ID is found in the request. Allowing sessions to autostart
adds unnecessary overhead if session values aren’t
required for all scripts.
session.cookie_lifetime
This parameter holds the life of a session cookie in seconds and is
used by PHP when setting the expiry date and time of a cookie. The
default value of 0
sets up a session cookie that
lasts only while the browser program is running. Setting this value
to a number of seconds other than 0
sets up the
cookie with an expiry date and time. The expiry date and time of the
cookie is set as an absolute date and time, calculated by adding the
cookie_lifetime
value to the current date and time
on the server machine.[11]
session.cookie_path
This parameter sets the valid path for a cookie. The default value is
/
, which means that browsers include the session
cookie in requests for resources in all paths for the
cookie’s domain. Setting this value to the path of
the session-based scripts can reduce the number of requests that need
to include the cookie. For example, setting the parameter
to /winestore
instructs the
browser to include the session cookie only with requests that start
with http://www.webdatabasebook.com/winestore/.
session.cookie_domain
This parameter can override the domain for which the cookie is valid. The default is a blank string, meaning that the cookie is set with the domain of the machine running the web server, and the browser includes the cookie only in requests sent to that domain.
session.cookie_secure
This parameter sets the secure flag of a cookie, which prevents a
browser from sending the session cookie over nonencrypted
connections. When this setting is 1
, the browser
sends the session cookie over a network connection that is protected
using the Secure Sockets Layer, SSL. We discuss SSL in the next
chapter and provide installation instructions in Appendix A. The default value of 0
allows a browser to send the session cookie over encrypted and
nonencrypted services.
session.serialize_handler
This parameter sets up the method by which variables are serialized,
that is, how they are converted into a stream of bytes suitable for
the chosen session store. The default value is
php
, which indicates use of the standard PHP
serialization functions. An alternative is wddx
,
which uses the WDDX libraries that encode variables as XML.
session.gc_probability
This parameter determines the probability that the garbage collection
process will be performed when a session is initialized. The default
value of 1
sets a 1% chance of garbage collection.
See the discussion in the previous section for a full explanation of
garbage collection.
session.gc_maxlifetime
This parameter sets the life of a session in number of seconds. The
default value is 1440
, or 24 minutes. Garbage
collection destroys a session that has been inactive for this period.
See the discussion in the previous section for a full explanation of
garbage collection.
session.referer_check
This parameter can restrict the creation of sessions to requests that
have the HTTP Referer:
header field set. This is a
useful feature if access to an application is allowed only by
following a hypertext link from a particular page such as a welcome
page. If the HTTP Referer
header field
doesn’t match the value of this parameter, PHP
creates a session, but the session is marked as invalid and unusable.
The default value of a blank string applies no restriction.
session.entropy_file
PHP generates the session IDs from a random number seeded by the
system date and time. Because the algorithm is known—it can be
looked up in the PHP source code—it makes guessing session IDs
a little easier. If this parameter is set to the name of a file, the
first n bytes from that file (where
n is specified by the
session.entropy_length
parameter) make the ID less
predictable. The default value is left blank, meaning the default
seeding method is used. One alternative is to use
/dev/urandom
, a special Unix device that produces
a pseudorandom number.
session.entropy_length
This parameter is the number of bytes to use when generating a
session ID from the file specified by
session.entropy_file
. The default value is
0
, the required value when no entropy file is
set.
session.cache_limiter
This parameter controls how responses can be cached by the browser.
The default is nocache
, meaning that PHP sets up
the HTTP response to avoid browser caching. PHP sets the
HTTP/1.1-defined header field Cache-Control
to
no-cache
, the HTTP/1.0 header field
Pragma
to no-cache
,
and—for good measure—the Expires
header field to Thu, 19 Nov 1981 08:52:00
GMT
. Applications that use sessions—and even
stateless web database applications—can be adversely affected
when browsers cache pages. The other values allowed,
private
and public
, allow
responses to be cached. The distinction between private and public is
apparent when a proxy server caches responses. See Appendix B for more details about HTTP caching.
session.cache_expire
This parameter is used when caching is allowed; it sets the expiry
date and time of the response to be the current system time plus the
parameter value in minutes. The default value
is
180
.
[10] Perhaps the gc_maxlifetime
parameter should have been called gc_minlifetime
,
because the value represents the minimum time garbage collection
permits an inactive session to exist. Remember that garbage
collection is performed only when a request that initializes a
session is made, and then only with the probability set by
gc_probability
.
[11] The actual expiry of the cookie is performed by the browser, which compares the expiry date and time of the cookie with the client machine’s date and time. If the date and time are incorrectly set on the client, a cookie might expire immediately or persist longer than expected.
3.145.173.199