OJS 2 to 3 upgrade: fileName article setting is trying to be unserialised but it's a string

I’m upgrading from OJS 2.4.8-5 to 3.2.1-4, with the intention of then upgrading to 3.3.

Under Installer::setFileName I’m getting unserialize errors. There are no significant errors before this point apart from some missing PDFs from the file system.

…
[code: Installer Installer::setStatsEmailSettings]
[code: Installer Installer::fixLibraryFiles]
[code: Installer Installer::installEmailTemplate]
[note: docs/release-notes/README-3.2.0]
[code: Installer Installer::setFileName]
PHP Notice:  unserialize(): Error at offset 0 of 29 bytes in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 357
…

This PHP notice repeats quite a few times.

I patched DAO.inc.php to tell me what the value is when unserialize fails.

--- a/classes/db/DAO.inc.php
+++ b/classes/db/DAO.inc.php
@@ -354,7 +354,13 @@ class DAO {
                break;
            case 'object':
            case 'array':
-               $value = unserialize($value);
+               $v2 = unserialize($value);
+               if (is_bool($v2) && !$v2) {
+                   trigger_error("Failed to convert from DB: ${value}");
+                   $value = null;
+               } else {
+                   $value = $v2;
+               }
                break;
            case 'date':
                if ($value !== null) $value = strtotime($value);

The upgrade log them became (after removing duplicate pairs of lines).

…
[code: Installer Installer::setFileName]
PHP Notice:  unserialize(): Error at offset 0 of 29 bytes in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 357
PHP Notice:  Failed to convert from DB: cover_article_11330_en_US.jpg in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 359
…
PHP Notice:  unserialize(): Error at offset 0 of 29 bytes in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 357
PHP Notice:  Failed to convert from DB: cover_article_13158_en_US.png in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 359
…
PHP Notice:  unserialize(): Error at offset 0 of 29 bytes in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 357
PHP Notice:  Failed to convert from DB: cover_article_13943_en_US.png in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 359
…

All of the $values that couldn’t be unserialized are these simple strings about cover images.

Having already fixed quite a lot of data issues already, I thought “I know what this is! The setting type will be object or array instead string”. Alas, it’s not.

I searched a text dump of the my OJS database for these strings, and the only place they turned up in was as values for article fileName settings.

+------------+--------+--------------+-------------------------------+--------------+
| article_id | locale | setting_name | setting_value                 | setting_type |
+------------+--------+--------------+-------------------------------+--------------+
|       8325 | en_US  | fileName     | cover_article_8325_en_US.jpg  | string       |
|       9045 | en_US  | fileName     | cover_article_9045_en_US.jpg  | string       |
|       9065 | en_US  | fileName     | cover_article_9065_en_US.jpg  | string       |
|       9066 | en_US  | fileName     | cover_article_9066_en_US.jpg  | string       |
|       9067 | en_US  | fileName     | cover_article_9067_en_US.jpg  | string       |
|       9068 | en_US  | fileName     | cover_article_9068_en_US.jpg  | string       |
|       9069 | en_US  | fileName     | cover_article_9069_en_US.jpg  | string       |
|       9115 | en_US  | fileName     | cover_article_9115_en_US.jpg  | string       |
…
+------------+--------+--------------+-------------------------------+--------------+

Every fileName value in this table is mentioned in the logs as not being able to be unserialized.

Given the setting_type is string, I don’t understand how I’m even getting to this point in the code where it is trying to be unserialized. And so I don’t know what my next step is.

I added a debug_print_backtrace() to my patch.

Below is example of the backtrace at point where unserialize is being called on a simple string. I replaced some of the very verbose output with …

PHP Notice:  unserialize(): Error at offset 0 of 29 bytes in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 357
PHP Notice:  Failed to convert from DB: cover_article_11330_en_US.jpg in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 359
#0  DAO->convertFromDB(cover_article_11330_en_US.jpg, object) called at [/var/www/html/lib/pkp/classes/db/SchemaDAO.inc.php:252]
#1  SchemaDAO->_fromRow(Array(
        [publication_id] => 9960,
        [access_status] => 0,
        [date_published] => 2019-06-09,
        [last_modified] => 2019-04-02 20:33:30,
        [locale] => en_US,
        [primary_contact_id] => 14934,
        [section_id] => 401,
        [seq] => 1,
        [submission_id] => 11330,
        [status] => 3,
        [url_path] => ,
        [version] => 1)
    ) called at [/var/www/html/lib/pkp/classes/publication/PKPPublicationDAO.inc.php:50]
