diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 7bddf76640..0da042b6f0 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.16 under development ------------------------ +- Bug #16028: Fix serialization of complex cache keys that contain non-UTF sequences (rugabarbo) - Bug #16945: Fixed RBAC DbManager ruleName fetching on the case of PDO::ATTR_ORACLE_NULLS => PDO::NULL_TO_STRING (razonyang) - Bug #16081: Fixed composite IN using just one column (rugabarbo) - Bug #16926: Fix shell autocompletion (GHopperMSK) diff --git a/framework/caching/Cache.php b/framework/caching/Cache.php index 64106e6fc3..6f03482a98 100644 --- a/framework/caching/Cache.php +++ b/framework/caching/Cache.php @@ -79,6 +79,19 @@ abstract class Cache extends Component implements CacheInterface */ public $defaultDuration = 0; + /** + * @var bool whether [igbinary serialization](http://pecl.php.net/package/igbinary) is available or not. + */ + private $_igbinaryAvailable = false; + + /** + * {@inheritdoc} + */ + public function init() + { + parent::init(); + $this->_igbinaryAvailable = \extension_loaded('igbinary'); + } /** * Builds a normalized cache key from a given key. @@ -95,7 +108,13 @@ abstract class Cache extends Component implements CacheInterface if (is_string($key)) { $key = ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key); } else { - $key = md5(json_encode($key)); + if ($this->_igbinaryAvailable) { + $serializedKey = igbinary_serialize($key); + } else { + $serializedKey = serialize($key); + } + + $key = md5($serializedKey); } return $this->keyPrefix . $key; diff --git a/tests/framework/caching/ArrayCacheTest.php b/tests/framework/caching/ArrayCacheTest.php index 9aa7a1d406..bcfdd98ec3 100644 --- a/tests/framework/caching/ArrayCacheTest.php +++ b/tests/framework/caching/ArrayCacheTest.php @@ -52,4 +52,24 @@ class ArrayCacheTest extends CacheTestCase static::$microtime++; $this->assertFalse($cache->get('expire_testa')); } + + /** + * @see https://github.com/yiisoft/yii2/issues/16028 + */ + public function testSerializationOfComplexKeysThatContainNonUTFSequences() + { + $cache = $this->getCacheInstance(); + + $firstCacheKey = $cache->buildKey([ + "First example of invalid UTF-8 sequence: \xF5", + "Valid UTF-8 string", + ]); + + $secondCacheKey = $cache->buildKey([ + "Second example of invalid UTF-8 sequence: \xF6", + "Valid UTF-8 string", + ]); + + $this->assertNotEquals($firstCacheKey, $secondCacheKey); + } }