3

The following actions produce the results listed below each action.

If a category has more than 50 items it seems to always happen, categories with less than 50 items will usually work, but will still sometimes trigger the same issue. I had thought perhaps it had to do with the particular items in the category, but I can perform the same actions over and over, and a category which worked previously will then fail, so I don't suspect that individual items are at fault.

When attempting to move a category, does not seem to matter if it has subcategories or not.

There was a category move error.
main.CRITICAL: Unable to unserialize value. {"exception":"[object] (InvalidArgumentException(code: 0): Unable to unserialize value. at /home/___/public_html/vendor/magento/framework/Serialize/Serializer/Json.php:39)"} []

When attempting to change anchor on a category.

Something went wrong while saving the category.
main.CRITICAL: Unable to unserialize value. {"exception":"[object] (InvalidArgumentException(code: 0): Unable to unserialize value. at /home/___/public_html/vendor/magento/framework/Serialize/Serializer/Json.php:39)"} []

If I had just previously tried editing a category, and it failed, changing anchor value will also fail, unless first navigating to another category, and then returning to change anchor.

Something went wrong while saving the category.
main.CRITICAL: Unable to unserialize value. {"exception":"[object] (InvalidArgumentException(code: 0): Unable to unserialize value. at /home/___/public_html/vendor/magento/framework/Serialize/Serializer/Json.php:39)"} []

I've verified that this occurs with all 3rd party extensions disabled.

I recently had another serialization issue, which turned out to be a permissions issue, Magento 2.2: Unable to unserialize value?, but that solution did not have any impact on this issue.

1 Answer 1

2

The problem is in /vendor/magento/framework/Serialize/Serializer/Json.php there is a function unserialize($string) which gives You a syntax error if string is serialized.

There is a workaround - You can check if string is serialized and then use serialize($string). Change unserialize to:

public function unserialize($string)
{
    if($this->is_serialized($string))
    {
        $string = $this->serialize($string);
    }
    $result = json_decode($string, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
         throw new \InvalidArgumentException('Unable to unserialize value.');

    }
    return $result;
}

and add function to check if string is serialized:

function is_serialized($value, &$result = null)
{
    // Bit of a give away this one
    if (!is_string($value))
    {
        return false;
    }
    // Serialized false, return true. unserialize() returns false on an
    // invalid string or it could return false if the string is serialized
    // false, eliminate that possibility.
    if ($value === 'b:0;')
    {
        $result = false;
        return true;
    }
    $length = strlen($value);
    $end    = '';
    switch ($value[0])
    {
        case 's':
            if ($value[$length - 2] !== '"')
            {
                return false;
            }
        case 'b':
        case 'i':
        case 'd':
            // This looks odd but it is quicker than isset()ing
            $end .= ';';
        case 'a':
        case 'O':
            $end .= '}';
            if ($value[1] !== ':')
            {
                return false;
            }
            switch ($value[2])
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                    break;
                default:
                    return false;
            }
        case 'N':
            $end .= ';';
            if ($value[$length - 1] !== $end[0])
            {
                return false;
            }
            break;
        default:
            return false;
    }
    if (($result = @unserialize($value)) === false)
    {
        $result = null;
        return false;
    }
    return true;
}

After save fe. category without problem, You can restore class to default and there wont be such problem in future.

1
  • Where in Magento 2.2.0 I can find: /vendor/magento/framework/Serialize/Serializer/Json.php ?? it does not exists. However I found in: /vendor/magento/zendframework1/library/Zend/Serializer/Adapter/Json.php and PHPSerializer.php. Which one ?
    – Rob D. A.
    Commented Nov 6, 2017 at 10:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.