gjerokrsteski/pimf-framework

View on GitHub
core/Pimf/Session/Payload.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 * Pimf
 *
 * @copyright Copyright (c)  Gjero Krsteski (http://krsteski.de)
 * @license   http://opensource.org/licenses/MIT MIT License
 */

namespace Pimf\Session;

use Pimf\Config;
use Pimf\Session;
use Pimf\Util\Character;
use Pimf\Cookie;

/**
 * Using the session payload
 *
 * <code>
 *
 *    // Get an item from the session
 *    $name = Session::get('name');
 *
 *    // Return a default value if the item doesn't exist
 *    $name = Session::get('name', 'Robin');
 *
 *    // Write an item to the session payload
 *    Session::put('name', 'Robin');
 *
 *    // Write an item to the session payload's flash data
 *    Session::flash('name', 'Robin');
 *
 *    // Keep the "name" item from expiring from the flash data
 *    Session::keep('name');
 *
 *    // Keep the "name" and "email" items from expiring from the flash data
 *    Session::keep(array('name', 'email'));
 *
 * </code>
 *
 * @package Session
 * @author  Gjero Krsteski <gjero@krsteski.de>
 */
class Payload
{
    /**
     * The session array that is stored by the storage.
     *
     * @var array|null
     */
    public $session;

    /**
     * The session storage used to retrieve and store the session payload.
     *
     * @var \Pimf\Session\Storages\Storage
     */
    public $storage;

    /**
     * Indicates if the session already exists in storage.
     *
     * @var bool
     */
    public $exists = true;

    /**
     * @param Storages\Storage $storage
     */
    public function __construct(\Pimf\Session\Storages\Storage $storage)
    {
        $this->storage = $storage;
    }

    /**
     * Load the session for the current request.
     *
     * @param null|string $key
     */
    public function load($key)
    {
        if ($key !== null) {
            $this->session = $this->storage->load($key);
        }

        // If the session doesn't exist or is invalid.
        if (is_null($this->session) || static::expired($this->session)) {
            $this->exists = false;
            $this->session = $this->storage->fresh();
        }

        // A CSRF token is stored in every session to protect
        // the application from cross-site request
        if (!$this->has(Session::CSRF)) {
            $this->put(Session::CSRF, Character::random(40));
        }
    }

    /**
     * Determine if the session payload instance is valid.
     *
     * @param array $session
     *
     * @return bool
     */
    protected static function expired($session)
    {
        if (array_key_exists('last_activity', $session)) {
            return (time() - $session['last_activity']) > (Config::get('session.lifetime') * 60);
        }

        return false;
    }

    /**
     * Determine if the session or flash data contains an item.
     *
     * @param string $key
     *
     * @return bool
     */
    public function has($key)
    {
        return ($this->get($key) !== null);
    }

    /**
     * Get an item from the session.
     *
     * @param string $key
     * @param null   $default
     *
     * @return mixed|null
     */
    public function get($key, $default = null)
    {
        $session = $this->session['data'];

        // check first for the item in the general session data.
        if (null !== ($value = $this->isIn($key, $session))) {
            return $value;
        }

        // or find it in the new session data.
        if (null !== ($value = $this->isIn($key, $session[':new:']))) {
            return $value;
        }

        // or finally return the default value.
        if (null !== ($value = $this->isIn($key, $session[':old:']))) {
            return $value;
        }

        return $default;
    }

    /**
     * Checks if key is in session.
     *
     * @param string $key
     * @param array  $session
     *
     * @return mixed|null
     */
    protected function isIn($key, array $session)
    {
        if (array_key_exists($key, $session) && $session[$key] !== null) {
            return $session[$key];
        }

        return null;
    }

    /**
     * Write an item to the session.
     *
     * @param        $key
     * @param string $value
     */
    public function put($key, $value)
    {
        $this->session['data'][$key] = $value;
    }

    /**
     * Write an item to the session flash data.
     *
     * @param $key
     * @param $value
     */
    public function flash($key, $value)
    {
        $this->session['data'][':new:'][$key] = $value;
    }

    /**
     * Keep all of the session flash data from expiring after the request.
     *
     * @return void
     */
    public function reflash()
    {
        $this->session['data'][':new:'] = array_merge(
            $this->session['data'][':new:'], $this->session['data'][':old:']
        );
    }

    /**
     * Keep a session flash item from expiring at the end of the request.
     *
     * @param $keys
     */
    public function keep($keys)
    {
        foreach ((array)$keys as $key) {
            $this->flash($key, $this->get($key));
        }
    }

    /**
     * Remove an item from the session data.
     *
     * @param $key
     */
    public function forget($key)
    {
        unset($this->session['data'][$key]);
    }

    /**
     * Remove all of the items from the session (CSRF token will not be removed).
     */
    public function flush()
    {
        $this->session['data'] = array(Session::CSRF => $this->token(), ':new:' => array(), ':old:' => array());
    }

    /**
     * Assign a new, random ID to the session.
     */
    public function regenerate()
    {
        $this->session['id'] = $this->storage->id();
        $this->exists = false;
    }

    /**
     * Get the CSRF token that is stored in the session data.
     *
     * @return string
     */
    public function token()
    {
        return $this->get(Session::CSRF);
    }

    /**
     * Get the last activity for the session.
     *
     * @return int
     */
    public function activity()
    {
        return $this->session['last_activity'];
    }

    /**
     * Store the session payload in storage.
     * This method will be called automatically at the end of the request.
     *
     * @return void
     */
    public function save()
    {
        $this->session['last_activity'] = time();

        // age it that should expire at the end of the user's next request.
        $this->age();

        $sessionConf = Config::get('session');

        // save data into the specialized storage.
        $this->storage->save($this->session, $sessionConf, $this->exists);

        // determine the owner of the session
        // on the user's subsequent requests to the application.
        $this->cookie($sessionConf);

        // calculate and run garbage collection cleaning.
        $cleaning = $sessionConf['garbage_collection'];

        if (mt_rand(1, $cleaning[1]) <= $cleaning[0]) {
            $this->clean();
        }
    }

    /**
     * Clean up expired sessions.
     *
     * @return void
     */
    public function clean()
    {
        if ($this->storage instanceof \Pimf\Contracts\Cleanable) {
            $this->storage->clean(time() - (Config::get('session.lifetime') * 60));
        }
    }

    /**
     * Age the session flash data.
     *
     * @return void
     */
    protected function age()
    {
        $this->session['data'][':old:'] = $this->session['data'][':new:'];
        $this->session['data'][':new:'] = array();
    }

    /**
     * Send the session ID cookie to the browser.
     *
     * @param  array $config
     *
     * @return void
     */
    protected function cookie($config)
    {
        $minutes = (!$config['expire_on_close']) ? $config['lifetime'] : 0;

        Cookie::put($config['cookie'], $this->session['id'], $minutes, $config['path'], $config['domain'],
            $config['secure']);
    }
}