Completed
Push — 6.0 ( 28cc55...ecaa46 )
by liu
03:26
created

File::set()   B

Complexity

Conditions 7
Paths 24

Size

Total Lines 37
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 19
nc 24
nop 3
dl 0
loc 37
ccs 0
cts 19
cp 0
crap 56
rs 8.8333
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\cache\driver;
14
15
use think\App;
16
use think\cache\Driver;
17
use think\contract\CacheHandlerInterface;
18
19
/**
20
 * 文件缓存类
21
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
22
class File extends Driver implements CacheHandlerInterface
23
{
24
    /**
25
     * 配置参数
26
     * @var array
27
     */
28
    protected $options = [
29
        'expire'        => 0,
30
        'cache_subdir'  => true,
31
        'prefix'        => '',
32
        'path'          => '',
33
        'hash_type'     => 'md5',
34
        'data_compress' => false,
35
        'tag_prefix'    => 'tag_',
36
        'serialize'     => [],
37
    ];
38
39
    /**
40
     * 有效期
41
     * @var int|\DateTime
42
     */
43
    protected $expire;
44
45
    /**
46
     * 架构函数
47
     * @param App   $app 应用对象
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
48
     * @param array $options 参数
49
     */
50
    public function __construct(App $app, array $options = [])
51
    {
52
        if (!empty($options)) {
53
            $this->options = array_merge($this->options, $options);
54
        }
55
56
        if (empty($this->options['path'])) {
57
            $this->options['path'] = $app->getRuntimePath() . 'cache' . DIRECTORY_SEPARATOR;
58
        } elseif (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) {
59
            $this->options['path'] .= DIRECTORY_SEPARATOR;
60
        }
61
    }
62
63
    /**
64
     * 取得变量的存储文件名
65
     * @access public
66
     * @param  string $name 缓存变量名
67
     * @return string
68
     */
69
    public function getCacheKey(string $name): string
70
    {
71
        $name = hash($this->options['hash_type'], $name);
72
73
        if ($this->options['cache_subdir']) {
74
            // 使用子目录
75
            $name = substr($name, 0, 2) . DIRECTORY_SEPARATOR . substr($name, 2);
76
        }
77
78
        if ($this->options['prefix']) {
79
            $name = $this->options['prefix'] . DIRECTORY_SEPARATOR . $name;
80
        }
81
82
        return $this->options['path'] . $name . '.php';
83
    }
84
85
    /**
86
     * 判断缓存是否存在
87
     * @access public
88
     * @param  string $name 缓存变量名
89
     * @return bool
90
     */
91
    public function has($name): bool
92
    {
93
        return false !== $this->get($name) ? true : false;
94
    }
95
96
    /**
97
     * 读取缓存
98
     * @access public
99
     * @param  string $name 缓存变量名
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
100
     * @param  mixed  $default 默认值
101
     * @return mixed
102
     */
103
    public function get($name, $default = false)
104
    {
105
        $this->readTimes++;
106
107
        $filename = $this->getCacheKey($name);
108
109
        if (!is_file($filename)) {
110
            return $default;
111
        }
112
113
        $content      = file_get_contents($filename);
114
        $this->expire = null;
115
116
        if (false !== $content) {
117
            $expire = (int) substr($content, 8, 12);
118
            if (0 != $expire && time() > filemtime($filename) + $expire) {
119
                //缓存过期删除缓存文件
120
                $this->unlink($filename);
121
                return $default;
122
            }
123
124
            $this->expire = $expire;
125
            $content      = substr($content, 32);
126
127
            if ($this->options['data_compress'] && function_exists('gzcompress')) {
128
                //启用数据压缩
129
                $content = gzuncompress($content);
130
            }
131
            return $this->unserialize($content);
132
        } else {
133
            return $default;
134
        }
135
    }
136
137
    /**
138
     * 写入缓存
139
     * @access public
140
     * @param  string        $name 缓存变量名
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
141
     * @param  mixed         $value  存储数据
142
     * @param  int|\DateTime $expire  有效时间 0为永久
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
143
     * @return bool
144
     */
