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);
}
}
/** {@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);
}
*/
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;
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'));
+ }
}
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;
+}