$ser = 'a:2:{i:0;s:5:"héllö";i:1;s:5:"wörld";}'; // fails $ser2 = 'a:2:{i:0;s:5:"hello";i:1;s:5:"world";}'; // works $out = unserialize($ser); $out2 = unserialize($ser2); print_r($out); print_r($out2); echo "<hr>";
Но почему?
Должен ли я кодировать перед сериализацией, чем? Как?
Я использую Javascript для записи сериализованной строки в скрытое поле, чем PHP $ _POST
В JS у меня есть что-то вроде:
function writeImgData() { var caption_arr = new Array(); $('.album img').each(function(index) { caption_arr.push($(this).attr('alt')); }); $("#hidden-field").attr("value", serializeArray(caption_arr)); };
Причина, по которой unserialize()
терпит неудачу:
$ser = 'a:2:{i:0;s:5:"héllö";i:1;s:5:"wörld";}';
Это потому, что длина для héllö
и wörld
неверна, поскольку PHP неправильно обрабатывает многобайтные строки изначально:
echo strlen('héllö'); // 7 echo strlen('wörld'); // 6
Однако если вы попробуете unserialize()
следующую правильную строку:
$ser = 'a:2:{i:0;s:7:"héllö";i:1;s:6:"wörld";}'; echo '<pre>'; print_r(unserialize($ser)); echo '</pre>';
Оно работает:
Array ( [0] => héllö [1] => wörld )
Если вы используете PHP serialize()
он должен правильно вычислить длины многобайтовых строковых индексов.
С другой стороны, если вы хотите работать с сериализованными данными на нескольких языках программирования, вы должны забыть об этом и перейти к чему-то вроде JSON, который более стандартизирован.
Я знаю, что это было опубликовано, как год назад, но у меня есть эта проблема, и я сталкивался с этим, и на самом деле я нашел для нее решение. Этот кусок кода работает как шарм!
Идея проста. Это просто помогает вам, пересчитывая длину многобайтовых строк, как указано в @Alix выше.
Несколько модификаций должны соответствовать вашему коду:
/** * Mulit-byte Unserialize * * UTF-8 will screw up a serialized string * * @access private * @param string * @return string */ function mb_unserialize($string) { $string = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $string); return unserialize($string); }
Источник: http://snippets.dzone.com/posts/show/6592
Протестировано на моей машине, и это работает как шарм !!
Lionel Chan отвечает на изменения с PHP> = 5.5:
function mb_unserialize($string) { $string2 = preg_replace_callback( '!s:(\d+):"(.*?)";!s', function($m){ $len = strlen($m[2]); $result = "s:$len:\"{$m[2]}\";"; return $result; }, $string); return unserialize($string2); }
Этот код использует preg_replace_callback, поскольку preg_replace с модификатором / e устарел с PHP 5.5.
Проблема заключается в том, что, как указывает Alix, связано с кодированием.
До PHP 5.4 внутренняя кодировка для PHP была ISO-8859-1, эта кодировка использует один байт для некоторых символов, которые в юникоде являются многобайтными. В результате многобайтовые значения, сериализованные в системе UTF-8, не будут читаться в системах ISO-8859-1.
Во избежание подобных проблем убедитесь, что все системы используют одну и ту же кодировку:
mb_internal_encoding('utf-8'); $arr = array('foo' => 'bár'); $buf = serialize($arr);
Вы можете использовать utf8_(encode|decode)
для очистки:
// Set system encoding to iso-8859-1 mb_internal_encoding('iso-8859-1'); $arr = unserialize(utf8_encode($serialized)); print_r($arr);
В ответ на @Lionel выше фактически функция mb_unserialize (), которую вы предложили, не будет работать, если сама сериализованная строка содержит последовательность символов ";
(цитата, за которой следует точка с запятой). Используйте с осторожностью. Например:
$test = 'test";string'; // $test is now 's:12:"test";string";' $string = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $test); print $string; // output: s:4:"test";string"; (Wrong!!)
JSON – это путь, как упоминалось другими, ИМХО
Примечание. Я отправляю это как новый ответ, поскольку не знаю, как ответить напрямую (здесь новый).
Не используйте сериализацию / unserialization PHP, когда другой конец не является PHP. Он не предназначен для портативного формата – например, он даже включает символы ascii-1 для защищенных ключей, с которыми вы не хотите работать в javascript (хотя это будет работать отлично, это просто крайне уродливо).
Вместо этого используйте переносимый формат, такой как JSON . XML тоже будет работать, но JSON имеет меньше накладных расходов и более удобен для программистов, так как вы можете легко разобрать его в простой структуре данных, а не иметь дело с деревьями XPath, DOM и т. Д.
Я бы посоветовал вам использовать javascript для кодирования как json, а затем использовать json_decode для unserialize.
Здесь есть еще одна небольшая вариация, которая, надеюсь, поможет кому-то … Я сериализую массив, а затем записываю его в базу данных. При извлечении данных произошла сбой операции без операции.
Оказывается, что поле longtext базы данных, в которое я писал, использовало latin1, а не UTF8. Когда я включил его, все работало так, как планировалось.
Спасибо всем выше, кто упомянул кодировку символов и заставил меня на правильном пути!
мы можем разбить строку на массив:
$finalArray = array(); $nodeArr = explode('&', $_POST['formData']); foreach($nodeArr as $value){ $childArr = explode('=', $value); $finalArray[$childArr[0]] = $childArr[1]; }
Сериализация:
foreach ($income_data as $key => &$value) { $value = urlencode($value); } $data_str = serialize($income_data);
десериализируются:
$data = unserialize($data_str); foreach ($data as $key => &$value) { $value = urldecode($value); }
этот работал для меня.
function mb_unserialize($string) { $string = mb_convert_encoding($string, "UTF-8", mb_detect_encoding($string, "UTF-8, ISO-8859-1, ISO-8859-15", true)); $string = preg_replace_callback( '/s:([0-9]+):"(.*?)";/', function ($match) { return "s:".strlen($match[2]).":\"".$match[2]."\";"; }, $string ); return unserialize($string); }
/** * MULIT-BYTE UNSERIALIZE * * UTF-8 will screw up a serialized string * * @param string * @return string */ function mb_unserialize($string) { $string = preg_replace_callback('/!s:(\d+):"(.*?)";!se/', function($matches) { return 's:'.strlen($matches[1]).':"'.$matches[1].'";'; }, $string); return unserialize($string); }