145
    public function set($name, $value, $expire = null): bool
146
    {
147
        $this->writeTimes++;
148
149
        if (is_null($expire)) {
150
            $expire = $this->options['expire'];
151
        }
152
153
        $expire   = $this->getExpireTime($expire);
154
        $filename = $this->getCacheKey($name, true);
0 ignored issues
show
Unused Code introduced by
The call to think\cache\driver\File::getCacheKey() has too many arguments starting with true. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

154
        /** @scrutinizer ignore-call */ 
155
        $filename = $this->getCacheKey($name, true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
155
156
        $dir = dirname($filename);
157
158
        if (!is_dir($dir)) {
159
            try {
160
                mkdir($dir, 0755, true);
161
            } catch (\Exception $e) {
162
                // 创建失败
163
            }
164
        }
165
166
        $data = $this->serialize($value);
167
168
        if ($this->options['data_compress'] && function_exists('gzcompress')) {
169
            //数据压缩
170
            $data = gzcompress($data, 3);
171
        }
172
173
        $data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
174
        $result = file_put_contents($filename, $data);
175
176
        if ($result) {
177
            clearstatcache();
178
            return true;
179
        }
180
181
        return false;
182
    }
183
184
    /**
185
     * 自增缓存(针对数值缓存)
186
     * @access public
187
     * @param  string $name 缓存变量名
188
     * @param  int    $step 步长
189
     * @return false|int
190
     */
191
    public function inc(string $name, int $step = 1)
192
    {
193
        if ($this->has($name)) {
194
            $value  = $this->get($name) + $step;
195
            $expire = $this->expire;
196
        } else {
197
            $value  = $step;
198
            $expire = 0;
199
        }
200
201
        return $this->set($name, $value, $expire) ? $value : false;
202
    }
203
204
    /**
205
     * 自减缓存(针对数值缓存)
206
     * @access public
207
     * @param  string $name 缓存变量名
208
     * @param  int    $step 步长
209
     * @return false|int
210
     */
211
    public function dec(string $name, int $step = 1)
212
    {
213
        if ($this->has($name)) {
214
            $value  = $this->get($name) - $step;
215
            $expire = $this->expire;
216
        } else {
217
            $value  = -$step;
218
            $expire = 0;
219
        }
220
221
        return $this->set($name, $value, $expire) ? $value : false;
222
    }
223
224
    /**
225
     * 删除缓存
226
     * @access public
227
     * @param  string $name 缓存变量名
228
     * @return bool
229
     */
230
    public function delete($name): bool
231
    {
232
        $this->writeTimes++;
233
234
        try {
235
            return $this->unlink($this->getCacheKey($name));
236
        } catch (\Exception $e) {
237
            return false;
238
        }
239
    }
240
241
    /**
242
     * 清除缓存
243
     * @access public
244
     * @return bool
245
     */
246
    public function clear(): bool
247
    {
248
        $this->writeTimes++;
249
250
        $files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DIRECTORY_SEPARATOR : '') . '*');
251
252
        foreach ($files as $path) {
253
            if (is_dir($path)) {
254
                $matches = glob($path . DIRECTORY_SEPARATOR . '*.php');
255
                if (is_array($matches)) {
256
                    array_map('unlink', $matches);
257
                }
258
                rmdir($path);
259
            } else {
260
                unlink($path);
261
            }
262
        }
263
264
        return true;
265
    }
266
267
    /**
268
     * 删除缓存标签
269
     * @access public
270
     * @param  array $keys 缓存标识列表
271
     * @return void
272
     */
273
    public function clearTag(array $keys): void
274
    {
275
        foreach ($keys as $key) {
276
            $this->unlink($key);
277
        }
278
    }
279
280
    /**
281
     * 判断文件是否存在后,删除
282
     * @access private
283
     * @param  string $path
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
284
     * @return bool
285
     */
286
    private function unlink(string $path): bool
0 ignored issues
show
Coding Style introduced by
Private method name "File::unlink" must be prefixed with an underscore
Loading history...
287
    {
288
        return is_file($path) && unlink($path);
289
    }
290
291
}
292