Passed
Push — 2.x ( d6434d...dbf03f )
by Terry
01:59
created

SessionTrait::setSessionId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[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
11
declare(strict_types=1);
12
13
namespace Shieldon\Firewall\Kernel;
14
15
use function Shieldon\Firewall\get_session;
16
use function microtime;
17
use function str_replace;
18
use function time;
19
20
/*
21
 * The main functionality for this trait is to limit the online session amount.
22
 */
23
trait SessionTrait
24
{
25
   /**
26
     * Are you willing to limit the online session amount?
27
     *
28
     * @var array
29
     */
30
    protected $sessionLimit = [
31
32
        // How many sessions will be available?
33
        // 0 = no limit.
34
        'count' => 0,
35
36
        // How many minutes will a session be availe to visit?
37
        // 0 = no limit.
38
        'period' => 0, 
39
    ];
40
41
    /**
42
     * Record the online session status.
43
     * This will be enabled when $sessionLimit[count] > 0
44
     *
45
     * This array is recording a live data, not a setting value.
46
     *
47
     * @var array
48
     */
49
    protected $sessionStatus = [
50
51
        // Online session count.
52
        'count' => 0,
53
54
        // Current session order.
55
        'order' => 0,
56
57
        // Current waiting queue.
58
        'queue' => 0,
59
    ];
60
61
    /**
62
     * Limt online sessions.
63
     *
64
     * @param int $count
65
     * @param int $period
66
     *
67
     * @return void
68
     */
69
    public function limitSession(int $count = 1000, int $period = 300): void
70
    {
71
        $this->sessionLimit = [
72
            'count' => $count,
73
            'period' => $period
74
        ];
75
    }
76
77
    /**
78
     * Get online people count. If enable limitSession.
79
     *
80
     * @return int
81
     */
82
    public function getSessionCount(): int
83
    {
84
        return $this->sessionStatus['count'];
85
    }
86
87
    /**
88
     * Deal with online sessions.
89
     *
90
     * @param int $statusCode The response code.
91
     *
92
     * @return int The response code.
93
     */
94
    protected function sessionHandler($statusCode): int
95
    {
96
        if (self::RESPONSE_ALLOW !== $statusCode) {
0 ignored issues
show
Bug introduced by
The constant Shieldon\Firewall\Kernel...onTrait::RESPONSE_ALLOW was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
97
            return $statusCode;
98
        }
99
100
        // If you don't enable `limit traffic`, ignore the following steps.
101
        if (empty($this->sessionLimit['count'])) {
102
            return self::RESPONSE_ALLOW;
103
104
        } else {
105
106
            // Get the proerties.
107
            $limit = (int) ($this->sessionLimit['count'] ?? 0);
108
            $period = (int) ($this->sessionLimit['period'] ?? 300);
109
            $now = time();
110
111
            $sessionData = $this->driver->getAll('session');
112
            $sessionPools = [];
113
114
            $i = 1;
115
            $sessionOrder = 0;
116
117
            if (!empty($sessionData)) {
118
                foreach ($sessionData as $v) {
119
                    $sessionPools[] = $v['id'];
120
                    $lasttime = (int) $v['time'];
121
    
122
                    if (get_session()->get('id') === $v['id']) {
123
                        $sessionOrder = $i;
124
                    }
125
    
126
                    // Remove session if it expires.
127
                    if ($now - $lasttime > $period) {
128
                        $this->driver->delete($v['id'], 'session');
129
                    }
130
                    $i++;
131
                }
132
133
                if (0 === $sessionOrder) {
134
                    $sessionOrder = $i;
135
                }
136
            } else {
137
                $sessionOrder = 0;
138
            }
139
140
            // Count the online sessions.
141
            $this->sessionStatus['count'] = count($sessionPools);
142
            $this->sessionStatus['order'] = $sessionOrder;
143
            $this->sessionStatus['queue'] = $sessionOrder - $limit;
144
145
            if (!in_array(get_session()->get('id'), $sessionPools)) {
146
                $this->sessionStatus['count']++;
147
148
                // New session, record this data.
149
                $data['id'] = get_session()->get('id');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
150
                $data['ip'] = $this->ip;
151
                $data['time'] = $now;
152
153
                $microtimesamp = explode(' ', microtime());
154
                $microtimesamp = $microtimesamp[1] . str_replace('0.', '', $microtimesamp[0]);
155
                $data['microtimesamp'] = $microtimesamp;
156
157
                $this->driver->save(get_session()->get('id'), $data, 'session');
158
            }
159
160
            // Online session count reached the limit. So return RESPONSE_LIMIT_SESSION response code.
161
            if ($sessionOrder >= $limit) {
162
                return self::RESPONSE_LIMIT_SESSION;
0 ignored issues
show
Bug introduced by
The constant Shieldon\Firewall\Kernel...:RESPONSE_LIMIT_SESSION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
163
            }
164
        }
165
166
        return self::RESPONSE_ALLOW;
167
    }
168
169
170
171
    // @codeCoverageIgnoreStart
172
173
    /**
174
     * For testing propose.
175
     *
176
     * @param string $sessionId
177
     *
178
     * @return void
179
     */
180
    protected function setSessionId(string $sessionId = ''): void
181
    {
182
        if ('' !== $sessionId) {
183
            get_session()->set('id', $sessionId);
184
        }
185
    }
186
}
187