Session::getInstance()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace FMUP;
3
4
/**
5
 * Class Session
6
 * @package FMUP
7
 */
8
class Session
9
{
10
    use Sapi\OptionalTrait;
11
12
    private $sessionState;
13
    private $name;
14
    private $id;
15
    private static $instance;
16
17 1
    private function __construct()
18
    {
19 1
    }
20
21
    /**
22
     * @codeCoverageIgnore
23
     */
24
    private function __clone()
25
    {
26
    }
27
28
    /**
29
     * @param bool $deleteOldSession
30
     * @return bool
31
     */
32 2
    public function regenerate($deleteOldSession = false)
33
    {
34 2
        $success = false;
35 2
        if ($this->isStarted()) {
36 1
            $success = $this->sessionRegenerateId((bool)$deleteOldSession);
37
        }
38 2
        return $success;
39
    }
40
41
    /**
42
     * @param bool|false $deleteOldSession
43
     * @return bool
44
     * @codeCoverageIgnore
45
     */
46
    protected function sessionRegenerateId($deleteOldSession = false)
47
    {
48
        return session_regenerate_id((bool)$deleteOldSession);
49
    }
50
51
    /**
52
     * Retrieve session system - start session if not started
53
     * @return Session
54
     */
55 6
    final public static function getInstance()
56
    {
57 6
        if (!isset(self::$instance)) {
58 1
            $class = get_called_class();
59 1
            self::$instance = new $class;
60
        }
61 6
        return self::$instance;
62
    }
63
64
    /**
65
     * Define session name
66
     * @param string $name
67
     * @throws \FMUP\Exception if session name defined contain only numbers
68
     * @return $this
69
     */
70 4
    public function setName($name)
71
    {
72 4
        if (!$this->isStarted()) {
73 3
            if (is_numeric($name)) {
74 1
                throw new Exception('Session name could not contain only numbers');
75
            }
76 2
            $this->name = (string)$name;
77
        }
78 3
        return $this;
79
    }
80
81
    /**
82
     * Retrieve session name
83
     * @return string|null
84
     */
85 5
    public function getName()
86
    {
87 5
        if ($this->isStarted() && is_null($this->name)) {
88 1
            $this->name = $this->sessionName();
89
        }
90 5
        return $this->name;
91
    }
92
93
    /**
94
     * @param string $name
95
     * @return string
96
     * @codeCoverageIgnore
97
     */
98
    protected function sessionName($name = null)
99
    {
100
        return session_name($name);
101
    }
102
103
    /**
104
     * Define session id
105
     * @param string $id
106
     * @return $this
107
     * @throws Exception
108
     */
109 4
    public function setId($id)
110
    {
111 4
        if (!$this->isStarted()) {
112 3
            if (!preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $id)) {
113 1
                throw new Exception('Session name is not valid');
114
            }
115 2
            $this->id = (string)$id;
116
        }
117 3
        return $this;
118
    }
119
120
    /**
121
     * @param string|null $sessionId
122
     * @return string
123
     * @codeCoverageIgnore
124
     */
125
    protected function sessionId($sessionId = null)
126
    {
127
        return session_id($sessionId);
128
    }
129
130
    /**
131
     * Retrieve session name
132
     * @return string|null
133
     */
134 5
    public function getId()
135
    {
136 5
        if ($this->isStarted() && is_null($this->id)) {
137 1
            $this->id = $this->sessionId();
138
        }
139 5
        return $this->id;
140
    }
141
142
    /**
143
     * Check whether session is started
144
     * @return bool
145
     */
146 8
    public function isStarted()
147
    {
148 8
        if (is_null($this->sessionState)) {
149 8
            $this->sessionState = version_compare($this->phpVersion(), '5.4.0', '>=')
150 6
                ? $this->sessionStatus() === PHP_SESSION_ACTIVE
151 2
                : $this->sessionId() !== '';
152
        }
153 8
        return $this->sessionState;
154
    }
155
156
    /**
157
     * @return string
158
     * @codeCoverageIgnore
159
     */
