[BUG + SOLUTION] Replace string in database bugs
-
Hello
I found several bugs in the string replacement function and I fixed themYou can download the zip with the old and the new installer and make a diff to see the differences.
Installer old and new archiveIt has been tested with four different sites including multilingual e-commerce and did not generate any error in the serialized elements.
It took me a long time to debug and find the solution if you want to give me a gold license would be a nice gift otherwise it does nothing.
Below is a list of the problems encountered
1) In the old deserialization the types O, r, R were not considered
$regex = '!(?<=^|;)s:(\d+)(?=:"(.*?)";(?:}|a:|s:|b:|d:|i:|o:|N;))!s';
2) if you deserialize an object of an undefined class it will become of the __PHP_Incomplete_Class_Name class that is unusable
3) The fixSerialString function did not work with serializing an array with values that were themselves serialized
4) In some cases with complex objects, an infinite loop was generated. I did not understand the cause but having completely rewritten the logic the problem is no longer presented.
The plugins that gave me problems are
WPML
Woocommerce
Yoast SEOAll save extremely complex objects in the wp_options table.
Given these problems, there was only one possible solution; replace the strings without deserializing the objects.
The new function I wrote recursiveFixSerialString works without deserializing objects and working with multiple levels of serializations
/** * Fixes the string length of a string object that has been serialized but the length is broken * Work on nested serialized string recursively. * * @param string $data The string ojbect to recalculate the size on. * * @return string A serialized string that fixes and string length types */ public static function recursiveFixSerialString($data ) { if (!self::is_serialized_string($data)) { return $data; } $result = ''; $matches = null; $openLevel = 0; $openContent = ''; $openContentL2 = ''; // parse every char for ($i = 0 ; $i < strlen($data) ; $i++) { $cChar = $data[$i]; $addChar = true; if ($cChar == 's') { // test if is a open string if (preg_match ( '/^(s:\d+:")/', substr($data , $i) , $matches )) { $addChar = false; $openLevel ++; $i += strlen($matches[0]) - 1; } } else if ($openLevel > 0 && $cChar == '"') { // test if is a close string if (preg_match ( '/^";(?:}|a:|s:|S:|b:|d:|i:|o:|O:|C:|r:|R:|N;)/', substr($data , $i) ) ) { $addChar = false; switch ($openLevel) { case 1: // level 1 // flush string content $result .= 's:'.strlen($openContent).':"'.$openContent.'";'; $openContent = ''; break; case 2; // level 2 // fix serial string level2 $sublevelstr = self::recursiveFixSerialString($openContentL2); // flush content on level 1 $openContent .= 's:'.strlen($sublevelstr).':"'.$sublevelstr.'";'; $openContentL2 = ''; break; default: // level > 2 // keep writing at level 2; it will be corrected with recursion break; } $openLevel --; $closeString = '";'; $i += strlen($closeString) -1; } } if ($addChar) { switch ($openLevel) { case 0: // level 0 // add char on result $result .= $cChar; break; case 1: // level 1 // add char on content level1 $openContent .= $cChar; break; default: // level > 1 // add char on content level2 $openContentL2 .= $cChar; break; } } } return $result; }
I hope I’ve been useful in any case is a great plugin
- The topic ‘[BUG + SOLUTION] Replace string in database bugs’ is closed to new replies.