PluginProbe
WP Synchro – The Ultimate WordPress Migration Tool / trunk
WP Synchro – The Ultimate WordPress Migration Tool vtrunk
1.16.1 1.16.0 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.10.0 1.11.0 1.11.1 1.11.2 1.11.3 1.11.4 1.11.5 1.12.0 1.13.0 1.14.0 1.15.0 1.2.0 1.3.0 1.3.1 1.3.2 All 45 releases
wpsynchro / src / Database / SerializedStringHandler.php

SerializedStringHandler.php in WP Synchro – The Ultimate WordPress Migration Tool trunk, at src/Database/SerializedStringHandler.php

99 lines 4.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPSynchro\Database;
4
5 use WPSynchro\Database\Exception\SerializedStringException;
6
7 /**
8 * Handle serialized strings
9 */
10 class SerializedStringHandler
11 {
12 const STRING_START_PART = 's:';
13 const STRING_TOKENIZE_LENGTH = 2;
14 const STRING_END_PART = '";';
15 const MAX_TIME_ALLOWED = 500; // ms
16
17 /**
18 * Do search/replaces in serialized data
19 * @throws SerializedStringException Throws exception when serialized string is broken and no search/replace could be done
20 */
21 public function searchReplaceSerialized(string &$data, array $search_replaces)
22 {
23 $start_time = microtime(true);
24 $rounds = 0;
25 $offset = 0;
26 $last_offset = -1;
27 while (($data_pos = strpos($data, self::STRING_START_PART, $offset)) !== false) {
28 $rounds++;
29 // Make sure we dont do endless loops, if the serialized content is broken
30 if ($offset == $last_offset) {
31 throw new SerializedStringException('Skipping serialized value that is broken, so no search/replaces could be done in this value.', 0, $data);
32 }
33 $last_offset = $offset;
34
35 // Every some rounds, we just check that we have not spent more time here than we should.
36 if ($rounds % 10000 == 0) {
37 $current_time = microtime(true);
38 $time_spent_in_ms = ($current_time - $start_time) * 1000;
39 if ($time_spent_in_ms > self::MAX_TIME_ALLOWED) {
40 // Likely that something is broken, so we break
41 throw new SerializedStringException(
42 'Skipping large serialized value that could not be search/replaced within reasonable time. First part of string:',
43 0,
44 substr($data, 0, 200)
45 );
46 }
47 }
48
49 // Get string length
50 $length_start_pos = $data_pos + self::STRING_TOKENIZE_LENGTH;
51 $length_end_pos = strpos($data, ':', $length_start_pos);
52 $length_length = $length_end_pos - $length_start_pos;
53 $expected_string_length = substr($data, $length_start_pos, $length_length);
54
55 // Get string value
56 $string_start_pos = $length_start_pos + $length_length + 2;
57 $string_end_pos = $string_start_pos + $expected_string_length;
58 $string_length = $string_end_pos - $string_start_pos;
59
60 // Check that string ends there and if not, something is wrong and we abort
61 if (substr($data, $string_end_pos, 2) !== self::STRING_END_PART) {
62 throw new SerializedStringException('Skipping serialized value that is broken, so no search/replaces could be done in this value.', 0, $data);
63 }
64
65 $string_value = substr($data, $string_start_pos, $string_length);
66
67 // Set new offset
68 $data_end = $string_end_pos + 2;
69 $offset = $data_end;
70
71 // Do search/replace in string value
72 $string_value_replaced = $string_value;
73 $search_replace_changed_string = false;
74 foreach ($search_replaces as $replaces) {
75 $replaces_actually_done = 0;
76 $string_value_replaced = str_replace($replaces->from, $replaces->to, $string_value_replaced, $replaces_actually_done);
77 if ($replaces_actually_done > 0) {
78 $search_replace_changed_string = true;
79 }
80 }
81
82 // Change the string in the data, if it was changed
83 if ($search_replace_changed_string) {
84 $new_string = self::STRING_START_PART . strlen($string_value_replaced) . ':"' . $string_value_replaced . self::STRING_END_PART;
85 $new_string_length = strlen($new_string);
86 $data = substr_replace(
87 $data,
88 $new_string,
89 $data_pos,
90 $data_end - $data_pos
91 );
92
93 // Adjust our current position in serialized string, if the replaced string was longer or shorter
94 $offset += $new_string_length - ($data_end - $data_pos);
95 }
96 }
97 }
98 }
99