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); |
|
|
|
|
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()); |
|
|
|
|
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); |
|
|
|
|
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) |
|
|
|
|
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
|
|
|
} |
$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
$_COOKIE,
and$_COOKIE[$keyword]
is decoded by json_decode(), andjson_decode($_COOKIE[$keyword], true)
is passed to DriverBaseTrait::decode() in src/phpFastCache/Drivers/Cookie/Driver.php on line 104$_COOKIE,
and$_COOKIE[$keyword]
is decoded by json_decode(), andjson_decode($_COOKIE[$keyword], true)
is passed to DriverBaseTrait::decode()in src/phpFastCache/Drivers/Cookie/Driver.php on line 104
HTTP_HOST
from$_SERVER,
and$_SERVER['HTTP_HOST']
is passed through str_replace(), andstr_replace(':', '_', $_SERVER['HTTP_HOST'])
is passed through strtolower(), andstrtolower(str_replace(':', '_', $_SERVER['HTTP_HOST']))
is passed through preg_replace(), and$securityKey
is assigned in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 61HTTP_HOST
from$_SERVER,
and$_SERVER['HTTP_HOST']
is passed through str_replace(), andstr_replace(':', '_', $_SERVER['HTTP_HOST'])
is passed through strtolower(), andstrtolower(str_replace(':', '_', $_SERVER['HTTP_HOST']))
is passed through preg_replace(), and$securityKey
is assignedin src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 61
in vendor/src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 195
$securityKey
is assignedin src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 71
$full_path
is assignedin src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 88
$full_path
is passed through realpath()in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 105
in src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 134
$path
is assignedin src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 145
$file_path
is assignedin src/phpFastCache/Drivers/Files/Driver.php on line 98
in vendor/src/phpFastCache/Core/Pool/IO/IOHelperTrait.php on line 240
$content
is assignedin src/phpFastCache/Drivers/Files/Driver.php on line 103
$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 useJSON
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:
For numeric data, we recommend to explicitly cast the data: