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
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
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

Add a Patch

Pull Requests

Add a Pull Request

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-2024 The PHP Group
All rights reserved.
Last updated: Tue May 21 02:01:35 2024 UTC