Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/Adapter/Apc/ApcCachePool.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ protected function fetchObjectFromCache($key)
return [false, null, [], null];
}

$success = false;
$cacheData = apc_fetch($key, $success);
$success = false;

try {
$cacheData = apc_fetch($key, $success);
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
}

if (!$success) {
return [false, null, [], null];
}
list($data, $tags, $timestamp) = unserialize($cacheData);
list($data, $tags, $timestamp) = parent::unserialize($cacheData);

return [$success, $data, $tags, $timestamp];
}
Expand Down
3 changes: 3 additions & 0 deletions src/Adapter/Apc/Tests/IntegrationPoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@
namespace Cache\Adapter\Apc\Tests;

use Cache\Adapter\Apc\ApcCachePool;
use Cache\Adapter\Common\Tests\Traits\TestNotUnserializableTrait;
use Cache\IntegrationTests\CachePoolTest as BaseTest;

class IntegrationPoolTest extends BaseTest
{
use TestNotUnserializableTrait;

protected $skippedTests = [
'testExpiration' => 'The cache expire at the next request.',
'testSaveExpired' => 'The cache expire at the next request.',
Expand Down
12 changes: 9 additions & 3 deletions src/Adapter/Apcu/ApcuCachePool.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ protected function fetchObjectFromCache($key)
return [false, null, [], null];
}

$success = false;
$cacheData = apcu_fetch($key, $success);
$success = false;

try {
$cacheData = apcu_fetch($key, $success);
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
}

if (!$success) {
return [false, null, [], null];
}
list($data, $tags, $timestamp) = unserialize($cacheData);
list($data, $tags, $timestamp) = parent::unserialize($cacheData);

return [$success, $data, $tags, $timestamp];
}
Expand Down
3 changes: 3 additions & 0 deletions src/Adapter/Apcu/Tests/IntegrationPoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@
namespace Cache\Adapter\Apcu\Tests;

use Cache\Adapter\Apcu\ApcuCachePool;
use Cache\Adapter\Common\Tests\Traits\TestNotUnserializableTrait;
use Cache\IntegrationTests\CachePoolTest as BaseTest;

