Skip to content

[HttpFoundation] PhpBridgeSessionStorage - Exceptions thrown when error reporting reports warnings. #8554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
AtliThor opened this issue Jul 24, 2013 · 11 comments

Comments

@AtliThor
Copy link

When configuring Symfony 2.3 to use PhpBridgeSessionStorage as proposed in the second snippet in this doc article:
http://symfony.com/doc/2.3/cookbook/session/php_bridge.html

If the session is started in, or before, the standard app_dev.php script - or even the app.php script, if PHP is configured to display warnings - the two ini_set calls in the NativeFileSessionHandler constructor will trigger PHP warnings, as the session_path and session_handler directives can't be set after the session is started. Symfony converts them into exceptions, halting the execution of the page.

It would make more sense to check the session status in the constructor before issuing the ini_set calls, rather than relying on a lack of error reporting for this feature to be used in this manner. They would have no effect if the session is started either way.

if (PHP_SESSION_ACTIVE !== session_status()) {
    ini_set('session.save_path', $savePath);
    ini_set('session.save_handler', 'files');
}
@ghost
Copy link

ghost commented Jul 24, 2013

session_status() is not supported in php 5.3. :(

@AtliThor
Copy link
Author

O, right. Didn't realize that it was a relatively new feature.

The session_id function should be able to serve the same purpose though. It would only return an empty string if no session has been started. So this would be equivalent, and would be compatible with everything back to PHP 4.

if ("" === session_id()) {
    ini_set('session.save_path', $savePath);
    ini_set('session.save_handler', 'files');
}

We could also be overly creative and just define the function. Would make the "official" function usable wherever available, which is a plus :-)

if (version_compare(PHP_VERSION, '5.4.0', '<')) {
    define("PHP_SESSION_DISABLED", 0);
    define("PHP_SESSION_NONE", 1);
    define("PHP_SESSION_ACTIVE", 2);

    function session_status() {
        if (!function_exists("session_id")) {
            return PHP_SESSION_DISABLED;
        }
        else if ("" === session_id()) {
            return PHP_SESSION_NONE;
        }
        else {
            return PHP_SESSION_ACTIVE;
        }
    }
}

@ghost
Copy link

ghost commented Jul 24, 2013

i'm pretty sure this has all well been discussed. As you can see that symfony uses the SessionHandlerInterface from php 5.4, but does not redefine session_status. Other folks who actually worked on this can chime in as to the reasons though. perhaps @Drak ?

@stof
Copy link
Member

stof commented Jul 24, 2013

@jrobeson providing a stub for a function is harder than for a class/interface. Thanks to the autoloading, the class stub will not add any overhead when you have the native class (as the autoloader will never try to get the stub) while you need to have some logic executed all the time to load function stubs as they cannot be autoloaded

@ghost
Copy link

ghost commented Jul 24, 2013

@stof if it's possible to redo session_start() it'd be worth imo. I didn't think that was the only reason it wasn't done.

@ghost
Copy link

ghost commented Jul 24, 2013

@jrobeson the problem is the FC version of session_status() would not be 100% correct in all circumstances. You can set the session_id() before a session starts, so you cannot assume empty ID means no session has started. My memory is hazy but I am sure we talked about these kinds of things before.

@AtliThor can you please post the exact warnings PHP generates?

@AtliThor
Copy link
Author

@Drak Sure, this is what Symfony's error page shows me

ContextErrorException: Warning: ini_set(): A session is active. You cannot change the session module's ini settings at this time in [project root]\vendor\symfony\symfony\src\Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler.php line 56

And this is the stack trace.

