我有一个由PHP序列化的大规模多维数组。它已存储在MySQL中,并且数据字段不够大......结尾已被切断......我需要提取数据...... unserialize
不会工作......有没有人知道一个可以关闭所有数组的代码......重新计算字符串长度......手动数据太多了。
非常感谢。
答案 0 :(得分:32)
这是重新计算序列化数组中元素的长度:
$fixed = preg_replace_callback(
'/s:([0-9]+):\"(.*?)\";/',
function ($matches) { return "s:".strlen($matches[2]).':"'.$matches[2].'";'; },
$serialized
);
但是,如果您的字符串包含";
,则无效。在这种情况下,无法自动修复序列化数组字符串 - 需要手动编辑。
答案 1 :(得分:13)
我已尝试过这篇文章中发现的所有内容,但对我来说没有任何作用。经过几个小时的痛苦,我在google的深层页面找到了最终的工作:
function fix_str_length($matches) {
$string = $matches[2];
$right_length = strlen($string); // yes, strlen even for UTF-8 characters, PHP wants the mem size, not the char count
return 's:' . $right_length . ':"' . $string . '";';
}
function fix_serialized($string) {
// securities
if ( !preg_match('/^[aOs]:/', $string) ) return $string;
if ( @unserialize($string) !== false ) return $string;
$string = preg_replace("%\n%", "", $string);
// doublequote exploding
$data = preg_replace('%";%', "µµµ", $string);
$tab = explode("µµµ", $data);
$new_data = '';
foreach ($tab as $line) {
$new_data .= preg_replace_callback('%\bs:(\d+):"(.*)%', 'fix_str_length', $line);
}
return $new_data;
}
您按如下方式调用例行程序:
//Let's consider we store the serialization inside a txt file
$corruptedSerialization = file_get_contents('corruptedSerialization.txt');
//Try to unserialize original string
$unSerialized = unserialize($corruptedSerialization);
//In case of failure let's try to repair it
if(!$unSerialized){
$repairedSerialization = fix_serialized($corruptedSerialization);
$unSerialized = unserialize($repairedSerialization);
}
//Keep your fingers crossed
var_dump($unSerialized);
答案 2 :(得分:7)
1)尝试在线:
Serialized String Fixer (online tool)
2)使用功能:
unserialize(
serialize_corrector(
$serialized_string ) ) ;
代码:
function serialize_corrector($serialized_string){
// at first, check if "fixing" is really needed at all. After that, security checkup.
if ( @unserialize($serialized_string) !== true && preg_match('/^[aOs]:/', $serialized_string) ) {
$serialized_string = preg_replace_callback( '/s\:(\d+)\:\"(.*?)\";/s', function($matches){return 's:'.strlen($matches[2]).':"'.$matches[2].'";'; }, $serialized_string );
}
return $serialized_string;
}
答案 3 :(得分:2)
使用preg_replace_callback()
代替preg_replace(.../e)
(因为/e
修饰符为deprecated)。
$fixed_serialized_String = preg_replace_callback('/s:([0-9]+):\"(.*?)\";/',function($match) {
return "s:".strlen($match[2]).':"'.$match[2].'";';
}, $serializedString);
$correct_array= unserialize($fixed_serialized_String);
答案 4 :(得分:1)
以下代码段会尝试阅读&解析递归损坏的序列化字符串(blob数据)。例如,如果您存储到数据库列字符串太长并且它被切断了。保证数字基元和布尔有效,字符串可能被切断和/或数组键可能丢失。该例程可能是有用的,例如如果恢复重要(不是全部)数据部分是您的充分解决方案。
class Unserializer
{
/**
* Parse blob string tolerating corrupted strings & arrays
* @param string $str Corrupted blob string
*/
public static function parseCorruptedBlob(&$str)
{
// array pattern: a:236:{...;}
// integer pattern: i:123;
// double pattern: d:329.0001122;
// boolean pattern: b:1; or b:0;
// string pattern: s:14:"date_departure";
// null pattern: N;
// not supported: object O:{...}, reference R:{...}
// NOTES:
// - primitive types (bool, int, float) except for string are guaranteed uncorrupted
// - arrays are tolerant to corrupted keys/values
// - references & objects are not supported
// - we use single byte string length calculation (strlen rather than mb_strlen) since source string is ISO-8859-2, not utf-8
if(preg_match('/^a:(\d+):{/', $str, $match)){
list($pattern, $cntItems) = $match;
$str = substr($str, strlen($pattern));
$array = [];
for($i=0; $i<$cntItems; ++$i){
$key = self::parseCorruptedBlob($str);
if(trim($key)!==''){ // hmm, we wont allow null and "" as keys..
$array[$key] = self::parseCorruptedBlob($str);
}
}
$str = ltrim($str, '}'); // closing array bracket
return $array;
}elseif(preg_match('/^s:(\d+):/', $str, $match)){
list($pattern, $length) = $match;
$str = substr($str, strlen($pattern));
$val = substr($str, 0, $length + 2); // include also surrounding double quotes
$str = substr($str, strlen($val) + 1); // include also semicolon
$val = trim($val, '"'); // remove surrounding double quotes
if(preg_match('/^a:(\d+):{/', $val)){
// parse instantly another serialized array
return (array) self::parseCorruptedBlob($val);
}else{
return (string) $val;
}
}elseif(preg_match('/^i:(\d+);/', $str, $match)){
list($pattern, $val) = $match;
$str = substr($str, strlen($pattern));
return (int) $val;
}elseif(preg_match('/^d:([\d.]+);/', $str, $match)){
list($pattern, $val) = $match;
$str = substr($str, strlen($pattern));
return (float) $val;
}elseif(preg_match('/^b:(0|1);/', $str, $match)){
list($pattern, $val) = $match;
$str = substr($str, strlen($pattern));
return (bool) $val;
}elseif(preg_match('/^N;/', $str, $match)){
$str = substr($str, strlen('N;'));
return null;
}
}
}
// usage:
$unserialized = Unserializer::parseCorruptedBlob($serializedString);
答案 5 :(得分:0)
基于@Emil M答案 这是一个固定版本,适用于包含双引号的文本。
function fix_broken_serialized_array($match) {
return "s:".strlen($match[2]).":\"".$match[2]."\";";
}
$fixed = preg_replace_callback(
'/s:([0-9]+):"(.*?)";/',
"fix_broken_serialized_array",
$serialized
);
答案 6 :(得分:0)
$output_array = unserialize(My_checker($serialized_string));
代码:
function My_checker($serialized_string){
// securities
if (empty($serialized_string)) return '';
if ( !preg_match('/^[aOs]:/', $serialized_string) ) return $serialized_string;
if ( @unserialize($serialized_string) !== false ) return $serialized_string;
return
preg_replace_callback(
'/s\:(\d+)\:\"(.*?)\";/s',
function ($matches){ return 's:'.strlen($matches[2]).':"'.$matches[2].'";'; },
$serialized_string )
;
}
答案 7 :(得分:0)
结论:-) 在3天(而不是2个估计的小时)内,将祝福的WordPress网站迁移到一个新域名后,我终于找到了该页面! 同事们,请把它当作我对所有答案的“谢谢”(Thank_You_Very_Much_Indeed)。 下面的代码由您所有的解决方案组成,几乎没有添加。 杰斐依(JFYI):对我个人而言,解决方案3最为有效。卡玛勒·萨利赫(Kamal Saleh)-你是最好的!!
DECLARE @list varchar(max) = '';
DECLARE @comma varchar(2) = '';
SELECT @list = @list + @comma + County, @comma = ', ' FROM County
print @list
答案 8 :(得分:-2)
我怀疑是否有人会编写代码来检索部分保存的数组:) 我修理过这样的东西,但只需要手工操作,花了几个小时,然后我意识到我不需要阵列的那一部分......
除非它真正重要的数据(我的意思是非常重要),否则你最好离开这一行
答案 9 :(得分:-2)
您可以通过数组将无效的序列化数据恢复正常:)
str = "a:1:{i:0;a:4:{s:4:\"name\";s:26:\"20141023_544909d85b868.rar\";s:5:\"dname\";s:20:\"HTxRcEBC0JFRWhtk.rar\";s:4:\"size\";i:19935;s:4:\"dead\";i:0;}}";
preg_match_all($re, $str, $matches);
if(is_array($matches) && !empty($matches[1]) && !empty($matches[2]))
{
foreach($matches[1] as $ksel => $serv)
{
if(!empty($serv))
{
$retva[] = $serv;
}else{
$retva[] = $matches[2][$ksel];
}
}
$count = 0;
$arrk = array();
$arrv = array();
if(is_array($retva))
{
foreach($retva as $k => $va)
{
++$count;
if($count/2 == 1)
{
$arrv[] = $va;
$count = 0;
}else{
$arrk[] = $va;
}
}
$returnse = array_combine($arrk,$arrv);
}
}
print_r($returnse);
答案 10 :(得分:-3)
序列化几乎总是很糟糕,因为你无法以任何方式搜索它。对不起,但好像你已经回到了角落......
答案 11 :(得分:-5)
我认为这几乎是不可能的。 在修复阵列之前,您需要知道它是如何损坏的。 有多少孩子失踪?内容是什么?
抱歉,你不能这样做。
证明:
<?php
$serialized = serialize(
[
'one' => 1,
'two' => 'nice',
'three' => 'will be damaged'
]
);
var_dump($serialized); // a:3:{s:3:"one";i:1;s:3:"two";s:4:"nice";s:5:"three";s:15:"will be damaged";}
var_dump(unserialize('a:3:{s:3:"one";i:1;s:3:"two";s:4:"nice";s:5:"tee";s:15:"will be damaged";}')); // please note 'tee'
var_dump(unserialize('a:3:{s:3:"one";i:1;s:3:"two";s:4:"nice";s:5:"three";s:')); // serialized string is truncated
即使您可以重新计算键/值的长度,也不能信任从此源检索的数据,因为您无法重新计算这些值的值。例如。如果序列化数据是对象,则不再可以访问您的属性。