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 d7d91b3

Browse filesBrowse files
[Cache] automatically use igbinary when available, with graceful error handling
1 parent c0ca2af commit d7d91b3
Copy full SHA for d7d91b3

11 files changed

+231
-40
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/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ 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
+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
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,13 @@ public function reset()
210210
* @return mixed
211211
*
212212
* @throws \Exception
213+
*
214+
* @deprecated since Symfony 4.2, use SerializingTrait instead.
213215
*/
214216
protected static function unserialize($value)
215217
{
218+
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.2, use SerializingTrait instead.', __METHOD__), E_USER_DEPRECATED);
219+
216220
if ('b:0;' === $value) {
217221
return false;
218222
}

‎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/PhpFilesTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Traits/PhpFilesTrait.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ protected function doFetch(array $ids)
9191
} elseif ($value instanceof \Closure) {
9292
$values[$id] = $value();
9393
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
94-
$values[$id] = parent::unserialize($value);
94+
$values[$id] = unserialize($value);
9595
} else {
9696
$values[$id] = $value;
9797
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Traits/RedisTrait.php
+6-15Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
*/
2828
trait RedisTrait
2929
{
30+
use SerializingTrait;
31+
3032
private static $defaultConnectionOptions = array(
3133
'class' => null,
3234
'persistent' => 0,
@@ -177,7 +179,7 @@ protected function doFetch(array $ids)
177179
});
178180
foreach ($values as $id => $v) {
179181
if ($v) {
180-
yield $id => parent::unserialize($v);
182+
yield $id => $this->unserializeValue($v);
181183
}
182184
}
183185
}
@@ -273,23 +275,12 @@ protected function doDelete(array $ids)
273275
*/
274276
protected function doSave(array $values, $lifetime)
275277
{
276-
$serialized = array();
277-
$failed = array();
278-
279-
foreach ($values as $id => $value) {
280-
try {
281-
$serialized[$id] = serialize($value);
282-
} catch (\Exception $e) {
283-
$failed[] = $id;
284-
}
285-
}
286-
287-
if (!$serialized) {
278+
if (!$values = $this->serializeValues($values, $failed)) {
288279
return $failed;
289280
}
290281

291-
$results = $this->pipeline(function () use ($serialized, $lifetime) {
292-
foreach ($serialized as $id => $value) {
282+
$results = $this->pipeline(function () use ($values, $lifetime) {
283+
foreach ($values as $id => $value) {
293284
if (0 >= $lifetime) {
294285
yield 'set' => array($id, $value);
295286
} else {

0 commit comments

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