PHP取消序列化失败,使用非编码字符?
我建议您使用javascript编码为json,然后使用来取消序列化。不要使用PHP序列化/取消序列化,而另一端不是PHP。它并不意味着是一种可移植的格式——例如,它甚至包括用于受保护密钥的ascii-1字符,这在javascript中是不需要处理的(尽管它工作得非常好,但它非常难看)PHP取消序列化失败,使用非编码字符?,php,character,encode,serialization,Php,Character,Encode,Serialization,我建议您使用javascript编码为json,然后使用来取消序列化。不要使用PHP序列化/取消序列化,而另一端不是PHP。它并不意味着是一种可移植的格式——例如,它甚至包括用于受保护密钥的ascii-1字符,这在javascript中是不需要处理的(尽管它工作得非常好,但它非常难看) 相反,使用类似JSON的可移植格式。XML也可以完成这项工作,但JSON的开销更小,而且对程序员更友好,因为您可以轻松地将其解析为简单的数据结构,而不必处理XPath、DOM树等。为什么取消序列化()失败的原因是
相反,使用类似JSON的可移植格式。XML也可以完成这项工作,但JSON的开销更小,而且对程序员更友好,因为您可以轻松地将其解析为简单的数据结构,而不必处理XPath、DOM树等。为什么
取消序列化()
失败的原因是:
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));
};
这是因为héllö
和wörld
的长度是错误的,因为PHP无法正确处理本机的多字节字符串:
$ser = 'a:2:{i:0;s:5:"héllö";i:1;s:5:"wörld";}';
但是,如果尝试取消序列化()
以下正确字符串:
echo strlen('héllö'); // 7
echo strlen('wörld'); // 6
如果使用PHPserialize()
,它应该正确计算多字节字符串索引的长度
另一方面,如果你想用多种(编程)语言处理序列化数据,你应该忘记它,转而使用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);
}
资料来源:
在我的机器上测试过,效果很好 作为对上面@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是前进的方向
注意:我将此作为新答案发布,因为我不知道如何直接回复(此处为新答案)。正如Alix所指出的,问题与编码有关
在PHP 5.4之前,PHP的内部编码是ISO-8859-1,这种编码对某些unicode中的多字节字符使用单字节。结果是,在UTF-8系统上序列化的多字节值在ISO-8859-1系统上不可读
避免这样的问题确保所有系统使用相同的编码:
$finalArray = array();
$nodeArr = explode('&', $_POST['formData']);
foreach($nodeArr as $value){
$childArr = explode('=', $value);
$finalArray[$childArr[0]] = $childArr[1];
}
mb_内部编码('utf-8');
$arr=array('foo'=>'bár');
$buf=序列化($arr);
您可以使用utf8(编码|解码)
进行清理:
$finalArray = array();
$nodeArr = explode('&', $_POST['formData']);
foreach($nodeArr as $value){
$childArr = explode('=', $value);
$finalArray[$childArr[0]] = $childArr[1];
}
//将系统编码设置为iso-8859-1
mb_内部_编码('iso-8859-1');
$arr=unserialize(utf8_编码($serialized));
印刷费($arr);
这里还有一个小小的变化,希望能对某人有所帮助……我正在序列化一个数组,然后将其写入数据库。在检索数据时,取消序列化操作失败
原来我写的数据库longtext字段使用的是latin1而不是UTF8。当我切换它时,一切都按计划进行了
感谢以上提到字符编码并使我走上正轨的所有人!答案已修改为使用PHP>=5.5:
/**
* 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);
}
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_回调,就像PHP 5.5一样。我们可以将字符串分解为一个数组:
$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);
}
在我的例子中,问题出在行结尾上(可能是某个编辑器将我的文件从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;
}
这个解决方案对我有效:
$unserialized = unserialize(utf8_encode($st));
也就是说,$ser='a:2:{i:0;s:5:'héllö;i:1;s:5:'wörld”};var_dump(unserialize($ser)),对我来说很好。你说失败是什么意思?调用unserialize()失败?更不用说从不受信任的源进行序列化可能会导致任意代码执行。不幸的是,其他人的工作将此选择强加给了我们。这在从旧项目/系统导入数据时尤其常见,因为该项目/系统的数据中已经建立了序列化。您将能够很快回复注释。继续贡献!干杯~很高兴知道。有解决方案吗?在我的例子中,问题出在数据库编码中,所以我在
?
中丢失了部分数据,但是这个函数帮助我使代码工作,即使这样,谢谢,这让我省去了大量的头痛!感谢+1这项非常有用的工作。我也测试了它,它对我的UTF-8数据也有效使用法语口音(我的服务器上是PHP5.3)。我在下面发布了你的函数改为使用PHP5.5。感谢你的有用贡献。实际上正则表达式是错误的,因为字符串本身可能包含与序列化模式无关的模式。例如,序列化部分…s:28:“一些”引号;在中间“…
之后,函数将返回…s:13:“some\”引号;在中间“…
。这是创建序列化的原因之一。json_encode:“此函数仅适用于UTF-8编码的数据…”以及在使用serialize()和unserialize()的情况下如果仍然失败,请检查您的存储介质。例如,mysql您应该存储为二进制或blob。如果您在mysql中存储为文本,它将无法处理您的多字节字符。在php环境之间切换时也要小心。在保存到数据库之前,我在本地计算机上遇到了编码问题,然后尝试在live server上取消序列化。Adj不使用字符计数解决了这个问题。这可能也是我两年前遇到的一个问题的答案,我从未找到答案。我必须使用这个版本来防止编码数组中的HTML字符串在未序列化的字符串中得到错误的转义双引号。非常感谢@David。我一直是
$unserialized = unserialize(utf8_encode($st));