php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #41230 session written AFTER global variables have been destroyed
Submitted: 2007-04-29 20:31 UTC Modified: 2007-04-30 13:21 UTC
From: amirlaher at yahoo dot co dot uk Assigned:
Status: Not a bug Package: Session related
PHP Version: 5.2.1 OS: Debian Sarge,Ubuntu
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: amirlaher at yahoo dot co dot uk
New email:
PHP Version: OS:

 

 [2007-04-29 20:31 UTC] 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



Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-04-29 21:07 UTC] amirlaher at yahoo dot co dot uk
I see this is now a 'feature' - see 'warning' in the session_write_close() PHP manual page.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Fri Jul 04 15:01:36 2025 UTC