Completed
Push — develop ( 17cff1...8e0c4b )
by Henry
02:30
created

Session::getData()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 10
1
<?php
2
/**
3
 * This file is part of the Divergence package.
4
 *
5
 * (c) Henry Paradiz <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace Divergence\Models\Auth;
11
12
use Divergence\Models\Model;
13
use Divergence\Models\Relations;
14
15
/**
16
 * Session object
17
 *
18
 * @author Henry Paradiz <[email protected]>
19
 * @author Chris Alfano <[email protected]>
20
 * @inheritDoc
21
 * @property string $Handle Unique identifier for this session used by the cookie.
22
 * @property string $LastRequest Timestamp of the last time this session was updated.
23
 * @property string $Binary Actually raw binary in the string
24
 */
25
class Session extends Model
26
{
27
    use Relations;
28
29
    // Session configurables
30
    public static $cookieName = 's';
31
    public static $cookieDomain = null;
32
    public static $cookiePath = '/';
33
    public static $cookieSecure = false;
34
    public static $cookieExpires = false;
35
    public static $timeout = 31536000; //3600;
36
37
    // support subclassing
38
    public static $rootClass = __CLASS__;
39
    public static $defaultClass = __CLASS__;
40
    public static $subClasses = [__CLASS__];
41
42
    // ActiveRecord configuration
43
    public static $tableName = 'sessions';
44
    public static $singularNoun = 'session';
45
    public static $pluralNoun = 'sessions';
46
47
    public static $fields = [
48
        'ContextClass' => null,
49
        'ContextID' => null,
50
        'Handle' => [
51
            'unique' => true,
52
        ],
53
        'LastRequest' => [
54
            'type' => 'timestamp',
55
            'notnull' => false,
56
        ],
57
        'LastIP' => [
58
            'type' => 'binary',
59
            'length' => 16
60
        ],
61
    ];
62
63
64
    /**
65
     * Gets or sets up a session based on current cookies.
66
     * Will always update the current session's LastIP and LastRequest fields.
67
     *
68
     * @param boolean $create
69
     * @return static|false
70
     */
71
    public static function getFromRequest($create = true)
72
    {
73
        $sessionData = [
74
            'LastIP' => inet_pton($_SERVER['REMOTE_ADDR']),
75
            'LastRequest' => time(),
76
        ];
77
78
        // try to load from cookie
79
        if (!empty($_COOKIE[static::$cookieName])) {
80
            if ($Session = static::getByHandle($_COOKIE[static::$cookieName])) {
81
                // update session & check expiration
82
                $Session = static::updateSession($Session, $sessionData);
83
            }
84
        }
85
        // try to load from any request method
86
        if (empty($Session) && !empty($_REQUEST[static::$cookieName])) {
87
            if ($Session = static::getByHandle($_REQUEST[static::$cookieName])) {
88
                // update session & check expiration
89
                $Session = static::updateSession($Session, $sessionData);
90
            }
91
        }
92
        if (!empty($Session)) {
93
            // session found
94
            return $Session;
95
        } elseif ($create) {
96
            // create session
97
            return static::create($sessionData, true);
98
        } else {
99
            // no session available
100
            return false;
101
        }
102
    }
103
104
    public static function updateSession(Session $Session, $sessionData)
105
    {
106
        // check timestamp
107
        if (time() > $Session->LastRequest + static::$timeout) {
108
            $Session->terminate();
109
110
            return false;
111
        } else {
112
            // update session
113
            $Session->setFields($sessionData);
114
            if (function_exists('fastcgi_finish_request')) {
115
                // @codeCoverageIgnoreStart
116
                register_shutdown_function(function (&$Session) {
117
                    $Session->save();
118
                }, $Session);
119
            // @codeCoverageIgnoreEnd
120
            } else {
121
                $Session->save();
122
            }
123
124
            return $Session;
125
        }
126
    }
127
128
    /**
129
     * Gets by handle.
130
     *
131
     * @param string $handle
132
     * @return static
133
     */
134
    public static function getByHandle($handle)
135
    {
136
        return static::getByField('Handle', $handle, true);
137
    }
138
139
    /**
140
     * @inheritDoc
141
     *
142
     * Saves the session to the database and sets the session cookie.
143
     * Will generate a unique handle for the session if none exists.
144
     *
145
     * @param boolean $deep
146
     * @return void
147
     */
148
    public function save($deep = true)
149
    {
150
        // set handle
151
        if (!$this->Handle) {
152
            $this->Handle = static::generateUniqueHandle();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $this->Handle is correct as static::generateUniqueHandle() targeting Divergence\Models\Auth\S...:generateUniqueHandle() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Documentation Bug introduced by
It seems like static::generateUniqueHandle() of type void is incompatible with the declared type string of property $Handle.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
153
        }
154
155
        // call parent
156
        parent::save($deep);
157
158
        // set cookie
159
        if (!headers_sent()) {
160
            // @codeCoverageIgnoreStart
161
            setcookie(
162
                static::$cookieName,
163
                $this->Handle,
164
                static::$cookieExpires ? (time() + static::$cookieExpires) : 0,
165
                static::$cookiePath,
166
                static::$cookieDomain,
167
                static::$cookieSecure
168
            );
169
            // @codeCoverageIgnoreEnd
170
        }
171
    }
172
173
    /**
174
     * Attempts to unset the cookie.
175
     * Unsets the variable from the $_COOKIE global.
176
     * Deletes session from database.
177
     *
178
     * @return void
179
     */
180
    public function terminate()
181
    {
182
        if (!headers_sent()) {
183
            // @codeCoverageIgnoreStart
184
            setcookie(static::$cookieName, '', time() - 3600);
185
            // @codeCoverageIgnoreEnd
186
        }
187
        unset($_COOKIE[static::$cookieName]);
188
189
        $this->destroy();
190
    }
191
192
    /**
193
     * Makes a random 32 digit string by generating 16 random bytes
194
     * Is cryptographically secure.
195
     * @see http://php.net/manual/en/function.random-bytes.php
196
     *
197
     * @return void
198
     */
199
    public static function generateUniqueHandle()
200
    {
201
        do {
202
            $handle = bin2hex(random_bytes(16));
203
        } while (static::getByHandle($handle));
204
        // just in case checks if the handle exists in the database and if it does makes a new one.
205
        // chance of happening is 1 in 2^128 though so might want to remove the database call
206
207
        return $handle;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $handle returns the type string which is incompatible with the documented return type void.
Loading history...
208
    }
209
}
210