class IntegrationPoolTest extends BaseTest
{
use TestNotUnserializableTrait;

protected $skippedTests = [
'testExpiration' => 'The cache expire at the next request.',
'testSaveExpired' => 'The cache expire at the next request.',
Expand Down
43 changes: 43 additions & 0 deletions src/Adapter/Common/AbstractCachePool.php
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ private function handleException(\Exception $e, $function)
}

$this->log($level, $e->getMessage(), ['exception' => $e]);

if (!$e instanceof CacheException) {
$e = new CachePoolException(sprintf('Exception thrown when executing "%s". ', $function), 0, $e);
}
Expand Down Expand Up @@ -555,4 +556,46 @@ public function has($key)
{
return $this->hasItem($key);
}

/**
* Like the native unserialize() function but throws an exception if anything goes wrong.
*
* @param string $value
*
* @throws \Exception
*
* @return mixed
*/
protected static function unserialize($value)
{
if ('b:0;' === $value) {
return false;
}

$unserializeCallbackHandler = \ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');

try {
if (false !== $value = \unserialize($value)) {
return $value;
}

throw new \DomainException('Failed to unserialize cached value');
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
} finally {
\ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}

/**
* @internal
*
* @param string $class
*
* @throws \DomainException
*/
public static function handleUnserializeCallback($class)
{
throw new \DomainException('Class not found: '.$class);
}
}
11 changes: 9 additions & 2 deletions src/Adapter/Common/CacheItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class CacheItem implements PhpCacheItem
/**
* @param string $key
* @param \Closure|bool $callable or boolean hasValue
* @param mixed $value
*/
public function __construct($key, $callable = null, $value = null)
{
Expand Down Expand Up @@ -241,8 +242,14 @@ private function initialize()
{
if ($this->callable !== null) {
// $func will be $adapter->fetchObjectFromCache();
$func = $this->callable;
$result = $func();
$func = $this->callable;

try {
$result = $func();
} catch (\DomainException $exception) {
return;
}

$this->hasValue = $result[0];
$this->value = $result[1];
$this->prevTags = isset($result[2]) ? $result[2] : [];
Expand Down
25 changes: 25 additions & 0 deletions src/Adapter/Common/Tests/Fixture/NotUnserializable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/*
* This file is part of php-cache organization.
*
* (c) 2015 Aaron Scherer <[email protected]>, Tobias Nyholm <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Cache\Adapter\Common\Tests\Fixture;

class NotUnserializable implements \Serializable
{
public function serialize()
{
return serialize(123);
}

public function unserialize($ser)
{
throw new \Exception(__CLASS__);
}
}
50 changes: 50 additions & 0 deletions src/Adapter/Common/Tests/Traits/TestNotUnserializableTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* This file is part of php-cache organization.
*
* (c) 2015 Aaron Scherer <[email protected]>, Tobias Nyholm <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Cache\Adapter\Common\Tests\Traits;

use Cache\Adapter\Common\Tests\Fixture\NotUnserializable;
use Psr\Cache\CacheItemPoolInterface;

trait TestNotUnserializableTrait
{
public function testNotUnserializable()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);

return;
}

$cache = $this->createCachePool();

$item = $cache->getItem('foo');
$cache->save($item->set(new NotUnserializable()));

$item = $cache->getItem('foo');
$this->assertFalse($item->isHit());

foreach ($cache->getItems(['foo']) as $item) {
}

$cache->save($item->set(new NotUnserializable()));

foreach ($cache->getItems(['foo']) as $item) {
}

$this->assertFalse($item->isHit());
}

/**
* @return CacheItemPoolInterface that is used in the tests
*/
abstract public function createCachePool();
}
24 changes: 20 additions & 4 deletions src/Adapter/Doctrine/DoctrineCachePool.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,27 @@ public function __construct(Cache $cache)
*/
protected function fetchObjectFromCache($key)
{
if (false === $data = $this->cache->fetch($key)) {
return [false, null, [], null];
}
$unserializeCallbackHandler = ini_set('unserialize_callback_func', parent::class.'::handleUnserializeCallback');

try {
if (false === $data = $this->cache->fetch($key)) {
return [false, null, [], null];
}

return parent::unserialize($data);
} catch (\Error $e) {
$trace = $e->getTrace();

return unserialize($data);
if (isset($trace[0]['function']) && !isset($trace[0]['class'])) {
if ($trace[0]['function'] === 'unserialize' || $trace[0]['function'] === 'apcu_fetch' || $trace[0]['function'] === 'apc_fetch') {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
}
}

throw $e;
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/Adapter/Doctrine/Tests/IntegrationPoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@

namespace Cache\Adapter\Doctrine\Tests;

use Cache\Adapter\Common\Tests\Traits\TestNotUnserializableTrait;
use Cache\IntegrationTests\CachePoolTest;

class IntegrationPoolTest extends CachePoolTest
{
use CreatePoolTrait;
use TestNotUnserializableTrait;
}
4 changes: 2 additions & 2 deletions src/Adapter/Filesystem/FilesystemCachePool.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ protected function fetchObjectFromCache($key)
$file = $this->getFilePath($key);

try {
$data = @unserialize($this->filesystem->read($file));
$data = parent::unserialize($this->filesystem->read($file));
if ($data === false) {
return $empty;
}
Expand Down Expand Up @@ -159,7 +159,7 @@ protected function getList($name)
$this->filesystem->write($file, serialize([]));
}

return unserialize($this->filesystem->read($file));
return parent::unserialize($this->filesystem->read($file));
}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/Adapter/Filesystem/Tests/FilesystemCachePoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Cache\Adapter\Filesystem\Tests;

use Cache\Adapter\Common\Tests\Traits\TestNotUnserializableTrait;

use PHPUnit\Framework\TestCase;

/**
Expand All @@ -19,6 +21,7 @@
class FilesystemCachePoolTest extends TestCase
{
use CreatePoolTrait;
use TestNotUnserializableTrait;

/**
* @expectedException \Psr\Cache\InvalidArgumentException
Expand Down
27 changes: 23 additions & 4 deletions src/Adapter/Illuminate/IlluminateCachePool.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,27 @@ protected function storeItemInCache(PhpCacheItem $item, $ttl)
*/
protected function fetchObjectFromCache($key)
{
if (null === $data = $this->store->get($this->getHierarchyKey($key))) {
return [false, null, [], null];
}
$unserializeCallbackHandler = ini_set('unserialize_callback_func', parent::class.'::handleUnserializeCallback');

try {
if (null === $data = $this->store->get($this->getHierarchyKey($key))) {
return [false, null, [], null];
}

return parent::unserialize($data);
} catch (\Error $e) {
$trace = $e->getTrace();

if (isset($trace[0]['function']) && !isset($trace[0]['class'])) {
if ($trace[0]['function'] === 'apcu_fetch' || $trace[0]['function'] === 'apc_fetch') {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
}
}

return unserialize($data);
throw $e;
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}

/**
Expand All @@ -80,12 +96,15 @@ protected function clearOneObjectFromCache($key)
{
$path = null;
$keyString = $this->getHierarchyKey($key, $path);

if ($path) {
if ($this->store->get($path) === null) {
$this->store->put($path, 0, 0);
}

$this->store->increment($path);
}

$this->clearHierarchyKeyCache();

return $this->store->forget($keyString);
Expand Down
2 changes: 2 additions & 0 deletions src/Adapter/Illuminate/Tests/IntegrationPoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@

namespace Cache\Adapter\Illuminate\Tests;

use Cache\Adapter\Common\Tests\Traits\TestNotUnserializableTrait;
use Cache\IntegrationTests\CachePoolTest;

class IntegrationPoolTest extends CachePoolTest
{
use CreatePoolTrait;
use TestNotUnserializableTrait;
}
2 changes: 1 addition & 1 deletion src/Adapter/Memcache/MemcacheCachePool.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function __construct(Memcache $cache)
*/
protected function fetchObjectFromCache($key)
{
if (false === $result = unserialize($this->cache->get($key))) {
if (false === $result = parent::unserialize($this->cache->get($key))) {
return [false, null, [], null];
}

Expand Down
3 changes: 3 additions & 0 deletions src/Adapter/Memcache/Tests/IntegrationPoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@

namespace Cache\Adapter\Memcache\Tests;

use Cache\Adapter\Common\Tests\Traits\TestNotUnserializableTrait;
use Cache\Adapter\Memcache\MemcacheCachePool;
use Cache\IntegrationTests\CachePoolTest;
use Memcache;

class IntegrationPoolTest extends CachePoolTest
{
use TestNotUnserializableTrait;

private $client;

public function createCachePool()
Expand Down
Loading