160
    protected function phpVersion()
161
    {
162
        return phpversion();
163
    }
164
165
    /**
166
     * @return int
167
     * @codeCoverageIgnore
168
     */
169
    protected function sessionStatus()
170
    {
171
        return session_status();
172
    }
173
174
    /**
175
     * Start session if not started and return if session is started
176
     * @return bool
177
     */
178 4
    public function start()
179
    {
180 4
        if (!$this->isStarted() && $this->getSapi()->get() != Sapi::CLI) {
181 3
            if ($this->getId()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getId() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
182 1
                $this->sessionId($this->getId());
183
            }
184 3
            if ($this->getName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
185 1
                $this->sessionName($this->getName());
186
            }
187 3
            $this->sessionState = $this->sessionStart();
188
        }
189
190 4
        return (bool)$this->sessionState;
191
    }
192
193
    /**
194
     * @return bool
195
     * @codeCoverageIgnore
196
     */
197
    protected function sessionStart()
198
    {
199
        return session_start();
200
    }
201
202
    /**
203
     * Retrieve all session values defined
204
     * @return array
205
     */
206 2
    public function getAll()
0 ignored issues
show
Coding Style introduced by
getAll uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
207
    {
208 2
        return $this->start() ? $_SESSION : array();
209
    }
210
211
    /**
212
     * Define all session values
213
     * @param array $values
214
     * @return $this
215
     */
216 2
    public function setAll(array $values = array())
0 ignored issues
show
Coding Style introduced by
setAll uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
217
    {
218 2
        if ($this->start()) {
219 1
            $_SESSION = $values;
220
        }
221 2
        return $this;
222
    }
223
224
    /**
225
     * Retrieve a session value
226
     * @param string $name
227
     * @return mixed
228
     * @codeCoverageIgnore
229
     */
230
    public function get($name)
0 ignored issues
show
Coding Style introduced by
get uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
231
    {
232
        $name = (string) $name;
233
        return $this->has($name) ? $_SESSION[$name] : null;
234
    }
235
236
    /**
237
     * Check whether a specific information exists in session
238
     * @param string $name
239
     * @return bool
240
     * @codeCoverageIgnore
241
     */
242
    public function has($name)
0 ignored issues
show
Coding Style introduced by
has uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
243
    {
244
        $name = (string) $name;
245
        return $this->start() && array_key_exists($name, $_SESSION);
246
    }
247
248
    /**
249
     * Define a specific value in session
250
     * @param string $name
251
     * @param mixed $value
252
     * @return $this
253
     * @codeCoverageIgnore
254
     */
255
    public function set($name, $value)
0 ignored issues
show
Coding Style introduced by
set uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
256
    {
257
        if ($this->start()) {
258
            $name = (string) $name;
259
            $_SESSION[$name] = $value;
260
        }
261
        return $this;
262
    }
263
264
    /**
265
     * Forget all values in session without destructing it
266
     * @return $this
267
     * @codeCoverageIgnore
268
     */
269
    public function clear()
0 ignored issues
show
Coding Style introduced by
clear uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
270
    {
271
        if ($this->start()) {
272
            $_SESSION = array();
273
        }
274
        return $this;
275
    }
276
277
    /**
278
     * Delete a specific information from session
279
     * @param string $name
280
     * @return $this
281
     * @codeCoverageIgnore
282
     */
283
    public function remove($name)
0 ignored issues
show
Coding Style introduced by
remove uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
284
    {
285
        if ($this->has($name)) {
286
            unset($_SESSION[$name]);
287
        }
288
        return $this;
289
    }
290
291
    /**
292
     * Destroy current session
293
     * @return bool success or failure on session destruction
294
     * @codeCoverageIgnore
295
     */
296
    public function destroy()
0 ignored issues
show
Coding Style introduced by
destroy uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
297
    {
298
        if ($this->start()) {
299
            $this->sessionState = !session_destroy();
300
            unset($_SESSION);
301
302
            return !$this->sessionState;
303
        }
304
305
        return false;
306
    }
307
}
308