Passed
Push — 6.0 ( 88644f...134599 )
by liu
03:12 queued 10s
created

File::unlink()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think\session\driver;
14
15
use think\App;
16
use think\session\SessionHandler;
17
18
class File implements SessionHandler
1 ignored issue
show
Coding Style introduced by
Missing class doc comment
Loading history...
19
{
20
    protected $config = [
21
        'path'           => '',
22
        'expire'         => 0,
23
        'cache_subdir'   => true,
24
        'data_compress'  => false,
25
        'gc_divisor'     => 1000,
26
        'gc_maxlifetime' => 1440,
27
    ];
28
29
    public function __construct(App $app, array $config = [])
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
30
    {
31
        $this->config = array_merge($this->config, $config);
32
33
        if (empty($this->config['path'])) {
34
            $this->config['path'] = $app->getRuntimePath() . 'session' . DIRECTORY_SEPARATOR;
35
        } elseif (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) {
36
            $this->config['path'] .= DIRECTORY_SEPARATOR;
37
        }
38
39
        $this->init();
40
    }
41
42
    /**
43
     * 打开Session
44
     * @access protected
45
     * @return bool
46
     * @throws Exception
47
     */
48
    protected function init(): bool
49
    {
50
        try {
51
            !is_dir($this->config['path']) && mkdir($this->config['path'], 0755, true);
52
        } catch (\Exception $e) {
53
            // 写入失败
54
            return false;
55
        }
56
57
        if (1 == mt_rand(1, $this->config['gc_divisor'])) {
58
            $this->gc();
59
        }
60
61
        return true;
62
    }
63
64
    /**
65
     * Session 垃圾回收
66
     * @access public
67
     * @return true
68
     */
69
    public function gc()
70
    {
71
        $maxlifetime = $this->config['gc_maxlifetime'];
72
        $list        = glob($this->config['path'] . '*');
73
74
        foreach ($list as $path) {
75
            if (is_dir($path)) {
76
                $files = glob($path . DIRECTORY_SEPARATOR . '*.php');
77
                foreach ($files as $file) {
78
                    if (time() > filemtime($file) + $maxlifetime) {
79
                        unlink($file);
80
                    }
81
                }
82
            } elseif (time() > filemtime($path) + $maxlifetime) {
83
                unlink($path);
84
            }
85
        }
86
    }
87
88
    /**
89
     * 取得变量的存储文件名
90
     * @access protected
91
     * @param  string $name 缓存变量名
92
     * @param  bool   $auto 是否自动创建目录
93
     * @return string
94
     */
95
    protected function getFileName(string $name, bool $auto = false): string
96
    {
97
        if ($this->config['cache_subdir']) {
98
            // 使用子目录
99
            $name = substr($name, 0, 2) . DIRECTORY_SEPARATOR . 'sess_' . $name;
100
        } else {
101
            $name = 'sess_' . $name;
102
        }
103
104
        $filename = $this->config['path'] . $name . '.php';
105
        $dir      = dirname($filename);
106
107
        if ($auto && !is_dir($dir)) {
108
            try {
109
                mkdir($dir, 0755, true);
110
            } catch (\Exception $e) {
111
                // 创建失败
112
            }
113
        }
114
115
        return $filename;
116
    }
117
118
    /**
119
     * 读取Session
120
     * @access public
121
     * @param  string $sessID
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
122
     * @return string
123
     */
124
    public function read(string $sessID): string
125
    {
126
        $filename = $this->getFileName($sessID);
127
128
        if (!is_file($filename)) {
129
            return '';
130
        }
131
132
        $content = file_get_contents($filename);
133
134
        if (false !== $content) {
135
            $expire = (int) substr($content, 8, 12);
136
            if (0 != $expire && time() > filemtime($filename) + $expire) {
137
                //缓存过期删除缓存文件
138
                $this->unlink($filename);
139
                return '';
140
            }
141
142
            $content = substr($content, 32);
143
144
            if ($this->config['data_compress'] && function_exists('gzcompress')) {
145
                //启用数据压缩
146
                $content = gzuncompress($content);
147
            }
148
149
            return $content;
150
        } else {
151
            return '';
152
        }
153
    }
154
155
    /**
156
     * 写入Session
157
     * @access public
158
     * @param  string $sessID
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
159
     * @param  string $sessData
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
160
     * @return bool
161
     */
162
    public function write(string $sessID, string $sessData): bool
163
    {
164
        $expire = $this->config['expire'];
165
166
        $expire = $this->getExpireTime($expire);
167
168
        $filename = $this->getFileName($sessID, true);
169
170
        $data = $sessData;
171
172
        if ($this->config['data_compress'] && function_exists('gzcompress')) {
173
            //数据压缩
174
            $data = gzcompress($data, 3);
175
        }
176
177
        $data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
178
        $result = file_put_contents($filename, $data);
179
180
        if ($result) {
181
            clearstatcache();
182
            return true;
183
        }
184
185
        return false;
186
    }
187
188
    /**
189
     * 删除Session
190
     * @access public
191
     * @param  string $sessID
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
192
     * @return array
193
     */
194
    public function delete(string $sessID): bool
195
    {
196
        try {
197
            return $this->unlink($this->getFileName($sessID));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->unlink($this->getFileName($sessID)) returns the type boolean which is incompatible with the documented return type array.
Loading history...
198
        } catch (\Exception $e) {
199
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
200
        }
201
    }
202
203
    /**
204
     * 获取有效期
205
     * @access protected
206
     * @param  integer|\DateTimeInterface $expire 有效期
207
     * @return int
208
     */
209
    protected function getExpireTime($expire): int
210
    {
211
        if ($expire instanceof \DateTimeInterface) {
212
            $expire = $expire->getTimestamp() - time();
213
        }
214
215
        return (int) $expire;
216
    }
217
218
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $file should have a doc-comment as per coding-style.
Loading history...
219
     * 判断文件是否存在后,删除
220
     * @access private
221
     * @param  string $path
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Doc comment for parameter $path does not match actual variable name $file
Loading history...
222
     * @return bool
223
     */
224
    private function unlink(string $file): bool
0 ignored issues
show
Coding Style introduced by
Private method name "File::unlink" must be prefixed with an underscore
Loading history...
225
    {
226
        return is_file($file) && unlink($file);
227
    }
228
229
}
230