Welcome Guest, Not a member yet? Register   Sign In
A session on $_SESSION
#1
Question 
(This post was last modified: 06-24-2021, 04:07 PM by Gary.)

I'm usually paranoid and have:   $session = \Config\Services:: session();  in most routines that I am referencing $_SESSION in.

This appears to be necessary, otherwise I find that sometimes the $_SESSION variables (like those denoting the user is signed in) go missing for a while, and the user looses some of their signed-in privileges, even though they're not signed out.

I have found that sometimes, thought different happenings, that some routines requiring $_SESSION don't have this initialization, and don't appear to have ever caused a problem in the past.

Having recently moved my little project from a Windows machine onto a Linux box, although initially there didn't seem to be a problem with $_SESSION becoming lost, as of late it's become a horrible irritation.  To be fair, perhaps I've broken something somewhere... though, it appears to become lost at random intervals, even when there is no user activity (besides the background (automated) 1-minute connection-check polling from the client side using JavaScript).

My questions are as follows:

    1)  Is there a better way / place to invoke the $session =... initialization than in every function/method that I use it (sticking it in BaseController didn't seem to work for me in the past)?

    2)  At some point in the past I thought using this to initialize it would be more sensible:
              if (!isset($_SESSION))  $session = \Config\Services:: session();
        I found it didn't work very well (and $_SESSION still appeared to go AWOL from time-to-time).  I'd be grateful if anyone could explain why, and perhaps also suggest a better way to (conditionally) reattach $_SESSION's handle.

Thanks.
Reply
#2

I've been using the 1th solution, in my controllers i can access $this->session, so if i'm checking a session it would be $this->session->get() or $this->session->has(). Never had any issues using it that way, i'm using 4.1.3 at this point and it still works for me.
Reply
#3

(06-25-2021, 07:50 AM)superior Wrote: I've been using the 1th solution, in my controllers i can access $this->session, so if i'm checking a session it would be $this->session->get() or $this->session->has(). Never had any issues using it that way, i'm using 4.1.3 at this point and it still works for me.

Thanks superior.  It was a while back when I had tried it in the BaseController... I'll give it another another try.
Reply
#4

(This post was last modified: 07-03-2021, 09:00 PM by InsiteFX.)

You can also use the session helper session()->get($variable);

Personally I load the session in the BaseController and then use the session helper and session object.
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply
#5

I’m also a fan of the session helper function, it handles all that for you in a very clean way so your component can focus on accessing the session data instead of what the session state may be. Also, if there’s ever big changes to the service or library in version 5 the helper will be the most consistent, which means the least code changes for developers. For that reason I recommend using all the helper functions when applicable: model(), config(), session(), service(), cache(), etc
Reply
#6

(This post was last modified: 07-06-2021, 12:24 PM by Gary. Edit Reason: Correcting alcohol-assisted typos. I'm sure there's still others. )

Thanks InsiteFX, MGatner... I've been experimenting with your suggestions over the last couple of evenings.

Prior to opening this thread, I was using the following in BaseController:
Code:
$session = \Config\Services:: session();

