Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9a5c2ff

Browse filesBrowse files
[Cache] automatically use igbinary when available, with graceful error handling
1 parent 1abfb2c commit 9a5c2ff
Copy full SHA for 9a5c2ff
Expand file treeCollapse file tree

14 files changed

+255
-52
lines changed

‎.travis.yml

Copy file name to clipboardExpand all lines: .travis.yml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ before_install:
151151
tfold ext.libsodium tpecl libsodium sodium.so $INI
152152
tfold ext.mongodb tpecl mongodb-1.4.0RC1 mongodb.so $INI
153153
tfold ext.amqp tpecl amqp-1.9.3 amqp.so $INI
154+
tfold ext.igbinary tpecl igbinary-2.0.6 igbinary.so $INI
154155
fi
155156
156157
- |

‎src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php
+12-6Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public function get(string $key, callable $callback, float $beta = null)
8888
$this->initialize();
8989
}
9090
if (!isset($this->keys[$key])) {
91+
get_from_pool:
9192
if ($this->pool instanceof CacheInterface) {
9293
return $this->pool->get($key, $callback, $beta);
9394
}
@@ -99,11 +100,16 @@ public function get(string $key, callable $callback, float $beta = null)
99100
if ('N;' === $value) {
100101
return null;
101102
}
102-
if ($value instanceof \Closure) {
103-
return $value();
104-
}
105-
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
106-
return unserialize($value);
103+
try {
104+
if ($value instanceof \Closure) {
105+
return $value();
106+
}
107+
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
108+
return $this->unserializeValue($value);
109+
}
110+
} catch (\Throwable $e) {
111+
unset($this->keys[$key]);
112+
goto get_from_pool;
107113
}
108114

109115
return $value;
@@ -278,7 +284,7 @@ private function generateItems(array $keys): \Generator
278284
}
279285
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
280286
try {
281-
yield $key => $f($key, unserialize($value), true);
287+
yield $key => $f($key, $this->unserializeValue($value), true);
282288
} catch (\Throwable $e) {
283289
yield $key => $f($key, null, false);
284290
}

‎src/Symfony/Component/Cache/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/CHANGELOG.md
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ CHANGELOG
44
4.2.0
55
-----
66