#2  PKPPublicationDAO->_fromRow(…) called at [/var/www/html/classes/publication/PublicationDAO.inc.php:40]
#3  PublicationDAO->_fromRow(Array (…), Array ()) called at [/var/www/html/lib/pkp/classes/db/DAOResultFactory.inc.php:108]
#4  DAOResultFactory->next() called at [/var/www/html/lib/pkp/classes/db/DAOResultIterator.inc.php:33]
#5  DAOResultIterator->__construct(…) called at [/var/www/html/lib/pkp/classes/db/DAOResultFactory.inc.php:231]
#6  DAOResultFactory->toIterator() called at [/var/www/html/lib/pkp/classes/services/PKPPublicationService.inc.php:80]
#7  PKP\Services\PKPPublicationService->getMany(Array ([submissionIds] => 11330)) called at [/var/www/html/lib/pkp/classes/submission/PKPSubmissionDAO.inc.php:91]
#8  PKPSubmissionDAO->_fromRow(Array(
        [submission_id] => 11330,
        [locale] => en_US,
        [context_id] => 48
        [section_id] => 401,
        [date_submitted] => 2016-10-21 01:07:08,
        [last_modified] => 2019-04-02 20:33:30,
        [status] => 3,
        [submission_progress] => 0
        [current_publication_id] => 9960,
        [date_last_activity] => 2019-04-02 18:46:05,
        [stage_id] => 4,
        [work_type] => 0
    ), Array ()) called at [/var/www/html/lib/pkp/classes/db/DAOResultFactory.inc.php:108]
#9  DAOResultFactory->next() called at [/var/www/html/classes/install/Upgrade.inc.php:1012]
#10 Upgrade->setFileName(…) called at [/var/www/html/lib/pkp/classes/install/Installer.inc.php:263]
#12 Installer->executeInstaller() called at [/var/www/html/lib/pkp/classes/install/Installer.inc.php:186]
#13 Installer->execute() called at [/var/www/html/lib/pkp/classes/cliTool/UpgradeTool.inc.php:88]
#14 UpgradeTool->upgrade() called at [/var/www/html/lib/pkp/classes/cliTool/UpgradeTool.inc.php:64]
#15 UpgradeTool->execute() called at [/var/www/html/tools/upgrade.php:22]

In OJS 3.2.1-4, SchemaDAO->_fromRow has the following code.

$this->convertFromDB(
    $settingRow['setting_value'],
    $schema->properties->{$settingRow['setting_name']}->type
),

So it would seem that the code is not using the type in the setting_type column, but the type set in the schema (XML?).

In the backtrace we can see that DAO->convertFromDB has been called with "object" as the second argument, and so we can deduce that the schema’s type is object for fileName.

This seems to be in disagreement with what I have in my database.

I can update my database to have serialized PHP objects, but I don’t know if that is the correct thing to do and I don’t know what key to use inside the object for the string.

More investigation reveals that at this point in the upgrade, that setting that was fileName in OJS 2 has become coverImage in OJS 3.

In OJS 3.2.1-4, lib/php/schemas/publication.json does indeed define coverImage to be an object.

{
    /* … */
    "coverImage": {
        "type": "object",
        "multilingual": true,
        "apiSummary": true,
        "validation": [ "nullable" ],
        "properties": {
            "temporaryFileId": { "type": "integer", "writeOnly": true },
            "dateUploaded": { "type": "string" },
            "uploadName": { "type": "string" },
            "altText": { "type": "string" }
        }
    }
    /* … */
}

xml/upgrade/3.0.0_submission_settings.xml renames the setting, but doesn’t transform the value. I’m assuming at this point article_settings has become submission_settings.

