From d772331b9173550f98a5ba8c55f576170fc1120b Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 19 Feb 2023 12:57:39 +0100 Subject: [PATCH 1/3] Fix multiple serialized values --- src/Core/Config/Model/DatabaseConfig.php | 10 ++++---- src/Core/Config/Util/SerializeUtil.php | 18 +++++++++++++-- tests/src/Core/Config/ConfigTest.php | 29 ++++++++++++++++++++++++ update.php | 20 ++++++++++++++++ 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/Core/Config/Model/DatabaseConfig.php b/src/Core/Config/Model/DatabaseConfig.php index 01366cf71a..7167ccbf8e 100644 --- a/src/Core/Config/Model/DatabaseConfig.php +++ b/src/Core/Config/Model/DatabaseConfig.php @@ -61,15 +61,13 @@ class DatabaseConfig implements IManageConfigValues foreach ($setCache->getAll() as $category => $data) { foreach ($data as $key => $value) { - $this->cache->set($category, $key, $value, Cache::SOURCE_DATA); - $this->database->insert('config', ['cat' => $category, 'k' => $key, 'v' => serialize($value)], Database::INSERT_UPDATE); + $this->set($category, $key, $value); } } foreach ($delCache->getAll() as $category => $keys) { foreach ($keys as $key => $value) { - $this->cache->delete($category, $key); - $this->database->delete('config', ['cat' => $category, 'k' => $key]); + $this->delete($category, $key); } } @@ -85,6 +83,10 @@ class DatabaseConfig implements IManageConfigValues /** {@inheritDoc} */ public function set(string $cat, string $key, $value): bool { + // In case someone or something already serialized a config entry, unserialize it first + // We serialize values just once + $value = SerializeUtil::maybeUnserialize($value); + $this->cache->set($cat, $key, $value, Cache::SOURCE_DATA); return $this->database->insert('config', ['cat' => $cat, 'k' => $key, 'v' => serialize($value)], Database::INSERT_UPDATE); } diff --git a/src/Core/Config/Util/SerializeUtil.php b/src/Core/Config/Util/SerializeUtil.php index 0a886e2305..1d944f264b 100644 --- a/src/Core/Config/Util/SerializeUtil.php +++ b/src/Core/Config/Util/SerializeUtil.php @@ -28,10 +28,24 @@ namespace Friendica\Core\Config\Util; */ class SerializeUtil { + /** + * Checks if the value needs to get unserialized and returns the unserialized value + * + * @param mixed $value A possible serialized value + * + * @return mixed The unserialized value + */ public static function maybeUnserialize($value) { - if (static::isSerialized($value)) { - return @unserialize(trim($value)); + // This checks for possible multiple serialized values + while (SerializeUtil::isSerialized($value)) { + $oldValue = $value; + $value = @unserialize($value); + + // If there's no change after the unserialize call, break the loop (avoid endless loops) + if ($oldValue === $value) { + break; + } } return $value; diff --git a/tests/src/Core/Config/ConfigTest.php b/tests/src/Core/Config/ConfigTest.php index 643c737548..cf13ea05ae 100644 --- a/tests/src/Core/Config/ConfigTest.php +++ b/tests/src/Core/Config/ConfigTest.php @@ -537,4 +537,33 @@ class ConfigTest extends DatabaseTest self::assertEquals($assertion, $config->get($category)); } + + public function dataSerialized(): array + { + return [ + 'default' => [ + 'value' => ['test' => ['array']], + 'assertion' => ['test' => ['array']], + ], + 'issue-12803' => [ + 'value' => 's:48:"s:40:"s:32:"https://punkrock-underground.com";";";', + 'assertion' => 'https://punkrock-underground.com', + ], + 'double-serialized-array' => [ + 'value' => 's:53:"a:1:{s:9:"testArray";a:1:{s:4:"with";s:7:"entries";}}";', + 'assertion' => ['testArray' => ['with' => 'entries']], + ], + ]; + } + + /** + * @dataProvider dataSerialized + */ + public function testSerializedValues($value, $assertion) + { + $config = $this->getInstance(); + + $config->set('test', 'it', $value); + self:self::assertEquals($assertion, $config->get('test', 'it')); + } } diff --git a/update.php b/update.php index 15ef8b1dc0..672c11a4f4 100644 --- a/update.php +++ b/update.php @@ -1295,3 +1295,23 @@ function update_1515() DBA::update('verb', ['name' => Activity::VIEW], ['name' => 'https://joinpeertube.org/view']); return Update::SUCCESS; } + +function update_1516() +{ + // Fixes https://github.com/friendica/friendica/issues/12803 + // de-serialize multiple serialized values + $configTrans = DI::config()->beginTransaction(); + $configArray = DI::config()->getCache()->getDataBySource(Cache::SOURCE_DATA); + + foreach ($configArray as $category => $keyValues) { + if (is_array($keyValues)) { + foreach ($keyValues as $key => $value) { + $configTrans->set($category, $key, $value); + } + } + } + + $configTrans->commit(); + + return Update::SUCCESS; +} From 41251458a0050ccc6198a627c911de8f18d09a1d Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 19 Feb 2023 18:59:09 +0100 Subject: [PATCH 2/3] language and static --- src/Core/Config/Util/SerializeUtil.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core/Config/Util/SerializeUtil.php b/src/Core/Config/Util/SerializeUtil.php index 1d944f264b..821633ac49 100644 --- a/src/Core/Config/Util/SerializeUtil.php +++ b/src/Core/Config/Util/SerializeUtil.php @@ -31,14 +31,14 @@ class SerializeUtil /** * Checks if the value needs to get unserialized and returns the unserialized value * - * @param mixed $value A possible serialized value + * @param mixed $value A possibly serialized value * * @return mixed The unserialized value */ public static function maybeUnserialize($value) { // This checks for possible multiple serialized values - while (SerializeUtil::isSerialized($value)) { + while (static::isSerialized($value)) { $oldValue = $value; $value = @unserialize($value); From c233c666fb93f3101f83fcfcc909b1f7413014ff Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 20 Feb 2023 17:23:22 +0100 Subject: [PATCH 3/3] Update db-version --- database.sql | 2 +- static/dbstructure.config.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database.sql b/database.sql index 053f0c7279..fa11843e43 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2023.03-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1515 +-- DB_UPDATE_VERSION 1516 -- ------------------------------------------ diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 83c890915d..9179921d05 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1515); + define('DB_UPDATE_VERSION', 1516); } return [