7+
* automatically use igbinary when available, with graceful error handling
78
* added `CacheInterface`, which provides stampede protection via probabilistic early expiration and should become the preferred way to use a cache
89
* added sub-second expiry accuracy for backends that support it
910
* throw `LogicException` when `CacheItem::tag()` is called on an item coming from a non tag-aware pool
1011
* deprecated `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead
1112
* deprecated the `AbstractAdapter::createSystemCache()` method
13+
* deprecated the `AbstractAdapter::unserialize()` and `AbstractCache::unserialize()` methods
1214

1315
3.4.0
1416
-----

‎src/Symfony/Component/Cache/Simple/PhpArrayCache.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Simple/PhpArrayCache.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public function get($key, $default = null)
8383
}
8484
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
8585
try {
86-
return unserialize($value);
86+
return $this->unserializeValue($value);
8787
} catch (\Throwable $e) {
8888
return $default;
8989
}
+99Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache\Tests\Traits;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Cache\Traits\SerializingTrait;
16+
17+
class SerializingTraitTest extends TestCase
18+
{
19+
use SerializingTrait;
20+
21+
public function testSerialize()
22+
{
23+
$values = array(
24+
'a' => 123,
25+
'b' => function () {},
26+
);
27+
28+
$expected = array('a' => \function_exists('igbinary_serialize') ? igbinary_serialize(123) : serialize(123));
29+
$this->assertSame($expected, $this->serializeValues($values, $failed));
30+
$this->assertSame(array('b'), $failed);
31+
}
32+
33+
public function testNativeUnserialize()
34+
{
35+
$this->assertNull($this->unserializeValue(serialize(null)));
36+
$this->assertFalse($this->unserializeValue(serialize(false)));
37+
$this->assertSame('', $this->unserializeValue(serialize('')));
38+
$this->assertSame(0, $this->unserializeValue(serialize(0)));
39+
}
40+
41+
/**
42+
* @requires extension igbinary
43+
*/
44+
public function testIgbinaryUnserialize()
45+
{
46+
$this->assertNull($this->unserializeValue(igbinary_serialize(null)));
47+
$this->assertFalse($this->unserializeValue(igbinary_serialize(false)));
48+
$this->assertSame('', $this->unserializeValue(igbinary_serialize('')));
49+
$this->assertSame(0, $this->unserializeValue(igbinary_serialize(0)));
50+
}
51+
52+
/**
53+
* @expectedException \DomainException
54+
* @expectedExceptionMessage Class not found: NotExistingClass
55+
*/
56+
public function testNativeUnserializeNotFoundClass()
57+
{
58+
$this->unserializeValue('O:16:"NotExistingClass":0:{}');
59+
}
60+
61+
/**
62+
* @requires extension igbinary
63+
* @expectedException \DomainException
64+
* @expectedExceptionMessage Class not found: NotExistingClass
65+
*/
66+
public function testIgbinaryUnserializeNotFoundClass()
67+
{
68+
$this->unserializeValue(rawurldecode('%00%00%00%02%17%10NotExistingClass%14%00'));
69+
}
70+
71+
/**
72+
* @expectedException \DomainException
73+
* @expectedExceptionMessage unserialize(): Error at offset 0 of 3 bytes
74+
*/
75+
public function testNativeUnserializeInvalid()
76+
{
77+
set_error_handler(function () { return false; });
78+
try {
79+
@$this->unserializeValue(':::');
80+
} finally {
81+
restore_error_handler();
82+
}
83+
}
84+
85+
/**
86+
* @requires extension igbinary
87+
* @expectedException \DomainException
88+
* @expectedExceptionMessage igbinary_unserialize_zval: unknown type '61', position 5
89+
*/
90+
public function testIgbinaryUnserializeInvalid()
91+
{
92+
set_error_handler(function () { return false; });
93+
try {
94+
@$this->unserializeValue(rawurldecode('%00%00%00%02abc'));
95+
} finally {
96+
restore_error_handler();
97+
}
98+
}
99+
}

‎src/Symfony/Component/Cache/Traits/AbstractTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Traits/AbstractTrait.php
+9-5Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,13 @@ public function clear()
110110
if ($cleared = $this->versioningIsEnabled) {
111111
$namespaceVersion = 2;
112112
try {
113-
foreach ($this->doFetch(array('@'.$this->namespace)) as $v) {
113+
foreach ($this->doFetch(array('/'.$this->namespace)) as $v) {
114114
$namespaceVersion = 1 + (int) $v;
115115
}
116116
} catch (\Exception $e) {
117117
}
118-
$namespaceVersion .= ':';
119-
$cleared = $this->doSave(array('@'.$this->namespace => $namespaceVersion), 0);
118+
$namespaceVersion .= '/';
119+
$cleared = $this->doSave(array('/'.$this->namespace => $namespaceVersion), 0);
120120
if ($cleared = true === $cleared || array() === $cleared) {
121121
$this->namespaceVersion = $namespaceVersion;
122122
}
@@ -216,9 +216,13 @@ public function reset()
216216
* @return mixed
217217
*
218218
* @throws \Exception
219+
*
220+
* @deprecated since Symfony 4.2, use SerializingTrait instead.
219221
*/
220222
protected static function unserialize($value)
221223
{
224+
@trigger_error(sprintf('The "%s::unserialize()" method is deprecated since Symfony 4.2, use SerializingTrait instead.', __CLASS__), E_USER_DEPRECATED);
225+
222226
if ('b:0;' === $value) {
223227
return false;
224228
}
@@ -238,9 +242,9 @@ protected static function unserialize($value)
238242
private function getId($key)
239243
{
240244
if ($this->versioningIsEnabled && '' === $this->namespaceVersion) {
241-
$this->namespaceVersion = '1:';
245+
$this->namespaceVersion = '1/';
242246
try {
243-
foreach ($this->doFetch(array('@'.$this->namespace)) as $v) {
247+
foreach ($this->doFetch(array('/'.$this->namespace)) as $v) {
244248
$this->namespaceVersion = $v;
245249
}
246250
} catch (\Exception $e) {

‎src/Symfony/Component/Cache/Traits/ApcuTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Traits/ApcuTrait.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ private function init($namespace, $defaultLifetime, $version)
5151
*/
5252
protected function doFetch(array $ids)
5353
{
54+
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
5455
try {
5556
$values = array();
5657
foreach (apcu_fetch($ids, $ok) ?: array() as $k => $v) {
@@ -62,6 +63,8 @@ protected function doFetch(array $ids)
6263
return $values;
6364
} catch (\Error $e) {
6465
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
66+
} finally {
67+
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
6568
}
6669
}
6770

‎src/Symfony/Component/Cache/Traits/FilesystemTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Traits/FilesystemTrait.php
+8-5Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
trait FilesystemTrait
2323
{
2424
use FilesystemCommonTrait;
25+
use SerializingTrait;
2526

2627
/**
2728
* @return bool
@@ -68,7 +69,7 @@ protected function doFetch(array $ids)
6869
$value = stream_get_contents($h);
6970
fclose($h);
7071
if ($i === $id) {
71-
$values[$id] = parent::unserialize($value);
72+
$values[$id] = $this->unserializeValue($value);
7273
}
7374
}
7475
}
@@ -91,17 +92,19 @@ protected function doHave($id)
9192
*/
9293
protected function doSave(array $values, $lifetime)
9394
{
94-
$ok = true;
9595
$expiresAt = $lifetime ? (time() + $lifetime) : 0;
96+
$values = $this->serializeValues($values, $failed);
9697

9798
foreach ($values as $id => $value) {
98-
$ok = $this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".serialize($value), $expiresAt) && $ok;
99+
if (!$this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".$value, $expiresAt)) {
100+
$failed[] = $id;
101+
}
99102
}
100103

101-
if (!$ok && !is_writable($this->directory)) {
104+
if ($failed && !is_writable($this->directory)) {
102105
throw new CacheException(sprintf('Cache directory is not writable (%s)', $this->directory));
103106
}
104107

105-
return $ok;
108+
return $failed;
106109
}
107110
}

‎src/Symfony/Component/Cache/Traits/MemcachedTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Traits/MemcachedTrait.php
+8-5Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
*/
2323
trait MemcachedTrait
2424
{
25+
use SerializingTrait;
26+
2527
private static $defaultClientOptions = array(
2628
'persistent_id' => null,
2729
'username' => null,
@@ -194,6 +196,10 @@ public static function createConnection($servers, array $options = array())
194196
*/
195197
protected function doSave(array $values, $lifetime)
196198
{
199+
if (!$values = $this->serializeValues($values, $failed)) {
200+
return $failed;
201+
}
202+
197203
if ($lifetime && $lifetime > 30 * 86400) {
198204
$lifetime += time();
199205
}
@@ -203,30 +209,27 @@ protected function doSave(array $values, $lifetime)
203209
$encodedValues[rawurlencode($key)] = $value;
204210
}
205211

206-
return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime));
212+
return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime)) ? $failed : false;
207213
}
208214

209215
/**
210216
* {@inheritdoc}
211217
*/
212218
protected function doFetch(array $ids)
213219
{
214-
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
215220
try {
216221
$encodedIds = array_map('rawurlencode', $ids);
217222

218223
$encodedResult = $this->checkResultCode($this->getClient()->getMulti($encodedIds));
219224

220225
$result = array();
221226
foreach ($encodedResult as $key => $value) {
222-
$result[rawurldecode($key)] = $value;
227+
$result[rawurldecode($key)] = $this->unserializeValue($value);
223228
}
224229

225230
return $result;
226231
} catch (\Error $e) {
227232
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
228-
} finally {
229-
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
230233
}
231234
}
232235

‎src/Symfony/Component/Cache/Traits/PdoTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Traits/PdoTrait.php
+5-14Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
*/
2323
trait PdoTrait
2424
{
25+
use SerializingTrait;
26+
2527
private $conn;
2628
private $dsn;
2729
private $driver;
@@ -181,7 +183,7 @@ protected function doFetch(array $ids)
181183
if (null === $row[1]) {
182184
$expired[] = $row[0];
183185
} else {
184-
yield $row[0] => parent::unserialize(is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]);
186+
yield $row[0] => $this->unserializeValue(is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]);
185187
}
186188
}
187189

@@ -252,18 +254,7 @@ protected function doDelete(array $ids)
252254
*/
253255
protected function doSave(array $values, $lifetime)
254256
{
255-
$serialized = array();
256-
$failed = array();
257-
258-
foreach ($values as $id => $value) {
259-
try {
260-
$serialized[$id] = serialize($value);
261-
} catch (\Exception $e) {
262-
$failed[] = $id;
263-
}
264-
}
265-
266-
if (!$serialized) {
257+
if (!$values = $this->serializeValues($values, $failed)) {
267258
return $failed;
268259
}
269260

@@ -328,7 +319,7 @@ protected function doSave(array $values, $lifetime)
328319
$insertStmt->bindValue(':time', $now, \PDO::PARAM_INT);
329320
}
330321

331-
foreach ($serialized as $id => $data) {
322+
foreach ($values as $id => $data) {
332323
$stmt->execute();
333324

334325
if (null === $driver && !$stmt->rowCount()) {

‎src/Symfony/Component/Cache/Traits/PhpArrayTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Traits/PhpArrayTrait.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
trait PhpArrayTrait
2525
{
2626
use ProxyTrait;
27+
use SerializingTrait {
28+
serializeValues as private;
29+
unserializeValue as private;
30+
}
2731

2832
private $file;
2933
private $keys;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.