PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.11.2
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.11.2
4.11.2 4.11.1 4.11.0 4.10.0 4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Database / SearchReplace.php
wp-staging / Framework / Database Last commit date
Exporter 1 week ago QueryBuilder 1 week ago CustomTable.php 1 week ago DbInfo.php 1 week ago ExcludedTables.php 1 week ago ExternalDatabaseConfiguration.php 1 week ago OptionPreservationHandler.php 1 week ago SearchReplace.php 3 days ago SelectedTables.php 1 week ago TableDto.php 1 week ago TableService.php 1 week ago TablesRenamer.php 1 week ago WpDbInfo.php 1 week ago WpOptionsInfo.php 1 week ago iDbInfo.php 3 years ago
SearchReplace.php
286 lines
1 <?php
2
3 namespace WPStaging\Framework\Database;
4
5 use WPStaging\Framework\Traits\ApplyFiltersTrait;
6 use WPStaging\Framework\Traits\DebugLogTrait;
7 use WPStaging\Framework\Traits\SerializeTrait;
8 use WPStaging\Framework\Traits\UrlTrait;
9
10
11
12
13
14 class SearchReplace
15 {
16 use ApplyFiltersTrait;
17 use DebugLogTrait;
18 use SerializeTrait;
19 use UrlTrait;
20
21
22
23
24
25
26
27
28
29 const FILTER_REPLACE_EXTENDED_DATA = 'wpstg.database.searchreplace.replace_extended_data';
30
31
32 private $search;
33
34
35 private $replace;
36
37
38 private $exclude;
39
40
41 private $caseSensitive;
42
43
44 private $currentSearch;
45
46
47 private $currentReplace;
48
49
50 private $isWpBakeryActive;
51
52 protected $smallerReplacement = PHP_INT_MAX;
53
54 public function __construct(array $search = [], array $replace = [], $caseSensitive = true, array $exclude = [])
55 {
56 $this->search = $search;
57 $this->replace = $replace;
58 $this->caseSensitive = $caseSensitive;
59 $this->exclude = $exclude;
60 $this->isWpBakeryActive = false;
61 }
62
63
64
65
66 public function getSmallerSearchLength()
67 {
68 if ($this->smallerReplacement < PHP_INT_MAX) {
69 return $this->smallerReplacement;
70 }
71
72 foreach ($this->search as $search) {
73 if (strlen($search) < $this->smallerReplacement) {
74 $this->smallerReplacement = strlen($search);
75 }
76 }
77
78 return $this->smallerReplacement;
79 }
80
81
82
83
84
85 public function replace($data)
86 {
87 if (defined('DISABLE_WPSTG_SEARCH_REPLACE') && (bool)DISABLE_WPSTG_SEARCH_REPLACE) {
88 return $data;
89 }
90
91 if (!$this->search || !$this->replace) {
92 return $data;
93 }
94
95 $totalSearch = count($this->search);
96 $totalReplace = count($this->replace);
97 if ($totalSearch !== $totalReplace) {
98 throw new \RuntimeException(
99 sprintf(
100 'Can not search and replace. There are %d items to search and %d items to replace',
101 $totalSearch,
102 $totalReplace
103 )
104 );
105 }
106
107 for ($i = 0; $i < $totalSearch; $i++) {
108 $this->currentSearch = (string)$this->search[$i];
109 $this->currentReplace = (string)$this->replace[$i];
110 $data = $this->walker($data);
111 }
112
113 return $data;
114 }
115
116
117
118
119
120
121
122
123 public function replaceExtended($data)
124 {
125 if (defined('DISABLE_WPSTG_SEARCH_REPLACE') && (bool)DISABLE_WPSTG_SEARCH_REPLACE) {
126 return $data;
127 }
128
129 if ($this->isWpBakeryActive) {
130 $data = preg_replace_callback('/\[vc_raw_html\](.+?)\[\/vc_raw_html\]/S', [$this, 'replaceWpBakeryValues'], $data);
131 }
132
133 $data = $this->replace($data);
134
135 if (!function_exists('has_filter') || has_filter(self::FILTER_REPLACE_EXTENDED_DATA) === false) {
136 return $data;
137 }
138
139 return $this->applyFilters(self::FILTER_REPLACE_EXTENDED_DATA, $data, $this->search, $this->replace);
140 }
141
142 public function replaceWpBakeryValues($matched)
143 {
144 $data = $this->base64Decode($matched[1]);
145 $data = $this->replace($data);
146 return '[vc_raw_html]' . base64_encode($data) . '[/vc_raw_html]';
147 }
148
149 public function setSearch(array $search)
150 {
151 $this->search = $search;
152 return $this;
153 }
154
155 public function setReplace(array $replace)
156 {
157 $this->replace = $replace;
158 return $this;
159 }
160
161
162
163
164
165
166
167
168
169
170
171 public function appendSearchReplacePair(string $search, string $replace)
172 {
173 $this->search[] = $search;
174 $this->replace[] = $replace;
175 $this->smallerReplacement = PHP_INT_MAX;
176 return $this;
177 }
178
179 public function setCaseSensitive($caseSensitive)
180 {
181 $this->caseSensitive = $caseSensitive;
182 return $this;
183 }
184
185 public function setExclude(array $exclude)
186 {
187 $this->exclude = $exclude;
188 return $this;
189 }
190
191
192
193
194
195
196 public function setWpBakeryActive($isActive = true)
197 {
198 $this->isWpBakeryActive = $isActive;
199 return $this;
200 }
201
202
203
204
205
206 private function walker($data)
207 {
208 switch (gettype($data)) {
209 case "string":
210 return $this->replaceString($data);
211 case "array":
212 return $this->replaceArray($data);
213 case "object":
214 return $this->replaceObject($data);
215 }
216
217 return $data;
218 }
219
220
221
222
223
224 private function replaceString($data)
225 {
226 if (!$this->isSerialized($data)) {
227 return $this->strReplace($data);
228 }
229
230 $rejected = false;
231 $unserialized = $this->safeMaybeUnserialize($data, [\stdClass::class], $rejected);
232
233 if ($rejected || $unserialized === false) {
234 return $data;
235 }
236
237 return serialize($this->walker($unserialized));
238 }
239
240 private function replaceArray(array $data)
241 {
242 foreach ($data as $key => $value) {
243 $data[$key] = $this->walker($value);
244 }
245
246 return $data;
247 }
248
249 private function replaceObject($data)
250 {
251
252
253
254 $props = get_object_vars($data);
255 if (!empty($props['__PHP_Incomplete_Class_Name'])) {
256 return $data;
257 }
258
259 foreach ($props as $key => $value) {
260 if ($key === '' || (isset($key[0]) && ord($key[0]) === 0)) {
261 continue;
262 }
263
264 $data->{$key} = $this->walker($value);
265 }
266
267 return $data;
268 }
269
270 private function strReplace($data = '')
271 {
272 $regexExclude = '';
273 foreach ($this->exclude as $excludeString) {
274
275 $regexExclude .= $excludeString . '(*SKIP)(*FAIL)|';
276 }
277
278 $pattern = '#' . $regexExclude . preg_quote($this->currentSearch, '#') . '#';
279 if (!$this->caseSensitive) {
280 $pattern .= 'i';
281 }
282
283 return preg_replace($pattern, $this->currentReplace, $data);
284 }
285 }
286