Completed
Push — 6.0 ( a4ef3c...64a49e )
by yun
04:55
created

File::rmdir()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5.025

Importance

Changes 0
Metric Value
cc 5
eloc 10
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 19
ccs 9
cts 10
cp 0.9
crap 5.025
rs 9.6111
1
<?php
2
// +----------------------------------------------------------------------
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 FilesystemIterator;
16
use think\App;
17
use think\cache\Driver;
18
19
/**
20
 * 文件缓存类
21
 */
22
class File extends Driver
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
     * @param App   $app
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
42
     * @param array $options 参数
43
     */
44 2
    public function __construct(App $app, array $options = [])
45
    {
46 2
        if (!empty($options)) {
47 2
            $this->options = array_merge($this->options, $options);
48
        }
49
50 2
        if (empty($this->options['path'])) {
51 1
            $this->options['path'] = $app->getRuntimePath() . 'cache';
52
        }
53
54 2
        if (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) {
55 2
            $this->options['path'] .= DIRECTORY_SEPARATOR;
56
        }
57 2
    }
58
59
    /**
60
     * 取得变量的存储文件名
61
     * @access public
62
     * @param string $name 缓存变量名
63
     * @return string
64
     */
65 1
    public function getCacheKey(string $name): string
66
    {
67 1
        $name = hash($this->options['hash_type'], $name);
68
69 1
        if ($this->options['cache_subdir']) {
70
            // 使用子目录
71 1
            $name = substr($name, 0, 2) . DIRECTORY_SEPARATOR . substr($name, 2);
72
        }
73
74 1
        if ($this->options['prefix']) {
75
            $name = $this->options['prefix'] . DIRECTORY_SEPARATOR . $name;
76
        }
77
78 1
        return $this->options['path'] . $name . '.php';
79
    }
80
81
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $name should have a doc-comment as per coding-style.
Loading history...
82
     * 获取缓存数据
83
     * @param $name
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
84
     * @return array|null
85
     */
86 1
    protected function getRaw($name)
87
    {
88 1
        $filename = $this->getCacheKey($name);
89
90 1
        if (!is_file($filename)) {
91 1
            return null;
92
        }
93
94 1
        $content = @file_get_contents($filename);
95
96 1
        if (false !== $content) {
97 1
            $expire = (int) substr($content, 8, 12);
98 1
            if (0 != $expire && time() > filemtime($filename) + $expire) {
99
                //缓存过期删除缓存文件
100
                $this->unlink($filename);
101
                return null;
102
            }
103
104 1
            $content = substr($content, 32);
105
106 1
            if ($this->options['data_compress'] && function_exists('gzcompress')) {
107
                //启用数据压缩
108
                $content = gzuncompress($content);
109
            }
110
111 1
            return ['content' => $content, 'expire' => $expire];
112
        }
113
114
        return null;
115
    }
116
117
    /**
118
     * 判断缓存是否存在
119
     * @access public
120
     * @param string $name 缓存变量名
121
     * @return bool
122
     */
123 1
    public function has($name): bool
124
    {
125 1
        return $this->getRaw($name) !== null;
126
    }
127
128
    /**
129
     * 读取缓存
130
     * @access public
131
     * @param string $name    缓存变量名
132
     * @param mixed  $default 默认值
133
     * @return mixed
134
     */
135 1
    public function get($name, $default = null)
136
    {
137 1
        $this->readTimes++;
138
139 1
        $raw = $this->getRaw($name);
140
141 1
        if (is_null($raw)) {
142 1
            return $default;
143
        }
144
145 1
        return $this->unserialize($raw['content']);
146
    }
147
148
    /**
149
     * 写入缓存
150
     * @access public
151
     * @param string        $name   缓存变量名
152
     * @param mixed         $value  存储数据
153
     * @param int|\DateTime $expire 有效时间 0为永久
154
     * @return bool
155
     */
156 1
    public function set($name, $value, $expire = null): bool
