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