Serialization is a way to store multidimensional data as a string. It’s commonly used in the WordPress database, because of the architecture of the tables. When it breaks (for various reasons) it’s a disaster. But not with our handy-dandy scripts.
Fixing a database dump with broken serialization
Steps are simple:
- Create the database dump (you should have a .sql file)
- Run the script: `php
./fix-serialization.php database.sql
` - Upload the .sql file back to the server
The script has been created by an awesome WordPress developer – Wojtek Szałkiewicz.
Recovering the corrupted serialized array
If you have a variable with a string which cannot be unserialized, try to use the below function:
/**
* Extract what remains from an unintentionally truncated serialized string
*
* @param string The serialized array
*/
public function repairSerializedArray($serialized)
{
$tmp = preg_replace('/^a:\d+:\{/', '', $serialized);
return $this->repairSerializedArray_R($tmp); // operates on and whittles down the actual argument
}
/**
* The recursive function that does all of the heavy lifing. Do not call directly.
* @param string The broken serialzized array
* @return string Returns the repaired string
*/
private function repairSerializedArray_R(&$broken)
{
// array and string length can be ignored
// sample serialized data
// a:0:{}
// s:4:"four";
// i:1;
// b:0;
// N;
$data = array();
$index = null;
$len = strlen($broken);
$i = 0;
while(strlen($broken))
{
$i++;
if ($i > $len)
{
break;
}
if (substr($broken, 0, 1) == '}') // end of array
{
$broken = substr($broken, 1);
return $data;
}
else
{
$bite = substr($broken, 0, 2);
switch($bite)
{
case 's:': // key or value
$re = '/^s:\d+:"([^\"]*)";/';
if (preg_match($re, $broken, $m))
{
if ($index === null)
{
$index = $m[1];
}
else
{
$data[$index] = $m[1];
$index = null;
}
$broken = preg_replace($re, '', $broken);
}
break;
case 'i:': // key or value
$re = '/^i:(\d+);/';
if (preg_match($re, $broken, $m))
{
if ($index === null)
{
$index = (int) $m[1];
}
else
{
$data[$index] = (int) $m[1];
$index = null;
}
$broken = preg_replace($re, '', $broken);
}
break;
case 'b:': // value only
$re = '/^b:[01];/';
if (preg_match($re, $broken, $m))
{
$data[$index] = (bool) $m[1];
$index = null;
$broken = preg_replace($re, '', $broken);
}
break;
case 'a:': // value only
$re = '/^a:\d+:\{/';
if (preg_match($re, $broken, $m))
{
$broken = preg_replace('/^a:\d+:\{/', '', $broken);
$data[$index] = $this->repairSerializedArray_R($broken);
$index = null;
}
break;
case 'N;': // value only
$broken = substr($broken, 2);
$data[$index] = null;
$index = null;
break;
}
}
}
return $data;
}
The usage is simple:
$data = @unserialize( $serialized );
if ( false === $data ) {
$data = repairSerializedArray( $serialized );
}
Let me know in the comments if it worked in your case! 👨💻