PluginProbe
UpdraftPlus: WP Backup & Migration Plugin / 1.16.5
UpdraftPlus: WP Backup & Migration Plugin v1.16.5
1.26.7 1.26.6 1.26.5 1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 All 371 releases
updraftplus / includes / class-manipulation-functions.php

class-manipulation-functions.php in UpdraftPlus: WP Backup & Migration Plugin 1.16.5, at includes/class-manipulation-functions.php

430 lines 14.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access.');
4
5 /**
6 * Here live manipulation functions that just transform input into output and do not perform any other activities
7 */
8 class UpdraftPlus_Manipulation_Functions {
9
10 /**
11 * Replace last occurence
12 *
13 * @param String $search The value being searched for, otherwise known as the needle
14 * @param String $replace The replacement value that replaces found search values
15 * @param String $subject The string or array being searched and replaced on, otherwise known as the haystack
16 * @param Boolean $case_sensitive Whether the replacement should be case sensitive or not
17 *
18 * @return String
19 */
20 public static function str_lreplace($search, $replace, $subject, $case_sensitive = true) {
21 $pos = $case_sensitive ? strrpos($subject, $search) : strripos($subject, $search);
22 if (false !== $pos) $subject = substr_replace($subject, $replace, $pos, strlen($search));
23 return $subject;
24 }
25
26 /**
27 * Replace the first, and only the first, instance within a string
28 *
29 * @param String $needle - the search term
30 * @param String $replace - the replacement term
31 * @param String $haystack - the string to replace within
32 *
33 * @return String - the filtered string
34 */
35 public static function str_replace_once($needle, $replace, $haystack) {
36 $pos = strpos($haystack, $needle);
37 return (false !== $pos) ? substr_replace($haystack, $replace, $pos, strlen($needle)) : $haystack;
38 }
39
40 /**
41 * Remove slashes that precede a comma or the end of the string
42 *
43 * @param String $string - input string
44 *
45 * @return String - the altered string
46 */
47 public static function strip_dirslash($string) {
48 return preg_replace('#/+(,|$)#', '$1', $string);
49 }
50
51 /**
52 * Remove slashes from a string or array of strings.
53 *
54 * The function wp_unslash() is WP 3.6+, so therefore we have a compatibility method here
55 *
56 * @param String|Array $value String or array of strings to unslash.
57 * @return String|Array Unslashed $value
58 */
59 public static function wp_unslash($value) {
60 return function_exists('wp_unslash') ? wp_unslash($value) : stripslashes_deep($value);
61 }
62
63 /**
64 * Parse a filename into components
65 *
66 * @param String $filename - the filename
67 *
68 * @return Array|Boolean - the parsed values, or false if parsing failed
69 */
70 public static function parse_filename($filename) {
71 if (preg_match('/^backup_([\-0-9]{10})-([0-9]{4})_.*_([0-9a-f]{12})-([\-a-z]+)([0-9]+)?+\.(zip|gz|gz\.crypt)$/i', $filename, $matches)) {
72 return array(
73 'date' => strtotime($matches[1].' '.$matches[2]),
74 'nonce' => $matches[3],
75 'type' => $matches[4],
76 'index' => (empty($matches[5]) ? 0 : $matches[5]-1),
77 'extension' => $matches[6]
78 );
79 } else {
80 return false;
81 }
82 }
83
84 /**
85 * Convert a number of bytes into a suitable textual string
86 *
87 * @param Integer $size - the number of bytes
88 *
89 * @return String - the resulting textual string
90 */
91 public static function convert_numeric_size_to_text($size) {
92 if ($size > 1073741824) {
93 return round($size / 1073741824, 1).' GB';
94 } elseif ($size > 1048576) {
95 return round($size / 1048576, 1).' MB';
96 } elseif ($size > 1024) {
97 return round($size / 1024, 1).' KB';
98 } else {
99 return round($size, 1).' B';
100 }
101 }
102
103 /**
104 * Add backquotes to tables and db-names in SQL queries. Taken from phpMyAdmin.
105 *
106 * @param string $a_name - the table name
107 * @return string - the quoted table name
108 */
109 public static function backquote($a_name) {
110 if (!empty($a_name) && '*' != $a_name) {
111 if (is_array($a_name)) {
112 $result = array();
113 foreach ($a_name as $key => $val) {
114 $result[$key] = '`'.$val.'`';
115 }
116 return $result;
117 } else {
118 return '`'.$a_name.'`';
119 }
120 } else {
121 return $a_name;
122 }
123 }
124
125 /**
126 * Remove empty (according to empty()) members of an array
127 *
128 * @param Array $list - input array
129 * @return Array - pruned array
130 */
131 public static function remove_empties($list) {
132 if (!is_array($list)) return $list;
133 foreach ($list as $ind => $entry) {
134 if (empty($entry)) unset($list[$ind]);
135 }
136 return $list;
137 }
138
139 /**
140 * Sort restoration entities
141 *
142 * @param String $a - first entity
143 * @param String $b - second entity
144 *
145 * @return Integer - sort result
146 */
147 public static function sort_restoration_entities($a, $b) {
148 if ($a == $b) return 0;
149 // Put the database first
150 // Put wpcore after plugins/uploads/themes (needed for restores of foreign all-in-one formats)
151 if ('db' == $a || 'wpcore' == $b) return -1;
152 if ('db' == $b || 'wpcore' == $a) return 1;
153 // After wpcore, next last is others
154 if ('others' == $b) return -1;
155 if ('others' == $a) return 1;
156 // And then uploads - this is only because we want to make sure uploads is after plugins, so that we know before we get to the uploads whether the version of UD which might have to unpack them can do this new-style or not.
157 if ('uploads' == $b) return -1;
158 if ('uploads' == $a) return 1;
159 return strcmp($a, $b);
160 }
161
162 /**
163 * This options filter removes ABSPATH off the front of updraft_dir, if it is given absolutely and contained within it
164 *
165 * @param String $updraft_dir Directory
166 * @return String
167 */
168 public static function prune_updraft_dir_prefix($updraft_dir) {
169 if ('/' == substr($updraft_dir, 0, 1) || "\\" == substr($updraft_dir, 0, 1) || preg_match('/^[a-zA-Z]:/', $updraft_dir)) {
170 $wcd = trailingslashit(WP_CONTENT_DIR);
171 if (strpos($updraft_dir, $wcd) === 0) {
172 $updraft_dir = substr($updraft_dir, strlen($wcd));
173 }
174 }
175 return $updraft_dir;
176 }
177
178 public static function get_mime_type_from_filename($filename, $allow_gzip = true) {
179 if ('.zip' == substr($filename, -4, 4)) {
180 return 'application/zip';
181 } elseif ('.tar' == substr($filename, -4, 4)) {
182 return 'application/x-tar';
183 } elseif ('.tar.gz' == substr($filename, -7, 7)) {
184 return 'application/x-tgz';
185 } elseif ('.tar.bz2' == substr($filename, -8, 8)) {
186 return 'application/x-bzip-compressed-tar';
187 } elseif ($allow_gzip && '.gz' == substr($filename, -3, 3)) {
188 // When we sent application/x-gzip as a content-type header to the browser, we found a case where the server compressed it a second time (since observed several times)
189 return 'application/x-gzip';
190 } else {
191 return 'application/octet-stream';
192 }
193 }
194
195 /**
196 * Filter the value to ensure it is between 1 and 9999
197 *
198 * @param Integer $input
199 *
200 * @return Integer
201 */
202 public static function retain_range($input) {
203 $input = (int) $input;
204 return ($input > 0) ? min($input, 9999) : 1;
205 }
206
207 /**
208 * Find matching string from $str_arr1 and $str_arr2
209 *
210 * @param array $str_arr1 array of strings
211 * @param array $str_arr2 array of strings
212 * @param boolean $match_until_first_numeric only match until first numeric occurence
213 * @return string matching str which will be best for replacement
214 */
215 public static function get_matching_str_from_array_elems($str_arr1, $str_arr2, $match_until_first_numeric = true) {
216 $matching_str = '';
217 if ($match_until_first_numeric) {
218 $str_partial_arr = array();
219 foreach ($str_arr1 as $str1) {
220 $str1_str_length = strlen($str1);
221 $temp_str1_chars = str_split($str1);
222 $temp_partial_str = '';
223 // The flag is for whether non-numeric character passed after numeric character occurence in str1. For ex. str1 is utf8mb4, the flag wil be true when parsing m after utf8.
224 $numeric_char_pass_flag = false;
225 $char_position_in_str1 = 0;
226 while ($char_position_in_str1 < $str1_str_length) {
227 if ($numeric_char_pass_flag && !is_numeric($temp_str1_chars[$char_position_in_str1])) {
228 break;
229 }
230 if (is_numeric($temp_str1_chars[$char_position_in_str1])) {
231 $numeric_char_pass_flag = true;
232 }
233 $temp_partial_str .= $temp_str1_chars[$char_position_in_str1];
234 $char_position_in_str1++;
235 }
236 $str_partial_arr[] = $temp_partial_str;
237 }
238 foreach ($str_partial_arr as $str_partial) {
239 if (!empty($matching_str)) {
240 break;
241 }
242 foreach ($str_arr2 as $str2) {
243 if (0 === stripos($str2, $str_partial)) {
244 $matching_str = $str2;
245 break;
246 }
247 }
248 }
249 } else {
250 $str1_partial_first_arr = array();
251 $str1_partial_first_arr = array();
252 $str1_partial_start_n_middle_arr = array();
253 $str1_partial_middle_n_last_arr = array();
254 $str1_partial_last_arr = array();
255 foreach ($str_arr1 as $str1) {
256 $str1_partial_arr = explode('_', $str1);
257 $str1_parts_count = count($str1_partial_arr);
258 $str1_partial_first_arr[] = $str1_partial_arr[0];
259 $str1_last_part_index = $str1_parts_count - 1;
260 if ($str1_last_part_index > 0) {
261 $str1_partial_last_arr[] = $str1_partial_arr[$str1_last_part_index];
262 $str1_partial_start_n_middle_arr[] = substr($str1, 0, stripos($str1, '_'));
263 $str1_partial_middle_n_last_arr[] = substr($str1, stripos($str1, '_') + 1);
264 }
265 }
266 for ($case_no = 1; $case_no <= 5; $case_no++) {
267 if (!empty($matching_str)) {
268 break;
269 }
270 foreach ($str_arr2 as $str2) {
271 switch ($case_no) {
272 // Case 1: Both Start and End match
273 case 1:
274 $str2_partial_arr = explode('_', $str2);
275 $str2_first_part = $str2_partial_arr[0];
276 $str2_parts_count = count($str2_partial_arr);
277 $str2_last_part_index = $str2_parts_count - 1;
278 if ($str2_last_part_index > 0) {
279 $str2_last_part = $str2_partial_arr[$str2_last_part_index];
280 } else {
281 $str2_last_part = '';
282 }
283 if (!empty($str2_last_part) && !empty($str1_partial_last_arr) && in_array($str2_first_part, $str1_partial_first_arr) && in_array($str2_last_part, $str1_partial_last_arr)) {
284 $matching_str = $str2;
285 }
286 break;
287 // Case 2: Start Middle Match
288 case 2:
289 $str2_partial_first_n_middle_parts = substr($str2, 0, stripos($str2, '_'));
290 if (in_array($str2_partial_first_n_middle_parts, $str1_partial_start_n_middle_arr)) {
291 $matching_str = $str2;
292 }
293 break;
294 // Case 3: End Middle Match
295 case 3:
296 $str2_partial_middle_n_last_parts = stripos($str2, '_') !== false ? substr($str2, stripos($str2, '_') + 1) : '';
297 if (!empty($str2_partial_middle_n_last_parts) && in_array($str2_partial_middle_n_last_parts, $str1_partial_middle_n_last_arr)) {
298 $matching_str = $str2;
299 }
300 break;
301 // Case 4: Start Match (low possibilities)
302 case 4:
303 $str2_partial_arr = explode('_', $str2);
304 $str2_first_part = $str2_partial_arr[0];
305 if (in_array($str2_first_part, $str1_partial_first_arr)) {
306 $matching_str = $str2;
307 }
308 break;
309 // Case 5: End Match (low possibilities)
310 case 5:
311 $str2_partial_arr = explode('_', $str2);
312 $str2_parts_count = count($str2_partial_arr);
313 $str2_last_part_index = $str2_parts_count - 1;
314 if ($str2_last_part_index > 0) {
315 $str2_last_part = $str2_partial_arr[$str2_last_part_index];
316 } else {
317 $str2_last_part = '';
318 }
319 if (!empty($str2_last_part) && in_array($str2_last_part, $str1_partial_last_arr)) {
320 $matching_str = $str2;
321 }
322 break;
323 }
324 if (!empty($matching_str)) {
325 break;
326 }
327 }
328 }
329 }
330 return $matching_str;
331 }
332
333 /**
334 * Produce a normalised version of a URL, useful for comparisons. This may produce a URL that does not actually reference the same location; its purpose is only to use in comparisons of two URLs that *both* go through this function.
335 *
336 * @param String $url - the URL
337 *
338 * @return String - normalised
339 */
340 public static function normalise_url($url) {
341 $parsed_descrip_url = parse_url($url);
342 if (is_array($parsed_descrip_url)) {
343 if (preg_match('/^www\./i', $parsed_descrip_url['host'], $matches)) $parsed_descrip_url['host'] = substr($parsed_descrip_url['host'], 4);
344 $normalised_descrip_url = 'http://'.strtolower($parsed_descrip_url['host']);
345 if (!empty($parsed_descrip_url['port'])) $normalised_descrip_url .= ':'.$parsed_descrip_url['port'];
346 if (!empty($parsed_descrip_url['path'])) $normalised_descrip_url .= untrailingslashit($parsed_descrip_url['path']);
347 } else {
348 $normalised_descrip_url = untrailingslashit($url);
349 }
350 return $normalised_descrip_url;
351 }
352
353 /**
354 * Normalize a filesystem path.
355 *
356 * On windows systems, replaces backslashes with forward slashes
357 * and forces upper-case drive letters.
358 * Allows for two leading slashes for Windows network shares, but
359 * ensures that all other duplicate slashes are reduced to a single.
360 *
361 * @param string $path Path to normalize.
362 * @return string Normalized path.
363 */
364 public static function wp_normalize_path($path) {
365 // wp_normalize_path is not present before WP 3.9
366 if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
367 // Taken from WP 4.6
368 $path = str_replace('\\', '/', $path);
369 $path = preg_replace('|(?<=.)/+|', '/', $path);
370 if (':' === substr($path, 1, 1)) {
371 $path = ucfirst($path);
372 }
373 return $path;
374 }
375
376 /**
377 * Given a set of times, find details about the maximum
378 *
379 * @param Array $time_passed - a list of times passed, with numerical indexes
380 * @param Integer $upto - last index to consider
381 * @param Integer $first_run - first index to consider
382 *
383 * @return Array - a list with entries, in order: maximum time, list in string format, how many run times were found
384 */
385 public static function max_time_passed($time_passed, $upto, $first_run) {
386 $max_time = 0;
387 $timings_string = "";
388 $run_times_known=0;
389 for ($i = $first_run; $i <= $upto; $i++) {
390 $timings_string .= "$i:";
391 if (isset($time_passed[$i])) {
392 $timings_string .= round($time_passed[$i], 1).' ';
393 $run_times_known++;
394 if ($time_passed[$i] > $max_time) $max_time = round($time_passed[$i]);
395 } else {
396 $timings_string .= '? ';
397 }
398 }
399 return array($max_time, $timings_string, $run_times_known);
400 }
401
402 /**
403 * Determine if a given string ends with a given substring.
404 *
405 * @param string $haystack string
406 * @param string $needle substring which should be checked at the end of the string
407 * @return boolean Whether string ends with the substring or not
408 */
409 public static function str_ends_with($haystack, $needle) {
410 if (substr($haystack, - strlen($needle)) == $needle) return true;
411 return false;
412 }
413
414 /**
415 * Returns a random string of given length.
416 *
417 * @param string $length integer
418 * @return string random string
419 */
420 public static function generate_random_string($length = 2) {
421 $characters = '0123456789abcdefghijklmnopqrstuvwxyz';
422 $characters_length = strlen($characters);
423 $random_string = '';
424 for ($i = 0; $i < $length; $i++) {
425 $random_string .= $characters[rand(0, $characters_length - 1)];
426 }
427 return $random_string;
428 }
429 }
430