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 9a94e6c

Browse filesBrowse files
author
Aleksey Prilipko
committed
cache-serializer
1 parent 5c338cc commit 9a94e6c
Copy full SHA for 9a94e6c

17 files changed

+437
-84
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
+12-17Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use Psr\Log\LoggerAwareInterface;
1616
use Symfony\Component\Cache\CacheInterface;
1717
use Symfony\Component\Cache\CacheItem;
18+
use Symfony\Component\Cache\Serializer\IdentitySerializer;
19+
use Symfony\Component\Cache\Serializer\PhpSerializer;
1820
use Symfony\Component\Cache\ResettableInterface;
1921
use Symfony\Component\Cache\Traits\ArrayTrait;
2022
use Symfony\Component\Cache\Traits\GetTrait;
@@ -35,7 +37,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
3537
*/
3638
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
3739
{
38-
$this->storeSerialized = $storeSerialized;
40+
$this->setSerializer($storeSerialized ? new PhpSerializer() : new IdentitySerializer());
3941
$this->createCacheItem = \Closure::bind(
4042
function ($key, $value, $isHit) use ($defaultLifetime) {
4143
$item = new CacheItem();
@@ -60,13 +62,8 @@ public function getItem($key)
6062
try {
6163
if (!$isHit) {
6264
$this->values[$key] = $value = null;
63-
} elseif (!$this->storeSerialized) {
64-
$value = $this->values[$key];
65-
} elseif ('b:0;' === $value = $this->values[$key]) {
66-
$value = false;
67-
} elseif (false === $value = unserialize($value)) {
68-
$this->values[$key] = $value = null;
69-
$isHit = false;
65+
} else {
66+
$value = $this->unserialize($this->values[$key]);
7067
}
7168
} catch (\Exception $e) {
7269
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
@@ -120,15 +117,13 @@ public function save(CacheItemInterface $item)
120117

121118
return true;
122119
}
123-
if ($this->storeSerialized) {
124-
try {
125-
$value = serialize($value);
126-
} catch (\Exception $e) {
127-
$type = is_object($value) ? get_class($value) : gettype($value);
128-
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
129-
130-
return false;
131-
}
120+
try {
121+
$value = $this->serialize($value);
122+
} catch (\Exception $e) {
123+
$type = is_object($value) ? get_class($value) : gettype($value);
124+
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
125+
126+
return false;
132127
}
133128
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
134129
$expiry = microtime(true) + $item["\0*\0defaultLifetime"];
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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\Serializer;
13+
14+
use Symfony\Component\Cache\SerializerInterface;
15+
16+
class IdentitySerializer implements SerializerInterface
17+
{
18+
public function serialize($data)
19+
{
20+
return $data;
21+
}
22+
23+
public function unserialize($serialized)
24+
{
25+
return $serialized;
26+
}
27+
}
+43Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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\Serializer;
13+
14+
use Symfony\Component\Cache\Exception\CacheException;
15+
use Symfony\Component\Cache\SerializerInterface;
16+
17+
class IgbinarySerializer implements SerializerInterface
18+
{
19+
public function serialize($data)
20+
{
21+
return igbinary_serialize($data);
22+
}
23+
24+
public function unserialize($serialized)
25+
{
26+
$unserializeCallbackHandler = ini_set(
27+
'unserialize_callback_func',
28+
PhpSerializer::class.'::handleUnserializeCallback'
29+
);
30+
try {
31+
$value = igbinary_unserialize($serialized);
32+
if (false === $value && igbinary_serialize(false) !== $serialized) {
33+
throw new CacheException('failed to unserialize value');
34+
}
35+
36+
return $value;
37+
} catch (\Error $e) {
38+
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
39+
} finally {
40+
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
41+
}
42+
}
43+
}
+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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\Serializer;
13+
14+
use Symfony\Component\Cache\Exception\CacheException;
15+
use Symfony\Component\Cache\SerializerInterface;
16+
17+
class PhpSerializer implements SerializerInterface
18+
{
19+
public function serialize($data)
20+
{
21+
return serialize($data);
22+
}
23+
24+
public function unserialize($serialized)
25+
{
26+
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
27+
try {
28+
if ('b:0;' === $serialized) {
29+
return false;
30+
} elseif (false === $value = unserialize($serialized)) {
31+
throw new CacheException('failed to unserialize value');
32+
}
33+
34+
return $value;
35+
} catch (\Error $e) {
36+
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
37+
} finally {
38+
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
39+
}
40+
}
41+
42+
/**
43+
* @internal
44+
*/
45+
public static function handleUnserializeCallback($class)
46+
{
47+
throw new \DomainException('Class not found: '.$class);
48+
}
49+
}
+40Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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;
13+
14+
use Symfony\Component\Cache\Exception\InvalidArgumentException;
15+
16+
/**
17+
* @author Alexei Prilipko <palex.fpt@gmail.com>
18+
*/
19+
interface SerializerInterface
20+
{
21+
/**
22+
* Generates a storable representation of a value.
23+
*
24+
* @param $data mixed
25+
*
26+
* @return string|mixed serialized value
27+
*
28+
* @throws InvalidArgumentException when $data can not be serialized
29+
*/
30+
public function serialize($data);
31+
32+
/**
33+
* Creates a PHP value from a stored representation.
34+
*
35+
* @param string|mixed $serialized the serialized string
36+
*
37+
* @return mixed Original value
38+
*/
39+
public function unserialize($serialized);
40+
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Simple/ArrayCache.php
+11-11Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use Psr\SimpleCache\CacheInterface;
1616
use Symfony\Component\Cache\CacheItem;
1717
use Symfony\Component\Cache\Exception\InvalidArgumentException;
18+
use Symfony\Component\Cache\Serializer\IdentitySerializer;
19+
use Symfony\Component\Cache\Serializer\PhpSerializer;
1820
use Symfony\Component\Cache\ResettableInterface;
1921
use Symfony\Component\Cache\Traits\ArrayTrait;
2022

@@ -37,7 +39,7 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
3739
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
3840
{
3941
$this->defaultLifetime = $defaultLifetime;
40-
$this->storeSerialized = $storeSerialized;
42+
$this->setSerializer($storeSerialized ? new PhpSerializer() : new IdentitySerializer());
4143
}
4244

4345
/**
@@ -109,16 +111,14 @@ public function setMultiple($values, $ttl = null)
109111
if (false === $ttl = $this->normalizeTtl($ttl)) {
110112
return $this->deleteMultiple(array_keys($valuesArray));
111113
}
112-
if ($this->storeSerialized) {
113-
foreach ($valuesArray as $key => $value) {
114-
try {
115-
$valuesArray[$key] = serialize($value);
116-
} catch (\Exception $e) {
117-
$type = is_object($value) ? get_class($value) : gettype($value);
118-
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
119-
120-
return false;
121-
}
114+
foreach ($valuesArray as $key => $value) {
115+
try {
116+
$valuesArray[$key] = $this->serialize($value);
117+
} catch (\Exception $e) {
118+
$type = is_object($value) ? get_class($value) : gettype($value);
119+
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
120+
121+
return false;
122122
}
123123
}
124124
$expiry = 0 < $ttl ? microtime(true) + $ttl : PHP_INT_MAX;
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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\Serializer;
13+
14+
use Symfony\Component\Cache\Serializer\IgbinarySerializer;
15+
use Symfony\Component\Cache\SerializerInterface;
16+
17+
class IgbinarySerializerTest extends SerializerTest
18+
{
19+
public static function setUpBeforeClass()
20+
{
21+
parent::setUpBeforeClass();
22+
if (!extension_loaded('igbinary')) {
23+
self::markTestSkipped('Extension igbinary is not loaded.');
24+
}
25+
}
26+
27+
protected function createSerializer(): SerializerInterface
28+
{
29+
return new IgbinarySerializer();
30+
}
31+
}
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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\Serializer;
13+
14+
use Symfony\Component\Cache\Serializer\PhpSerializer;
15+
use Symfony\Component\Cache\SerializerInterface;
16+
17+
class PhpSerializerTest extends SerializerTest
18+
{
19+
protected function createSerializer(): SerializerInterface
20+
{
21+
return new PhpSerializer();
22+
}
23+
}
+72Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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\Serializer;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Cache\SerializerInterface;
16+
17+
abstract class SerializerTest extends TestCase
18+
{
19+
/** @var SerializerInterface */
20+
private $serializer;
21+
22+
protected function setUp()
23+
{
24+
parent::setUp();
25+
26+
$this->serializer = $this->createSerializer();
27+
}
28+
29+
abstract protected function createSerializer(): SerializerInterface;
30+
31+
/**
32+
* @dataProvider validData
33+
*/
34+
public function testSerializeInvariants($value)
35+
{
36+
$serialized = $this->serializer->serialize($value);
37+
$restored = $this->serializer->unserialize($serialized);
38+
$this->assertEquals($value, $restored);
39+
}
40+
41+
/**
42+
* Data provider for valid data to store.
43+
*
44+
* @return array
45+
*/
46+
public static function validData()
47+
{
48+
return array(
49+
array(false),
50+
array('AbC19_.'),
51+
array(4711),
52+
array(47.11),
53+
array(true),
54+
array(null),
55+
array(array('key' => 'value')),
56+
array(new \stdClass()),
57+
);
58+
}
59+
}
60+
61+
class NotUnserializable implements \Serializable
62+
{
63+
public function serialize()
64+
{
65+
return serialize(123);
66+
}
67+
68+
public function unserialize($ser)
69+
{
70+
throw new \Exception(__CLASS__);
71+
}
72+
}

0 commit comments

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