Here is a function that returns decoded session data, that seems to work in every cases, even when strings contain reserved chars :
<?php
define('PS_DELIMITER', '|');
define('PS_UNDEF_MARKER', '!');
function session_real_decode($str)
{
$str = (string)$str;
$endptr = strlen($str);
$p = 0;
$serialized = '';
$items = 0;
$level = 0;
while ($p < $endptr) {
$q = $p;
while ($str[$q] != PS_DELIMITER)
if (++$q >= $endptr) break 2;
if ($str[$p] == PS_UNDEF_MARKER) {
$p++;
$has_value = false;
} else {
$has_value = true;
}
$name = substr($str, $p, $q - $p);
$q++;
$serialized .= 's:' . strlen($name) . ':"' . $name . '";';
if ($has_value) {
for (;;) {
$p = $q;
switch ($str[$q]) {
case 'N': case 'b': case 'i': case 'd': do $q++;
while ( ($q < $endptr) && ($str[$q] != ';') );
$q++;
$serialized .= substr($str, $p, $q - $p);
if ($level == 0) break 2;
break;
case 'R': $q+= 2;
for ($id = ''; ($q < $endptr) && ($str[$q] != ';'); $q++) $id .= $str[$q];
$q++;
$serialized .= 'R:' . ($id + 1) . ';'; if ($level == 0) break 2;
break;
case 's': $q+=2;
for ($length=''; ($q < $endptr) && ($str[$q] != ':'); $q++) $length .= $str[$q];
$q+=2;
$q+= (int)$length + 2;
$serialized .= substr($str, $p, $q - $p);
if ($level == 0) break 2;
break;
case 'a': case 'O': do $q++;
while ( ($q < $endptr) && ($str[$q] != '{') );
$q++;
$level++;
$serialized .= substr($str, $p, $q - $p);
break;
case '}': $q++;
$serialized .= substr($str, $p, $q - $p);
if (--$level == 0) break 2;
break;
default:
return false;
}
}
} else {
$serialized .= 'N;';
$q+= 2;
}
$items++;
$p = $q;
}
return @unserialize( 'a:' . $items . ':{' . $serialized . '}' );
}
?>
Please let met know if you find any bug.