Session Management
Session management is a mechanism for maintaining and sharing
the state of variables
(called session variables) for every participating program in a web project.
These variables are not lost when you go offsite and return.
This is one of the key ingredients of a web-based
shopping cart
used in e-commerce.
The server can maintain a relationship with a browser session
by sending and receiving information packets called
cookies.
A cookie is simply a name/value pair of data which
contains other attributes such as the target URL (server name and path)
and expiration timestamp.
In session management using cookies, when a browser first contacts
a web server, the server sends a cookie called the
session id
which is then stored in the browser.
The value of the session id is
some fixed-length "random" sequence of hex digits
which the server uses to identify the browser connection and
associate some persistent information.
When the browser makes a subsequent contact to the server so that
the cookie's URL
matches the server URL, the cookie is sent to
the server.
Session handling is built-in to Php using cookies
whose name is PHPSESSID.
As mentioned above, the cookie is originally
sent from the server to the browser and then subsequently
sent back to the server for all future contacts to that site
during the current browser session.
The default lifetime for a PHPSESSID cookie is the
browser session, i.e., as long as the browser remains open.
Php session management
A Php program begins session management by calling the function:
session_start();
From then on, the $_SESSION array can be used to
keep track of any number of variables via user-determined keys.
The session_start function must be called prior to the echoing of
any HTML code. Any file in which this is used must start with
very first characters in the file, i.e.,
no other characters (even whitespace) prior to this.
Once a session has been established and we set
$_SESSION['name'] = /* some serializable value */;
then $_SESSION['name'] is available to all
other participating scripts.
To invalidate a session variable:
unset($_SESSION['name']);
To invalidate all session variables:
session_destroy();
Content of the session files
For a better understanding, look at the session files themselves.
They are stored in the temporary directory specified by
session.save_path in the Php init file.
In Linux, these files are owned by the Apache user and so you
have to become root to read them.
The session files are of the form:
sess_
like this:
sess_71c3cf38b232720002c25fd7919066e5.
The content is a string created by serializing the
$_SESSION array with the Php serialize function.
For example,
serialize( array( "xx" => -15, "yy" => array(3,4) ) ) =
"a:2:{s:2:"xx";i:-15;s:2:"yy";a:2:{i:0;i:3;i:1;i:4;}}"
A Php program which uses sessions obtains the stored values by
de-serializing the session using the Php
unserialize function.
Controlling the path of the session
By default, the path of the PHPSESSID
cookie is "/", meaning usually that the
cookie will be sent to anywhere within the domain.
If you want to restrict the path to the directory
in which these scripts are
defined, you need to use the
session_set_cookie_params function
prior to the first session_start() call when
the cookie is sent to the browser.
For example, this call makes the session valid only
for scripts within the current directory:
session_set_cookie_params(0, dirname(__FILE__) . "/");
Here we're using the built-in Php special __FILE__ constant which
always gives the absolute path of the file in which it's used.
Using $_SESSION with a KEY
The $_SESSION superglobal variable, like others, is an associative array, which
means that we can store and retrieve information in it's entries, like:
$_SESSION['valid']
As you will see in our examples, the $_SESSION array is used in a more complicated
fashion. Instead of using it in this "one-dimensional" manner, we use it in a two-dimensional
manner by creating the array:
$_SESSION[KEY][...] = ...
The value of KEY is a constant defined somewhere and made available to all scripts which
use sessions. The function of this KEY usage is to separate your application's session
from other sessions on the same server.
Suppose you were to omit the usage of KEY and suppose
in one application you had, for some reason, set
$_SESSION['valid'] = 1
Now suppose you enter a separate application on the same server which
uses the same validation strategy and
tests for validated access by doing:
if ( isset($_SESSION['valid']) ) {
// I can access some protected resource
}
In effect,
you have achieved priviledged status in the former application and exported this
status in the latter application.
One might refer to this effect
as bleed-over. It is a consequence of the global nature of the
$_SESSION variable.
You will be secure in avoiding bleed-over if, like a password, KEY is both
- secret
- not likely to be reproduced
The good news is that, unlike a password, you do not need to remember it.
A Session class
Because of the syntactic complexity of using session variable of the form:
$_SESSION[KEY]['param']
it is easier and less error prone to wrap the read/write operations as
getter/setter operations in a dedicated class.
In particular, throughout our web development, we will
make exensive use of the included file:
session_start();
define( "SECRET", "-set-this-to-make-sessions-secure-" );
define( "HASH", md5(dirname(__FILE__) . SECRET) );
define( "KEY", "sess_" . HASH );
class Session {
public function __set($name,$value) {
$_SESSION[KEY][$name] = $value;
}
public function & __get($name) {
return $_SESSION[KEY][$name];
}
public function __toString() {
$sess = $_SESSION[KEY];
foreach ($sess as $key => $value) {
if (!isset($value)) unset($sess[$key]);
}
return print_r($sess,true);
}
public function __isset($name) {
return isset($_SESSION[KEY][$name]);
}
public function __unset($name) {
unset($_SESSION[KEY][$name]);
}
public function unsetAll() {
unset($_SESSION[KEY]);
}
}
The session KEY uses the
md5 hash of the full path to the application's
include directory
plus a chosen SECRET value. With this combination we are ensured that:
- the KEY will vary from one application to another
- if SECRET is an unknown value, another user cannot
"guess" the KEY even when the include directory path is know.
Sample Scripts
This demo web app uses the template from the
Website Template
document. Three view scripts
session-demo.php
form1.php, form2.php, form3.php along with
additional so-called handler files
handler-sess-set.php,
handler-sess-unset.php, and
handler-sess-clear.php
offer a demonstration of session behavior.
A modified version of the Session class is used to illustrate
the behavior of the member functions:
In this modified version,
member function activations are reported whenever this constant
is defined:
define("DEBUG",1)
session-demo.php
This illustrates the "magic methods" used in Php classes. In particular the
magic methods establish this relationship between usage and underlying behavior:
$session->var = 17; // __set: $_SESSION[KEY]['var'] = 17
$value = $session->var; // __get: $value =& $_SESSION[KEY]['var'];
if (isset($session->var)) // __isset: if (isset($_SESSION[KEY]['var']))
unset($session->var) // __unset: unset($_SESSION[KEY]['var']);
echo "$session"; // __toString
Here is the code:
require_once "include/Session.php";
$session = new Session();
define("DEBUG",1);
?>
...
Session Demo
$session->x = 5;
echo $session->x, "\n";
echo $session->y, "\n";
echo "$session\n";
if (isset($session->x)) echo "yes\n"; else echo "no\n";
if (isset($session->y)) echo "yes\n"; else echo "no\n";
unset($session->x);
echo "$session\n";
print_r($_SESSION);
?>
The most unusual of these methods is __get which returns the variable
by reference. The implication is that, when it is used in the statement
$value = $session->some_var;
the variables $value and $session->some_var are identical.
In particular this is necessary to make a statement like this, which auto-generates
and array, work:
$session->some_var[] = "foo";
One strange side-effect of return-by-reference in __get is that
attempting to use an undefined session key will make the key appear, associated
with the null value.
In our test program we use the undefined "y" session key:
echo $session->y, "\n";
Later we confirm that this session variable is unset:
echo $session->y, "\n";
if (isset($session->y)) echo "yes\n"; else echo "no\n";
At the end, however, we see the "y" session key turn up in:
print_r($_SESSION);
form1.php
This first script presents a standard reentrant form which holds its values by resetting
them based on the incoming query parameters.
This simple stateless form script has the "problem" that
when we leave the script and return, the state values are lost.
Here is the script code:
All form scripts include this file:
$items = array( 1=>"AA", "BB", "CC", "DD", "EE", "FF", "GG" );
The array indices will be used as the underlying selection option values and the
array values will be the option labels. It is usually a good idea to avoid
having a "false" option value for "real" option choices; therefore we use
a 1-based array instead of the default 0-based array.
form2.php
The form2.php
and form3.php scripts are variations in which we use sessions.
The form2.php script stores parameter values
as session values when the internal form has been activated is set.
The code expresses the idiosyncratic way to do so by
resetting the session value only for a reentrant activation.
By doing so, we can remember the values throughout the session,
thereby making the form elements session-stable.
Since the form element values are held in the session, there is no
need to proceed through the form when they are set from the parameters.
In some cases it is useful to simply redirect to the initial activation.
We can do so by uncommenting the statements:
header("location: " . $_SERVER['PHP_SELF']); exit();
The header
function places information into the server's response sent back to the
browser which causes the browser to redirect to the specified location,
i.e., redirect to the script provided by the location information.
This usage of the header function makes the browser
"redirect to the script itself" which means that we're forcing the
browser to reload.
The exit
function call is used to stop executing code within this current script
which would be ignored anyway because the browser is being redirected.
The issue now is that, when the redirection is in place,
the $message is no longer passed from the top contoller part
to the bottom view part. In the next section we will illustrate a mechanism
for sending information such as this across the redirection.
form3.php
This calls an external handler script, session-from-query.php,
whose sole job is to set the session values from the
query parameters and redirect back to the original script.
The code is this:
There are three forms in the form3.php script. Each of them calls one of
the three corresponding
external "handler" scripts
which all redirect back to form3.php.
require_once "include/Session.php";
$session = new Session();
// set session values from query parameters
foreach ($_REQUEST as $key => $value) {
$session->__set($key,$value);
}
$session->message = "set keys: " . join(", ", array_keys($_REQUEST));
header( "location: " . $_SERVER['HTTP_REFERER'] );
require_once "include/Session.php";
$session = new Session();
$params = (object) $_REQUEST;
foreach ($params->key2unset as $key) {
$session->__unset($key);
}
$session->message = "unset keys: " . join(", ", $params->key2unset);
header( "location: " . $_SERVER['HTTP_REFERER'] );
require_once "include/Session.php";
$session = new Session();
$session->unsetAll();
$session->message = "unset all keys";
header( "location: " . $_SERVER['HTTP_REFERER'] );
We term these handler scripts because they do not in themselves generate a view;
they simply perform some action and then redirect somewhere else.
The special server variable
$_SERVER['HTTP_REFERER']
provides the full URL of the caller.
The redirection, after peforming its actions effectively goes back to
form3.php via the statement:
header("location: " . $_SERVER['HTTP_REFERER']);
An important idea illustrated in these script is the use of so-called
flash memory which is "one-time" session usage variables. The mechanism
is that, prior to redirection back, we set a message:
$session->message = /* some message */;
Back in form3.php we retrieve this message in the controller section:
$message = $session->message;
unset($session->message);
and then drop it into the view section below as we did in form2.php:
echo $message?>
The read/unset treatment in the controller section ensures that the message will
be displayed only once. If we subsequently refresh the page
or access form3.php from the outside, the message is gone, thus establishing
its "flash" behavior.
阅读(415) | 评论(0) | 转发(0) |