|
|
CXLVI. Session Handling Functions
Session support in PHP consists of a way to preserve certain data
across subsequent accesses. This enables you to build more
customized applications and increase the appeal of your web site.
A visitor accessing your web site is assigned a unique id, the
so-called session id. This is either stored in a cookie on the
user side or is propagated in the URL.
The session support allows you to register arbitrary numbers of
variables to be preserved across requests. When a visitor accesses
your site, PHP will check automatically (if session.auto_start
is set to 1) or on your request (explicitly through
session_start() or implicitly through
session_register()) whether a specific session
id has been sent with the request. If this is the case, the prior
saved environment is recreated.
| Предостережение |
If you do turn on
session.auto_start then you cannot put objects into
your sessions since the class definition has to be
loaded before starting the session in order to recreate the
objects in your session.
|
All registered variables are serialized after the request
finishes. Registered variables which are undefined are marked as
being not defined. On subsequent accesses, these are not defined
by the session module unless the user defines them later.
| Внимание |
Some types of data can not be serialized thus stored in sessions. It
includes resource variables or objects with circular
references (i.e. objects which passes a reference to itself to another
object).
|
Замечание:
Session handling was added in PHP 4.0.
Замечание:
Please note when working with sessions that a record of a session
is not created until a variable has been registered using the
session_register() function or by adding a new
key to the $_SESSION superglobal array. This
holds true regardless of if a session has been started using the
session_start() function.
External links: Session fixation
The session module cannot guarantee that the information you store
in a session is only viewed by the user who created the session. You need
to take additional measures to actively protect the integrity of the
session, depending on the value associated with it.
Assess the importance of the data carried by your sessions and deploy
additional protections -- this usually comes at a price, reduced
convenience for the user. For example, if you want to protect users from
simple social engineering tactics, you need to enable
session.use_only_cookies. In that case,
cookies must be enabled unconditionally on the user side, or
sessions will not work.
There are several ways to leak an existing session id to third parties.
A leaked session id enables the third party to access all resources which
are associated with a specific id. First, URLs carrying session ids. If
you link to an external site, the URL including the session id might be
stored in the external site's referrer logs. Second, a more active
attacker might listen to your network traffic. If it is not encrypted,
session ids will flow in plain text over the network. The solution here
is to implement SSL on your server and make it mandatory for users.
Эти функции всегда доступны. Замечание:
Optionally you can use shared memory allocation (mm), developed by
Ralf S. Engelschall, for session storage. You have to download
mm and install it. This option is not
available for Windows platforms. Note that the session storage module
for mm does not guarantee that concurrent accesses to the same session
are properly locked. It might be more appropriate to use a shared memory
based filesystem (such as tmpfs on Solaris/Linux, or /dev/md on BSD) to
store sessions in files, because they are properly locked.
Session data is stored in memory thus web server restart deletes it.
Session support is enabled in PHP by default. If you would
not like to build your PHP with session support, you should
specify the --disable-session
option to configure. To use shared memory allocation (mm) for session
storage configure PHP --with-mm[=DIR] .
Версия PHP для
Windows имеет встроенную поддержку данного расширения. Это означает, что
для использования данных функций не требуется загрузка никаких
дополнительных расширений. Замечание:
By default, all data related to a particular session will be stored in
a file in the directory specified by the session.save_path INI option.
A file for each session (regardless of if any data is associated with
that session) will be created. This is due to the fact that a session
is opened (a file is created) but no data is even written to that file.
Note that this behavior is a side-effect of the limitations of working
with the file system and it is possible that a custom session handler
(such as one which uses a database) does not keep track of sessions
which store no data.
Поведение этих функций зависит от установок в php.ini.
Таблица 1. Session configuration options | Name | Default | Changeable | Changelog |
|---|
| session.save_path | "" | PHP_INI_ALL | | | session.name | "PHPSESSID" | PHP_INI_ALL | | | session.save_handler | "files" | PHP_INI_ALL | | | session.auto_start | "0" | PHP_INI_ALL | | | session.gc_probability | "1" | PHP_INI_ALL | | | session.gc_divisor | "100" | PHP_INI_ALL | Available since PHP 4.3.2. | | session.gc_maxlifetime | "1440" | PHP_INI_ALL | | | session.serialize_handler | "php" | PHP_INI_ALL | | | session.cookie_lifetime | "0" | PHP_INI_ALL | | | session.cookie_path | "/" | PHP_INI_ALL | | | session.cookie_domain | "" | PHP_INI_ALL | | | session.cookie_secure | "" | PHP_INI_ALL | Available since PHP 4.0.4. | | session.cookie_httponly | "" | PHP_INI_ALL | Available since PHP 5.2.0. | | session.use_cookies | "1" | PHP_INI_ALL | | | session.use_only_cookies | "1" | PHP_INI_ALL | Available since PHP 4.3.0. | | session.referer_check | "" | PHP_INI_ALL | | | session.entropy_file | "" | PHP_INI_ALL | | | session.entropy_length | "0" | PHP_INI_ALL | | | session.cache_limiter | "nocache" | PHP_INI_ALL | | | session.cache_expire | "180" | PHP_INI_ALL | | | session.use_trans_sid | "0" | PHP_INI_ALL | PHP_INI_ALL in PHP <= 4.2.3. PHP_INI_PERDIR in PHP < 5. Available since PHP 4.0.3. | | session.bug_compat_42 | "1" | PHP_INI_ALL | Available since PHP 4.3.0. | | session.bug_compat_warn | "1" | PHP_INI_ALL | Available since PHP 4.3.0. | | session.hash_function | "0" | PHP_INI_ALL | Available since PHP 5.0.0. | | session.hash_bits_per_character | "4" | PHP_INI_ALL | Available since PHP 5.0.0. | | url_rewriter.tags | "a=href,area=href,frame=src,form=,fieldset=" | PHP_INI_ALL | Available since PHP 4.0.4. |
Для подробного описания констант
PHP_INI_*, обратитесь к документации функции ini_set().
The session management system supports a number of configuration
options which you can place in your php.ini file. We will give a
short overview.
session.save_handler
string
session.save_handler defines the name of the
handler which is used for storing and retrieving data
associated with a session. Defaults to
files. Note that individual extensions may register
their own save_handlers; registered handlers can be
obtained on a per-installation basis by referring to
phpinfo(). See also
session_set_save_handler().
session.save_path
string
session.save_path defines the argument which
is passed to the save handler. If you choose the default files
handler, this is the path where the files are created. Defaults to
/tmp. See also
session_save_path().
There is an optional N argument to this directive that determines
the number of directory levels your session files will be spread
around in. For example, setting to '5;/tmp'
may end up creating a session file and location like
/tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If
. In order to use N you must create all of these
directories before use. A small shell script exists in
ext/session to do this, it's called
mod_files.sh. Also note that if N is
used and greater than 0 then automatic garbage collection will
not be performed, see a copy of php.ini for further
information. Also, if you use N, be sure to surround
session.save_path in
"quotes" because the separator (;) is
also used for comments in php.ini.
| Внимание |
If you leave this set to a world-readable directory, such as
/tmp (the default), other users on the
server may be able to hijack sessions by getting the list of
files in that directory.
|
Замечание:
Prior to PHP 4.3.6, Windows users had to change this variable in order
to use PHP's session functions. A valid path must be specified, e.g.:
c:/temp.
session.name
string
session.name specifies the name of the
session which is used as cookie name. It should only contain
alphanumeric characters. Defaults to PHPSESSID.
See also session_name().
session.auto_start
boolean
session.auto_start specifies whether the
session module starts a session automatically on request
startup. Defaults to 0 (disabled).
session.serialize_handler
string
session.serialize_handler defines the name
of the handler which is used to serialize/deserialize
data. Currently, a PHP internal format (name
php) and WDDX are supported (name
wddx). WDDX is only available, if PHP is
compiled with WDDX
support. Defaults to php.
session.gc_probability
integer
session.gc_probability in conjunction with
session.gc_divisor is used to manage probability
that the gc (garbage collection) routine is started.
Defaults to 1. See session.gc_divisor for details.
session.gc_divisor
integer
session.gc_divisor coupled with
session.gc_probability defines the probability
that the gc (garbage collection) process is started on every session
initialization.
The probability is calculated by using gc_probability/gc_divisor,
e.g. 1/100 means there is a 1% chance that the GC process starts
on each request.
session.gc_divisor defaults to 100.
session.gc_maxlifetime
integer
session.gc_maxlifetime specifies the number
of seconds after which data will be seen as 'garbage' and
cleaned up. Garbage collection occurs during session start.
Замечание:
If different scripts have different values of
session.gc_maxlifetime but share the same place for
storing the session data then the script with the minimum value will be
cleaning the data. In this case, use this directive together with session.save_path.
Замечание: If you are using the default file-based session handler, your
filesystem must keep track of access times (atime). Windows FAT does
not so you will have to come up with another way to handle garbage
collecting your session if you are stuck with a FAT filesystem or any
other filesystem where atime tracking is not available.
Since PHP 4.2.3 it has used mtime (modified date) instead of atime. So, you
won't have problems with filesystems where atime tracking is not available.
session.referer_check
string
session.referer_check contains the
substring you want to check each HTTP Referer for. If the
Referer was sent by the client and the substring was not
found, the embedded session id will be marked as invalid.
Defaults to the empty string.
session.entropy_file
string
session.entropy_file gives a path to an
external resource (file) which will be used as an additional
entropy source in the session id creation process. Examples are
/dev/random or /dev/urandom
which are available on many Unix systems.
session.entropy_length
integer
session.entropy_length specifies the number
of bytes which will be read from the file specified
above. Defaults to 0 (disabled).
session.use_cookies
boolean
session.use_cookies specifies whether the
module will use cookies to store the session id on the client
side. Defaults to 1 (enabled).
session.use_only_cookies
boolean
session.use_only_cookies specifies whether
the module will only use
cookies to store the session id on the client side.
Enabling this setting prevents attacks involved passing session
ids in URLs. This setting was added in PHP 4.3.0.
session.cookie_lifetime
integer
session.cookie_lifetime specifies the lifetime of
the cookie in seconds which is sent to the browser. The value 0
means "until the browser is closed." Defaults to
0. See also
session_get_cookie_params() and
session_set_cookie_params().
Since the cookie is returned by the browser, it is not prolonged to
suffice the lifetime. It must be sent manually by
setcookie().
session.cookie_path
string
session.cookie_path specifies path to set
in session_cookie. Defaults to /. See also
session_get_cookie_params() and
session_set_cookie_params().
session.cookie_domain
string
session.cookie_domain specifies the domain to
set in session_cookie. Default is none at all meaning the host name of
the server which generated the cookie according to cookies specification.
See also session_get_cookie_params() and
session_set_cookie_params().
session.cookie_secure
boolean
session.cookie_secure specifies whether
cookies should only be sent over secure connections. Defaults to
off.
This setting was added in PHP 4.0.4. See also
session_get_cookie_params() and
session_set_cookie_params().
session.cookie_httponly
boolean
Marks the cookie as accessible only through the HTTP protocol. This means
that the cookie won't be accessible by scripting languages, such as
JavaScript. This setting can effectively help to reduce identity theft
through XSS attacks (although it is not supported by all browsers).
session.cache_limiter
string
session.cache_limiter specifies cache
control method to use for session pages
(none/nocache/private/private_no_expire/public). Defaults to
nocache. See also
session_cache_limiter().
session.cache_expire
integer
session.cache_expire specifies time-to-live
for cached session pages in minutes, this has no effect for
nocache limiter. Defaults to 180. See also
session_cache_expire().
session.use_trans_sid
boolean
session.use_trans_sid whether transparent
sid support is enabled or not. Defaults to
0 (disabled).
Замечание:
For PHP 4.1.2 or less, it is enabled by compiling with
--enable-trans-sid.
From PHP 4.2.0, trans-sid feature is always compiled.
URL based session management has additional security risks
compared to cookie based session management. Users may send
a URL that contains an active session ID to their friends by
email or users may save a URL that contains a session ID to
their bookmarks and access your site with the same session ID
always, for example.
session.bug_compat_42
boolean
PHP versions 4.2.3 and lower have an undocumented feature/bug that
allows you to initialize a session variable in the global scope,
albeit register_globals
is disabled. PHP 4.3.0 and later will warn you, if this feature is
used, and if
session.bug_compat_warn is also enabled. This feature/bug can be
disabled by disabling this directive.
session.bug_compat_warn
boolean
PHP versions 4.2.3 and lower have an undocumented feature/bug that
allows you to initialize a session variable in the global scope,
albeit register_globals
is disabled. PHP 4.3.0 and later will warn you, if this feature is
used by enabling both
session.bug_compat_42
and
session.bug_compat_warn.
session.hash_function
mixed
session.hash_function allows you to specify the hash
algorithm used to generate the session IDs. '0' means MD5 (128 bits) and
'1' means SHA-1 (160 bits).
Since PHP 6.0.0 it is also possible to specify any of the algorithms
provided by the hash extension (if it is
available), like sha512 or
whirlpool. A complete list of supported algorithms can
be obtained with the hash_algos() function.
Замечание:
This was introduced in PHP 5.
session.hash_bits_per_character
integer
session.hash_bits_per_character allows you to define
how many bits are stored in each character when converting the binary
hash data to something readable. The possible values are '4' (0-9, a-f),
'5' (0-9, a-v), and '6' (0-9, a-z, A-Z, "-", ",").
Замечание:
This was introduced in PHP 5.
url_rewriter.tags
string
url_rewriter.tags specifies which HTML tags
are rewritten to include session id if transparent sid support
is enabled. Defaults to
a=href,area=href,frame=src,input=src,form=fakeentry,fieldset=
Замечание:
If you want HTML/XHTML strict conformity, remove the form entry and
use the <fieldset> tags around your form fields.
The track_vars and
register_globals
configuration settings influence how the session variables get
stored and restored.
Замечание:
As of PHP 4.0.3, track_vars is
always turned on.
Данное расширение не определяет никакие типы ресурсов.
Перечисленные ниже константы определены данным расширением и могут быть
доступны только в том случае, если PHP был собран с
поддержкой этого расширения или же в том случае, если
данное расширение подгружается во время выполнения.
- SID
(string)
Constant containing either the session name and session ID in
the form of "name=ID" or empty string
if session ID was set in an appropriate session cookie.
Замечание:
As of PHP 4.1.0, $_SESSION is available as a
global variable just like $_POST,
$_GET, $_REQUEST and so on.
Unlike $HTTP_SESSION_VARS,
$_SESSION is always global. Therefore, you do not
need to use the global
keyword for $_SESSION. Please note that this
documentation has been changed to use
$_SESSION everywhere. You can substitute
$HTTP_SESSION_VARS for
$_SESSION, if you prefer the former. Also note
that you must start your session using session_start()
before use of $_SESSION becomes available.
The keys in the $_SESSION associative
array are subject to the
same limitations as regular variable names in PHP, i.e. they cannot
start with a number and must start with a letter or underscore.
For more details see the section on
variables in this manual.
If register_globals
is disabled, only members of the global associative array
$_SESSION can be registered as session
variables. The restored session variables will only be available
in the array $_SESSION.
Use of $_SESSION (or
$HTTP_SESSION_VARS with PHP 4.0.6 or less) is
recommended for improved security and code readability. With
$_SESSION, there is no need to use the
session_register(),
session_unregister(),
session_is_registered() functions. Session variables
are accessible like any other variables.
Пример 1.
Registering a variable with $_SESSION.
|
<?php
session_start();
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
} else {
$_SESSION['count']++;
}
?>
|
|
Пример 2.
Unregistering a variable with $_SESSION and
register_globals disabled.
|
<?php
session_start();
unset($_SESSION['count']);
?>
|
|
| Предостережение |
Do NOT unset the whole $_SESSION with
unset($_SESSION) as this will disable the
registering of session variables through the
$_SESSION superglobal.
|
| Внимание |
You can't use references in session variables as there is no feasible way
to restore a reference to another variable.
|
If register_globals
is enabled, then each global variable can be registered as session
variable. Upon a restart of a session, these variables will be restored
to corresponding global variables. Since PHP must know which global
variables are registered as session variables, users need to register
variables with session_register() function.
You can avoid this by simply setting entries in
$_SESSION.
If register_globals
is enabled, then the global variables and the
$_SESSION entries will automatically reference the
same values which were registered in the prior session instance.
However, if the variable is registered by $_SESSION
then the global variable is available since the next request.
There is a defect in PHP 4.2.3 and earlier. If you register a new
session variable by using session_register(), the
entry in the global scope and the $_SESSION entry will
not reference the same value until the next
session_start(). I.e. a modification to the newly
registered global variable will not be reflected by the
$_SESSION entry. This has been corrected in PHP 4.3.
There are two methods to propagate a session id:
The session module supports both methods. Cookies are optimal, but
because they are not always available, we also provide an alternative
way. The second method embeds the session id directly into URLs.
PHP is capable of transforming links transparently. Unless you are using
PHP 4.2 or later, you need to enable it manually when building PHP.
Under Unix, pass
--enable-trans-sid to configure. If this build
option and the run-time option
session.use_trans_sid are enabled, relative
URIs will be changed to contain the session id automatically.
Замечание:
The arg_separator.output
php.ini directive allows to customize the argument seperator. For full
XHTML conformance, specify & there.
Alternatively, you can use the constant SID which is
defined if the session started. If the client did not send an appropriate session
cookie, it has the form session_name=session_id.
Otherwise, it expands to an empty string. Thus, you can embed it
unconditionally into URLs.
The following example demonstrates how to register a variable, and
how to link correctly to another page using SID.
Пример 3. Counting the number of hits of a single user |
<?php
if (!session_is_registered('count')) {
session_register('count');
$count = 1;
} else {
$count++;
}
?>
<p>
Hello visitor, you have seen this page <?php echo $count; ?> times.
</p>
<p>
To continue, <a href="nextpage.php?<?php echo strip_tags(SID); ?>">click
here</a>.
</p>
|
|
The strip_tags() is used when printing the SID
in order to prevent XSS related attacks.
Printing the SID, like shown above, is not necessary if
--enable-trans-sid was used to compile PHP.
Замечание:
Non-relative URLs are assumed to point to external sites and
hence don't append the SID, as it would be a security risk to
leak the SID to a different server.
To implement database storage, or any other storage method, you
will need to use session_set_save_handler() to
create a set of user-level storage functions.
add a note
User Contributed Notes
Session Handling Functions
mikeh at view22 dot com
19-Oct-2007 11:59
Observed what I think is a bug: session cookies were expiring even though the session was still active. (To test, set a cookie expiry of 5 seconds and keep hitting the page every second. The session will expire and create a new SESSID after 5 seconds despite the fact that you hit the page only a second ago.)
Calling this function before starting the session fixed it. It copies the cookie contents back to itself while forcing an update to the expiry time in the cookie.
function FreshenSessionCookie($lifetimeSeconds, $cookieName = 'PHPSESSID')
{
if (isset($_COOKIE[$cookieName]))
{
$data = $_COOKIE[$cookieName];
$timeout = time()+$lifetimeSeconds;
setcookie($cookieName, $data, $timeout);
}
}
carl /a/ suchideas /o/ com
30-Sep-2007 09:45
Another gotcha to add to this list is that using a relative session.save_path is a VERY BAD idea.
You can just about pull it off, if you're very careful, but note two related points:
1) The path is taken relative to the directory of the ORIGINALLY executed script, so unless all pages are run from the same directory, you'll have to set the directory separately in each individual subfolder
2) If you call certain functions, such as session_regenerate_id(), PHP will try to take the session directory relative to the exectuable, or something like that, creating an error IN the executable. This provides slightly cryptic error messages, like this:
Warning: Unknown: open(relative_path\ilti9oq3j9ks0jvih1fmiq4sv1.session, O_RDWR) failed: No such file or directory (2) in Unknown on line 0
Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (relative_path) in Unknown on line 0
... so don't even bother. Just use
<?php ini_set("session.save_path",dirname(__FILE__)."/relative_path"); ?>
(or equivalent) in a file which you know is always in the same place relative to the file.
{PHP version 5.1.6}
greenie__ at hotmail dot com
29-Aug-2007 09:29
A problem i've come up with is when sending a js file to the browser that has session_start in it ie will crack it and not download and execute the file. FF is fine and i think i know what the problem is. ie does not except cookie's for js files being downloaded and session_start is trying to send a message telling it to increase the id time longer even though its already initiated. I can read the session id from the browser, by $_COOKIE["PHPSESSID"] though i dont know of anyway of setting up the session from that without sending a cookie back.
jsnell at e-normous dot com
29-Aug-2007 01:58
Careful not to try to use integer as a key to the $_SESSION array (such as $_SESSION[0] = 1;) or you will get the error "Notice: Unknown: Skipping numeric key 0. in Unknown on line 0"
benjaminlindelof at yahoo dot com
20-Aug-2007 11:23
print $_SESSION['CustomVariable'];
this works like ASP Sessions.
Other methods do not
benjaminlindelof at yahoo dot com
20-Aug-2007 10:54
Please note: PHP Session Variables do not work like ASP Session Variables.
You can't just call a session variable. All you get is the Session ID. With the Session ID you can track the user.
But there are no Session Variables that you can create that work like ASP's Session("VariableName").
nn162077php at smallcue dot com
11-Aug-2007 04:20
Bruno's posting of mod_files works for default (16) or 32, but it doesn't work for 64. The following isn't great code since I'm not a great shell coder, but it does work better. It replaces the middle section of Bruno's script
hash_chars="0 1 2 3 4 5 6 7 8 9 a b c d e f"
if test "$3" ; then
if test "$3" -eq "32"; then
hash_chars="$hash_chars g h i j k l m n o p q r s t u v"
fi
if test "$3" -eq "64"; then
hash_chars="$hash_chars g h i j k l m n o p q r s t u v"
hash_chars="$hash_chars w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z - ,"
fi
fi
His posting should be updated (and mine should be removed). :-)
Nigel Barlass
28-Jun-2007 06:07
Lima's note on sessions and browser's tabs needs to be modified for my version of php as the call to uniqid('') will return an alphanumeric string.
Hence the ereg statement should be:
if(!ereg('^SESS[0-9a-z]+$',$_REQUEST['SESSION_NAME'])) {...
spam at chovy dot com
02-Jun-2007 12:01
Regarding xhtml validation errors with w3c validator:
The problem is the validator doesn't support cookies, so our session_start() mechanism injects hidden input fields just below all form tags (and in urls).
You need to do two things to pass validation:
1) use fieldsets around *all* input fields (for xhtml 1.0+) to pass validation
2) then, before session_start() change the url_rewriter.tags list of tags to drop form and add fieldset:
ini_set("url_rewriter.tags", "a=href,area=href,frame=src,fieldset=");
session_start();
You can also set url_rewriter.tags anywhere, (see appendix for php.ini)
legolas558 d0t users dot sf dot net
01-May-2007 08:45
To clear out a possible doubt of other readers which have read this part of "Eric dot Deplagne at nerim dot net" note:
--------
In fact, two other variables (at least) play a role in session duration, and will explain that the session might last more than expected. The gc erasing your data is a probabilistic thing. Each time a session is opened, the probability the gc is started is session.gc_probability/session.gc_divisor. session.gc_probability defaults to 1 and session.gc_divisor defaults to 100, which makes a 1% probability.
This is to have sessions long enough. I'm unsure about having sessions lasting exactly the time we want them to.
--------
The gc erasing of the sessions is NOT a probabilistic thing, they are erased ONLY when they are older than the number of seconds specified in "session.gc_maxlifetime" ini setting.
The probabilistic fact is that old sessions will not be erased if the garbage collector is not run frenquently enough, but anyway it is your choice to have a higher or lower "session.gc_probability" on "session.gc_divisor" ratio.
So, talking from the server side point of view, a session can last more than the specified amount of time but not less. And if the client respects the cookies duration (in case of cookie-based sessions) those invalid sessions will not last more than expected.
You finally might want to add a timestamp inside the session and validate its age through it to radically solve the problem, if necessary. Example:
<?php
session_start();
if (!isset($_SESSION['generated']))
$_SESSION['generated'] = time();
else { if (time() - $_SESSION['generated'] > ini_get('session.gc_maxlifetime'))
$_SESSION = array('generated' => time());
}
?>
g_s_b
27-Apr-2007 08:37
If you try to use your own session handling functions (eg. for saving session data to DB) make sure session.auto_start directive is 0.
The manual warns about not being able to put objects in your sessions with auto_start=1: I guess that for the same reason your customized handling functions are ignored is sessions start automatically.
Hope this saves somebody a few minutes.
skysama at googles_mail dot com
17-Apr-2007 11:56
If your session are not retrieving correctly make sure that session.cookie_secure is to set to 'Off' if you are NOT going through https. Everytime you navigate the site your session data will not be retrieved and your sessionid will change. It may be obvious but I spent two days trying to figuring this out. Hope it helps someone.
Edemilson Lima <pulstar at gmail dot com>
17-Apr-2007 06:17
Sessions and browser's tabs
May you have noticed when you open your website in two or more tabs in Firefox, Opera, IE 7.0 or use 'Control+N' in IE 6.0 to open a new window, it is using the same cookie or is passing the same session id, so the another tab is just a copy of the previous tab. What you do in one will affect the another and vice-versa. Even if you open Firefox again, it will use the same cookie of the previous session. But that is not what you need mostly of time, specially when you want to copy information from one place to another in your web application. This occurs because the default session name is "PHPSESSID" and all tabs will use it. There is a workaround and it rely only on changing the session's name.
Put these lines in the top of your main script (the script that call the subscripts) or on top of each script you have:
if(version_compare(phpversion(),'4.3.0')>=0) {
if(!ereg('^SESS[0-9]+$',$_REQUEST['SESSION_NAME'])) {
$_REQUEST['SESSION_NAME']='SESS'.uniqid('');
}
output_add_rewrite_var('SESSION_NAME',$_REQUEST['SESSION_NAME']);
session_name($_REQUEST['SESSION_NAME']);
}
How it works:
First we compare if the PHP version is at least 4.3.0 (the function output_add_rewrite_var() is not available before this release).
After we check if the SESSION_NAME element in $_REQUEST array is a valid string in the format "SESSIONxxxxx", where xxxxx is an unique id, generated by the script. If SESSION_NAME is not valid (ie. not set yet), we set a value to it.
uniqid('') will generate an unique id for a new session name. It don't need to be too strong like uniqid(rand(),TRUE), because all security rely in the session id, not in the session name. We only need here a different id for each session we open. Even getmypid() is enough to be used for this, but I don't know if this may post a treat to the web server. I don't think so.
output_add_rewrite_var() will add automatically a pair of 'SESSION_NAME=SESSxxxxx' to each link and web form in your website. But to work properly, you will need to add it manually to any header('location') and Javascript code you have, like this:
header('location: script.php?'.session_name().'='.session_id()
. '&SESSION_NAME='.session_name());
<input type="image" src="button.gif" onClick="javascript:open_popup('script.php?<?php
echo session_name(); ?>=<?php echo session_id(); ?>&SESSION_NAME=<?php echo session_name(); ?>')" />
The last function, session_name() will define the name of the actual session that the script will use.
So, every link, form, header() and Javascript code will forward the SESSION_NAME value to the next script and it will know which is the session it must use. If none is given, it will generate a new one (and so, create a new session to a new tab).
May you are asking why not use a cookie to pass the SESSION_NAME along with the session id instead. Well, the problem with cookie is that all tabs will share the same cookie to do it, and the sessions will mix anyway. Cookies will work partially if you set them in different paths and each cookie will be available in their own directories. But this will not make sessions in each tab completly separated from each other. Passing the session name through URL via GET and POST is the best way, I think.
Marcin Wiazowski
03-Apr-2007 01:11
'session.cookie_domain' should be set to empty string for all local domain names, not only for 'localhost' (but should not be empty for local IP addresses):
<?php
ini_set('session.cookie_domain', (strpos($_SERVER['HTTP_HOST'],'.') !== false) ? $_SERVER['HTTP_HOST'] : '');
?>
gordon_e_rouse at yahoo dot com dot au
28-Mar-2007 08:06
Multi-site security risk!
Suppose you use session security to determine login status, and you have several such sites on the webserver which essentially assign a session token to determine your login status. A common occurence for webdeveloping companies that have a standard system or package, and are not using a high security setup. (ie all sites share the same session path directory)
PHP sends the browser a cookie and that cookie should only be valid for the site it was retrieved from, but only the browser determines this, the server does not record the path or domain with the session cookie, so technically you could modify the browsers cookie jar to send the same cookie request for a different domain or path than what was originally meant.
This means that if the same session variables are used to determine a logon status on different sites on this server, then the user can access all these sites with the one session id.
The solution is to write the domain and or path as session variables as well, thus when logged on status is checked, the script checks that the session was created through the current domain or path.
jphansen at uga dot edu
12-Mar-2007 02:06
I wanted to retain a session variable's value after a session_unset() and encountered this anomaly: PHP can assign your variable by reference/pointer if your data source is a session variable, even if "&" isn't supplied.
<?
$_SESSION['x'] = "foo";
$x = $_SESSION['x'];
echo $x; // "foo"
$_SESSION['x'] = "bar";
echo $x; // "bar";
?>
To fix this, you can assign your variable to a new variable:
<?
$_SESSION['x'] = "foo";
$x = $_SESSION['x'];
$y = $x;
echo $y; // "foo"
$_SESSION['x'] = "bar";
echo $y; // "foo";
?>
Parikesit
09-Feb-2007 10:26
localhost problem
-----------------
When using localhost and session.cookies not work, simply remove domain from session.cookie_domain.
We can use "session_set_cookie_params" function or ini_set to do this. Example:
$cookie_path = 'my_path';
$cookie_domain = 'localhost'; //or any valid domain
init_session_cookies($cookie_path, $cookie_domain);
//maybe we create new function for handling this
function init_session_cookies($path, $domain) {
if ($domain=='localhost') $domain='';
if (function_exists('session_set_cookie_params')) {
session_set_cookie_params(0, $path, $domain);
} else {
ini_set('session.cookie_lifetime', '0');
ini_set('session.cookie_path', $path);
ini_set('session.cookie_domain', $domain);
}
}
Best,
Parikesit (zae_lokamaya #at# yahoo #dot# co #dot# uk)
Jim Rogers at mail dot com
30-Jan-2007 08:57
url_rewriter.tags = "a=href,area=href,frame=src,fieldset="
Modifying url_rewriter.tags to the above line in the php.ini file gave me mixed results, including some pages adding the sessionid after BOTH the form tag and the fieldset tag.
Then I noticed the comment at the top of the php.ini file: "If you modify the file, you must copy it to all subdirectories that contain php." This has to do with the search order php uses to find the php.ini file. PHP looks in the current working directory first.
Works.
Dave Matlock
29-Jan-2007 02:35
In reference to the IE6 issue that results in loss of session data after a page refresh, I found a solution. In my case, the host that was experiencing the issue contained an underscore (host_dev). Apparently underscores are not valid in host names and IE is the only browser that seems to care. I removed the underscore and all is well. I found this information here: http://us2.php.net/manual/en/function.setcookie.php#67262
Stephen
02-Jan-2007 04:47
jmoore at sober dot dk wrote: "Note: Changing sessions to use a directory other than /tmp will be harder to find, but no more secure."
This is true. I used to think that this could be solved by storing sessions in a different folder that is accessible only by apache, but the reality is that assuming you are only running a single apache server (as any shared host will), every user can command apache to retrieve that data.
The best solution is to store session data in a database by writing (and informing PHP about) specific session handling functions that store the data using a private username and password that only you know. There is a good discussion of this in Essential PHP Security by Chris Shiflett (O'Reilly Books).
02-Jan-2007 03:44
Bruno's shell script below is very helpful for those who want to customize their session storage. I would only warn that there is a typo in his instructions. He states that the script should be called as:
./mod_files.sh ./mod_files.sh /tmp/session 3 32
But you should only type mod_files.sh (or whatever the name of your script file is) once, not twice. It doesn't need its own name as an argument.
Also - make sure you don't make the silly mistake I did of naming your script file "script" and then trying to call it with the argument:
script /tmp/session 3 32
...because "script" is the name of a real Unix function, which will launch a completely different function and then overwrite your original file with whatever you type after that. If you do that by accident, you will need to type "exit" to get out of the script recording mode, and then replace your script file. Also, you have to include the './' prior to the name (i.e. './mod_files.sh' instead of 'mod_files.sh') unless you are running the script from the folder where you installed it, because the location where you are installing this probably (hopefully!) isn't in your PATH shell variable.
Marce!
22-Dec-2006 12:20
Be careful when using use_trans_sid and javascript together. When adding a form dynamically with javascript, you usually need to put it in quotes and use addslashes() for your html code.
This will nicely put slashes into the code for your form and the javascript will work perfectly. Or so you would think. PHP does recognise the form, even with the slashes added. So it will neatly insert a hidden variable to your form, with the name of your session variable and the value of the session ID. This hidden variable isn't slashed though, and it may break your javascript code.
The only solution I came up with, is to manually add the hidden variable, before applying the addslashes() function. It will then be shown correctly, and PHP will not insert the hidden value. Of course you may get both a cookie and the variable, depending on your settings, but it does work.
bens at effortlessis dot com
13-Dec-2006 08:25
Note on using (the excellent!) Sharedance:
Sharedance as of 0.6 doesn't do any kind of locking. It works well for an application cluster (which I'm using) and allows concurrent writes, which means that the "last one to write wins" order stands. (which has virtually no effect on how I use sessions)
aserboni at gmail dot com
04-Dec-2006 12:59
The session variable is still lost when navigating even if I change $setting or $_SESSION['setting'].
If you assign a session subscript/key to the same name as a variable, the session variable will be volatile and lost upon navigating.
For example, if passing a setting that you want in $_SESSION, don't do this:
<?
$setting = $_REQUEST['setting'];
if (!empty($setting))
$_SESSION['setting'] = $setting;
?>
Instead, rename $setting or $_SESSION['setting'].
01-Dec-2006 12:52
To Jestin S Larson :
Your generated ids arent safe, they are guessable because depending only on guessable vars. You must add a random var to your id (ie in md5( ... ) )
robin at amiance dot com
26-Nov-2006 10:19
If you want the simplest way there is to log a session out after 30 minutes (or any other period of inactivity) simply add a second line after session_start(), like this:
session_start();
setcookie("PHPSESSID",$_COOKIE['PHPSESSID'],time()+1800);
Where 1800 is the time in seconds before the session should expire. PHPSESSID is the default session ID. This way, every time a user loads a page they get their session extended.
klenwell at gmail dot com
05-Oct-2006 05:39
In response to marou at marou dot com responding to fondman at hotmail dot com regarding local variables overwriting SESSION variables:
I was encountering this same problem. On my local PHP 5 server, no problem. Remote host's server running PHP 4: major headaches.
Initially, I concluded it was some kind of bug in PHP 4 and older. However, according to the devs, this is not a bug (see http://bugs.php.net/bug.php?id=36366). Apparently, this is intended behavior when register_globals is set to ON.
But, as noted elsewhere in the docs, register_globals cannot be turned off at runtime using ini_set(). However, you can use a local .htaccess or php.ini to override the setting. This site helped me solve the problem:
http://www.nyphp.org/phundamentals/ini.php
Full details of my experience with this issue can be found here:
http://tinyurl.com/o6p7y
wings at 25th dot com
05-Oct-2006 06:59
Jestin's Session class is a nice alternative, but I had trouble with it. The results of the filesize() function are cached. I ended up having to put a call to clearstatcache() at the head of Session::_getdata(); Otherwise, your session data gets truncated.
jon at jonroig dot -----com
26-Sep-2006 04:30
This code is to solve a problem that's probably becoming more common as we move into the AJAX world -- how the &*^*&^ to access session data if you're transferring data back 'n' forth from a server and you don't have cookies to help you out.
The function accepts the session ID then grabs the session data straight from the directory, parses it, and returns it as an array.
<?
function grabSessionData($sessionInput)
{
$sessionThing = "/tmp/sess_".$sessionInput;
$textContentsArray = file($sessionThing);
$serializedData = '';
foreach ($textContentsArray as $line => $textLine)
{
$serializedData = $serializedData.$textLine;
}
$sessionArray = explode(";",$serializedData);
$sessionDataArray = array();
foreach ($sessionArray as $line => $dataLine)
{
$dataArray2 = explode('|',$dataLine);
$dataArray3 = explode(':',$dataLine);
$sessionDataArray[$dataArray2[0]] =
str_replace('"','',$dataArray3[count($dataArray3)-1]);
}
return $sessionDataArray;
}
// example
$sessionInfoArray = grabSessionData('f58c92b76c1dd553c56dd428ea7a1bfc');
?>
steffen at steffen-ille dot de
13-Sep-2006 05:02
old problem was:
internet explorer has security settings which reject your php session cookie within different framesets (third party cookies). one approach to handle this was to pass the session id to the other frames in the url. the www says, this is a little bit unsafe...
another trick to handle this is, to trick the explorer with the php header funktion. as described in the microsoft knowledgebase
article http://support.microsoft.com/kb/323752/EN-US/
you simply add a header at the top of your scripts _bevore_ the session_start() is called:
header('P3P: CP="CAO PSA OUR"');
and now test it and enjoy...
12-Sep-2006 11:28
Here is a replacement I wrote for Session Handeling.
Before use, you must replace "[--PATH-TO-SESSION-FOLDER--]" with the path to where sessions should be stored. Make sure to set the proper permissions for that folder :)
--------------------------------------------------------------------
<?
class Session
{
function _makeid()
{
$time = time();
$ip = $_SERVER["REMOTE_ADDR"];
$agent = $_SERVER["HTTP_USER_AGENT"];
$md5 = md5($time.$ip.$agent);
setcookie("SClass", $md5);
return($md5);
}
function getid()
{
$md5 = $_COOKIE['SClass'];
return($md5);
}
function start()
{
$id = $this->getid();
if (!$id) { $id = $this->_makeid(); }
}
function _getfile()
{
$file = $this->getid();
$file .= ".ssn";
$file = "[--PATH-TO-SESSION-FOLDER--]".$file;
return($file);
}
function _setdata($data)
{
$file = $this->_getfile();
$fs = @fopen($file, w);
if ($fs) { fwrite($fs, $data); fclose($fs);}
if (!$fs) { return(FALSE); }
}
function _getdata()
{
$file = $this->_getfile();
$fs = @fopen($file, 'r');
if ($fs) { $data = fread($fs, filesize($file)); fclose($fs); return $data; }
if (!$fs) { return(FALSE); }
}
function set($key, $value)
{
$data = $this->_getdata();
$data = base64_decode($data);
$array = unserialize($data);
$array["$key"] = $value;
$newdata = serialize($array);
$newdata = base64_encode($newdata);
$this->_setdata($newdata);
}
function get($key)
{
$data = $this->_getdata();
$data = base64_decode($data);
$array = unserialize($data);
return($array[$key]);
}
}
?>
--------------------------------------------------------------------
Useage:
$Session = new Session();
$Session->start();
$Session->set($key, $value);
$sessionvalue = $Session->get($key);
--------------------------------------------------------------------
- Jestin S Larson
nhap24
09-Sep-2006 05:03
I spent about 8 hours debugging a problem with sessions and redirecting, and I finally found the problem, which after looking back, should have been the first thing I tried.
I use sessions to prevent hotlinking, so if someone hotlinks my file, I will redirect them to a different page by re-writing the header information. When I redirected, I sent path information in the GET data about the file they were trying to access. Long story short, when I redirected with a forward-slash "/" AFTER the .php, the page would create a different session ID than the rest of my domain was using. This happened despite the fact that the cookie path was set to "/" (which should have captured any path on my domain).
The issue was even harder to figure out, because the page with the wrong session ID was NOT creating a second cookie. The only cookie was the one with the proper ID, but the broken page did not use this cookie (where then, did it get this ID from?).
To fix the problem, I simply removed the forward-slash from the GET data (base64_encoding works nicely).
I imagine this is an issue with my browser parsing the url, but I tried both Opera and Firefox (IE doesn't load anymore :/) and both browsers showed the same problem.
I looked into hidden header data, failure to write the cookie, trans_ses_id (even though it was set to false), HTTP_HOST, everything, but in the end it was just a stupid forward-slash that had done me in.
greenthumb at 4point-webdesign dot de
01-Sep-2006 11:56
Similar to the use of captcha images you can easely track and advise user who don't accept cookies, especially no session cookies without redirecting them.
so here's the deal:
if the main script (which outputs the html) doesn't have a value in it's session which says that a session is running successfully a different value is saved in the session and an image is included in the html which checks wether the session-check value is set or not.
If it's set the image-script sets a confirming value which will verify the session to be running correctly and output a transparent 1*1px gif.
If the value is not set the image outputs an advising image which tells to allow cookies.
You can also wrap the image with a link who refers the user to a page addressing the cookie issue. If the 1px trans is generated the user will hardly find the link, but if the error-image is generated he will surely be able to click it.
pros:
- works
- no rerouting, you can see the result on the first page opened by the user
- no javascript
cons:
- bad accessebility (if you give the image an alt-text any blind user will read it at least on the first call, but you cold also write this into the alt text... so maybe there are no cons)
i hope this'll help
in dot tray at NOSPAM dot tiscali dot co dot uk
24-Aug-2006 06:19
Some users turn off cookies on their browser. It would be nice to advise such users that they need to switch on cookies to use your web site, especially if you do not allow URL session IDs.
The first request to your site will not contain cookie data from the user. Some developers do a little trick on the server at this point to redirect the user to the same or different page and in so doing endeavour to deliver a cookie so that it can then be determined if this was successful on the second request. It has the advantage of letting the no-cookie user know at the on-set if there is a problem. Of course this adds an overhead of time and server resources. It also might impare your site's position with popular search engines.
So, since many sites will work to a point without sessions working (i.e. scatterings of static links and basic searches), I allow the user to load the first page and then perform the cookie check upon the user's subsequent request. If the cookie canot be found I place advice text accordingly
simple (unchecked) solution...
function cookie_check() {
if (!isset($_COOKIE['PHPSESSID'])) {
return false;
} else {
return true;
}
if (!cookie_check()) {
echo "This site uses cookies, dah dah dah...";
}
I have looked fairly extensively for information on this issue but there isn't a great deal about. So, if anyone out there has more experience of this...
Bruno Negrao G Zica
24-Aug-2006 06:13
#! /bin/sh
# NAME
# mod_files.sh - Update of the php-source/ext/session/mod_files.sh
#
# SYNOPSIS
# mod_files.sh basedir depth [numberofsubdirs]
#
# DESCRIPTION
# this script creates the directories tree used by php to store the session files
# (see php.ini - 'session.save_path' option)
#
# Example: if you want php to store the session files in a directory tree
# of 3 levels of depth containing 32 directories in each directory,
# first, put the setting bellow in the php.ini file:
#
# session.save_path = "3;/tmp/session"
#
# Now create the basedir directory: 'mkdir /tmp/session'
#
# Then, call this scrip with the following arguments:
#
# ./mod_files.sh ./mod_files.sh /tmp/session 3 32
if test "$2" = ""; then
echo "usage: $0 basedir depth [numberofsubdirs]"
echo "numberofsubdirs: if unset, defaults to 16. if 32, 32 subdirs, if 64, 64 subdirs."
exit 1
fi
if test "$2" = "0"; then
exit 0
fi
hash_chars="0 1 2 3 4 5 6 7 8 9 a b c d e f"
if test "$3" -a "$3" -eq "32"; then
hash_chars="$hash_chars g h i j k l m n o p q r s t u v"
if test "$3" -eq "64"; then
hash_chars="$hash_chars w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z - ,"
fi
fi
for i in $hash_chars; do
newpath="$1/$i"
mkdir $newpath || exit 1
sh $0 $newpath `expr $2 - 1` $3
done
entropicchild
23-Aug-2006 09:09
I just went looking through the /tmp dir on a shared hosting server, and noticed all the php sessions stored there (bad idea for shared hosting). I noticed that some of these people/scripts are storing plain-text passwords in their sessions (another very bad idea). Here's a hint people: do not store ANYTHING that may present a security risk in the session data! This includes, passwords, creditcard information, etc.
It is best, under ALL circumstances that a dir other than /tmp be used for session data. Btw, whomever it was that said it was no more secure to use a diff dir was wrong. The /tmp dir is a globally readable/writable dir.
If you are using shared hosting, then you better be sure your session data is being saved within your home dir and NOT web-accessible. If you are a shared hosting sysadmin, you should be doing this for your users automatically... as well as any other tmp files (file uploads, etc...).
http://mike.eire.ca/
09-Aug-2006 03:08
It should be noted that PHP makes the decision about whether SID is empty based on the HTTP request. Specifically, if there is no cookie sent with the GET or POST request, SID is populated when the session is initiated.
What does this mean? If you want your site to support clients who have cookies disabled, your links will have PHPSESSID appended to them on the page where the session is created.
It seems like the only way around this is a double redirect...
Eric dot Deplagne at nerim dot net
01-Aug-2006 03:34
One more note on session duration, and especially long sessions. I hope I've now understood the problem, and this may be useful.
The duration of a session is indeed controlled by many things (too many for my taste).
The first thing is session.cache_expire, which should be *the* thing, you can set it with ini_set(), or with session_cache_expire(). The value is in minutes, and defaults to 180, which is 3 hours and should be enough.
<?php ?>
But that does not work !
Second thing to take into account, session.gc_maxlifetime. Indeed, if the garbage collector kills your session data, you're lost. So we set it with ini_set. The value is in seconds, and defaults to 1440, which is only 24 minutes and might be a little short.
<?php ini_set("session.gc_maxlifetime","3600"); ?>
Here I should have a 1 hour session. But in fact, I don't !
Third thing to take into account, session.save_path. If other people mess up with it, like if it's "/tmp" as it is by default, and their gc has not the same idea as yours, you're lost. So we set it with ini_set or session_save_path.
<?php session_save_path("/my/own/path/without/url/sessions"); ?>
Here we are. As you can read in the example it should be a path you control (and your web server can write), with no access via URL.
Of course, all these parameters must be set before calling session_start().
In fact, two other variables (at least) play a role in session duration, and will explain that the session might last more than expected. The gc erasing your data is a probabilistic thing. Each time a session is opened, the probability the gc is started is session.gc_probability/session.gc_divisor. session.gc_probability defaults to 1 and session.gc_divisor defaults to 100, which makes a 1% probability.
This is to have sessions long enough. I'm unsure about having sessions lasting exactly the time we want them to.
rehevkor5 at fastmail dot fm
25-May-2006 11:34
If you have a value specified for session.referer_check you may run into difficulty when someone accesses your site and attempts to log in with a mis-capitalized URL. The logon will fail because any calls to session_start() will result in the existing session being trashed and a new one being created. This becomes a bigger problem when the logon is followed by a header("Location: ...") redirect, because the session_start() at the top of the page will fail.
Because session_start() always returns true, it's not obvious how to detect when the referer check fails. To detect it, I have come up with a method which compares the intended session id with the session id after session_start() is run. If they are different, the user is redirected to the proper location. This example uses a technique to avoid session id fixation, as well.
ini_set('session.referer_check', 'www.yourdomain.edu/ltr/');
ini_set('session.use_only_cookies', 1);
session_name('yourapp'.str_replace('.', '', $_SERVER['REMOTE_ADDR']));
session_start();
if($_GET['badreferer'])
echo 'You tried accessing the site with a bad URL. Try logging on again.';
if(isUserAuthed($name, $pass))
{
$old_sessid = session_id(); //save current session id so we can delete it later
if( !session_regenerate_id() ) //get a new session id (must do this before destroying the old session)
die("Couldn't regenerate your session id.");
$new_sessid = session_id(); //save new session id so we can get back to it
session_id($old_sessid);
unset($old_sessid);
session_destroy(); //destroy the session they got before they logged in
session_id($new_sessid);
session_start(); //start the new session
$_SESSION = array(); //not really necessary any more, but still a good idea
if(session_id() != $new_sessid)
{
/*If this is true, then the session_start() failed to work properly. If session_start() failed to work properly, the most likely cause is that the referer url is different from that set in fuxebox.ini on session.referer_check. The most common cause of this is URL capitalization problems. Therefore, we relocate them to the proper URL, and set a flag to display an error because we can't use pushError() if the session isn't valid. */
$good_url = ini_get('session.referer_check');
header('Location: http://'.$good_url.'?badreferer=1');
exit;
} else {
unset($new_sessid);
//Set session variables here
$_SESSION['isloggedin'] = 1;
echo 'You have been logged in.';
}
}
rajasekhar_s7 at yahoo dot co dot in
19-May-2006 04:07
POST the variable can give the page Expire Warnig when you press the BACK button.
Solution: Put this code on the page top.
<? session.cashe.limiter(‘private, must-revalidate’) ?>
php AT coryforsyth [removeme] d0t com
08-May-2006 07:14
I just finished a marathon debugging session with sessions, and I wanted to share what I learned with the rest of the PHP community because this has been a problem I've battled on several projects before finally solving it today.
I am using sessions to register a user's ID, and every so often, for no apparent reason, the session would seem to expire and my logged-in user would get kicked out.
This is the code I am using to validate a user:
<?php
session_start();
$auth = false;
if (isset($_SESSION['user_id'])) {
$user = new User($_SESSION['user_id']);
$auth = true;
else {
$login = $_REQUEST['login'];
$password = $_REQUEST['password'];
$login = clean($login);
$password = clean($password);
$user = checkLogin($login,$password);
if (!is_null($user)) {
$auth = true;
}
}
if (!$auth) {
die("you must log in.");
}
?>
I was scratching my head as to why, on about 10% of the times I sent a user to a new page (a PHP page that didn't have any of the sessions stuff--no session_start() and no mention of any session variables), when they came back the session variables were all empty.
I came upon a clue when I used ini_set to change the session.save_path location. My idea was that maybe the session files in /tmp were being deleted by other users on the system or something. So I added this line before session_start():
<?php
ini_set('session.save_path',"/path/to/unique/dir/");
?>
I knew no one else was saving their sessions there, so I started logging in to my page and at the same time checking for the creation of new sess_* files. I noticed that sometimes, especially when I had problems, a second session file (that was empty) would appear.
What I realized was that the URL was changing from www.coryforsyth.com to coryforsyth.com. When the presence of the WWW changed, PHP thought it was a different session and created an empty one that caused my script to log me out. If I went to the location bar of my browser and added/removed the WWW (to the way it had been before), all was well and I was still logged in.
An incredibly thorny problem. I hope this post helps someone else fix it, or even better prevent it. I changed my hosting preferences to automatically add a WWW to my domain if it wasn't typed that way.
thanks,
Cory Forsyth
brady at volchok dot com
17-Apr-2006 12:15
Session locking (concurrency) notes:
As mentioned several times throughout this section on Sessions, the default PHP session model locks a session until the page has finished loading. So if you have two or three frames that load, and each one uses sessions, they will load one at a time. This is so that only one PHP execution context has write access to the session at any one time.
Some people work around this by calling session_write_close() as soon as they've finished writing any data to the $_SESSION - they can continue to read data even after they've called it. The disadvantage to session_write_close() is that your code still will lock on that first call to session_start() on any session'ed page, and that you have to sprinkle session_write_close() everywhere you use sessions, as soon as you can. This is still a very good method, but if your Session access follows some particular patterns, you may have another way which requires less modification of your code.
The idea is that if your session code <b>mostly</b> reads from sessions, and rarely writes to them, then you can allow concurrent access. To prevent completely corrupted session data, we will lock the session's backing store (tmp files usually) while we write to them. This means the session is only locked for the brief instant that we are writing to the backing store. However, this means that if you have two pages loading simultaneously, and both modify the session, the <i>Last One Wins</i>. Whichever one loads first will get its data overwritten by the one that loads second. If this is okay with you, you may continue - otherwise, use the session_write_close method, above.
If you have complicated bits of code that depend on some state in the session, and some state in a database or text file, or something else - again, you may not want to use this method. When you have two simultaneous pages running, you might find that one page runs halfway through, modifying your text file, then the second one runs all the way through, further modifying your text file, then the first one finishes - and your data might be mangled, or completely lost.
So if you're prepared to debug potentially very, very nasty race conditions, and your access patterns for your sessions is read-mostly and write-rarely (and not write-dearly), then you can try the following system.
Copy the example from session_set_save_handler() into your include file, above where you start your sessions. Modify the session write() method:
<?
function write($id, $sess_data)
{
global $sess_save_path, $sess_session_name;
$sess_file = "$sess_save_path/sess_$id";
if ($fp = @fopen($sess_file, "w")) {
flock($fp,LOCK_EX);
$results=fwrite($fp, $sess_data);
flock($fp,LOCK_UN);
return($results);
} else {
return(false);
}
}
?>
You will probably also want to add a GC (Garbage Collection) method for the sessions, as well.
And of course, take this advice with a grain of salt - We currently have it running on our testing server, and it seems to work OK there, but people have reported terrible problems with the Shared Memory session handler, and this method may be as unsafe as that.
You can also consider implementing your own locks for scary concurrency-sensitive bits of your code.
marcosdsanchez {a t} gmail [_dot_] com
07-Apr-2006 07:52
********************WARNING***********************
There's a bug in Internet explorer in which sessions do not work if the name of the server is not a valid name. For example...if your server is called web_server (_ isn't a valid character), if you call a page which uses sessions like http://web_server/example.php your sessions won't work but sessions will work if you call the script like this
[IP NUMBER]/example.php
Took me a lot of time to find out why my PHP sessions worked perfectly in Firefox and Opera but they didn't work in internet explorer
***************************************************
Cosmo
01-Apr-2006 04:47
Fairly new to PHP, I've been looking to alter session timeouts on a shared host where I don't have direct access to configure php.ini. There doesn't appear to be any easy way to find out how to do this in this manual (nor from a quick web search).
The code below seems to work OK to set session timeout. a timeout of 30 secs is used for convenient testing. gc settings must come before session_start().
The garbage collection is made 100% by setting probability and divisor to the same value - if I have correctly understood what these functions do.
(on the first pass of the file, there is no session file - that's established only when the script ends for the first time. Keep reloading to test).
Comments welcome.
<?php
ini_set('session.gc_maxlifetime',30);
ini_set('session.gc_probability',1);
ini_set('session.gc_divisor',1);
session_start();
$filepath = ini_get('session.save_path').'/sess_'.session_id();
if(file_exists($filepath))
{
$filetime = filemtime ($filepath);
$timediff = mktime() - $filetime;
echo 'session established '.$timediff.' seconds ago<br><br>';
}
?>
Josh
08-Mar-2006 10:35
I had users of my site occsaionally complaining that they were being logged out after short times of inactivity (usually when they were creating content to send to the site). I had a high cookie timout so I couldn't understand why this was happening, and I never managed to replicate the behaviour myself.
I've just come accross the "gc_maxlifetime" property. This seems to be the culprit; it's set to only 24 minutes! The worst part is that it combines with the "gc_probability" property to produce unpredictable results. I'm mysified as to why the time limit is so low by default, but hopefully increasing it will fix up my errors.
crown2gain at yahoo dot com
01-Mar-2006 10:19
I just spent a lot of time trying to figure out why my session variables were not available after I seemed to have set them(could echo after setting). I use the same script for several different functions, so the user may reload the page for other purposes. Someone else posted the use of session_write_close(); before a Location redirect. This also worked in put this after I set the session variables the variables are available when the page reloads for another function.
$_SESSION['guid'] = $guid;
$_SESSION['userdata'] = $response;
session_write_close();
a l bell at hutchison dot com dot au
28-Feb-2006 03:17
Please Note;
Internet explorer users beware.
When using session_start() to begin a session this session will remain open until the page has finished loading or it is explicitly terminated.
You can lose the session however if the the page contains a reference to <img src=""> with name and id references (which may be used if the image is referencing a dynamic image, called by javascript) This seems to casue IE6 to refresh the page session id and hence loose the session.
This took hours for me to diagnose when users were getting unexpectedly logged out of my site due to this "" in the img src.
kintar at infinities-within dot net
28-Feb-2006 09:10
Important note that it just took me the better part of two hours to figure out: Even if you're using session_write_close(), calling exit after a redirect will eat your session variables. I had the following:
Source of register.php:
<?PHP
$result = processPost();
if ($result)
{
redirect('success.php');
}
else
{
redirect('failure.php');
}
exit;
?>
processPost() was setting a couple of session variables, including an error message, but neither results page was seeing those variables. I removed the exit call from the register page, and all works fine.
/bonks self
phpkloss at wholewheatradio dot org
22-Feb-2006 12:57
If you're having trouble with unset($_SESSION[$something]) working, here's what I discovered (Win2K/PHP 5.x.x). Assume you want to step through $_SESSION and delete (i.e. unset) certain elements. So,
foreach ($_SESSION as $key=>$value) {
if (stristr($key,'something_to_delete')) {
echo "Will unset $key that has value of $value";
unset($_SESSION[$key]);
}
What I found was that although the $_SESSION elements were deleted in memory, the actual session file was not being written out with the changes (even after using session_write_close). What fixed it for me was to COPY $_SESSION INTO A DUMMY ARRAY, THEN STEP THROUGH THAT DUMMY ARRAY TO FIGURE OUT WHICH ELEMENTS OF THE REAL $_SESSION TO DELETE. I.e.
foreach($_SESSION as $key=>$value) {
$dummy[$key]=$value; // copy to a dummy array
}
foreach ($dummy as $key=>$value) {
if (stristr($key,'something_to_delete')) {
echo "Will unset $key that has value of $value";
unset($_SESSION[$key]);
}
It appears that as you're stepping through the actual $_SESSION array in a foreach, if you unset elements of it, those changes won't be recorded to the session disk file.
'Course then again, my coffee is running low so I could be wrong. But hopefully it's something others can try who might be having a similar problem.
20-Feb-2006 10:21
In response to "djohnson at jsatech dot com", posted 09-Dec-2005 09:00
"Be warned, when working with tab-based browsers like Opera and Firefox, sessions are preserved across tabs....IE deals with sessions just fine. There is probably some way to adjust the settings in Firefox or Opera, but that is not the default, and will affect most users."
In fact, the way sessions are managed among different browsers is not all that different among MSIE and Opera and Firefox. You will find that MSIE sessions can be maintained across browser windows, just like in FF or Opera. However the difference that djohnson noted is because of the way MSIE windows are created vs FF and Opera.
If you choose, in MSIE, "File->New Window", you will find that PHP sessions are preserved from browser window to browser window.
If, OTOH, you start a new window of MSIE using the start menu or desktop icon, a new instance of MSIE, with a new process ID, is started. *This* instance does not have anything to do with any other previously existing MSIE instances, and, thus, PHP sessions started in this new MSIE process are distinct from PHP sessions in existing MSIE instances.
See the difference?
Whereas FF and Opera apparently always start a new window into an existing FF or Opera process. Thus PHP sessions are always maintained across browser instances with FF and Opera.
hans at nieser dot net
14-Feb-2006 07:15
FreeBSD users, instead of modifying the PHP5 port Makefile, you can either install the session extension using the www/php5-session port, or you can install several extensions at once (you can pick them from a menu) using the lang/php5-extensions port. Same goes for PHP4
just_somedood at yahoo dot com
01-Feb-2006 09:31
If you're running FreeBSD, and installed php5 (have not checked 4) from the ports, and are getting errors saying the session functions are undefined, try running phpinfo(). You'll probably see that the '--disable-all' configure command was used. To fix, edit the /usr/ports/lang/php5/Makefile, and remove the '--disable-all' line. In that directory, run a 'make deinstall', if you installed already. Next, run 'make install' while still in that same directory. It should work fine after that.
warkangaroo
26-Jan-2006 08:33
After hitting my head on the desk a few times trying to debug this construct,
$_SESSION['result']['number'] = $blah;
returning the warning,
"Warning: Cannot use a scalar value as an array"
and not saving my value, I found out that apparently $_SESSION['result'] is a reserved variable... I changed it to $_SESSION['bresult'] and it works fine.
Just trying to save someone a headache...
james dot ellis at gmail dot com
26-Jan-2006 12:23
If you are wondering why your garbage cleanup method is not being called, read on.
The manual notes for garbage cleanup state that the session.gc_divisor defaults to 100:
[code]
//http://php.net/manual/en/ref.session.php
session.gc_probability ... Defaults to 1.
session.gc_divisor .... session.gc_divisor defaults to 100.
[/code]
This would provide a gc probability of 1 in 100 ie. your garbage cleanup is going to be called 1% of the time.
Conversely, my PHP 5.1.1 install, compiled from source, contains this in the php.ini-recommended file (and my php.ini file):
[code]
; Define the probability that the 'garbage collection' process is started
; on every session initialization.
; The probability is calculated by using gc_probability/gc_divisor,
; e.g. 1/100 means there is a 1% chance that the GC process starts
; on each request.
session.gc_probability = 1
session.gc_divisor = 1000
[/code]
A 0.1% probability by default. Based on the information provided, I set my gc_probability to 100, thus providing a 1% probability stale sessions would be culled.
Moral:your local php.ini may differ from what the manual provides.
jerry dot walsh at gmail dot com
24-Jan-2006 06:56
If you're using sharedance to distributed php sessions across a group of machines beware of the following:
On a freebsd 6.x system I have observed a huge performance hit caused by dns/host file lookups.
To ensure maximum performance using sharedance you should set the 'SESSION_HANDLER_HOST' constant to an IP rather than a hostname.
When i did this my requests per second jumped from 55 to 389 requests per second!
darkelf79 at gmail dot com
20-Jan-2006 03:00
If you set the session_id through the calling URL, it *will not* set the session cookie in 4.4.2.
For example:
www.example.com/?PHPSESSID=foo
This will set the session id to 'foo' but it won't actually set the session cookie. The last known version I'm aware of is 4.3.3 where it will set the cookie.
This doesn't appear to be definitively mentioned in here anywhere. But according to the devs, it's not a bug. Hopefully this knowledge will help you out if you're experiencing the same problem.
pascal.fr => gmail.com
20-Jan-2006 02:24
If you have saved an object in session, you must define the class of the object before the session_start().
If you don't do that, php will not know the class of the object, and his type will be "__PHP_Incomplete_Class".
This:
<?php
session_start();
class Foo{
var $fooVar = 'Hello world !!!';
}
$myFoo = new Foo();
$_SESSION['myFoo'] = $myFoo;
echo 'Save in session';
?>
define the Foo class and save an instance in session.
<?php
session_start();
echo '<pre>';
print_r( $_SESSION ); echo '</pre>';
?>
will print :
Array
(
[myFoo] => __PHP_Incomplete_Class Object
(
[__PHP_Incomplete_Class_Name] => foo
[fooVar] => Hello world !!!
)
)
royappa at spiralfx dot com
16-Jan-2006 01:19
This is just to note that I was able to fix my problems due to the many helpful comments here.
The problem I was having was as follows:
a) I was dynamically generating a file to download
b) When the user clicked "Save" in MSIE, and then imported the download file into the application, all was well.
c) When the user clicked "Open" to directly import the file, the application would throw an error.
I believe what was happening is that the browser was not saving a local copy of the file due to the "no-store" directive, when the user clicks "Open" directly.
Therefore the examples above regarding pragma & cache-control were useful to resolving it.
Thanks for all the help. I just want to add also that the following web page was of great help to see the actual HTTP headers being sent by the web app: http://www.rexswain.com/httpview.html
Much easier than doing telnet to port 80! Hope this helps other also.
Andrew Royappa
Ravi Chotalia
26-Dec-2005 07:12
In answer to..
-PHP SESSIONS NOT WORKING in with windows---
...solution on the session cookie path.
I am running Apache 2 and PHP 4.4.0 on a Windows XP SP2.
...
----------------------------------
It was a small mistake in my directory stucture,
I have changed from c:\temp to c:\Temp as I had directory called "temp" not "Temp".Now session is working properly in my case.
Make sure directory name is same, in windows environment too.
marou at marou dot com
22-Dec-2005 08:49
In reponse to fondman at hotmail dot com with the 4.4.0 issue with local variables replacing session variables.
It also happens in 4.4.3.
I have a development environment set up with 5.0, and the production environment is 4.4.3. I had set some local variables with the same name as one of my session variables. It did the same thing you described on the production box, yet worked fine in development.
Just an FYI.
jazfresh at hotmail dot com
19-Dec-2005 06:55
The vanilla implementation of session will blindly spew back the value of the session_id that the user sends it after URL decoding it. This can be used as an attack vector, by including strings like "%0D%0ALocation:%20http://someothersite.com/%0D%0A" in the cookie. Never trust user input, always cleanse it. If you only expect alphanumerics in the session hash, reject any session_id that doesn't contain it.
<?php
if(!preg_match('#^[[:alnum:]]+$#', $_COOKIE['session_id'])) {
unset($_COOKIE['session_id']);
}
session_start();
?>
bgshea at gmail dot com
04-Dec-2005 01:18
to johnlonely at gmail dot com
the sesion.cookie_path should be used for cookie security. The cookie_path is the path on the server for which the cookies are valid.
i.e. www.example.dom/mywepage/
if cookie_path="/mywebpage"
then
www.example.dom/someonespage/
will not have access to them. I use this parameter without problems.
I'm not saying that this will make cookies secure, but certainly others of www.example.dom will not have access to them.
However, if you have other directories say www.example.dom/niftystuff that you want the cookie to be valid for, then cookie_path needs to be "/".
This is better for servers that use the /~user/ user aliasing.
jodybrabec at yahoo dot com
29-Nov-2005 03:50
To stop PHPSESSID from appearing in the url, try inserting these two lines just before session_start() --
ini_set("url_rewriter.tags","");
ini_set(
|
|