Skip to content
This repository has been archived by the owner on Jun 10, 2019. It is now read-only.

Session issue in database PHP7 #4

Closed
lexbeelen opened this issue Dec 15, 2015 · 20 comments
Closed

Session issue in database PHP7 #4

lexbeelen opened this issue Dec 15, 2015 · 20 comments

Comments

@lexbeelen
Copy link

lexbeelen commented Dec 15, 2015

There is a issue with sessions.
This only happens when you set "session_save" in "local.xml" to "db".
If you try with the option "files" there are no problems.

Error.
Recoverable Error: session_regenerate_id(): Failed to create(read) session ID: user (path: /var/lib/php/sessions) in app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 492

@icurdinj
Copy link
Contributor

The problem might be in PHP itself: https://bugs.php.net/bug.php?id=70520
I have traced the code a bit, and the workaround in code would be somewhere deep in lib/varien or lib/zend.
Until that's fixed in PHP, just using file sessions seems like a smarter workaround. Other sessions storages, like Redis, need to be tested yet.

@arosenhagen
Copy link

had this issue too - redis backend is also broken this way (likely as it also uses the db interface).

@Marko-M
Copy link

Marko-M commented Dec 16, 2015

In hope this will aid your search for solution - when I encountered session issues with Magento 1.x + PHP 7 beta 3 + Redis, I used following workaround as quick fix to regain Magento admin access (save as "whatever.patch" and apply with "patch -p1 < whatever.patch"):

diff --git a/app/code/core/Mage/Core/Model/Session/Abstract.php b/app/code/core/Mage/Core/Model/Session/Abstract.php
index 8386fb8..a287df6 100644
--- a/app/code/core/Mage/Core/Model/Session/Abstract.php
+++ b/app/code/core/Mage/Core/Model/Session/Abstract.php
@@ -564,6 +564,8 @@ class Mage_Core_Model_Session_Abstract extends Mage_Core_Model_Session_Abstract_
      */
     public function renewSession()
     {
+        return $this;
+
         $this->getCookie()->delete($this->getSessionName());
         $this->regenerateSessionId();

Unfortunately I'm unable to do tests with PHP 7 final atm, but I'll test this workaround again first chance I get, if someone doesn't come up with something better in the meantime.

@ivanweiler
Copy link
Contributor

Just tested it a bit, win + php7 + db sessions ..

As @Marko-M posted, temp fix is bypassing session renewal.

It seems when session_regenerate_id() is called, write() of session handler is never called. You get new session id in php and $_SESSION value is ok after regeneration, but it's never written because it's never passed to session handler.

Why? No clue :) I also suspect it's php7 bug or some kind of change we're not aware of.

Interesting thing, if you manually change session id and manually set cookie, everything works as expected.

$this->setSessionId('my_custom_value');  
$this->getCookie()->set($this->getSessionName(),  $this->getSessionId());  

Is it possible to (easily) generate/get new session id in php without session_regenerate_id(), to use in above example?

I'm planning to test same thing on M2 tomorrow, to see how it behaves there.

@ivanweiler
Copy link
Contributor

Hello all, I managed to trace the problem.

Mage_Core_Model_Resource_Session::read($sessId) needs to always return string, for example changing
return $data; to return (string)$data; fix db session handler, login works.

When called on session_regenerate_id(true) it returns false which breaks regeneration. It seems it's going to be easy fix.

Can someone confirm this is correct? Thx.

@ivanweiler
Copy link
Contributor

I didn't test Redis, but I think it could be similar problem since I was getting this error with db handler:
session_regenerate_id(): Failed to create(read) session ID: user (path: )

and similar error is reported here colinmollenhour/Cm_RedisSession#70

@icurdinj
Copy link
Contributor

Ivan, I have just pushed a fix based on your findings. Lets see how it works on database sessions, and when we have a chance, it's probably a good starting point for Redis fix.

@lexbeelen
Copy link
Author

I have try the fix. But no luck.
I'm getting still the same error.

