Skip to content

Instantly share code, notes, and snippets.

@droduit
Last active May 27, 2021 15:07
Show Gist options
  • Save droduit/a3f9304d08a3d95d9e5d48b173e070a6 to your computer and use it in GitHub Desktop.
Save droduit/a3f9304d08a3d95d9e5d48b173e070a6 to your computer and use it in GitHub Desktop.
Fix serialized data broken due to search & replace in database
<?php
/*
* The `fix_serialized` function fixes serialized data which has been corrupted by an incorrect byte count length,
* especially in the case of a search & replace done on a dump of a wordpress database.
*/
$corruptedSerialization = 'a:3:{i:0;s:150:".DS_Store";i:1;s:100:".git";i:2;s:190:"node_modules";}';
if (is_serialized($corruptedSerialization)) {
$fixed = fix_serialized($corruptedSerialization);
print_r(unserialize($fixed));
}
// ===================================================
function fix_serialized($serialized) {
$fixed = fix_inner_serialized($serialized);
if (@unserialize($fixed)) {
return $fixed;
}
return fix_serialized_parts($fixed);
}
function fix_inner_serialized($string) {
return preg_replace_callback(
'/s:([0-9]+):\"(a:[0-9]+:{.*?})\";/',
function ($matches) {
$serializedString = stripslashes($matches[2]);
$fixed = fix_serialized_parts($serializedString);
return "s:".strlen($fixed).':"'.$fixed.'";';
},
$string
);
}
function fix_serialized_parts($string) {
if (!preg_match('/^[aOs]:/', $string) ) {
return $string;
}
$string = preg_replace("%\n%", "", $string);
return preg_replace_callback(
'/s:([0-9]+):\"(.*?)\";/',
function ($matches) {
if (preg_match('/a:[0-9]+:{/', $matches[2])) {
return $matches[0];
}
return "s:".strlen($matches[2]).':"'.$matches[2].'";';
},
$string
);
}
function is_serialized($data) {
if (!is_string($data)) {
return false;
}
$data = trim($data);
if ('N;' == $data) {
return true;
}
if (!preg_match('/^([adObis]):/', $data, $badions)) {
return false;
}
switch ($badions[1]) {
case 'a' :
case 'O' :
case 's' :
if (preg_match("/^{$badions[1]}:[0-9]+:.*[;}]\$/s", $data)) {
return true;
}
break;
case 'b' :
case 'i' :
case 'd' :
if (preg_match("/^{$badions[1]}:[0-9.E-]+;\$/", $data)) {
return true;
}
break;
}
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment