From 3c643fe7d27361d406e04c9eaf39a7255523392d Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 21 Jun 2018 20:05:04 -0700 Subject: [PATCH] CRM_Core_BAO_Cache - Load/store binary data in cache (via base64) --- CRM/Core/BAO/Cache.php | 35 +++++++++++++++++++++--- tests/phpunit/CRM/Core/BAO/CacheTest.php | 12 ++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/CRM/Core/BAO/Cache.php b/CRM/Core/BAO/Cache.php index 0e619143e3..be605afc59 100644 --- a/CRM/Core/BAO/Cache.php +++ b/CRM/Core/BAO/Cache.php @@ -71,7 +71,7 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache { $table = self::getTableName(); $where = self::whereCache($group, $path, $componentID); $rawData = CRM_Core_DAO::singleValueQuery("SELECT data FROM $table WHERE $where"); - $data = $rawData ? unserialize($rawData) : NULL; + $data = $rawData ? self::decode($rawData) : NULL; self::$_cache[$argString] = $data; $cache->set($argString, self::$_cache[$argString]); @@ -107,7 +107,7 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache { $result = array(); while ($dao->fetch()) { - $result[$dao->path] = unserialize($dao->data); + $result[$dao->path] = self::decode($dao->data); } $dao->free(); @@ -148,7 +148,7 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache { $where = self::whereCache($group, $path, $componentID); $dataExists = CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM $table WHERE {$where}"); $now = date('Y-m-d H:i:s'); // FIXME - Use SQL NOW() or CRM_Utils_Time? - $dataSerialized = serialize($data); + $dataSerialized = self::encode($data); // This table has a wonky index, so we cannot use REPLACE or // "INSERT ... ON DUPE". Instead, use SELECT+(INSERT|UPDATE). @@ -180,7 +180,7 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache { $argString = "CRM_CT_{$group}_{$path}_{$componentID}"; $cache = CRM_Utils_Cache::singleton(); - $data = unserialize($dataSerialized); + $data = self::decode($dataSerialized); self::$_cache[$argString] = $data; $cache->set($argString, $data); @@ -365,6 +365,33 @@ AND created_date < date_sub( NOW( ), INTERVAL $timeIntervalDays DAY ) } } + /** + * (Quasi-private) Encode an object/array/string/int as a string. + * + * @param $mixed + * @return string + */ + public static function encode($mixed) { + return base64_encode(serialize($mixed)); + } + + /** + * (Quasi-private) Decode an object/array/string/int from a string. + * + * @param $string + * @return mixed + */ + public static function decode($string) { + // Upgrade support -- old records (serialize) always have this punctuation, + // and new records (base64) never do. + if (strpos($string, ':') !== FALSE || strpos($string, ';') !== FALSE) { + return unserialize($string); + } + else { + return unserialize(base64_decode($string)); + } + } + /** * Compose a SQL WHERE clause for the cache. * diff --git a/tests/phpunit/CRM/Core/BAO/CacheTest.php b/tests/phpunit/CRM/Core/BAO/CacheTest.php index d29193e02a..ac181236cb 100644 --- a/tests/phpunit/CRM/Core/BAO/CacheTest.php +++ b/tests/phpunit/CRM/Core/BAO/CacheTest.php @@ -31,6 +31,18 @@ */ class CRM_Core_BAO_CacheTest extends CiviUnitTestCase { + public function testMultiVersionDecode() { + $encoders = ['serialize', ['CRM_Core_BAO_Cache', 'encode']]; + $values = [NULL, 0, 1, TRUE, FALSE, [], ['abcd'], 'ab;cd', new stdClass()]; + foreach ($encoders as $encoder) { + foreach ($values as $value) { + $encoded = $encoder($value); + $decoded = CRM_Core_BAO_Cache::decode($encoded); + $this->assertEquals($value, $decoded, "Failure encoding/decoding value " . var_export($value, 1) . ' with ' . var_export($encoder, 1)); + } + } + } + public function exampleValues() { $binary = ''; for ($i = 0; $i < 256; $i++) { -- 2.25.1