@ivanweiler
Copy link
Contributor

@lexbeelen, @arosenhagen: Can you please write on which OS problem occurred, is php stable 7.0.0 version or older RC and is it mod_php, php-fpm, etc.
Thx

@arosenhagen
Copy link

for me it is ubuntu 14.04.3 / debian 8.2.0 with a nginx / php-fpm setup. I hadn't the chance to try the proposed fix though.

@lexbeelen
Copy link
Author

Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-57-generic x86_64)

PHP 7.0.0-5+deb.sury.org~trusty+1 (cli) ( NTS )
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2015 Zend Technologies with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies

nginx version: nginx/1.4.6 (Ubuntu) php-fpm setup

@icurdinj
Copy link
Contributor

@lexbeelen try now, I think it's fixed. And, we are probably on the right track to fix Redis too.

@lexbeelen
Copy link
Author

@icurdinj I can confirm you, that the issue is fixed 👍 Great job 👍

@johnbendi
Copy link

Please what did you guys do to fix this issue? I don't understand what the solution to try is here.

@icurdinj
Copy link
Contributor

icurdinj commented Jan 4, 2016

@johnbendi - the solution was traced by our ingenious @ivanweiler :

Mage_Core_Model_Resource_Session::read($sessId) needs to always return string, for example >changing return $data; to return (string)$data; fix db session handler, login works.

What actually happened was that Magentos function lied in docbloc to always return string, while actually it sometimes returned FALSE. And that function was then fed to PHPs session handler. PHP 5.* silently converted that FALSE to empty string (I guess), and it worked. PHP 7.0 does type checking here and expects string, so it crashed.

Once the problem was traced, the solution was trivial. We replaced original
return $data;
with
return (string)$data;

:-)

@ghost
Copy link

ghost commented Jan 31, 2017

I'm having this same issue. It looks like it was a simple typecast. Where did you all make the change? I can't log into PhpMyAdmin after switching to memcached and would like to try this workaround

@icurdinj
Copy link
Contributor

icurdinj commented Feb 1, 2017

More about memcached: https://github.com/Inchoo/Inchoo_PHP7/wiki/Memcache

@dhaupin
Copy link

dhaupin commented Feb 16, 2017

@cscart - CS-Cart session handler (PHP7 + Redis session cache) shares a similar fix as Magento. In app/Tygh/Session.php within the read($sess_id) function, change the return $data; into return (string)$data; and all should work again.

In the case of CS-Cart, the way we noticed this error was using Chrome inspector in mobile emulator mode, then going back and forth to desktop mode. One or the other eventually caused session fail with error from a function further down the chain:

Catchable fatal error: session_regenerate_id(): Failed to create(read) session ID: user (path: ) in /app/Tygh/Session.php on line 403

@gcann-tbd
Copy link

If you get this problem using memcache, change to memcached into your app/etc/local.xml and remove protocol : tcp://

@reinaldomendes
Copy link

I have the same problem with php7 and session db mysql.

The problem is when session_regenerate_id is called it calls: destroy and read.
The destroy will set an expired timestamp in database, when read is called it will return nothing.

I did a fix which use debug_backtrace to check if call is from session_regenerate_id.

   class Mage_Core_Model_Resource_Session implements Zend_Session_SaveHandler_Interface { 
     ///....
    /**
    * @param string $sessId
     * @return string
     */
    public function read($sessId)
    {
        $flags = 0;
        $backtrace = debug_backtrace($flags,2);
        $regenerate = 'session_regenerate_id' === $backtrace[1]['function'];

        $select = $this->_read->select()
                ->from($this->_sessionTable, array('session_data'))
                ->where('session_id = :session_id')
                ->where('session_expires > :session_expires');

        $expires = $regenerate ? 0 : Varien_Date::toTimestamp(true);

        $bind = array(
            'session_id'      => $sessId,
            'session_expires' => $expires
        );


        $data = (string)$this->_read->fetchOne($select, $bind);

        return $data;
    }

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants