# Session middleware

**URL:** https://discourse.slimframework.com/t/session-middleware/696
**Category:** Questions
**Created:** [September 8, 2016, 12:04pm UTC](https://discourse.slimframework.com/t/session-middleware/696 "2016-09-08T12:04:57Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Scheper](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/scheper/32/209_2.png) [@Scheper](https://discourse.slimframework.com/u/Scheper)
#### Post date: [September 8, 2016, 12:04pm UTC](https://discourse.slimframework.com/t/session-middleware/696/1 "2016-09-08T12:04:58Z")

</div>

I made a Session middleware class (named “Session” and mostly borrowed from the internet).

```auto
<?php

namespace Custom\Middleware;

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

class Session {

     protected $options = array(
        'name' => 'sessie',
        'lifetime' => 3600,
        'path' => '/',
        'domain' => null,
        'secure' => false,
        'httponly' => true,
        'cache_limiter' => 'nocache',
        'autorefresh' => false
    );
	
    public function __construct(array $options = array()) {
        if (is_string($options['lifetime'])) {
            $options['lifetime'] = strtotime($options['lifetime']) - time();
        }

        $this->options = array_merge($this->options, $options);
    }

    public function __invoke(Request $request, Response $response, callable $next) {
        $this->startSession();

        return $next($request, $response);
    }

    protected function startSession() {
        $options = $this->options;
        session_set_cookie_params($options['lifetime'], $options['path'], $options['domain'], $options['secure'], $options['httponly']);
        if (session_id()) {
            if ($options['autorefresh'] === true && isset($_COOKIE[$options['name']]) && ini_get('session.use_cookies')) {
                setcookie($options['name'], $_COOKIE[$options['name']], time() + $options['lifetime'], $options['path'], $options['domain'], $options['secure'], $options['httponly']);
            }
        }
        session_name($options['name']);
        session_cache_limiter(false);
        session_start();
    }

}
```

I also have a SessionHelper class (and file) with methods like ‘get’, ‘set’, ‘delete’ etc.

```auto
<?php

namespace Custom\Session;

class SessionHelper {

    public function get($key) {
        return $this->keyExists($key) ? $_SESSION[$key] : false;
    }

    public function set($key, $value, $overwrite = false) {
        if ($this->keyExists($key) === false || $overwrite === true) {
            $_SESSION[$key] = $value;
            return true;
        }
        return false;
    }

    public function delete($key) {
        if ($this->keyExists($key) === false) {
            unset($_SESSION[$key]);
            return true;
        }
        return false;
    }

    public static function id($new = false) {
        if ($new === true && session_id()) {
            session_regenerate_id(true);
        }
        return session_id() ? : false;
    }

    public static function destroy() {
        if (self::id()) {
            session_unset();
            session_destroy();
            session_write_close();
            if (ini_get('session.use_cookies')) {
                $params = session_get_cookie_params();
                setcookie(session_name(), '', time() - 4200, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
            }
        }
    }

    protected function keyExists($key) {
        return array_key_exists($key, $_SESSION);
    }

    public function __get($key) {
        return $this->get($key);
    }

    public function __set($key, $value) {
        $this->set($key, $value);
    }

    public function __unset($key) {
        $this->delete($key);
    }

    public function __isset($key) {
        return $this->exists($key);
    }

}
```

In my bootstrap (index.php) I have the following code:

```auto
<?php

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require '../vendor/autoload.php';

$app = new \Slim\App(array(
    'debug' => true
        ));

$app->add($session = new Custom\Middleware\Session(array(
    'name' => 'DevSession',
    'autorefresh' => true,
    'lifetime' => '60 minutes'
)));

$container = $app->getContainer();
$container['session'] = function () {
    return new Custom\Session\SessionHelper();
};

$app->get('/', function (Request $request, Response $response) {
	$this->session->set('time', time());
	echo $this->session->get('time');
    return $response;
});

// Run app
$app->run();
```

The **if(session\_id())** in the **startSession()** method of the class **Session** always returns false. But, the session is active in my **$app** though. I don’t really understand why the **\_\_invoke** is called after each refresh of the page, the **if(session\_id())** returns false, but the session is still active. Can someone explain how this works?

The reason I’m asking is because I want to make a more secure PHP session class, with methods to check if the session has been hijacked for example. But if the session is never active, according to the **Session** middleware, I don’t know how to accomplish such a check.

Help?

---

<div class="post-metadata">

### Author: ![Scheper](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/scheper/32/209_2.png) [@Scheper](https://discourse.slimframework.com/u/Scheper)
#### Post date: [September 8, 2016, 12:33pm UTC](https://discourse.slimframework.com/t/session-middleware/696/2 "2016-09-08T12:33:47Z")

</div>

Just so you know: the **echo** is for testing purposes only. This is to see if the session variable changes if I reload the page. It doesn’t, which is what I would expect. But nevertheless the **if(session\_id())** in my middleware class returns false after a reload of the page. I don’t get why.

---

<div class="post-metadata">

### Author: ![RikuS](https://avatars.discourse-cdn.com/v4/letter/r/f07891/32.png) [@RikuS](https://discourse.slimframework.com/u/RikuS)
#### Post date: [September 8, 2016, 2:13pm UTC](https://discourse.slimframework.com/t/session-middleware/696/3 "2016-09-08T14:13:02Z")

</div>

Hi Scheper,

you check if session is active before starting session, that’s why it doesn’t work. You should remove session\_id checking completely and use autorefresh checking AFTER starting your session.

```
protected function startSession()
{
    session_name($this->options['name']);
    session_set_cookie_params(
        $this->options['lifetime'],
        $this->options['path'],
        $this->options['domain'],
        $this->options['secure'],
        $this->options['httponly']
    );
    session_cache_limiter(false);
    session_start();
    if ($options['autorefresh'] === true) {
        setcookie(
            $this->options['name'],
            $_COOKIE[$this->options['name']],
            time() + $options['lifetime'],
            $this->options['path'],
            $this->options['domain'],
            $this->options['secure'],
            $this->options['httponly']
        );
    }
}
```

---

<div class="post-metadata">

### Author: ![Scheper](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/scheper/32/209_2.png) [@Scheper](https://discourse.slimframework.com/u/Scheper)
#### Post date: [September 8, 2016, 2:19pm UTC](https://discourse.slimframework.com/t/session-middleware/696/4 "2016-09-08T14:19:25Z")

</div>

But please help me understand something. After I invoke the Session class as middleware, session\_start() is called. After I refresh the page there already is a session. I checked this by adding variables to the session from my bootstrap (index.php). How come the Session middleware doesn’t recognize there is an active session? I mean, session\_start() was called and then I refreshed the page, so there already is an active session.

---

<div class="post-metadata">

### Author: ![RikuS](https://avatars.discourse-cdn.com/v4/letter/r/f07891/32.png) [@RikuS](https://discourse.slimframework.com/u/RikuS)
#### Post date: [September 8, 2016, 2:25pm UTC](https://discourse.slimframework.com/t/session-middleware/696/5 "2016-09-08T14:25:12Z")

</div>

session\_start() is also kind of configuration that tells your app that it will use sessions, for that reason session\_start() has to be called before any session related actions and also before outputting anything to browser. App don’t have session id if you don’t call session\_start() before trying to use that session id.

You can try this to load your page and set something in session, then remove session\_start() completely and reload your page, you will see errors.

---

<div class="post-metadata">

### Author: ![Scheper](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/scheper/32/209_2.png) [@Scheper](https://discourse.slimframework.com/u/Scheper)
#### Post date: [September 8, 2016, 2:39pm UTC](https://discourse.slimframework.com/t/session-middleware/696/6 "2016-09-08T14:39:35Z")

</div>

Yes I think I understand, but my thougtprocess is as follows:

1. I call my website: [http://dev.local](http://dev.local)
2. index.php is run, where my session middleware is called and my sessionhelper is placed in the container
3. My session middleware calls session\_start(), so a session is started (if not already)
4. I reload [http://dev.local](http://dev.local)
5. I thought there would already be a session, because the session was previously started in step 3. Therefore I thought my 'if(session\_id())" would return true instead of false.

But, if I understand what you are saying I’ll always have to call “session\_start()” first, before checking anything that has to do with sessions?

Is it therefore wise to do a “session\_start()” at the beginning of my custom startSession() method and then checking certain things? Like, if some variables are set. For example if the IP address in the session matches the IP address of the currect user?

---

<div class="post-metadata">

### Author: ![RikuS](https://avatars.discourse-cdn.com/v4/letter/r/f07891/32.png) [@RikuS](https://discourse.slimframework.com/u/RikuS)
#### Post date: [September 8, 2016, 2:45pm UTC](https://discourse.slimframework.com/t/session-middleware/696/7 "2016-09-08T14:45:20Z")

</div>

Yes you need to call session\_start on every page load before any session related actions. Session is created on first load, but you can’t access it’s content without calling session\_start on every page load. You should set session name etc. before calling session\_start, so you can’t start session in the beginning if you wish to have custom values.

---

<div class="post-metadata">

### Author: ![Scheper](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/scheper/32/209_2.png) [@Scheper](https://discourse.slimframework.com/u/Scheper)
#### Post date: [September 8, 2016, 2:47pm UTC](https://discourse.slimframework.com/t/session-middleware/696/8 "2016-09-08T14:47:43Z")

</div>

Thanks to your advice, I now have the following (incomlete) method:

```auto
protected function startSession() {
        $options = $this->options;
        session_set_cookie_params($options['lifetime'], $options['path'], $options['domain'], $options['secure'], $options['httponly']);

        session_name($options['name']);
        session_cache_limiter(false);
        session_start();

        if (session_id()) {
            if ($options['autorefresh'] === true && isset($_COOKIE[$options['name']]) && ini_get('session.use_cookies')) {
                setcookie($options['name'], $_COOKIE[$options['name']], time() + $options['lifetime'], $options['path'], $options['domain'], $options['secure'], $options['httponly']);
            }
        }
        
        //checking if session variables (like IP address) exist
    }
```

---

<div class="post-metadata">

### Author: ![RikuS](https://avatars.discourse-cdn.com/v4/letter/r/f07891/32.png) [@RikuS](https://discourse.slimframework.com/u/RikuS)
#### Post date: [September 8, 2016, 2:54pm UTC](https://discourse.slimframework.com/t/session-middleware/696/9 "2016-09-08T14:54:14Z")

</div>

That’s better already, but

- you don’t need to call session\_id, because it’s always there after calling session\_start
- you don’t need to check if cookie exists, because it’s always there after calling session\_start and seem to use session cookies anyway
- same thing with ini\_get(‘session.use\_cookies’)) as you use cookies on other parts of your script anyway

---

<div class="post-metadata">

### Author: ![TheLobos](https://avatars.discourse-cdn.com/v4/letter/t/e9bcb4/32.png) [@TheLobos](https://discourse.slimframework.com/u/TheLobos)
#### Post date: [September 8, 2016, 5:38pm UTC](https://discourse.slimframework.com/t/session-middleware/696/10 "2016-09-08T17:38:26Z")

</div>

I just yesterday pushed some code to properly handle session stuff to github. Initial testing seems to indicate that it works well (but it needs a little cleanup, which I’ll try to do tonight). You might want to take a look to see if this suits your purposes.

> **[innobrig/session-middleware](https://github.com/innobrig/session-middleware)**
>
> Session middleware package supporting namespaced session variables and easy nested structures. Written for Slim 3.0 but should also work for other frameworks. - innobrig/session-middleware

---

<div class="post-metadata">

### Author: ![Scheper](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/scheper/32/209_2.png) [@Scheper](https://discourse.slimframework.com/u/Scheper)
#### Post date: [September 10, 2016, 7:13am UTC](https://discourse.slimframework.com/t/session-middleware/696/11 "2016-09-10T07:13:24Z")

</div>

Thanks. I don’t really understand why your session middleware doesn’t really do anything. You just seem to be calling the session class in the container. I wonder why you’d use session middleware in this way. Would you explain this?

Plus, you seem to be making the same mistake I did. You check for a session\_id() before session\_start().

---

<div class="post-metadata">

### Author: ![TheLobos](https://avatars.discourse-cdn.com/v4/letter/t/e9bcb4/32.png) [@TheLobos](https://discourse.slimframework.com/u/TheLobos)
#### Post date: [September 10, 2016, 9:53am UTC](https://discourse.slimframework.com/t/session-middleware/696/12 "2016-09-10T09:53:54Z")

</div>

> I don’t really understand why your session middleware doesn’t really do anything.

Yeah, it’s not done yet. At this point it just manages the session. I plan to add more services over the next few days. As for the structure, it basically does what [GitHub - akrabat/rka-slim-session-middleware: Simple session middleware for Slim Framework](https://github.com/akrabat/rka-slim-session-middleware) does, it’s just that the logic which he placed in the middleware class has been placed into the main session class; I don’t see a problem using it this way. There is a reason for this and I will be expanding the docs over the next few days to explain the reasoning behind this.

Thanks for alerting me to the session\_id() issue, I’ll look into this as soon as I find time.

---

<div class="post-metadata">

### Author: ![RikuS](https://avatars.discourse-cdn.com/v4/letter/r/f07891/32.png) [@RikuS](https://discourse.slimframework.com/u/RikuS)
#### Post date: [September 11, 2016, 9:38pm UTC](https://discourse.slimframework.com/t/session-middleware/696/13 "2016-09-11T21:38:38Z")

</div>

Here is my version of session middleware, got some ideas from codes above as well.

Secure session middleware for Slim 3 framework

- longer and harder to guess session id:s
- set session cookie path, domain and secure values automatically
- extend session lifetime after each user activity
- encrypt session data
- helper class to set and get session values easily

> **[adbario/slim-secure-session-middleware](https://github.com/adbario/slim-secure-session-middleware)**
>
> Secure session middleware for Slim 3 framework. Contribute to adbario/slim-secure-session-middleware development by creating an account on GitHub.

Feel free to use this if it’s helpful.

---

<div class="post-metadata">

### Author: ![Scheper](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/scheper/32/209_2.png) [@Scheper](https://discourse.slimframework.com/u/Scheper)
#### Post date: [September 12, 2016, 7:06am UTC](https://discourse.slimframework.com/t/session-middleware/696/14 "2016-09-12T07:06:45Z")

</div>

It really is helpful. This is a bit like I’d like to implement sessions in my framework. Although I also am building a handler for database storage of session data.

---

<div class="post-metadata">

### Author: ![TheLobos](https://avatars.discourse-cdn.com/v4/letter/t/e9bcb4/32.png) [@TheLobos](https://discourse.slimframework.com/u/TheLobos)
#### Post date: [September 12, 2016, 9:04pm UTC](https://discourse.slimframework.com/t/session-middleware/696/15 "2016-09-12T21:04:34Z")

</div>

Hi @Scheper, this is very nice. However, allow me a few comments:

1. I briefly looked at the code and have one pet peeve I’d like to mention. In SessionMiddleware::start() you use

Having been bitten in the past by this, I must say that I absolutely detest the use of extract(). The reason for this is that it imports variables into your main namespace and when accessing any variable, it is impossible to know whether it was expected to come from the extract() statement or whether it is a typo, leftover old code or anything else of that matter.

As such, in the interest of clarity, please consider removing extract() and replacing it by things like

```
$settings['lifetime']

```

If you’d accept it, I’d be willing to make a pull request for this.

1. Furthermore, the session package I published relied on “joebengalen/config” to provide two very useful features:

a) A namespaced session container … while this might seem frivolous, speaking from experience, I can say that this can be a highly valuable and desirable feature.

b) The ability to deep-set array elements using the dot (.) notation. Again, nothing essential but a highly useful feature.

Please comment on my suggestions and let me know whether you’d be willing to add these features (or accept pull releases for them).

Please don’t misunderstand, I’m very grateful for your work, but IMHO it can be further improved to provide an even more useful session handler.

---

<div class="post-metadata">

### Author: ![RikuS](https://avatars.discourse-cdn.com/v4/letter/r/f07891/32.png) [@RikuS](https://discourse.slimframework.com/u/RikuS)
#### Post date: [September 12, 2016, 9:46pm UTC](https://discourse.slimframework.com/t/session-middleware/696/16 "2016-09-12T21:46:11Z")

</div>

Hi TheLobos, and thanks for posting. That’s actually my package, not Schepers 🙂

1. Basically good point, but I don’t see that as a problem, as variables are only used as they are inside start() and start is not supposed to change those variables. But yes that can be done, basically code is just a bit cleaner the way it is now.

2. Yes those are good features, but my package is meant to be simple, super fast and offer some good security features. I might add some similar features later.

By the way, none of these middleware session classes, which starts session at invoke, are not working with Slim-Csrf package (because Slim-Csrf validates session at construct), so I’ll write my own fix for that.

Thanks for posting!

---

<div class="post-metadata">

### Author: ![TheLobos](https://avatars.discourse-cdn.com/v4/letter/t/e9bcb4/32.png) [@TheLobos](https://discourse.slimframework.com/u/TheLobos)
#### Post date: [September 12, 2016, 9:52pm UTC](https://discourse.slimframework.com/t/session-middleware/696/17 "2016-09-12T21:52:06Z")

</div>

Sorry @RikuS, I misread/misquoted (it’s getting late in my timezone 🙂)

Let me know if you want me to help out with your package. I’m very interested to get a solid & secure session package for Slim and yours seems to be the the best one in terms of security so far, so I’d love to build on it.

---

<div class="post-metadata">

### Author: ![RikuS](https://avatars.discourse-cdn.com/v4/letter/r/f07891/32.png) [@RikuS](https://discourse.slimframework.com/u/RikuS)
#### Post date: [September 12, 2016, 10:01pm UTC](https://discourse.slimframework.com/t/session-middleware/696/18 "2016-09-12T22:01:14Z")

</div>

No worries 🙂

Also start() is using only settings variables, so my implementation should be pretty fine and clean.

I’ll test dotnotation some time soon as well, might be good feature to have. I’m hapy to have some new ideas, but still going to keep this small and fast, slim 🙂

---

<div class="post-metadata">

### Author: ![TheLobos](https://avatars.discourse-cdn.com/v4/letter/t/e9bcb4/32.png) [@TheLobos](https://discourse.slimframework.com/u/TheLobos)
#### Post date: [September 12, 2016, 10:20pm UTC](https://discourse.slimframework.com/t/session-middleware/696/19 "2016-09-12T22:20:27Z")

</div>

> I’ll test dotnotation some time soon as well, might be good feature to have. I’m hapy to have some new ideas, but still going to keep this small and fast, slim 🙂

All of those are highly appreciated. If you check the namespace implementation I referenced, you’ll see that it’s only a reference assignment at initialization; as such it should not impact performance in any signification way.

Once again, thanks for your work.

---

<div class="post-metadata">

### Author: ![RikuS](https://avatars.discourse-cdn.com/v4/letter/r/f07891/32.png) [@RikuS](https://discourse.slimframework.com/u/RikuS)
#### Post date: [September 12, 2016, 10:35pm UTC](https://discourse.slimframework.com/t/session-middleware/696/20 "2016-09-12T22:35:52Z")

</div>

Yes sure namespacing doesn’t impact performance in any way, as it only adds extra level of array in session. I’ll set that up soon.

About dotnotation I’m not so sure yet, need to play with it first.

[Next page](https://discourse.slimframework.com/t/session-middleware/696.md?page=2)
