6

I have a result of export variable in Perl like this string:

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

How can I deserialize this data in PHP?

P.S. I already have data in this format in DB, I cannot change it to json or another.

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
Dimmduh
  • 803
  • 1
  • 11
  • 18
  • 3
    [PERL does not exist](http://perldoc.perl.org/perlfaq1.html#What's-the-difference-between-%22perl%22-and-%22Perl%22%3f) – Quentin Sep 10 '12 at 13:26
  • 4
    I'd serialize the data to a common standard, such as [JSON](https://metacpan.org/module/JSON) rather then whatever format you are using (Data::Dumper I'd guess). – Quentin Sep 10 '12 at 13:27
  • 1
    Are you sure you mean "serialize" and not "deserialize"? – Quentin Sep 10 '12 at 13:28
  • 2
    Saving the data in a language-specific serialised format was a bad move. Lesson learned: always use standards, even when you don't think you'll need them. – SDC Sep 10 '12 at 14:08
  • 1
    [Data::Dumper](http://p3rl.org/Data::Dumper) is not really a good serialization format. – Brad Gilbert Sep 10 '12 at 23:54
  • Agreed with @BradGilbert - indeed. Data::Dumper is not even *intended* to be used as a serialisation format. (nor is PHP's print_r() for that matter, in case you're ever tempted) – SDC Sep 11 '12 at 11:55

6 Answers6

5

You've got a number of suggestions for trying to parse it one way or another, but the real question is why?

Why not just have a small Perl program that loads it, and spits out an equivalent JSON string.

You could then either call that Perl program from within your PHP to do the conversion; this would mean you are using Perl to read the Perl format, which would guarantee correct conversion.

Or (better yet) run it against your entire database in a batch, to get rid of the Perl-specific data format from the DB; then you can just use PHP's standard JSON functions.

That would then make life so much simpler in your PHP code (or in any other language you need to read the data with at a later date).

SDC
  • 14,192
  • 2
  • 35
  • 48
4

The obvious and only robust solution is to use Perl to deserialize and reserialize the input to a standard format. The Perl program that can accomplish this task does not need to be very large, either.

// 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);
}
mob
  • 117,087
  • 18
  • 149
  • 283
3

Since it's not JSON but it looks like JSON, you could try to modify a JSON library to work with that format. I took this JSON library, replaced : with => and added undef as you can see here (lines 496, 671 and 681). It's pretty straightforward, really, and I assume you can work around other differences in a similar manner.

Result is:

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] => 
)

Is that what you're looking for?

Alexei
  • 672
  • 1
  • 5
  • 13
1
use JSON;

(or any other data interchange format like XML)

JSON documentation and examples are available at CPAN

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
amon
  • 57,091
  • 2
  • 89
  • 149
1

If you can change the Perl code, then do as amon suggests and use some standard serialization format like JSON or XML or YAML that you can deserialize in PHP.

You could even make Perl output PHP's native serialization format if you really wanted to, although I wouldn't generally recommend that. (What about when you next want to deserialize the same data in, say, Python?)

If you can't change the Perl code, you'll just have to bite the bullet and try to parse the Data::Dumper output in PHP. I couldn't find any existing code to do that, so it looks like you may have to write your own. This could be job for a parser generator, although the format is (usually) simple enough that you might be able to just hand-code it.


Edit: Since you say that you have this serialized data in a database, why not just write a Perl program to read the data and convert it to a more standard serialization format like JSON?

Community
  • 1
  • 1
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
0

Since you stated you cannot change format:

I don't like using eval, but because your syntax is so close to the expected PHP array syntax, I think we can let it slide.

Set $string equal to the contents from your database that fits the format below. See below for a working example using the data you provided. At the end of the day, PHP will set the variable at the beginning of your perl var to the new parsed array.

Since it is going to be a textblock/large string, do:

<?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);

Your result is:

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

Note: I would suggest you take the time now to retrofit and upgrade your database content to a more standard format simply for the fact that it will be easier to maintain in the future.

You can loop through your database, grab all the contents row by row, at which point you run the data into the function above, and wrap it in json_encode() and update your database row with the new JSON string. This will save you a headache in the future and allow you to update all your data for the new standard.

Mike Mackintosh
  • 13,917
  • 6
  • 60
  • 87
  • This may yield surprising results if any of the strings in the input contain curly braces or the string `undef`. (For the latter, it might be easier and safer to just do `define('undef', null);` before the `eval`.) – Ilmari Karonen Sep 10 '12 at 13:59
  • (Also, do you _really_ have to include both a copy of the original string and the `print_r` output in your answer? I'll give you a +1 if you delete them.) – Ilmari Karonen Sep 10 '12 at 14:05
  • Truncated the above for readability. I like your point about the define, and that is a great suggestion. Working on a regex now to fix the issue where `{}` would appear in the string. – Mike Mackintosh Sep 10 '12 at 14:07
  • You could replace them with something like `"array(#{\n"` and `")#}\n"` and then loop through the output to undo the replacement. (By including `{` and `}` in the replacements, the encoding should in fact be fully reversible, too.) – Ilmari Karonen Sep 10 '12 at 14:11
  • I was thinking about that, but I wanted to avoid a second replacement loop, for the sake of simplicity and code cognition. – Mike Mackintosh Sep 10 '12 at 14:13
  • -1 for the `eval` and the fact that it's more like a kludge rather than a solution. – Alexei Sep 10 '12 at 14:16