ID: 41230
User updated by: amirlaher at yahoo dot co dot uk
Reported By: amirlaher at yahoo dot co dot uk
-Status: Open
+Status: Closed
Bug Type: Session related
Operating System: Debian Sarge,Ubuntu
PHP Version: 5.2.1
New Comment:
I see this is now a 'feature' - see 'warning' in the
session_write_close() PHP manual page.
Previous Comments:
------------------------------------------------------------------------
[2007-04-29 20:31:15] amirlaher at yahoo dot co dot uk
Description:
------------
This issue affects custom session handlers (as defined with
session_set_save_handler()), in which the write function attempts to
access a *global object*.
When upgrading a custom session handler (calling a perl daemon), from
php5.1 to php5.2, the session was never written owing to a "Call to a
member function xxx() on a non-object" error.
This seemingly occurs because global objects get destructed *before*
session_write_close() is called, during php's shutdown sequence.
I worked around the issue using
register_shutdown_function("session_write_close"); near the top of the
script.
register_shutdown_function() does take effect when a script is
terminated using exit(); I would have to call "session_write_close();"
after having finished writing to the session.
This error also still springs up sometimes when the memory limit is
reached.
This behaviour-change was painful but could be an intentional change by
the php team (?) I am reporting it because it may be an unintentional
change, and I have seen that it has also affected other users including
Drupal users
(e.g. this Zend Forums thread:
http://www.zend.com/forums/index.php?t=msg&th=3464
and Drupal: http://drupal.org/node/92802)
Cheers
Amir
Reproduce code:
---------------
<?php
//apologies: this is more than 20 lines.
//I have amended the php manual example to use a rudimentary object,
just for illustration purposes.
class sess {
var $savePath;
var $id;
function getSavePath() {
return $this->savePath;
}
function setSavePath($savePath) {
$this->savePath= $savePath;
}
function getFilePath() {
return $this->getSavePath().'/sess_'.$this->getId();
}
function getId() {
return $this->id;
}
function setId($id) {
$this->id= $id;
}
}
function open($savePath, $session_name)
{
global $sess;
$sess= new sess;
$sess->setSavePath('/tmp');
return(true);
}
function close()
{
return(true);
}
function read($id)
{
global $sess;
$sess->setId($id);
if(file_exists($sess->getFilePath())) {
return (string) file_get_contents($sess->getFilePath());
}
}
function write($id, $sess_data)
{
global $sess;
if ($fp = fopen($sess->getFilePath(), "w")) {
$return = fwrite($fp, $sess_data);
fclose($fp);
return $return;
} else {
return(false);
}
}
function destroy($id){
global $sess;
return(unlink($sess->getFilePath()));
}
function gc($maxlifetime)
{
global $sess;
foreach (glob($sess->getSavePath()."/sess_*") as $filename) {
if (filemtime($filename) + $maxlifetime < time()) {
unlink($filename);
}
}
return true;
}
session_set_save_handler("open", "close", "read", "write", "destroy",
"gc");
session_start();
print "session id : " . session_id() . "<br>";
if(!$_SESSION['hi']) {
$_SESSION['hi']='ho';
} else {
$_SESSION['ts']=time();
}
print "session data: <pre>"; print_r($_SESSION);
print "\nclass data: \n "; print_r($sess);
Expected result:
----------------
session written ok
Actual result:
--------------
session id : 8b2596bea65174ce950bb47140edfe2a
session data:
Array
(
[hi] => ho
)
class data:
sess Object
(
[savePath] => /tmp
[id] => 8b2596bea65174ce950bb47140edfe2a
)
Fatal error: Call to a member function getFilePath() on a non-object
in /var/www/sesstest.php on line 52
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=41230&edit=1