可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am using Hotaru CMS with the Image Upload plugin, I get this error if I try to attach an image to a post, otherwise there is no error.
The offending code (error points to line with **):
/**
* Retrieve submission step data
*
* @param $key - empty when setting
* @return bool
*/
public function loadSubmitData($h, $key = \'\')
{
// delete everything in this table older than 30 minutes:
$this->deleteTempData($h->db);
if (!$key) { return false; }
$cleanKey = preg_replace(\'/[^a-z0-9]+/\',\'\',$key);
if (strcmp($key,$cleanKey) != 0) {
return false;
} else {
$sql = \"SELECT tempdata_value FROM \" . TABLE_TEMPDATA . \" WHERE tempdata_key = %s ORDER BY tempdata_updatedts DESC LIMIT 1\";
$submitted_data = $h->db->get_var($h->db->prepare($sql, $key));
**if ($submitted_data) { return unserialize($submitted_data); } else { return false; }**
}
}
Data from the table, notice the end bit has the image info, I am not an expert in PHP so I was wondering what you guys/gals might think?
tempdata_value:
a:10:{s:16:\"submit_editorial\";b:0;s:15:\"submit_orig_url\";s:13:\"www.bbc.co.uk\";s:12:\"submit_title\";s:14:\"No title found\";s:14:\"submit_content\";s:12:\"dnfsdkfjdfdf\";s:15:\"submit_category\";i:2;s:11:\"submit_tags\";s:3:\"bbc\";s:9:\"submit_id\";b:0;s:16:\"submit_subscribe\";i:0;s:15:\"submit_comments\";s:4:\"open\";s:5:\"image\";s:19:\"C:fakepath100.jpg\";}
Edit: I think I\'ve found the serialize bit...
/**
* Save submission step data
*
* @return bool
*/
public function saveSubmitData($h)
{
// delete everything in this table older than 30 minutes:
$this->deleteTempData($h->db);
$sid = preg_replace(\'/[^a-z0-9]+/i\', \'\', session_id());
$key = md5(microtime() . $sid . rand());
$sql = \"INSERT INTO \" . TABLE_TEMPDATA . \" (tempdata_key, tempdata_value, tempdata_updateby) VALUES (%s,%s, %d)\";
$h->db->query($h->db->prepare($sql, $key, serialize($h->vars[\'submitted_data\']), $h->currentUser->id));
return $key;
}
回答1:
unserialize() [function.unserialize]: Error at offset
was dues to invalid serialization data
due to invalid length
Quick Fix
What you can do is is recalculating the length
of the elements in serialized array
You current serialized data
$data = \'a:10:{s:16:\"submit_editorial\";b:0;s:15:\"submit_orig_url\";s:13:\"www.bbc.co.uk\";s:12:\"submit_title\";s:14:\"No title found\";s:14:\"submit_content\";s:12:\"dnfsdkfjdfdf\";s:15:\"submit_category\";i:2;s:11:\"submit_tags\";s:3:\"bbc\";s:9:\"submit_id\";b:0;s:16:\"submit_subscribe\";i:0;s:15:\"submit_comments\";s:4:\"open\";s:5:\"image\";s:19:\"C:fakepath100.jpg\";}\';
Example without recalculation
var_dump(unserialize($data));
Output
Notice: unserialize() [function.unserialize]: Error at offset 337 of 338 bytes
Recalculating
$data = preg_replace(\'!s:(\\d+):\"(.*?)\";!e\', \"\'s:\'.strlen(\'$2\').\':\\\"$2\\\";\'\", $data);
var_dump(unserialize($data));
Output
array
\'submit_editorial\' => boolean false
\'submit_orig_url\' => string \'www.bbc.co.uk\' (length=13)
\'submit_title\' => string \'No title found\' (length=14)
\'submit_content\' => string \'dnfsdkfjdfdf\' (length=12)
\'submit_category\' => int 2
\'submit_tags\' => string \'bbc\' (length=3)
\'submit_id\' => boolean false
\'submit_subscribe\' => int 0
\'submit_comments\' => string \'open\' (length=4)
\'image\' => string \'C:fakepath100.jpg\' (length=17)
Recommendation .. I
Instead of using this kind of quick fix ... i\"ll advice you update the question with
================================ EDIT 1 ===============================
The Error
The Error was generated because of use of double quote \"
instead single quote \'
that is why C:\\fakepath\\100.png
was converted to C:fakepath100.jpg
To fix the error
You need to change $h->vars[\'submitted_data\']
From (Note the singe quite \'
)
Replace
$h->vars[\'submitted_data\'][\'image\'] = \"C:\\fakepath\\100.png\" ;
With
$h->vars[\'submitted_data\'][\'image\'] = \'C:\\fakepath\\100.png\' ;
Additional Filter
You can also add this simple filter before you call serialize
function satitize(&$value, $key)
{
$value = addslashes($value);
}
array_walk($h->vars[\'submitted_data\'], \"satitize\");
If you have UTF Characters you can also run
$h->vars[\'submitted_data\'] = array_map(\"utf8_encode\",$h->vars[\'submitted_data\']);
How to detect the problem in future serialized data
findSerializeError ( $data1 ) ;
Output
Diffrence 9 != 7
-> ORD number 57 != 55
-> Line Number = 315
-> Section Data1 = pen\";s:5:\"image\";s:19:\"C:fakepath100.jpg
-> Section Data2 = pen\";s:5:\"image\";s:17:\"C:fakepath100.jpg
^------- The Error (Element Length)
findSerializeError
Function
function findSerializeError($data1) {
echo \"<pre>\";
$data2 = preg_replace ( \'!s:(\\d+):\"(.*?)\";!e\', \"\'s:\'.strlen(\'$2\').\':\\\"$2\\\";\'\",$data1 );
$max = (strlen ( $data1 ) > strlen ( $data2 )) ? strlen ( $data1 ) : strlen ( $data2 );
echo $data1 . PHP_EOL;
echo $data2 . PHP_EOL;
for($i = 0; $i < $max; $i ++) {
if (@$data1 {$i} !== @$data2 {$i}) {
echo \"Diffrence \", @$data1 {$i}, \" != \", @$data2 {$i}, PHP_EOL;
echo \"\\t-> ORD number \", ord ( @$data1 {$i} ), \" != \", ord ( @$data2 {$i} ), PHP_EOL;
echo \"\\t-> Line Number = $i\" . PHP_EOL;
$start = ($i - 20);
$start = ($start < 0) ? 0 : $start;
$length = 40;
$point = $max - $i;
if ($point < 20) {
$rlength = 1;
$rpoint = - $point;
} else {
$rpoint = $length - 20;
$rlength = 1;
}
echo \"\\t-> Section Data1 = \", substr_replace ( substr ( $data1, $start, $length ), \"<b style=\\\"color:green\\\">{$data1 {$i}}</b>\", $rpoint, $rlength ), PHP_EOL;
echo \"\\t-> Section Data2 = \", substr_replace ( substr ( $data2, $start, $length ), \"<b style=\\\"color:red\\\">{$data2 {$i}}</b>\", $rpoint, $rlength ), PHP_EOL;
}
}
}
A better way to save to Database
$toDatabse = base64_encode(serialize($data)); // Save to database
$fromDatabase = unserialize(base64_decode($data)); //Getting Save Format
回答2:
I don\'t have enough reputation to comment, so I hope this is seen by people using the above \"correct\" answer:
Since php 5.5 the /e modifier in preg_replace() has been deprecated completely and the preg_match above will error out. The php documentation recommends using preg_match_callback in its place.
Please find the following solution as an alternative to the above proposed preg_match.
$fixed_data = preg_replace_callback ( \'!s:(\\d+):\"(.*?)\";!\', function($match) {
return ($match[1] == strlen($match[2])) ? $match[0] : \'s:\' . strlen($match[2]) . \':\"\' . $match[2] . \'\";\';
},$bad_data );
回答3:
There\'s another reason unserialize()
failed because you improperly put serialized data into the database see Official Explanation here. Since serialize()
returns binary data and php variables don\'t care encoding methods, so that putting it into TEXT, VARCHAR() will cause this error.
Solution: store serialized data into BLOB in your table.
回答4:
Quick Fix
Recalculating the length of the elements in serialized array - but don\'t use (preg_replace) it\'s deprecated - better use preg_replace_callback:
$data = preg_replace_callback(\'!s:(\\d+):\"(.*?)\";!\', function($m) { return \'s:\'.mb_strlen($m[2]).\':\"\'.$m[2].\'\";\'; }, $data);
回答5:
This error is caused because your charset is wrong.
Set charset after open tag:
header(\'Content-Type: text/html; charset=utf-8\');
And set charset utf8 in your database :
mysql_query(\"SET NAMES \'utf8\'\");
回答6:
public function unserializeKeySkills($string) {
$output = array();
$string = trim(preg_replace(\'/\\s\\s+/\', \' \',$string));
$string = preg_replace_callback(\'!s:(\\d+):\"(.*?)\";!\', function($m) { return \'s:\'.strlen($m[2]).\':\"\'.$m[2].\'\";\'; }, utf8_encode( trim(preg_replace(\'/\\s\\s+/\', \' \',$string)) ));
try {
$output = unserialize($string);
} catch (\\Exception $e) {
\\Log::error(\"unserialize Data : \" .print_r($string,true));
}
return $output;
}
回答7:
You can fix broken serialize string using following function, with multibyte character handling.
function repairSerializeString($value)
{
$regex = \'/s:([0-9]+):\"(.*?)\"/\';
return preg_replace_callback(
$regex, function($match) {
return \"s:\".mb_strlen($match[2]).\":\\\"\".$match[2].\"\\\"\";
},
$value
);
}
回答8:
$badData = \'a:2:{i:0;s:16:\"as:45:\"d\";
Is \\n\";i:1;s:19:\"as:45:\"d\";
Is \\r\\n\";}\';
You can not fix a broken serialize string using the proposed regexes:
$data = preg_replace(\'!s:(\\d+):\"(.*?)\";!e\', \"\'s:\'.strlen(\'$2\').\':\\\"$2\\\";\'\", $badData);
var_dump(@unserialize($data)); // Output: bool(false)
// or
$data = preg_replace_callback(
\'/s:(\\d+):\"(.*?)\";/\',
function($m){
return \'s:\' . mb_strlen($m[2]) . \':\"\' . $m[2] . \'\";\';
},
$badData
);
var_dump(@unserialize($data)); // Output: bool(false)
You can fix broken serialize string using following regex:
$data = preg_replace_callback(
\'/(?<=^|\\{|;)s:(\\d+):\\\"(.*?)\\\";(?=[asbdiO]\\:\\d|N;|\\}|$)/s\',
function($m){
return \'s:\' . mb_strlen($m[2]) . \':\"\' . $m[2] . \'\";\';
},
$badData
);
var_dump(@unserialize($data));
Output
array(2) {
[0] =>
string(17) \"as:45:\"d\";
Is \\n\"
[1] =>
string(19) \"as:45:\"d\";
Is \\r\\n\"
}
or
array(2) {
[0] =>
string(16) \"as:45:\"d\";
Is \\n\"
[1] =>
string(18) \"as:45:\"d\";
Is \\r\\n\"
}
回答9:
the official docs says it should return false and set E_NOTICE
but since you got error then the error reporting is set to be triggered by E_NOTICE
here is a fix to allow you detect false returned by unserialize
$old_err=error_reporting();
error_reporting($old_err & ~E_NOTICE);
$object = unserialize($serialized_data);
error_reporting($old_err);
you might want to consider use base64 encode/decode
$string=base64_encode(serialize($obj));
unserialize(base64_decode($string));
回答10:
In my case I was storing serialized data in BLOB
field of MySQL DB which apparently wasn\'t big enough to contain the whole value and truncated it. Such a string obviously could not be unserialized.
Once converted that field to MEDIUMBLOB
the problem dissipated.
Also it may be needed to switch in table options ROW_FORMAT
to DYNAMIC
or COMPRESSED
.
回答11:
After having tried some things on this page without success I had a look in the page-source and remarked that all quotes in the serialized string have been replaced by html-entities.
Decoding these entities helps avoiding much headache:
$myVar = html_entity_decode($myVar);
回答12:
You will have to alter the collation type to utf8_unicode_ci
and the problem will be fixed.
回答13:
Another reason of this problem can be column type of \"payload\" sessions table. If you have huge data on session, a text column wouldn\'t be enough. You will need MEDIUMTEXT or even LONGTEXT.
回答14:
I faced same problem while unserializing data. Found out that if there\'s a \", \', :, or ; in any of the array values, the serialization gets corrupted. I had a : in my array, so removed it and it was fixed.
Hope it helps someone.