0
votes

Let's say a web application store an object of class My_Object in the php session, under the name 'myobject'. When I open another php application where this class doesn't exist, Zend_Session::start() throw an exception when attempting to unserialize My_Object.

Thus, I need to clean the $_SESSION variable to get rid of 'myobject'. But to clean $_SESSION variable, I first need to call session_start() and once it has been called, Zend_Session::start() throws the following exception :

Uncaught exception 'Zend_Session_Exception' with message 'session has already been started by session.auto-start or session_start()'

This is thrown even if I class session_destroy() before calling Zend_Session::start().

Can anyone help me on this ?

Thanks by advance,

Eric.

EDIT : To add clarification, here is the function I call on my controller initializer plugin :

    protected function _initSession() {
        try {
            session_start();

            unset($_SESSION['myobject']);

            session_destroy();

            Zend_Session::start(); // throws an exception !!!
        }
        catch (Exception $e) {
            echo $e; exit;
        }
    }

EDIT 2 :

To add further clarification, here is the exception thrown by Zend_Session::start() when it encounters an unknown class :

Warning: include_once(My/Object.php): failed to open stream: No such file or directory in /usr/local/zend/share/ZendFramework/library/Zend/Loader.php on line 146

Now that I've written this, I wonder if I sould start the session before instanciating the Zend autoloader...

3
What happens if you just put $_SESSION = array(); before it?Luke
It doesn't change anything. $_SESSION is replaced by whatever is lying in the session storage when Zend_Session::start() is called and Zend_Session still tries to instanciate a My_Object instance...Eric MORAND

3 Answers

1
votes

What version of Zend Framework are you using?

The reference manual states this:

Using Sessions with Objects

If you plan to persist objects in the PHP session, know that they will be » serialized for storage. Thus, any object persisted with the PHP session must be unserialized upon retrieval from storage. The implication is that the developer must ensure that the classes for the persisted objects must have been defined before the object is unserialized from session storage. If an unserialized object's class is not defined, then it becomes an instance of stdClass.

It sounds like one possible workaround would be to include the source file for the object that is serialized in the session, so it doesn't encounter that error. But it also states that if the class is not defined, it becomes an instance of stdClass, so since that is not the behavior you are seeing, it seems like a bug or you may be using an older version.

1
votes

OK, sorry for to answer my own question but it looks like I misunderstood the exception thrown by Zend_Session. The problem actually came from Zend_Loader and not the underlying PHP session. The fact was that I was instanciating Zend autoloader in index.php, which is not a good idea since from the moment it is instanciated, Zend_Loader will try to autoload every class that has not been explicitly included [EDIT : To be clearer, it will try to instanciate every class whode name begins by one of the namespaces registered - and in my code, I had the namespace "My_" registered with the zend loader...]

The solution is pretty simple : instanciate Zend_Loader after Zend:Session::start(). I just put the initialization of Zend_Loader in my bootstrap, after Zend_Session::start() and everything works flawlessly : My_Object class is unserialized by Zend_Session::start() as stdClass (thanks to drew010 for pointing me in the right direction); which is what is excepted.

Thanks for your help, guys.

0
votes

By the sounds of the error, it doesn't sound like the object is the problem, but the way that you are starting the session is.

"Uncaught exception 'Zend_Session_Exception' with message 'session has already been started by session.auto-start or session_start();"

protected function _initSession() {
    try {
        **session_start();**

        unset($_SESSION['myobject']);

        session_destroy();

        **Zend_Session::start();** // throws an exception !!!
    }
    catch (Exception $e) {
        echo $e; exit;
    }
}

In this code you ARE invoking the session_start(), and THEN using the Zend_Session::start().

This insinuates that the Zend session throws an exception if sessions have already been invoked previously.

You could just catch the Exception and just choose to do nothing with it?

protected function _initSession() {
    try {
        session_start();

        unset($_SESSION['myobject']);

        session_destroy();

        Zend_Session::start(); // throws an exception !!!
    }
    catch (Exception $e) {
        echo $e; exit;
    }
    catch (Zend_Session_Exception $zendException)
    {
         // Do nothing, ignore exception
    }
}