Search code examples
phparraysvalidationdeserialization

Parse pipe-delimited serialized strings


How can I correctly extract this information in php? For example, I need information about the customer and the id.

contents shipping_address currency customer ....

Thank you

"sessiontoken|s:32:"6450a6e3ced9cdbc38c82e51376efc0f";ClicShoppingCart|a:5:{s:8:"contents";a:1:{i:21;a:1:{s:3:"qty";i:5;}}s:14:"sub_total_cost";i:0;s:10:"total_cost";i:0;s:12:"total_weight";d:0;s:16:"shipping_address";a:2:{s:7:"zone_id";s:3:"265";s:10:"country_id";s:2:"73";}}language|s:2:"fr";currency|s:3:"USD";new_products_id_in_cart|i:21;cart_country_id|s:2:"73";Shop|a:1:{s:17:"NavigationHistory";a:1:{s:8:"snapshot";N;}cart_address_id|N;sendto|i:24;customer_group_id|a:1:{s:18:"customers_group_id";s:1:"0";}customer|a:8:{s:2:"id";i:11;s:10:"first_name";s:4:"XXX";s:9:"last_name";s:7:"XXXXXX";s:13:"email_address";s:21:"xxx.xxxx@xxxxxx.fr";s:9:"telephone";N;s:10:"country_id";i:38;s:7:"zone_id";i:76;s:18:"default_address_id";i:24;}cartID|s:5:"57448";billto|i:24;payment|s:21:"Payment\Desjardins\HO";comments|s:0:"";shipping|a:3:{s:2:"id";s:45:"colispostalprioritaire_colispostalprioritaire";s:5:"title";s:70:"Colis International Prioritaire (France) (Livraison vers CA : 0 Kg(s))";s:4:"cost";i:18;}coupon|s:0:"";"

Solution

  • Because I can't find any documentation on the web that uses pipes to designate top-level keys in the serialized data, I have to assume this is a home-grown concoction. To make matters worse there are a few errors in what is otherwise a nearly-regular serialized data string. This being the case, your string must be custom parsed into an array for reliable handling.

    I have done that job for you. My script will correct your sample data (no guaranteed on it being 100% effective for your other home grown strings) and convert it to an array. From the resulting array, you can either access the elements directly by key or loop. You can also choose to use serialize() to convert it into a valid serialized data string for proper future storage/handling.

    Demo

    Code:

    $serialstring='sessiontoken|s:32:"6450a6e3ced9cdbc38c82e51376efc0f";ClicShoppingCart|a:5:{s:8:"contents";a:1:{i:21;a:1:{s:3:"qty";i:5;}}s:14:"sub_total_cost";i:0;s:10:"total_cost";i:0;s:12:"total_weight";d:0;s:16:"shipping_address";a:2:{s:7:"zone_id";s:3:"265";s:10:"country_id";s:2:"73";}}language|s:2:"fr";currency|s:3:"USD";new_products_id_in_cart|i:21;cart_country_id|s:2:"73";Shop|a:1:{s:17:"NavigationHistory";a:1:{s:8:"snapshot";N;}cart_address_id|N;sendto|i:24;customer_group_id|a:1:{s:18:"customers_group_id";s:1:"0";}customer|a:8:{s:2:"id";i:11;s:10:"first_name";s:4:"XXX";s:9:"last_name";s:7:"XXXXXX";s:13:"email_address";s:21:"xxx.xxxx@xxxxxx.fr";s:9:"telephone";N;s:10:"country_id";i:38;s:7:"zone_id";i:76;s:18:"default_address_id";i:24;}cartID|s:5:"57448";billto|i:24;payment|s:21:"Payment\Desjardins\HO";comments|s:0:"";shipping|a:3:{s:2:"id";s:45:"colispostalprioritaire_colispostalprioritaire";s:5:"title";s:70:"Colis International Prioritaire (France) (Livraison vers CA : 0 Kg(s))";s:4:"cost";i:18;}coupon|s:0:""';
    //var_export(unserialize($serialstring));  this fails because the string has errors in it
    
    if(preg_match_all('/(\w+)\|(.*?)(?=(\w+)\||$)/',$serialstring,$matches)){
        foreach($matches[1] as $i=>$k){
            $v=$matches[2][$i];  // post-pipe group
            if(preg_match_all('/s:(\d+):"([^"]*?)"/',$v,$matches2)){ // capture string lengths and values
                foreach($matches2[1] as $i=>$len){
                    if(($newlen=strlen($matches2[2][$i]))!=$len){  // if bad string length count, fix it
                        $v=str_replace("s:{$len}:\"{$matches2[2][$i]}\"","s:{$newlen}:\"{$matches2[2][$i]}\"",$v);
                    }
                }
            }
            if(substr_count($v,"{")>substr_count($v,"}")){ // if insufficient closing curly brackets, fix it
                $v.=str_repeat("}",substr_count($v,"{")-substr_count($v,"}"));
            }
            if(!in_array(substr($v,-1),[";","}"])){
                $v.=";"; // append semicolon where not ending in } or ;
            }
            $result[$k]=unserialize($v);
        }
    }
    var_export($result);  // this is the array
    echo "\n\n";
    echo serialize($result);  // this is the valid serialized data string