Completed
Push — V6 ( 23eee8...7e10de )
by Georges
02:57
created

DriverBaseTrait::getConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
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
namespace phpFastCache\Core\Pool;
15
16
use phpFastCache\Exceptions\phpFastCacheDriverException;
17
use phpFastCache\Core\Item\ExtendedCacheItemInterface;
18
use phpFastCache\Util\Directory;
19
20
21
/**
22
 * Class DriverBaseTrait
23
 * @package phpFastCache\Cache
24
 */
25
trait DriverBaseTrait
26
{
27
    use ExtendedCacheItemPoolTrait;
28
29
    /**
30
     * @var array default options, this will be merge to Driver's Options
31
     */
32
    protected $config = [];
33
34
    /**
35
     * @var bool
36
     */
37
    protected $fallback = false;
38
39
    /**
40
     * @var mixed Instance of driver service
41
     */
42
    protected $instance;
43
44
    /**
45
     * @param $config_name
46
     * @param string $value
47
     */
48
    public function setup($config_name, $value = '')
49
    {
50
        /**
51
         * Config for class
52
         */
53
        if (is_array($config_name)) {
54
            $this->config = array_merge($this->config, $config_name);
55
        } else {
56
            $this->config[ $config_name ] = $value;
57
        }
58
    }
59
60
    /**
61
     * @return array
62
     */
63
    public function getConfig()
64
    {
65
        return $this->config;
66
    }
67
68
    /**
69
     * Encode data types such as object/array
70
     * for driver that does not support
71
     * non-scalar value
72
     * @param $data
73
     * @return string
74
     */
75
    protected function encode($data)
76
    {
77
        return serialize($data);
78
    }
79
80
    /**
81
     * Decode data types such as object/array
82
     * for driver that does not support
83
     * non-scalar value
84
     * @param $value
85
     * @return mixed
86
     */
87
    protected function decode($value)
88
    {
89
        return @unserialize($value);
0 ignored issues
show
Security Object Injection introduced by
$value can contain request data and is used in unserialized context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Read from $_COOKIE, and $_COOKIE[$keyword] is decoded by json_decode(), and json_decode($_COOKIE[$keyword], true) is passed to DriverBaseTrait::decode() in src/phpFastCache/Drivers/Cookie/Driver.php on line 104
  1. Read from $_COOKIE, and $_COOKIE[$keyword] is decoded by json_decode(), and json_decode($_COOKIE[$keyword], true) is passed to DriverBaseTrait::decode()
    in src/phpFastCache/Drivers/Cookie/Driver.php on line 104
  2. Path: Fetching key HTTP_HOST from $_SERVER, and $_SERVER['HTTP_HOST'] is passed through str_replace(), and str_replace(':', '_', $_SERVER['HTTP_HOST']) is passed through strtolower(), and strtolower(str_replace(':', '_', $_SERVER['HTTP_HOST'])) is passed through preg_replace(), and $securityKey is assigned in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 61
  1. Fetching key HTTP_HOST from $_SERVER, and $_SERVER['HTTP_HOST'] is passed through str_replace(), and str_replace(':', '_', $_SERVER['HTTP_HOST']) is passed through strtolower(), and strtolower(str_replace(':', '_', $_SERVER['HTTP_HOST'])) is passed through preg_replace(), and $securityKey is assigned
    in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 61
  2. Data is passed through trim(), and Data is passed through preg_replace()
    in vendor/src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 195
  3. $securityKey is assigned
    in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 71
  4. $full_path is assigned
    in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 88
  5. $full_path is passed through realpath()
    in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 105
  6. IOHelperTrait::getPath() returns tainted data
    in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 134
  7. IOHelperTrait::getFileDir() returns tainted data, and $path is assigned
    in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 145
  8. IOHelperTrait::getFilePath() returns tainted data, and $file_path is assigned
    in src/phpFastCache/Drivers/Files/Driver.php on line 98
  9. Data is passed through file_get_contents()
    in vendor/src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 240
  10. $content is assigned
    in src/phpFastCache/Drivers/Files/Driver.php on line 103
  11. $content is passed to DriverBaseTrait::decode()
    in src/phpFastCache/Drivers/Files/Driver.php on line 105

Preventing Object Injection Attacks

If you pass raw user-data to unserialize() for example, this can be used to create an object of any class that is available in your local filesystem. For an attacker, classes that have magic methods like __destruct or __wakeup are particularly interesting in such a case, as they can be exploited very easily.

We recommend to not pass user data to such a function. In case of unserialize, better use JSON to transfer data.

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...
90
    }
91
92
    /**
93
     * Check phpModules or CGI
94
     * @return bool
95
     */
96
    protected function isPHPModule()
97
    {
98
        if (PHP_SAPI === 'apache2handler') {
99
            return true;
100
        } else {
101
            if (strpos(PHP_SAPI, 'handler') !== false) {
102
                return true;
103
            }
104
        }
105
106
        return false;
107
    }
108
109
110
    /**
111
     * @param $class
112
     * @return bool
113
     */
114
    protected function isExistingDriver($class)
115
    {
116
        return class_exists("\\phpFastCache\\Drivers\\{$class}");
117
    }
118
119
120
    /**
121
     * @param $tag
122
     * @return string
123
     */
124
    protected function _getTagName($tag)
125
    {
126
        return "__tag__" . $tag;
127
    }
128
129
    /**
130
     * @param \phpFastCache\Core\Item\ExtendedCacheItemInterface $item
131
     * @return array
132
     */
133
    public function driverPreWrap(ExtendedCacheItemInterface $item)
134
    {
135
        $wrap = [
136
          self::DRIVER_DATA_WRAPPER_INDEX => $item->get(),
137
          self::DRIVER_TAGS_WRAPPER_INDEX => $item->getTags(),
138
          self::DRIVER_EDATE_WRAPPER_INDEX => $item->getExpirationDate(),
139
        ];
140
141
        if($this->config['itemDetailedDate']){
142
            $wrap[ self::DRIVER_MDATE_WRAPPER_INDEX ] = new \DateTime();
143
            /**
144
             * If the creation date exists
145
             * reuse it else set a new Date
146
             */
147
            $wrap[ self::DRIVER_CDATE_WRAPPER_INDEX ] = $item->getCreationDate() ?: new \DateTime();
148
        }else{
149
            $wrap[ self::DRIVER_MDATE_WRAPPER_INDEX ] = null;
150
            $wrap[ self::DRIVER_CDATE_WRAPPER_INDEX ] = null;
151
        }
152
153
        return $wrap;
154
    }
155
156
    /**
157
     * @param array $wrapper
158
     * @return mixed
159
     */
160
    public function driverUnwrapData(array $wrapper)
161
    {
162
        return $wrapper[ self::DRIVER_DATA_WRAPPER_INDEX ];
163
    }
164
165
    /**
166
     * @param array $wrapper
167
     * @return mixed
168
     */
169
    public function driverUnwrapTags(array $wrapper)
170
    {
171
        return $wrapper[ self::DRIVER_TAGS_WRAPPER_INDEX ];
172
    }
173
174
175
    /**
176
     * @param array $wrapper
177
     * @return \DateTime
178
     */
179
    public function driverUnwrapEdate(array $wrapper)
180
    {
181
        return $wrapper[ self::DRIVER_EDATE_WRAPPER_INDEX ];
182
    }
183
184
    /**
185
     * @param array $wrapper
186
     * @return \DateTime
187
     */
188
    public function driverUnwrapCdate(array $wrapper)
189
    {
190
        return $wrapper[ self::DRIVER_CDATE_WRAPPER_INDEX ];
191
    }
192
193
194
    /**
195
     * @param array $wrapper
196
     * @return \DateTime
197
     */
198
    public function driverUnwrapMdate(array $wrapper)
199
    {
200
        return $wrapper[ self::DRIVER_MDATE_WRAPPER_INDEX ];
201
    }
202
203
    /**
204
     * @return string
205
     */
206
    public function getDriverName()
207
    {
208
        static $driverName;
209
210
        return ($driverName ?: $driverName = ucfirst(substr(strrchr((new \ReflectionObject($this))->getNamespaceName(), '\\'), 1)));
211
    }
212
213
    /**
214
     * @param \phpFastCache\Core\Item\ExtendedCacheItemInterface $item
215
     * @return bool
216
     * @throws \LogicException
217
     */
218
    public function driverWriteTags(ExtendedCacheItemInterface $item)
219
    {
220
        /**
221
         * Do not attempt to write tags
222
         * on tags item, it can leads
223
         * to an infinite recursive calls
224
         */
225
        if(strpos($item->getKey(), self::DRIVER_TAGS_KEY_PREFIX ) === 0){
226
            throw new \LogicException('Trying to set tag(s) to an Tag item index: ' . $item->getKey());
227
        }
228
229
        /**
230
         * @var $tagsItems ExtendedCacheItemInterface[]
231
         */
232
        $tagsItems = $this->getItems($this->getTagKeys($item->getTags()));
233
234
        foreach ($tagsItems as $tagsItem) {
235
            $data = $tagsItem->get();
236
            $expTimestamp = $item->getExpirationDate()->getTimestamp();
237
238
            /**
239
             * Using the key will
240
             * avoid to use array_unique
241
             * that has slow performances
242
             */
243
244
            $tagsItem->set(array_merge((array) $data, [$item->getKey() => $expTimestamp]));
245
246
            /**
247
             * Set the expiration date
248
             * of the $tagsItem based
249
             * on the older $item
250
             * expiration date
251
             */
252
            if ($expTimestamp > $tagsItem->getExpirationDate()->getTimestamp()) {
253
                $tagsItem->expiresAt($item->getExpirationDate());
0 ignored issues
show
Bug introduced by
It seems like $item->getExpirationDate() can be null; however, expiresAt() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
254
            }
255
            $this->driverWrite($tagsItem);
256
            $tagsItem->setHit(true);
257
        }
258
259
        /**
260
         * Also update removed tags to
261
         * keep the index up to date
262
         */
263
        $tagsItems = $this->getItems($this->getTagKeys($item->getRemovedTags()));
264
265
        foreach ($tagsItems as $tagsItem) {
266
            $data = (array) $tagsItem->get();
267
268
            unset($data[ $item->getKey() ]);
269
            $tagsItem->set($data);
270
271
            /**
272
             * Recalculate the expiration date
273
             *
274
             * If the $tagsItem does not have
275
             * any cache item references left
276
             * then remove it from tagsItems index
277
             */
278
            if (count($data)) {
279
                $tagsItem->expiresAt(max($data));
280
                $this->driverWrite($tagsItem);
281
                $tagsItem->setHit(true);
282
            } else {
283
                $this->deleteItem($tagsItem);
0 ignored issues
show
Documentation introduced by
$tagsItem is of type object<Psr\Cache\CacheItemInterface>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
284
            }
285
        }
286
287
        return true;
288
    }
289
290
    /**
291
     * @param $key
292
     * @return string
293
     */
294
    public function getTagKey($key)
295
    {
296
        return self::DRIVER_TAGS_KEY_PREFIX . $key;
297
    }
298
299
    /**
300
     * @param $key
301
     * @return string
302
     */
303
    public function getTagKeys(array $keys)
304
    {
305
        foreach ($keys as &$key) {
306
            $key = $this->getTagKey($key);
307
        }
308
309
        return $keys;
310
    }
311
312
    /**
313
     * @param string $optionName
314
     * @param mixed $optionValue
315
     * @return bool
316
     * @throws \InvalidArgumentException
317
     */
318
    public static function isValidOption($optionName, $optionValue)
1 ignored issue
show
Unused Code introduced by
The parameter $optionValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
319
    {
320
        if (!is_string($optionName)) {
321
            throw new \InvalidArgumentException('$optionName must be a string');
322
        }
323
324
        return true;
325
    }
326
327
    /**
328
     * @return array
329
     */
330
    public static function getRequiredOptions()
331
    {
332
        return [];
333
    }
334
335
    /**
336
     * @return array
337
     */
338
    public static function getValidOptions()
339
    {
340
        return [];
341
    }
342
}