Ajde_Session   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
dl 0
loc 177
rs 10
c 0
b 0
f 0
wmc 26
lcom 1
cbo 9

9 Methods

Rating   Name   Duplication   Size   Complexity  
C __bootstrap() 0 103 12
A __construct() 0 4 1
A destroy() 0 13 3
A setModel() 0 4 1
A getModel() 0 11 2
A has() 0 8 3
A set() 0 10 2
A hash() 0 4 1
A getOnce() 0 7 1
1
<?php
2
3
class Ajde_Session extends Ajde_Object_Standard
4
{
5
    protected $_namespace = null;
6
7
    public function __bootstrap()
8
    {
9
        // Session name
10
        $sessionName = config('app.id').'_session';
11
        session_name($sessionName);
12
13
        // Session lifetime
14
        $lifetime = config('session.lifetime');
15
16
        // Security garbage collector
17
        ini_set('session.gc_maxlifetime',
18
            ($lifetime == 0 ? 180 * 60 : $lifetime * 60)); // PHP session garbage collection timeout in minutes
19
        ini_set('session.gc_divisor', 100);        // Set divisor and probability for cronjob Ubuntu/Debian
20
        //		ini_set('session.gc_probability', 1);	// @see http://www.php.net/manual/en/function.session-save-path.php#98106
21
22
        // Set session save path
23
        if (config('session.savepath')) {
24
            ini_set('session.save_path', str_replace('~', LOCAL_ROOT, config('session.savepath')));
25
        }
26
27
        // Set sessions to use cookies
28
        ini_set('session.use_cookies', 1);
29
        ini_set('session.use_only_cookies',
30
            1); // @see http://www.php.net/manual/en/session.configuration.php#ini.session.use-only-cookies
31
32
        // Session cookie parameter
33
        $path = config('app.path');
34
        $domain = config('security.cookie.domain');
35
        $secure = config('security.cookie.secure');
36
        $httponly = config('security.cookie.httponly');
37
38
        // Set cookie lifetime
39
        session_set_cookie_params($lifetime * 60, $path, $domain, $secure, $httponly);
40
        session_cache_limiter('private_no_expire');
41
42
        // Start the session!
43
        session_start();
44
45
        // Strengthen session security with REMOTE_ADDR and HTTP_USER_AGENT
46
        // @see http://shiflett.org/articles/session-hijacking
47
48
        // Removed REMOTE_ADDR, use HTTP_X_FORWARDED_FOR if available
49
        $remoteIp = Ajde_Http_Request::getClientIP();
50
51
        // Ignore Google Chrome frame as it has a split personality
52
        // @todo TODO: security issue!!
53
        // @see http://www.chromium.org/developers/how-tos/chrome-frame-getting-started/understanding-chrome-frame-user-agent
54
        if (
55
            isset($_SERVER['HTTP_USER_AGENT']) &&
56
            substr_count($_SERVER['HTTP_USER_AGENT'], 'chromeframe/') === 0 &&
57
            isset($_SESSION['client']) &&
58
            $_SESSION['client'] !== md5($remoteIp.$_SERVER['HTTP_USER_AGENT'].config('security.secret'))
59
        ) {
60
61
            // TODO: overhead to call session_regenerate_id? is it not required??
62
            //session_regenerate_id();
63
64
            // thoroughly destroy the current session
65
            session_destroy();
66
            unset($_SESSION);
67
            setcookie(session_name(), session_id(), time() - 3600, $path, $domain, $secure, $httponly);
68
69
            // TODO:
70
            $exception = new Ajde_Core_Exception_Security('Possible session hijacking detected. Bailing out.');
71
            if (config('app.debug') === true) {
72
                throw $exception;
73
            } else {
74
                // don't redirect/log for resource items, as they should have no side effect
75
                // this makes it possible for i.e. web crawlers/error pages to view resources
76
                $request = Ajde_Http_Request::fromGlobal();
77
                $route = $request->initRoute();
78
                Ajde::app()->setRequest($request);
0 ignored issues
show
Documentation Bug introduced by
The method setRequest does not exist on object<Ajde_Application>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
79
                if (!in_array($route->getFormat(), ['css', 'js'])) {
80
                    Ajde_Exception_Log::logException($exception);
0 ignored issues
show
Documentation introduced by
$exception is of type object<Ajde_Core_Exception_Security>, but the function expects a object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
81
                    Ajde_Cache::getInstance()->disable();
82
                    // Just destroying the session should be enough
83
                    //					Ajde_Http_Response::dieOnCode(Ajde_Http_Response::RESPONSE_TYPE_FORBIDDEN);
84
                }
85
            }
86
        } else {
87
            $_SESSION['client'] = md5($remoteIp.issetor($_SERVER['HTTP_USER_AGENT']).config('security.secret'));
88
89
            if ($lifetime > 0) {
90
                // Force send new cookie with updated lifetime (forcing keep-alive)
91
                // @see http://www.php.net/manual/en/function.session-set-cookie-params.php#100672
92
                //session_regenerate_id();
93
94
                // Set cookie manually if session_start didn't just sent a cookie
95
                // @see http://www.php.net/manual/en/function.session-set-cookie-params.php#100657
96
                if (isset($_COOKIE[$sessionName])) {
97
                    setcookie(session_name(), session_id(), time() + ($lifetime * 60), $path, $domain, $secure,
98
                        $httponly);
99
                }
100
            }
101
        }
102
103
        // remove cache headers invoked by session_start();
104
        if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
105
            header_remove('X-Powered-By');
106
        }
107
108
        return true;
109
    }
110
111
    public function __construct($namespace = 'default')
112
    {
113
        $this->_namespace = $namespace;
114
    }
115
116
    public function destroy($key = null)
117
    {
118
        if (isset($key)) {
119
            if ($this->has($key)) {
120
                $_SESSION[$this->_namespace][$key] = null;
121
                $this->remove($key);
122
            }
123
        } else {
124
            $_SESSION[$this->_namespace] = null;
125
            $this->reset();
126
        }
127
        Ajde_Cache::getInstance()->updateHash($this->hash());
128
    }
129
130
    public function setModel($name, $object)
131
    {
132
        $this->set($name, serialize($object));
133
    }
134
135
    public function getModel($name)
136
    {
137
        // If during the session class definitions has changed, this will throw an exception.
138
        try {
139
            return unserialize($this->get($name));
140
        } catch (Exception $e) {
141
            Ajde_Dump::warn('Model definition changed during session');
142
143
            return false;
144
        }
145
    }
146
147
    public function has($key)
148
    {
149
        if (!isset($this->_data[$key]) && isset($_SESSION[$this->_namespace][$key])) {
150
            $this->set($key, $_SESSION[$this->_namespace][$key]);
151
        }
152
153
        return parent::has($key);
154
    }
155
156
    public function set($key, $value)
157
    {
158
        parent::set($key, $value);
159
        if ($value instanceof Ajde_Model) {
160
            // TODO:
161
            throw new Ajde_Exception('It is not allowed to store a Model directly in the session, use Ajde_Session::setModel() instead.');
162
        }
163
        $_SESSION[$this->_namespace][$key] = $value;
164
        Ajde_Cache::getInstance()->updateHash($this->hash());
165
    }
166
167
    public function hash()
168
    {
169
        return serialize($_SESSION[$this->_namespace]);
170
    }
171
172
    public function getOnce($key)
173
    {
174
        $return = $this->get($key);
175
        $this->set($key, null);
176
177
        return $return;
178
    }
179
}
180