Как десериализовать вывод Perl Data::Dumper в PHP

У меня есть результат экспорта переменной в Perl, как эта строка:

$VAR1 = {
    'guard' => undef,
    'work_hand' => undef,
    'images' => 
        {'1' => 
            {
            'mini_height' => 150,
            'width' => 150,
            'extension' => 'jpg',
            'filename' => 'object_1.1330907414.96873.jpg',
            'mini_width' => 150,
            'class' => 'Ontico::Image',
            'height' => 150,
            'mini_filename' => 'object_1.1330907414.96873.mini.jpg',
            'size' => 26053,
            'symname' => 'big_logo'
            },
        '2' => 
            {
            'width' => 48,
            'extension' => 'jpg',
            'alt' => 'Даниэле Галлоппа',
            'height' => 48,
            'mini_filename' => 'object_91.1235312905.mini.jpg',
            'size' => 12809,
            'symname' => 'logo',
            'mini_height' => 150,
            'filename' => 'object_91.1235312905.jpg',
            'mini_width' => 150,
            'class' => 'Ontico::Image'
            }
        },
        'show_league_banner' => 0,
        'back_hand' => undef,
        'weight_category' => undef,
        'stick_position' => undef
    };

Как я могу десериализовать эти данные в PHP?

PS У меня уже есть данные в этом формате в БД, я не могу изменить их на json или другой.

6 ответов

Решение

Поскольку вы заявили, что не можете изменить формат:

Мне не нравится использовать eval, но поскольку ваш синтаксис настолько близок к ожидаемому синтаксису массива PHP, я думаю, что мы можем позволить ему скользить.

Задавать $string равный содержанию из вашей базы данных, которое соответствует формату ниже. Ниже приведен рабочий пример с использованием предоставленных вами данных. В конце дня PHP установит переменную в начале вашего perl var в новый разобранный массив.

Поскольку это будет текстовая строка / большая строка, выполните:

<?php
$string = "\$VAR1 = {
    'guard' => undef,
    'work_hand' => undef,
    'images' =>
        {'1' =>
            {
            'mini_height' => 150,
            ... // truncated for readability
    };";

$res = str_replace(array("{", "}", 'undef'), array("array(", ")", "''"), $string);

eval($res);

print_r($VAR1);

Ваш результат:

Array
(
    [guard] =>
    [work_hand] =>
    [images] => Array
        (
            [1] => Array
                (
                    [mini_height] => 150 ...

Примечание. Я бы посоветовал вам потратить время на модернизацию и обновление содержимого базы данных до более стандартного формата, просто потому, что в будущем его будет проще поддерживать.

Вы можете циклически проходить по вашей базе данных, захватывать все содержимое построчно, после чего вы запускаете данные в вышеприведенную функцию и переносите их в json_encode() и обновите строку базы данных новой строкой JSON. Это избавит вас от головной боли в будущем и позволит обновить все ваши данные для нового стандарта.

У вас есть несколько предложений для того, чтобы попытаться разобрать это так или иначе, но реальный вопрос - почему?

Почему бы просто не иметь небольшую Perl-программу, которая загружает ее и выплевывает эквивалентную строку JSON.

Затем вы можете либо вызвать эту Perl-программу из вашего PHP, чтобы выполнить преобразование; это означает, что вы используете Perl для чтения формата Perl, что гарантирует правильное преобразование.

Или (еще лучше) запустить его для всей базы данных в пакете, чтобы избавиться от специфичного для Perl формата данных из БД; тогда вы можете просто использовать стандартные функции JSON PHP.

Это сделало бы жизнь намного проще в вашем PHP-коде (или на любом другом языке, с которым вам нужно читать данные позже).

Очевидное и единственное надежное решение - использовать Perl для десериализации и повторной сериализации ввода в стандартный формат. Программа Perl, которая может выполнить эту задачу, также не должна быть очень большой.

// receive input in Perl's Data::Dumper format and produce PHP object output
function perl_dd_to_php( $dd_output ) {
    $process = proc_open( "perl -000 -MJSON -e 'print encode_json eval <>'",
                          array( array("pipe","r"), array("pipe","w") ),
                          $pipes );
    fwrite($pipes[0], $dd_output );
    fclose($pipes[0]);

    $json_string = stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    return json_decode($json_string);
}

Поскольку это не JSON, а выглядит как JSON, вы можете попробовать изменить библиотеку JSON для работы с этим форматом. Я взял эту библиотеку JSON, заменил : с => и добавил undef как вы можете видеть здесь (строки 496, 671 и 681). На самом деле это довольно просто, и я предполагаю, что вы можете обойти другие различия аналогичным образом.

Результат:

stdClass Object
(
    [guard] => 
    [work_hand] => 
    [images] => stdClass Object
        (
            [1] => stdClass Object
                (
                    [mini_height] => 150
                    [width] => 150
                    [extension] => jpg
                    [filename] => object_1.1330907414.96873.jpg
                    [mini_width] => 150
                    [class] => Ontico::Image
                    [height] => 150
                    [mini_filename] => object_1.1330907414.96873.mini.jpg
                    [size] => 26053
                    [symname] => big_logo
                )

            [2] => stdClass Object
                (
                    [width] => 48
                    [extension] => jpg
                    [alt] => Даниэле Галлоппа
                    [height] => 48
                    [mini_filename] => object_91.1235312905.mini.jpg
                    [size] => 12809
                    [symname] => logo
                    [mini_height] => 150
                    [filename] => object_91.1235312905.jpg
                    [mini_width] => 150
                    [class] => Ontico::Image
                )

        )

    [show_league_banner] => 0
    [back_hand] => 
    [weight_category] => 
    [stick_position] => 
)

Это то, что вы ищете?

Если вы можете изменить код Perl, сделайте так, как предлагает Амон, и используйте какой-нибудь стандартный формат сериализации, такой как JSON, XML или YAML, который вы можете десериализовать в PHP.

Вы даже можете сделать так, чтобы Perl выводил собственный формат сериализации PHP, если бы вы действительно этого хотели, хотя я бы вообще не рекомендовал этого. (Как насчет того, когда вы в следующий раз захотите десериализовать те же данные, скажем, в Python?)

Если вы не можете изменить код Perl, вам просто нужно прикусить пулю и попытаться проанализировать вывод Data::Dumper в PHP. Я не смог найти какой-либо существующий код для этого, так что, похоже, вам придется написать свой собственный. Это может быть работа для генератора синтаксического анализатора, хотя формат (как правило) достаточно прост, чтобы вы могли просто кодировать его вручную.


Изменить: Поскольку вы говорите, что у вас есть эти сериализованные данные в базе данных, почему бы просто не написать программу на Perl для чтения данных и преобразования их в более стандартный формат сериализации, такой как JSON?

use JSON;

(или любой другой формат обмена данными, например, XML)

Документация и примеры JSON доступны на CPAN

Другие вопросы по тегам