3

I hope that some of you can give a tip(s), which will lead me for a solution.

Error converting field additional_information in table ma2_sales_payment_transaction where transaction_id=4 using Magento\Framework\DB\DataConverter\SerializedToJson. Fix data or replace with a valid value. Failure reason: 'Unable to unserialized value, string is corrupted.'

What should I fix and from where??

3
  • have you find any solution for this Nov 29, 2017 at 6:15
  • Hi, I'm facing the same error, and tried below solution but it did not work.. Did you fix this issue ?
    – David
    Feb 17, 2018 at 11:13
  • I've faced the same issue. In my case it was data in the quotes table that contained what seemed to be bot added spam from a comment form. I would suggest you run the setup:upgrade with xdebug on and see where it fails, on what string. It might be comments in the transactions table or something that magento tries to convert to json but is unable. I bypassed this by cleaning the database of all the corupted entries, there were just a few. You could also just wrap that in a try catch and have it log the errors instead that way you know how many you have and what they are...
    – drew7721
    Feb 19, 2018 at 6:05

2 Answers 2

1

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:

protected 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;
}

Hope this will help

2
  • Thanks. I notice that there were this work around. Unfortunately this didn't help. I have to say I don't much about this. I notice that from Serialize.php following "Does not unserialize objects" The additional_information does have O: fields....
    – A.P
    Nov 26, 2017 at 9:39
  • Hi, I tried it also, but no luck. In this case, problem seems to come from /vendor/magento/framework/Serialize/Serializer/Serialize.php as error shows Unable to unserialize value, string is corrupted.
    – David
    Feb 17, 2018 at 11:19
1
+25

Check magento 2 official document which field you need to convert

After upgrade 2.1.x to 2.2.x you need to convert serialize data to json.Try to create module and fix following way:

VendorName/M22JsonFix/etc/di.xml


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\Console\CommandList">
        <arguments>
            <argument name="commands" xsi:type="array">
                <item name="m22json_fix_command" xsi:type="object">VendorName\M22JsonFix\Console\Command\JsonFix</item>
            </argument>
        </arguments>
    </type>
</config>

VendorName/M22JsonFix/Console/Command/JsonFix.php


namespace VendorName\M22JsonFix\Console\Command;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Output\OutputInterface;

class JsonFix extends Command
{
    private $tablesColumnsToFix;

    /**
     * @var \Magento\Framework\DB\Adapter\AdapterInterface
     */
    private $connection;

    /**
     * @var \Psr\Log\LoggerInterface
     */
    private $logger;

    /**
     * @var \Magento\Framework\App\State
     */
    private $appState;

    /**
     * @var \Symfony\Component\Console\Output\OutputInterface
     */
    private $output;

    /**
     * JsonFix constructor.
     *
     * @param \Magento\Framework\App\ResourceConnection $resource
     * @param \Psr\Log\LoggerInterface $logger
     * @param \Magento\Framework\App\State $appState
     */
    public function __construct(
        \Magento\Framework\App\ResourceConnection $resource,
        \Psr\Log\LoggerInterface $logger,
        \Magento\Framework\App\State $appState
    ) {
        $this->connection = $resource->getConnection();
        $this->logger = $logger;
        $this->appState = $appState;

        $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML);

        parent::__construct();
    }

    /**
     * Initialization of the command
     *
     * @return void
     */
    protected function configure()
    {
        $this->setName('vendorname:m22jsonfix')
            ->setDescription('Magento 22 json fix');
        parent::configure();
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        ini_set('memory_limit', '-1');

        $this->output = $output;

        try {
            $output->writeln(
                "Import Start"
            );

            $this->getTableList();
            $this->process($output);

            $output->writeln(
                "Import completed"
            );
        } catch (\Exception $e) {
            $output->writeln('' . $e->getMessage() . '');
            if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
                $output->writeln($e->getTraceAsString());
            }
            return;
        }
    }

    public function process()
    {
        foreach ($this->tablesColumnsToFix as $table => $params) {
            $this->output->writeln("Started converting data in table: {$table}");
            $primaryKey = $params['primary_key'];
            $selectColumnStr = implode(',', $params['select_column']);
            $sql = "SELECT $primaryKey, $selectColumnStr FROM ".$table;
            $result = $this->connection->fetchAll($sql);
            foreach ($result as $row) {
                foreach ($params['select_column'] as $selectColumn) {
                    try {
                        $serialized = unserialize($row[$selectColumn]);
                        $json = json_encode($serialized);

                        $updateSql = "UPDATE $table SET $selectColumn='{$json}' WHERE {$primaryKey}=". $row[$primaryKey];
                        $this->connection->query($updateSql);
                    } catch(\Exception $e) {
                        $this->logger->critical($e->getMessage());
                        $this->logger->critical($table." problem with ".$row[$primaryKey]);
                    }
                }
            }
            $this->output->writeln("Finished converting data in table: {$table}");
        }
    }

    public function getTableList()
    {
        $this->tablesColumnsToFix = [
            'salesrule' => [
                'primary_key' => 'rule_id',
                'select_column' => ['conditions_serialized', 'actions_serialized']
            ],
            'catalogrule' => [
                'primary_key' => 'rule_id',
                'select_column' => ['conditions_serialized', 'actions_serialized']
            ],
            'sales_order_item' => [
                'primary_key' => 'item_id',
                'select_column' => ['product_options']
            ],
            'sales_order_payment' => [
                'primary_key' => 'entity_id',
                'select_column' => ['additional_data']
            ],
            'sales_shipment' => [
                'primary_key' => 'entity_id',
                'select_column' => ['packages']
            ],
            'sales_payment_transaction' => [
                'primary_key' => 'transaction_id',
                'select_column' => ['additional_information']
            ],
            'quote_item_option' => [
                'primary_key' => 'option_id',
                'select_column' => ['value']
            ],
            'wishlist_item_option' => [
                'primary_key' => 'option_id',
                'select_column' => ['value']
            ],
            'quote_address' => [
                'primary_key' => 'address_id',
                'select_column' => ['applied_taxes']
            ],
            'quote_payment' => [
                'primary_key' => 'payment_id',
                'select_column' => ['additional_information']
            ],
            'customer_eav_attribute' => [
                'primary_key' => 'attribute_id',
                'select_column' => ['validate_rules']
            ],
            'url_rewrite' => [
                'primary_key' => 'url_rewrite_id',
                'select_column' => ['metadata']
            ],
            'sales_creditmemo_item' => [
                'primary_key' => 'entity_id',
                'select_column' => ['tax_ratio']
            ],
            'sales_invoice_item' => [
                'primary_key' => 'entity_id',
                'select_column' => ['tax_ratio']
            ],
            'admin_user' => [
                'primary_key' => 'user_id',
                'select_column' => ['extra']
            ],
            'catalog_eav_attribute' => [
                'primary_key' => 'attribute_id',
                'select_column' => ['additional_data']
            ],
            'layout_update' => [
                'primary_key' => 'layout_update_id',
                'select_column' => ['xml']
            ]
        ];

    }
}

Now command will be


php bin/magento vendorname:m22jsonfix
1
  • Hi @sohel-rana ! When I ran the command I got the error message: [Symfony\Component\Console\Exception\CommandNotFoundException] There are no commands defined in the "VendorName" namespace.
    – P. Paul
    Mar 3, 2018 at 23:34

Your Answer

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

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