in [project_root]\vendor\symfony\symfony\src\Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler.php line 56
at ErrorHandler->handle('2', 'ini_set(): A session is active. You cannot change the session module's ini settings at this time', '[project_root]\vendor\symfony\symfony\src\Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler.php', '56', array('savePath' => '', 'baseDir' => '', 'count' => '0'))
at ini_set('session.save_handler', 'files') in [project_root]\vendor\symfony\symfony\src\Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler.php line 56
at NativeFileSessionHandler->__construct(null) in [project_root]\app\cache\dev\appDevDebugProjectContainer.php line 2121
at appDevDebugProjectContainer->getSession_HandlerService() in [project_root]\app\bootstrap.php.cache line 1904
at Container->get('session.handler') in [project_root]\app\cache\dev\appDevDebugProjectContainer.php line 2160
at appDevDebugProjectContainer->getSession_Storage_PhpBridgeService() in [project_root]\app\bootstrap.php.cache line 1904
at Container->get('session.storage.php_bridge') in [project_root]\app\cache\dev\appDevDebugProjectContainer.php line 2108
at appDevDebugProjectContainer->getSessionService() in [project_root]\app\bootstrap.php.cache line 1904
at Container->get('session') in [project_root]\vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle\EventListener\SessionListener.php line 49
at SessionListener->onKernelRequest(object(GetResponseEvent))
at call_user_func(array(object(SessionListener), 'onKernelRequest'), object(GetResponseEvent)) in [project_root]\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher.php line 450
at TraceableEventDispatcher->Symfony\Component\HttpKernel\Debug\{closure}(object(GetResponseEvent))
at call_user_func(object(Closure), object(GetResponseEvent)) in [project_root]\vendor\symfony\symfony\src\Symfony\Component\EventDispatcher\EventDispatcher.php line 164
at EventDispatcher->doDispatch(array(object(Closure), object(Closure), object(Closure), object(Closure), object(Closure), object(Closure), object(Closure), object(Closure), object(Closure), object(Closure)), 'kernel.request', object(GetResponseEvent)) in [project_root]\vendor\symfony\symfony\src\Symfony\Component\EventDispatcher\EventDispatcher.php line 53
at EventDispatcher->dispatch('kernel.request', object(GetResponseEvent)) in [project_root]\vendor\symfony\symfony\src\Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher.php line 167
at ContainerAwareEventDispatcher->dispatch('kernel.request', object(GetResponseEvent)) in [project_root]\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher.php line 139
at TraceableEventDispatcher->dispatch('kernel.request', object(GetResponseEvent)) in [project_root]\app\bootstrap.php.cache line 2763
at HttpKernel->handleRaw(object(Request), '1') in [project_root]\app\bootstrap.php.cache line 2748
at HttpKernel->handle(object(Request), '1', true) in [project_root]\app\bootstrap.php.cache line 2878
at ContainerAwareHttpKernel->handle(object(Request), '1', true) in [project_root]\app\bootstrap.php.cache line 2179
at Kernel->handle(object(Request)) in [project_root]\web\app_dev.php line 33

Looking closer at this now, it seems it's only complaining about the session.save_handler, not the session.save_path. That one you seem to be able to set after the session has been started.

If the session_id() can't be relied on, what about just silencing the warning? Normally I wouldn't suggest something like that, but we know that this warning can be safely ignored, and as far as I know, this is the only error message you will ever get when setting the session handler to files.

@ghost
Copy link

ghost commented Jul 24, 2013

I think there is a mistake in the documentation. The purpose of the bridge is so you can use session handlers OUTSIDE of Symfony while still using the Symfony session API. If you have code that is starting the session outside of Symfony to use it's own save handlers, you do not want to tell Symfony to use save handlers.. the documentation seems mistaken:

This is correct:

framework:
    session:
        storage_id: session.storage.php_bridge
        handler_id: ~

There are two separate cases:

  1. You have code which starts the session outside of SF framework, but does not use it's own save handlers. In this case you can customise the save handler:
framework:
    session:
        storage_id: session.storage.php_bridge
        handler_id: session.handler.native_file

In the second case, you have a system which has it's own session save handler. You should be using ~ in the handler_id

@AtliThor
Copy link
Author

OK, I see. That appears to be spot on. I tried leaving out the handler_id as you suggested, and now the session is handled like I expected it to be handled with the handler_id set the native_file. No exceptions or warnings, and both my legacy code and Symfony's session API work side by side.

The docs say: "If the application has sets it's own PHP save handler, you can specify null for the handler_id". I read this and, having created no save handlers myself, took it to mean that this would not work for me. So I moved on to the second snippet. - It would seem that this phrase is meant to include PHP's default save handler.

@ghost
Copy link

ghost commented Jul 25, 2013

I will correct the documentation.

@ghost
Copy link

ghost commented Jul 25, 2013

Closing now the documentation PR has been made.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants