diff --git a/blocks/html/backup/moodle1/lib.php b/blocks/html/backup/moodle1/lib.php
index 3830ba99e99..da215c22298 100644
--- a/blocks/html/backup/moodle1/lib.php
+++ b/blocks/html/backup/moodle1/lib.php
@@ -30,9 +30,13 @@ defined('MOODLE_INTERNAL') || die();
class moodle1_block_html_handler extends moodle1_block_handler {
private $fileman = null;
protected function convert_configdata(array $olddata) {
+ global $CFG;
+ require_once($CFG->libdir . '/db/upgradelib.php');
$instanceid = $olddata['id'];
$contextid = $this->converter->get_contextid(CONTEXT_BLOCK, $olddata['id']);
- $configdata = unserialize(base64_decode($olddata['configdata']));
+ $decodeddata = base64_decode($olddata['configdata']);
+ list($updated, $configdata) = upgrade_fix_serialized_objects($decodeddata);
+ $configdata = unserialize($configdata);
// get a fresh new file manager for this instance
$this->fileman = $this->converter->get_file_manager($contextid, 'block_html');
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 91eb81fc9c2..e170ca53ab9 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -2826,5 +2826,14 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2017111300.02);
}
+ if ($oldversion < 2017111301.08) {
+
+ // Fix old block configurations that use the deprecated (and now removed) object class.
+ upgrade_fix_block_instance_configuration();
+
+ // Main savepoint reached.
+ upgrade_main_savepoint(true, 2017111301.08);
+ }
+
return true;
}
diff --git a/lib/db/upgradelib.php b/lib/db/upgradelib.php
index 134d4c0b3b7..e0913a5ed12 100644
--- a/lib/db/upgradelib.php
+++ b/lib/db/upgradelib.php
@@ -502,3 +502,40 @@ function upgrade_block_positions() {
WHERE pagetype IN ('my-index', 'user-profile') AND subpage NOT IN (SELECT $id FROM {my_pages})";
$DB->execute($sql, ['']);
}
+
+/**
+ * Fix configdata in block instances that are using the old object class that has been removed (deprecated).
+ */
+function upgrade_fix_block_instance_configuration() {
+ global $DB;
+
+ $sql = "SELECT *
+ FROM {block_instances}
+ WHERE configdata <> ''";
+ $blockinstances = $DB->get_recordset_sql($sql);
+ foreach ($blockinstances as $blockinstance) {
+ $configdata = base64_decode($blockinstance->configdata);
+ list($updated, $configdata) = upgrade_fix_serialized_objects($configdata);
+ if ($updated) {
+ $blockinstance->configdata = base64_encode($configdata);
+ $DB->update_record('block_instances', $blockinstance);
+ }
+ }
+ $blockinstances->close();
+}
+
+/**
+ * Provides a way to check and update a serialized string that uses the deprecated object class.
+ *
+ * @param string $serializeddata Serialized string which may contain the now deprecated object.
+ * @return array Returns an array where the first variable is a bool with a status of whether the initial data was changed
+ * or not. The second variable is the said data.
+ */
+function upgrade_fix_serialized_objects($serializeddata) {
+ $updated = false;
+ if (strpos($serializeddata, ":6:\"object") !== false) {
+ $serializeddata = str_replace(":6:\"object", ":8:\"stdClass", $serializeddata);
+ $updated = true;
+ }
+ return [$updated, $serializeddata];
+}
diff --git a/lib/tests/upgradelib_test.php b/lib/tests/upgradelib_test.php
index 8df2704dfcd..7bbe0aa42dd 100644
--- a/lib/tests/upgradelib_test.php
+++ b/lib/tests/upgradelib_test.php
@@ -820,4 +820,103 @@ class core_upgradelib_testcase extends advanced_testcase {
$this->assertFalse(upgrade_theme_is_from_family('testtheme', 'loop'), 'Infinite loop without testtheme parent is false');
$this->assertTrue(upgrade_theme_is_from_family('testtheme', 'themewithbrokenparent'), 'No error on broken parent');
}
+
+ /**
+ * Data provider of serialized string.
+ *
+ * @return array
+ */
+ public function serialized_strings_dataprovider() {
+ return [
+ 'A configuration that uses the old object' => [
+ 'O:6:"object":3:{s:4:"text";s:32:"Nothing that anyone cares about.";s:5:"title";s:16:"Really old block";s:6:"format";s:1:"1";}',
+ true,
+ 'O:8:"stdClass":3:{s:4:"text";s:32:"Nothing that anyone cares about.";s:5:"title";s:16:"Really old block";s:6:"format";s:1:"1";}'
+ ],
+ 'A configuration that uses stdClass' => [
+ 'O:8:"stdClass":5:{s:5:"title";s:4:"Tags";s:12:"numberoftags";s:2:"80";s:12:"showstandard";s:1:"0";s:3:"ctx";s:3:"289";s:3:"rec";s:1:"1";}',
+ false,
+ 'O:8:"stdClass":5:{s:5:"title";s:4:"Tags";s:12:"numberoftags";s:2:"80";s:12:"showstandard";s:1:"0";s:3:"ctx";s:3:"289";s:3:"rec";s:1:"1";}'
+ ],
+ 'A setting I saw when importing a course with blocks from 1.9' => [
+ 'N;',
+ false,
+ 'N;'
+ ],
+ 'An object in an object' => [
+ 'O:6:"object":2:{s:2:"id";i:5;s:5:"other";O:6:"object":1:{s:4:"text";s:13:"something new";}}',
+ true,
+ 'O:8:"stdClass":2:{s:2:"id";i:5;s:5:"other";O:8:"stdClass":1:{s:4:"text";s:13:"something new";}}'
+ ],
+ 'An array with an object in it' => [
+ 'a:3:{s:4:"name";s:4:"Test";s:10:"additional";O:6:"object":2:{s:2:"id";i:5;s:4:"info";s:18:"text in the object";}s:4:"type";i:1;}',
+ true,
+ 'a:3:{s:4:"name";s:4:"Test";s:10:"additional";O:8:"stdClass":2:{s:2:"id";i:5;s:4:"info";s:18:"text in the object";}s:4:"type";i:1;}'
+ ]
+ ];
+ }
+
+ /**
+ * Test that objects in serialized strings will be changed over to stdClass.
+ *
+ * @dataProvider serialized_strings_dataprovider
+ * @param string $initialstring The initial serialized setting.
+ * @param bool $expectededited If the string is expected to be edited.
+ * @param string $expectedresult The expected serialized setting to be returned.
+ */
+ public function test_upgrade_fix_serialized_objects($initialstring, $expectededited, $expectedresult) {
+ list($edited, $resultstring) = upgrade_fix_serialized_objects($initialstring);
+ $this->assertEquals($expectededited, $edited);
+ $this->assertEquals($expectedresult, $resultstring);
+ }
+
+ /**
+ * Data provider for base64_encoded block instance config data.
+ */
+ public function encoded_strings_dataprovider() {
+ return [
+ 'Normal data using stdClass' => [
+ 'Tzo4OiJzdGRDbGFzcyI6NTp7czo1OiJ0aXRsZSI7czo0OiJUYWdzIjtzOjEyOiJudW1iZXJvZnRhZ3MiO3M6MjoiODAiO3M6MTI6InNob3dzdGFuZGFyZCI7czoxOiIwIjtzOjM6ImN0eCI7czozOiIyODkiO3M6MzoicmVjIjtzOjE6IjEiO30=',
+ 'Tzo4OiJzdGRDbGFzcyI6NTp7czo1OiJ0aXRsZSI7czo0OiJUYWdzIjtzOjEyOiJudW1iZXJvZnRhZ3MiO3M6MjoiODAiO3M6MTI6InNob3dzdGFuZGFyZCI7czoxOiIwIjtzOjM6ImN0eCI7czozOiIyODkiO3M6MzoicmVjIjtzOjE6IjEiO30='
+ ],
+ 'No data at all' => [
+ '',
+ ''
+ ],
+ 'Old data using object' => [
+ 'Tzo2OiJvYmplY3QiOjM6e3M6NDoidGV4dCI7czozMjoiTm90aGluZyB0aGF0IGFueW9uZSBjYXJlcyBhYm91dC4iO3M6NToidGl0bGUiO3M6MTY6IlJlYWxseSBvbGQgYmxvY2siO3M6NjoiZm9ybWF0IjtzOjE6IjEiO30=',
+ 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo0OiJ0ZXh0IjtzOjMyOiJOb3RoaW5nIHRoYXQgYW55b25lIGNhcmVzIGFib3V0LiI7czo1OiJ0aXRsZSI7czoxNjoiUmVhbGx5IG9sZCBibG9jayI7czo2OiJmb3JtYXQiO3M6MToiMSI7fQ=='
+ ]
+ ];
+ }
+
+ /**
+ * Check that entries in the block_instances table are coverted over correctly.
+ *
+ * @dataProvider encoded_strings_dataprovider
+ * @param string $original The original base64_encoded block config setting.
+ * @param string $expected The expected base64_encoded block config setting.
+ */
+ public function test_upgrade_fix_block_instance_configuration($original, $expected) {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ $data = new stdClass();
+ $data->blockname = 'html';
+ $data->parentcontextid = 1;
+ $data->showinsubcontexts = 0;
+ $data->requirebytheme = 0;
+ $data->pagetypepattern = 'admin-setting-frontpagesettings';
+ $data->defaultregion = 'side-post';
+ $data->defaultweight = 1;
+ $data->timecreated = time();
+ $data->timemodified = time();
+
+ $data->configdata = $original;
+ $entryid = $DB->insert_record('block_instances', $data);
+ upgrade_fix_block_instance_configuration();
+ $record = $DB->get_record('block_instances', ['id' => $entryid]);
+ $this->assertEquals($expected, $record->configdata);
+ }
}
diff --git a/version.php b/version.php
index 25509d7ccdb..d5362d0915c 100644
--- a/version.php
+++ b/version.php
@@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
-$version = 2017111301.07; // 20171113 = branching date YYYYMMDD - do not modify!
+$version = 2017111301.08; // 20171113 = branching date YYYYMMDD - do not modify!
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.