Completed
Push — v5 ( 3fd0ee...307e18 )
by Georges
02:33
created

Driver::getValidOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 4
rs 10
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
     */
37
    const FILES_DIR = 'files';
38
39
    /**
40
     * Driver constructor.
41
     * @param array $config
42
     * @throws phpFastCacheDriverException
43
     */
44
    public function __construct(array $config = [])
45
    {
46
        $this->setup($config);
47
48
        if (!$this->driverCheck()) {
49
            throw new phpFastCacheDriverCheckException(sprintf(self::DRIVER_CHECK_FAILURE, $this->getDriverName()));
50
        }
51
    }
52
53
    /**
54
     * @return bool
55
     */
56
    public function driverCheck()
57
    {
58
        return is_writable($this->getFilesDir()) || @mkdir($this->getFilesDir(), $this->setChmodAuto(), true);
0 ignored issues
show
Security File Manipulation introduced by
$this->getFilesDir() 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...
59
    }
60
61
    /**
62
     * @param \Psr\Cache\CacheItemInterface $item
63
     * @return mixed
64
     * @throws \InvalidArgumentException
65
     */
66
    public function driverWrite(CacheItemInterface $item)
67
    {
68
        /**
69
         * Check for Cross-Driver type confusion
70
         */
71
        if ($item instanceof Item) {
72
            $file_path = $this->getFilePath($item->getKey());
73
            $data = $this->encode($this->driverPreWrap($item));
74
75
            $toWrite = true;
76
            /*
77
             * Skip if Existing Caching in Options
78
             */
79
            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...
80
                $content = $this->readfile($file_path);
81
                $old = $this->decode($content);
82
                $toWrite = false;
83
                if ($old->isExpired()) {
84
                    $toWrite = true;
85
                }
86
            }
87
88
            // Force write
89
            try {
90
                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...
91
                    $f = fopen($file_path, 'w+');
92
                    fwrite($f, $data);
93
                    fclose($f);
94
95
                    return true;
96
                }
97
            } catch (\Exception $e) {
98
                return false;
99
            }
100
        } else {
101
            throw new \InvalidArgumentException('Cross-Driver type confusion detected');
102
        }
103
    }
104
105
    /**
106
     * @param string $key
107
     * @return mixed
108
     * @throws \InvalidArgumentException
109
     */
110
    public function driverRead($key)
111
    {
112
        /**
113
         * Check for Cross-Driver type confusion
114
         */
115
        $file_path = $this->getFilePath($key);
116
        if (!file_exists($file_path)) {
117
            return null;
118
        }
119
120
        $content = $this->readfile($file_path);
121
        $object = $this->decode($content);
122
123
        if ($this->driverUnwrapTime($object)->getTimestamp() < time()) {
124
            @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...
125
126
            return null;
127
        }
128
129
        return $object;
130
131
    }
132
133
    /**
134
     * @param \Psr\Cache\CacheItemInterface $item
135
     * @return bool
136
     * @throws \InvalidArgumentException
137
     */
138
    public function driverDelete(CacheItemInterface $item)
139
    {
140
        /**
141
         * Check for Cross-Driver type confusion
142
         */
143
        if ($item instanceof Item) {
144
            $file_path = $this->getFilePath($item->getKey(), true);
145
            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...
146
                return true;
147
            } else {
148
                return false;
149
            }
150
        } else {
151
            throw new \InvalidArgumentException('Cross-Driver type confusion detected');
152
        }
153
    }
154
155
    /**
156
     * @return bool
157
     */
158
    public function driverClear()
159
    {
160
        $return = null;
161
        $path = $this->getFilePath(false);
162
        $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...
163
        if (!$dir) {
164
            throw new phpFastCacheDriverException("Can't read PATH:" . $path);
165
        }
166
167
        while ($file = readdir($dir)) {
168
            if ($file != '.' && $file != '..' && is_dir($path . '/' . $file)) {
169
                // read sub dir
170
                $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...
171
                if (!$subdir) {
172
                    throw new phpFastCacheDriverException("Can't read path:" . $path . '/' . $file);
173
                }
174
175
                while ($subdirFile = readdir($subdir)) {
176
                    if ($subdirFile != '.' && $subdirFile != '..') {
177
                        $file_path = $path . '/' . $file . '/' . $subdirFile;
178
                        $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...
179
                        if ($return !== false) {
180
                            $return = $result;
181
                        }
182
                    }
183
                }
184
            }
185
        }
186
187
        return (bool) $return;
188
    }
189
190
    /**
191
     * @return bool
192
     */
193
    public function driverConnect()
194
    {
195
        return true;
196
    }
197
198
    /**
199
     * @param \Psr\Cache\CacheItemInterface $item
200
     * @return bool
201
     * @throws \InvalidArgumentException
202
     */
203
    public function driverIsHit(CacheItemInterface $item)
204
    {
205
        $file_path = $this->getFilePath($item->getKey(), true);
206
        if (!file_exists($file_path)) {
207
            return false;
208
        } else {
209
            // check expired or not
210
            $value = $this->driverRead($item->getKey());
211
212
            return !($value == null);
213
        }
214
    }
215
216
    /**
217
     * @param string $optionName
218
     * @param mixed $optionValue
219
     * @return bool
220
     * @throws \InvalidArgumentException
221
     */
222
    public static function isValidOption($optionName, $optionValue)
223
    {
224
        parent::isValidOption($optionName, $optionValue);
225
        switch($optionName)
226
        {
227
            case 'path':
228
                return is_string($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 'default_chmod':
232
                return is_numeric($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
235
            case 'securityKey':
236
                return is_string($optionValue);
237
                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...
238
            case 'htaccess':
239
                return is_bool($optionValue);
240
                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...
241
            default:
242
                return false;
243
            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...
244
        }
245
    }
246
247
    /**
248
     * @return string
249
     * @throws \phpFastCache\Exceptions\phpFastCacheCoreException
250
     */
251
    public function getFilesDir()
252
    {
253
        return $this->getPath() . DIRECTORY_SEPARATOR . self::FILES_DIR;
254
    }
255
256
    /**
257
     * @return array
258
     */
259
    public static function getValidOptions()
260
    {
261
        return ['path', 'default_chmod', 'securityKey', 'htaccess'];
262
    }
263
264
    /**
265
     * @return array
266
     */
267
    public static function getRequiredOptions()
268
    {
269
        return ['path'];
270
    }
271
272
    /********************
273
     *
274
     * PSR-6 Extended Methods
275
     *
276
     *******************/
277
278
    /**
279
     * @return driverStatistic
280
     * @throws \phpFastCache\Exceptions\phpFastCacheCoreException
281
     * @throws \phpFastCache\Exceptions\phpFastCacheDriverException
282
     */
283
    public function getStats()
284
    {
285
        $stat = new driverStatistic();
286
        $path = $this->getFilePath(false);
287
        
288
        if (!is_dir($path)) {
289
            throw new phpFastCacheDriverException("Can't read PATH:" . $path, 94);
290
        }else{
291
            $size = Directory::dirSize($path);
292
        }
293
294
        $stat->setData('')
295
          ->setSize($size)
296
          ->setInfo('Number of files used to build the cache: ' . Directory::getFileCount($path));
297
298
        return $stat;
299
    }
300
}