<sql><!-- #1934 rename submission cover images settings (fileName to coverImage and coverPageAltText to coverImageAltText) -->
    <query>UPDATE submission_settings SET setting_name = 'coverImage' WHERE setting_name = 'fileName'</query>
    <query>UPDATE submission_settings SET setting_name = 'coverImageAltText' WHERE setting_name = 'coverPageAltText'</query>
</sql>

However in classes/install/Upgrade.inc.php there is a migrateSubmissionCoverImages function. This is in upgrade.xml.

<upgrade minversion="2.4.0.0" maxversion="3.1.9.9">
    <code function="migrateSubmissionCoverImages" />

The log from my upgrade does show that it was run, and it ran quite early in the upgrade.

…
[data: dbscripts/xml/upgrade/3.0.0_preupdate.xml]
…
[code: Installer Installer::migrateSubmissionCoverImages]
…
[data: dbscripts/xml/upgrade/3.0.0_submission_settings.xml]
…
[data: dbscripts/xml/upgrade/3.2.0_versioning.xml]
…
[code: Installer Installer::setFileName]
PHP Notice:  unserialize(): Error at offset 0 of 29 bytes in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 357
PHP Notice:  Failed to convert from DB: cover_article_11330_en_US.jpg in /var/www/html/lib/pkp/classes/db/DAO.inc.php on line 359
…

migrateSubmissionCoverImages starts with this comment.

/**
 * Update how submission cover images are stored
 *
 * Combines the coverImage and coverImageAltText settings in the
 * submissions table into an assoc array stored under the coverImage
 * setting.
 *
 * This will be migrated to the publication_settings table in
 * 3.2.0_versioning.xml.
 */

This is immediately concerning because migrateSubmissionCoverImages runs before 3.0.0_submission_settings.xml. It hasn’t yet been renamed and is still called fileName.

So it looks like the order in update.xml needs to change.

One last piece that is relevant is change OJS2 article_settings to OJS3 submission_settings. This happens in xml/upgrade/3.0.0_preupdate.xml. And it does happen before migrateSubmissionCoverImages.

<!-- article_settings to submission_settings -->
<rename table="article_settings" column="article_id" to="submission_id" />
<rename table="article_settings" to="submission_settings" />

I applied the following patch to OJS 3.2.1-4. This resolved the unserialize errors in setFileName.

This may not work if you have the Serbian language installed.

This may not work if you’re not upgrading specifically from OJS 2.4.8-5 directly to OJS 3.2.1-4.

--- a/dbscripts/xml/upgrade.xml
+++ b/dbscripts/xml/upgrade.xml
@@ -35,6 +35,8 @@
 		<data file="dbscripts/xml/upgrade/3.0.0_adaptBooksForReview.xml" condition="return $installer->tableExists('books_for_review');" />
 		<data file="dbscripts/xml/upgrade/remove_timed_views_bots.xml" condition="return $installer->tableExists('timed_views_log');" />
 		<data file="dbscripts/xml/upgrade/3.0.0_preupdate_commentsToEditor.xml" condition="return $installer->columnExists('submissions', 'comments_to_ed');" />
+		<data file="dbscripts/xml/upgrade/3.0.0_issue_settings.xml" />
+		<data file="dbscripts/xml/upgrade/3.0.0_submission_settings.xml" />
 	</upgrade>

 	<upgrade minversion="3.0.0.0" maxversion="3.0.1.9">
@@ -148,8 +150,6 @@
 		<data file="dbscripts/xml/upgrade/3.0.0_pubId_settings.xml" />
 		<data file="dbscripts/xml/upgrade/3.0.0_postupgrade_galley_files.xml" />
 		<data file="dbscripts/xml/upgrade/3.0.0_postupgrade_metrics.xml" />
-		<data file="dbscripts/xml/upgrade/3.0.0_issue_settings.xml" />
-		<data file="dbscripts/xml/upgrade/3.0.0_submission_settings.xml" />
 		<data file="dbscripts/xml/upgrade/3.0.0_review_method.xml" />
 		<data file="dbscripts/xml/upgrade/3.0.0_edit_decisions.xml" />
 		<code function="convertCommentsToEditor" condition="return $installer->tableExists('submissions_tmp');" />
3 Likes

This topic was automatically opened after 3 days.