Completed
Push — v5 ( 9120d0...3fd0ee )
by Georges
02:35
created

Driver::getStats()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 3 Features 1
Metric Value
cc 2
eloc 11
c 6
b 3
f 1
nc 2
nop 0
dl 0
loc 17
rs 9.4285
1
<?php
2
/**
3
 *
4
 * This file is part of phpFastCache.
5
 *
6
 * @license MIT License (MIT)
7
 *
8
 * For full copyright and license information, please see the docs/CREDITS.txt file.
9
 *
10
 * @author Khoa Bui (khoaofgod)  <[email protected]> http://www.phpfastcache.com
11
 * @author Georges.L (Geolim4)  <[email protected]>
12
 *
13
 */
14
15
namespace phpFastCache\Drivers\Files;
16
17
use phpFastCache\Cache\ExtendedCacheItemInterface;
18
use phpFastCache\Core\DriverAbstract;
19
use phpFastCache\Core\PathSeekerTrait;
20
use phpFastCache\Core\StandardPsr6StructureTrait;
21
use phpFastCache\Entities\driverStatistic;
22
use phpFastCache\Exceptions\phpFastCacheDriverCheckException;
23
use phpFastCache\Exceptions\phpFastCacheDriverException;
24
use phpFastCache\Util\Directory;
25
use Psr\Cache\CacheItemInterface;
26
27
/**
28
 * Class Driver
29
 * @package phpFastCache\Drivers
30
 */
31
class Driver extends DriverAbstract
32
{
33
    use PathSeekerTrait, StandardPsr6StructureTrait;
34
35
    /**
36
     * Driver constructor.
37
     * @param array $config
38
     * @throws phpFastCacheDriverException
39
     */
40
    public function __construct(array $config = [])
41
    {
42
        $this->setup($config);
43
44
        if (!$this->driverCheck()) {
45
            throw new phpFastCacheDriverCheckException(sprintf(self::DRIVER_CHECK_FAILURE, $this->getDriverName()));
46
        }
47
    }
48
49
    /**
50
     * @return bool
51
     */
52
    public function driverCheck()
53
    {
54
        return is_writable($this->getPath());
55
    }
56
57
    /**
58
     * @param \Psr\Cache\CacheItemInterface $item
59
     * @return mixed
60
     * @throws \InvalidArgumentException
61
     */
62
    public function driverWrite(CacheItemInterface $item)
63
    {
64
        /**
65
         * Check for Cross-Driver type confusion
66
         */
67
        if ($item instanceof Item) {
68
            $file_path = $this->getFilePath($item->getKey());
69
            $data = $this->encode($this->driverPreWrap($item));
70
71
            $toWrite = true;
72
            /*
73
             * Skip if Existing Caching in Options
74
             */
75
            if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true && file_exists($file_path)) {
0 ignored issues
show
Bug introduced by
The variable $option seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
76
                $content = $this->readfile($file_path);
77
                $old = $this->decode($content);
78
                $toWrite = false;
79
                if ($old->isExpired()) {
80
                    $toWrite = true;
81
                }
82
            }
83
84
            // Force write
85
            try {
86
                if ($toWrite == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
87
                    $f = fopen($file_path, 'w+');
88
                    fwrite($f, $data);
89
                    fclose($f);
90
91
                    return true;
92
                }
93
            } catch (\Exception $e) {
94
                return false;
95
            }
96
        } else {
97
            throw new \InvalidArgumentException('Cross-Driver type confusion detected');
98
        }
99
    }
100
101
    /**
102
     * @param string $key
103
     * @return mixed
104
     * @throws \InvalidArgumentException
105
     */
106
    public function driverRead($key)
107
    {
108
        /**
109
         * Check for Cross-Driver type confusion
110
         */
111
        $file_path = $this->getFilePath($key);
112
        if (!file_exists($file_path)) {
113
            return null;
114
        }
115
116
        $content = $this->readfile($file_path);
117
        $object = $this->decode($content);
118
119
        if ($this->driverUnwrapTime($object)->getTimestamp() < time()) {
120
            @unlink($file_path);
0 ignored issues
show
Security File Manipulation introduced by
$file_path can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
121
122
            return null;
123
        }
124
125
        return $object;
126
127
    }
128
129
    /**
130
     * @param \Psr\Cache\CacheItemInterface $item
131
     * @return bool
132
     * @throws \InvalidArgumentException
133
     */
134
    public function driverDelete(CacheItemInterface $item)