157
    {
158 1
        $this->writeTimes++;
159
160 1
        if (is_null($expire)) {
161 1
            $expire = $this->options['expire'];
162
        }
163
164 1
        $expire   = $this->getExpireTime($expire);
165 1
        $filename = $this->getCacheKey($name);
166
167 1
        $dir = dirname($filename);
168
169 1
        if (!is_dir($dir)) {
170
            try {
171 1
                mkdir($dir, 0755, true);
172
            } catch (\Exception $e) {
173
                // 创建失败
174
            }
175
        }
176
177 1
        $data = $this->serialize($value);
178
179 1
        if ($this->options['data_compress'] && function_exists('gzcompress')) {
180
            //数据压缩
181
            $data = gzcompress($data, 3);
182
        }
183
184 1
        $data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
185 1
        $result = file_put_contents($filename, $data);
186
187 1
        if ($result) {
188 1
            clearstatcache();
189 1
            return true;
190
        }
191
192
        return false;
193
    }
194
195
    /**
196
     * 自增缓存(针对数值缓存)
197
     * @access public
198
     * @param string $name 缓存变量名
199
     * @param int    $step 步长
200
     * @return false|int
201
     */
202 1
    public function inc(string $name, int $step = 1)
203
    {
204 1
        if ($raw = $this->getRaw($name)) {
205 1
            $value  = $this->unserialize($raw['content']) + $step;
206 1
            $expire = $raw['expire'];
207
        } else {
208
            $value  = $step;
209
            $expire = 0;
210
        }
211
212 1
        return $this->set($name, $value, $expire) ? $value : false;
213
    }
214
215
    /**
216
     * 自减缓存(针对数值缓存)
217
     * @access public
218
     * @param string $name 缓存变量名
219
     * @param int    $step 步长
220
     * @return false|int
221
     */
222 1
    public function dec(string $name, int $step = 1)
223
    {
224 1
        return $this->inc($name, -$step);
225
    }
226
227
    /**
228
     * 删除缓存
229
     * @access public
230
     * @param string $name 缓存变量名
231
     * @return bool
232
     */
233 1
    public function delete($name): bool
234
    {
235 1
        $this->writeTimes++;
236
237
        try {
238 1
            return $this->unlink($this->getCacheKey($name));
239
        } catch (\Exception $e) {
240
            return false;
241
        }
242
    }
243
244
    /**
245
     * 清除缓存
246
     * @access public
247
     * @return bool
248
     */
249 1
    public function clear(): bool
250
    {
251 1
        $this->writeTimes++;
252
253 1
        $dirname = $this->options['path'] . $this->options['prefix'];
254
255 1
        $this->rmdir($dirname);
256
257 1
        return true;
258
    }
259
260
    /**
261
     * 删除缓存标签
262
     * @access public
263
     * @param array $keys 缓存标识列表
264
     * @return void
265
     */
266 1
    public function clearTag(array $keys): void
267
    {
268 1
        foreach ($keys as $key) {
269 1
            $this->unlink($key);
270
        }
271 1
    }
272
273
    /**
274
     * 判断文件是否存在后,删除
275
     * @access private
276
     * @param string $path
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
277
     * @return bool
278
     */
279 1
    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...
280
    {
281 1
        return is_file($path) && unlink($path);
282
    }
283
284
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $dirname should have a doc-comment as per coding-style.
Loading history...
285
     * 删除文件夹
286
     * @param $dirname
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
287
     * @return bool
288
     */
289 1
    private function rmdir($dirname)
0 ignored issues
show
Coding Style introduced by
Private method name "File::rmdir" must be prefixed with an underscore
Loading history...
290
    {
291 1
        if (!is_dir($dirname)) {
292
            return false;
293
        }
294
295 1
        $items = new FilesystemIterator($dirname);
296
297 1
        foreach ($items as $item) {
298 1
            if ($item->isDir() && !$item->isLink()) {
299 1
                $this->rmdir($item->getPathname());
300
            } else {
301 1
                $this->unlink($item->getPathname());
302
            }
303
        }
304
305 1
        @rmdir($dirname);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rmdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

305
        /** @scrutinizer ignore-unhandled */ @rmdir($dirname);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
306
307 1
        return true;
308
    }
309
310
}
311