However, in addition to this, I also found it necessary (because they are not in the App\Controllers namespace) to also use the same in all my Filters, Libraries and also in the few places (where I've found it makes life happier) to use $session in the Models.

Generally, after providing the link to Services:: session() as above, I've used $_SESSION[' '] to access the PHP session variables directly (thinking it was as close to the bare basics as was feasible (also with the mindset of there being the least code changes in subsequent CodeIgniter upgrades)).

This has worked very well, without the slightest problem since I started playing with CodeIgniter 4, late 2019.

For what it's worth, because of running out of other things to try, I've also tried (doing pretty much the same thing this way) :
Code:
use \Config\Services;
....
$session = session();

What I found (after upgrading from v4.0.x to v4.1.3 and switching from a Windows to Linux, as mentioned in the first post) is that doing it this way works more than 99.9% of the time, but after an indeterminate (seemingly completely random) period, $_SESSION is lost.

This loss will typically happen in the first Filter that references $_SESSION (albeit that it's the last of the before Filters).

If the reference to $_SESSION is removed from that Filter, it will fail in the first Controller in the App\Controllers namespace (not the BaseController, which I suspect is called even before the Filters (?)).

I've experimented using InsiteFX's method, and have found that placing just this SINGLE session()->get() use in the Filter:
Code:
$session = session();
if (!empty(session()->get('user_session'))) {    // in place of !empty($_SESSION['user_session'])
appears to make everything work 100% reliably again, exactly as it previously was (the rest of the site still uses the $_SESSION[' '] reference)??!

The problem I now have is not knowing whether I can trust what seems to be a fundamental PHP construct in the CodeIgniter framework (albeit that the way I've been using it is 100% as per the recommendations in the User Manual (see:  https://codeigniter.com/user_guide/libra...%20use#id3 and https://codeigniter.com/user_guide/libra...ssion-data))... and whether it is perhaps better to switch to the session()->get() and ->set() methods throughout the whole project (not something I'd like to do, in part because there's some multi-dimensional arrays stuck among the $_SESSION variables (and functions that manipulate these arrays) in many places in the code (which, yes, will probably be simple enough to translate, but may make it more tedious than a simple text replacement, AND will mean actually having to think.  Please, NO!).

Does anyone have an idea of what could be causing the lost $_SESSION, and why using a single instance of session()->get() appears to fix it?

Also, is it safe to continue using $_SESSION?


On a separate note, I have made regular use of helpers (and have several custom helpers), but hadn't considered the Service routines as helpers (probably attributable to be a noob, and because they weren't listed under the Helpers in the User Manual).  Even the documentation on Services doesn't give one many clues that there is more to look at. For interest sake, session() is filed under 'Global Functions and Constants' in the User Manual (and I now see model() there too).

Some of those listed in your reply, I've not even aware of until now, thanks MGatner.



Update:

No... session()->get() appears to IMPROVE matter a whole lot, but $_SESSION is still being lost in the same place it was before.
Reply
#7

This is how I load my sessions, ignore the helper files.
PHP Code:
<?php

namespace App\Controllers;

use 
CodeIgniter\Controller;
use 
CodeIgniter\HTTP\RequestInterface;
use 
CodeIgniter\HTTP\ResponseInterface;
use 
CodeIgniter\Services;
use 
Psr\Log\LoggerInterface;

/**
 * Class BaseController
 *
 * BaseController provides a convenient place for loading components
 * and performing functions that are needed by all your controllers.
 * Extend this class in any new controllers:
 *    class Home extends BaseController
 *
 * For security be sure to declare any new methods as protected or private.
 */

/**
 * Class BaseController
 *
 * @package App\Controllers
 */
class BaseController extends Controller
{
 
/**
 * An array of helpers to be loaded automatically upon
 * class instantiation. These helpers will be available
 * to all other controllers that extend BaseController.
 *
 * @var array
 */
 
protected $helpers = [
 
'debug',
 
'auth',
 
'utility',
 ];

 
/**
 * @var \CodeIgniter\Session\Session
 */
 
protected $session;

 
/**
 * initController ()
 * -------------------------------------------------------------------
 *
 * @param RequestInterface  $request
 * @param ResponseInterface $response
 * @param LoggerInterface  $logger
 */
 
public function initController(RequestInterface $requestResponseInterface $responseLoggerInterface $logger)
 {
 
// Do Not Edit This Line
 
parent::initController($request$response$logger);

 
//--------------------------------------------------------------------
 // Preload any models, libraries, etc, here.
 //--------------------------------------------------------------------
 // E.g.:
 // $this->session = \Config\Services::session();

 // Ensure that the session is started and running
 
if (session_status() == PHP_SESSION_NONE)
 {
 
$this->session Services::session();
 }

 }

}
  // -------------------------------------------------------------------

/**
 * -----------------------------------------------------------------------
 * Filename: BaseController.php
 * Location: ./app/Controllers/BaseController.php
 * -----------------------------------------------------------------------
 */ 
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply
#8

(This post was last modified: 07-06-2021, 03:11 PM by Gary.)

(07-03-2021, 09:02 PM)InsiteFX Wrote: This is how I load my sessions, ignore the helper files.
PHP Code:
<?php

namespace App\Controllers;

use 
CodeIgniter\Controller;
use 
CodeIgniter\HTTP\RequestInterface;
use 
CodeIgniter\HTTP\ResponseInterface;
use 
CodeIgniter\Services;
use 
Psr\Log\LoggerInterface

Thanks InsiteFX, I've tried your code, character-for-character the same in my code, but I'm still intermittently loosing the session.

I've tried dozens of things, but for some reason, I still can't find the cause or even a duct-tape & chewing-gum patch (without knowing the root cause) for the $session going awol at what appears to be completely random times.

I've snooped around the framework code, and found the source function of the session (so I've bypassed the invocation via the \App\Config\Session route, and appear to not require the 'use' link in the Controller's/Models/Library headers now because it's a framework base service):
Code:
$session = \CodeIgniter\Config\Services::session();

So now I have this bit of code stuck in the first place in every namespace where $_SESSION[' '] is accessed... and it all works perfectly for a few minutes or perhaps 30 minutes... regardless if the signed in user does anything on the server or not.  After this the session is lost, and they unedpectedly find themselves on the landing page.

From my experimentation, I find that most of the time the session appears to go missing in the Filters (the first place the session is used in any of the before Filters)... not in the BaseController (though it has also been observed to go missing there on one or two times out of hundreds of lost-in-Filter disappearances).

Currently, for the debugging, I have some JavaScript on the client polling the server every two seconds (to get the session loss to happen faster).  The server responds with a new CSRF token, and a status code in a single byte character specifying flag status' (like new message alerts etc).  The CSRF token and status code are presented as a single string of characters.

The specific poll code results in the poll being sent though the before Filters, to the central 'controller', which does nothing besides a return; for this poll code.  The reply is automatically sent back via the after Filters that generate the CSRF token and attach the status code byte.

Having spent hours on this, I've double-checked the already double-checked settings, and all the other suggestions of permissions and avoiding redirects, and using session_write_close(), even though these are now done automatically by PHP (thanks includebeer).

I've also tried checking and forcing things that are already done (by Services:: session()) with a variety of things similar to:
Code:
if (!session_id()) session_start();
where $_SESSION is going missing, and even forcing it to be a shared session, for what that's worth.

I've tried increasing the memory_limit in the PHP ini file, and several changes, one change at a time in the Apache configuration files, but have ended up back with what was originally used (with no difference being observed in the session being lost with any of the changes).

Because I'm using a MPM (multi-processing module (multi-threaded)) build of Apache, it uses PHP-FPM (which requires configuration as a proxy), and I've tried with and without:
Code:
# RequestHeader unset Proxy early
// and
#RequestHeader unset Proxy
...just in case this was causing PHP to be lingering when closing the session between calls. No observable difference was found.

I've checked the log files (CodeIgniter v4.1.3, Apache v2.4.43 and PHP v7.4.6 (log_errors is On, display_errors is On, error_reporting = E_ALL))... though, because there isn't really an error, I don't expect to find anything relating to this problem (?).

As a duct-tape & chewing-gum fix, I even tried sticking a conditional session_write_close(); at the start of the BaseController in case it somehow hadn't been closed properly in the last call, but that also doesn't stop it from being lost.

There's not a lot of code to post to illustrate what I'm doing... and it's pretty much the same as InsiteFX's code... so I'm at a loss as to what to try next.

Any suggestions or general direction-pointers would be greatly appreciated.

Thanks.



An additional question:  I presume BaseController is called and executed prior to any of the Filters being invoked... could someone please confirm this?

If this is indeed the case, is there a reason that would cause the session be lost only in the Filters and not in the BaseController (which also uses the user's session to set the default location, timezone and several other user-specific customization overheads)?
Reply
#9

(This post was last modified: 07-07-2021, 04:28 AM by Gary.)

Ok... I'd be inclined to want to label this as a bug in the framework.

Here's one work-around:

In \App\Config\App.php, changing $sessionExpiration to any (probably large) non-zero constant:

Code:
/**
* --------------------------------------------------------------------------
* Session Expiration
* --------------------------------------------------------------------------
*
* The number of SECONDS you want the session to last.
* Setting to 0 (zero) means expire when the browser is closed.
*
* @var integer
*/
public $sessionExpiration = Vars::COOKIE_SESSION_VALIDITY;    //  !! 0 causes random, intermittent session loss
Reply




Theme © iAndrew 2016 - Forum software by © MyBB