135
    {
136
        /**
137
         * Check for Cross-Driver type confusion
138
         */
139
        if ($item instanceof Item) {
140
            $file_path = $this->getFilePath($item->getKey(), true);
141
            if (file_exists($file_path) && @unlink($file_path)) {
0 ignored issues
show
Security File Manipulation introduced by
$file_path can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
142
                return true;
143
            } else {
144
                return false;
145
            }
146
        } else {
147
            throw new \InvalidArgumentException('Cross-Driver type confusion detected');
148
        }
149
    }
150
151
    /**
152
     * @return bool
153
     */
154
    public function driverClear()
155
    {
156
        $return = null;
157
        $path = $this->getFilePath(false);
158
        $dir = @opendir($path);
0 ignored issues
show
Security File Exposure introduced by
$path can contain request data and is used in file inclusion context(s) leading to a potential security vulnerability.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
159
        if (!$dir) {
160
            throw new phpFastCacheDriverException("Can't read PATH:" . $path);
161
        }
162
163
        while ($file = readdir($dir)) {
164
            if ($file != '.' && $file != '..' && is_dir($path . '/' . $file)) {
165
                // read sub dir
166
                $subdir = @opendir($path . '/' . $file);
0 ignored issues
show
Security File Exposure introduced by
$path . '/' . $file can contain request data and is used in file inclusion context(s) leading to a potential security vulnerability.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
167
                if (!$subdir) {
168
                    throw new phpFastCacheDriverException("Can't read path:" . $path . '/' . $file);
169
                }
170
171
                while ($subdirFile = readdir($subdir)) {
172
                    if ($subdirFile != '.' && $subdirFile != '..') {
173
                        $file_path = $path . '/' . $file . '/' . $subdirFile;
174
                        $result = @unlink($file_path);
0 ignored issues
show
Security File Manipulation introduced by
$file_path can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
175
                        if ($return !== false) {
176
                            $return = $result;
177
                        }
178
                    }
179
                }
180
            }
181
        }
182
183
        return (bool) $return;
184
    }
185
186
    /**
187
     * @return bool
188
     */
189
    public function driverConnect()
190
    {
191
        return true;
192
    }
193
194
    /**
195
     * @param \Psr\Cache\CacheItemInterface $item
196
     * @return bool
197
     * @throws \InvalidArgumentException
198
     */
199
    public function driverIsHit(CacheItemInterface $item)
200
    {
201
        $file_path = $this->getFilePath($item->getKey(), true);
202
        if (!file_exists($file_path)) {
203
            return false;
204
        } else {
205
            // check expired or not
206
            $value = $this->driverRead($item->getKey());
207
208
            return !($value == null);
209
        }
210
    }
211
212
    /**
213
     * @param string $optionName
214
     * @param mixed $optionValue
215
     * @return bool
216
     * @throws \InvalidArgumentException
217
     */
218
    public static function isValidOption($optionName, $optionValue)
219
    {
220
        parent::isValidOption($optionName, $optionValue);
221
        switch($optionName)
222
        {
223
            case 'path':
224
                return is_string($optionValue);
225
                break;
1 ignored issue
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
226
227
            case 'default_chmod':
228
                return is_numeric($optionValue);
229
                break;
1 ignored issue
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
230
231
            case 'securityKey':
232
                return is_string($optionValue);
233
                break;
1 ignored issue
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
234
            case 'htaccess':
235
                return is_bool($optionValue);
236
                break;
1 ignored issue
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
237
            default:
238
                return false;
239
            break;
1 ignored issue
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
240
        }
241
    }
242
    /**
243
     * @return array
244
     */
245
    public static function getValidOptions()
246
    {
247
        return ['path', 'default_chmod', 'securityKey', 'htaccess'];
248
    }
249
250
    /**
251
     * @return array
252
     */
253
    public static function getRequiredOptions()
254
    {
255
        return ['path'];
256
    }
257
258
    /********************
259
     *
260
     * PSR-6 Extended Methods
261
     *
262
     *******************/
263
264
    /**
265
     * @return driverStatistic
266
     * @throws \phpFastCache\Exceptions\phpFastCacheCoreException
267
     * @throws \phpFastCache\Exceptions\phpFastCacheDriverException
268
     */
269
    public function getStats()
270
    {
271
        $stat = new driverStatistic();
272
        $path = $this->getFilePath(false);
273
        
274
        if (!is_dir($path)) {
275
            throw new phpFastCacheDriverException("Can't read PATH:" . $path, 94);
276
        }else{
277
            $size = Directory::dirSize($path);
278
        }
279
280
        $stat->setData('')
281
          ->setSize($size)
282
          ->setInfo('Number of files used to build the cache: ' . Directory::getFileCount($path));
283
284
        return $stat;
285
    }
286
}