$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));
};
答案 0 :(得分:51)
我知道这张贴就像一年前一样,但我只是遇到了这个问题而遇到了这个问题,事实上我找到了解决方案。这段代码就像魅力一样!
背后的想法很简单。它只是通过重新计算上面@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
在我的机器上测试过,它就像魅力一样!
答案 1 :(得分:50)
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的东西,这更加标准化。
答案 2 :(得分:24)
Lionel Chan回答以使用PHP&gt; = 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);
}
自PHP 5.5起,此代码将 preg_replace_callback 用作preg_replace with the /e modifier is obsolete。
答案 3 :(得分:8)
问题是 -
在PHP 5.4之前,PHP的内部编码是ISO-8859-1,此编码对unicode为多字节的某些字符使用单个字节。结果是在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);
答案 4 :(得分:2)
回复上面的@Lionel,实际上如果序列化字符串本身包含char序列";
(引号后跟分号),你提出的函数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是要走的路,恕我直言
注意:我将此作为新答案发布,因为我不知道如何直接回复(这里是新的)。
答案 5 :(得分:1)
当另一端不是PHP时,不使用PHP序列化/反序列化。它并不是一种可移植的格式 - 例如,它甚至包含受保护键的ascii-1字符,这是你想要在javascript中处理的任何内容(即使它可以完美地工作,它只是非常难看)。
相反,请使用 JSON 等可移植格式。 XML也可以完成这项工作,但JSON的开销更少,程序员更友好,因为您可以轻松地将其解析为简单的数据结构,而不必处理XPath,DOM树等。
答案 6 :(得分:1)
这里还有一个小小的变化,希望有助于某人...我正在序列化一个数组,然后将其写入数据库。在检索数据时,反序列化操作失败。
事实证明,我写的数据库longtext字段是使用latin1而不是UTF8。当我把它切换成一切按计划工作时。
感谢上面所有提到字符编码的人,让我走上正轨!
答案 7 :(得分:0)
我建议你使用javascript编码为json,然后使用json_decode来反序列化。
答案 8 :(得分:0)
我们可以将字符串分解为数组:
$finalArray = array();
$nodeArr = explode('&', $_POST['formData']);
foreach($nodeArr as $value){
$childArr = explode('=', $value);
$finalArray[$childArr[0]] = $childArr[1];
}
答案 9 :(得分:0)
序列化:
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);
}
答案 10 :(得分:0)
这个对我有用。
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);
}
答案 11 :(得分:0)
在我的情况下,问题出在行结尾(可能是某些编辑器将我的文件从DOS更改为Unix)。
我把这些apadtive包装器放在一起:
function unserialize_fetchError($original, &$unserialized, &$errorMsg) {
$unserialized = @unserialize($original);
$errorMsg = error_get_last()['message'];
return ( $unserialized !== false || $original == 'b:0;' ); // "$original == serialize(false)" is a good serialization even if deserialization actually returns false
}
function unserialize_checkAllLineEndings($original, &$unserialized, &$errorMsg, &$lineEndings) {
if ( unserialize_fetchError($original, $unserialized, $errorMsg) ) {
$lineEndings = 'unchanged';
return true;
} elseif ( unserialize_fetchError(str_replace("\n", "\n\r", $original), $unserialized, $errorMsg) ) {
$lineEndings = '\n to \n\r';
return true;
} elseif ( unserialize_fetchError(str_replace("\n\r", "\n", $original), $unserialized, $errorMsg) ) {
$lineEndings = '\n\r to \n';
return true;
} elseif ( unserialize_fetchError(str_replace("\r\n", "\n", $original), $unserialized, $errorMsg) ) {
$lineEndings = '\r\n to \n';
return true;
} //else
return false;
}
答案 12 :(得分:0)
此解决方案对我有用:
$unserialized = unserialize(utf8_encode($st));
答案 13 :(得分:-1)
/**
* 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);
}