PluginProbe ʕ •ᴥ•ʔ
All-in-One WP Migration and Backup / 7.105
All-in-One WP Migration and Backup v7.105
trunk 7.100 7.101 7.102 7.103 7.104 7.105 7.97 7.98 7.99
all-in-one-wp-migration / functions.php
all-in-one-wp-migration Last commit date
lib 1 month ago LICENSE 12 years ago all-in-one-wp-migration.php 1 month ago changelog.txt 2 years ago constants.php 1 month ago deprecated.php 1 year ago exceptions.php 2 months ago functions.php 2 months ago loader.php 2 months ago readme.txt 1 month ago uninstall.php 11 months ago
functions.php
2574 lines
1 <?php
2 /**
3 * Copyright (C) 2014-2025 ServMask Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Attribution: This code is part of the All-in-One WP Migration plugin, developed by
19 *
20 * ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
21 * ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
22 * ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
23 * ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
24 * ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
25 * ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
26 */
27
28 if ( ! defined( 'ABSPATH' ) ) {
29 die( 'Kangaroos cannot jump here' );
30 }
31
32 /**
33 * Get storage absolute path
34 *
35 * @param array $params Request parameters
36 * @return string
37 */
38 function ai1wm_storage_path( $params ) {
39 if ( empty( $params['storage'] ) ) {
40 throw new Ai1wm_Storage_Exception(
41 wp_kses(
42 __( 'Could not locate the storage path. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-storage-path/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
43 ai1wm_allowed_html_tags()
44 )
45 );
46 }
47
48 // Validate storage path
49 if ( ai1wm_validate_file( $params['storage'] ) !== 0 ) {
50 throw new Ai1wm_Storage_Exception(
51 wp_kses(
52 __( 'Your storage directory name contains invalid characters: < > : " | ? * \0. It must not include these characters. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-storage-name/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
53 ai1wm_allowed_html_tags()
54 )
55 );
56 }
57
58 // Get storage path
59 $storage = AI1WM_STORAGE_PATH . DIRECTORY_SEPARATOR . basename( $params['storage'] );
60 if ( ! is_dir( $storage ) ) {
61 mkdir( $storage, 0777, true );
62 }
63
64 return $storage;
65 }
66
67 /**
68 * Resolve the backups path.
69 * If the stored option points to a stale path (e.g., from a server migration)
70 * where neither the path nor its parent directory exist, the option is deleted
71 * and the default path is returned.
72 *
73 * @return string
74 */
75 function ai1wm_resolve_backups_path() {
76 $backups_path = get_option( AI1WM_BACKUPS_PATH_OPTION, false );
77 if ( $backups_path === false ) {
78 return AI1WM_DEFAULT_BACKUPS_PATH;
79 }
80
81 $parent_backups_path = dirname( $backups_path );
82 if ( ! is_dir( $parent_backups_path ) || ! is_writable( $parent_backups_path ) ) {
83 delete_option( AI1WM_BACKUPS_PATH_OPTION );
84 return AI1WM_DEFAULT_BACKUPS_PATH;
85 }
86
87 return $backups_path;
88 }
89
90 /**
91 * Get backup absolute path
92 *
93 * @param array $params Request parameters
94 * @return string
95 */
96 function ai1wm_backup_path( $params ) {
97 if ( empty( $params['archive'] ) ) {
98 throw new Ai1wm_Archive_Exception(
99 wp_kses(
100 __( 'Could not locate the archive path. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-archive-path/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
101 ai1wm_allowed_html_tags()
102 )
103 );
104 }
105
106 // Validate archive path
107 if ( ai1wm_validate_file( $params['archive'] ) !== 0 ) {
108 throw new Ai1wm_Archive_Exception(
109 wp_kses(
110 __( 'Your archive file name contains invalid characters: < > : " | ? * \0. It must not include these characters. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-archive-name/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
111 ai1wm_allowed_html_tags()
112 )
113 );
114 }
115
116 // Validate file extension
117 if ( ! ai1wm_is_filename_supported( $params['archive'] ) ) {
118 throw new Ai1wm_Archive_Exception(
119 wp_kses(
120 __( 'Invalid archive file type. Only .wpress files are allowed. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-file-type/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
121 ai1wm_allowed_html_tags()
122 )
123 );
124 }
125
126 return AI1WM_BACKUPS_PATH . DIRECTORY_SEPARATOR . $params['archive'];
127 }
128
129 /**
130 * Validates a file name and path against an allowed set of rules
131 *
132 * @param string $file File path
133 * @param array $allowed_files Array of allowed files
134 * @return integer
135 */
136 function ai1wm_validate_file( $file, $allowed_files = array() ) {
137 $file = str_replace( '\\', '/', $file );
138
139 // Validates special characters that are illegal in filenames on certain
140 // operating systems and special characters requiring special escaping
141 // to manipulate at the command line
142 $invalid_chars = array( '<', '>', ':', '"', '|', '?', '*', chr( 0 ) );
143 foreach ( $invalid_chars as $char ) {
144 if ( strpos( $file, $char ) !== false ) {
145 return 1;
146 }
147 }
148
149 return validate_file( $file, $allowed_files );
150 }
151
152 /**
153 * Get archive absolute path
154 *
155 * @param array $params Request parameters
156 * @return string
157 */
158 function ai1wm_archive_path( $params ) {
159 if ( empty( $params['archive'] ) ) {
160 throw new Ai1wm_Archive_Exception(
161 wp_kses(
162 __( 'Could not locate the archive path. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-archive-path/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
163 ai1wm_allowed_html_tags()
164 )
165 );
166 }
167
168 // Validate archive path
169 if ( ai1wm_validate_file( $params['archive'] ) !== 0 ) {
170 throw new Ai1wm_Archive_Exception(
171 wp_kses(
172 __( 'Your archive file name contains invalid characters: < > : " | ? * \0. It must not include these characters. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-archive-name/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
173 ai1wm_allowed_html_tags()
174 )
175 );
176 }
177
178 // Validate file extension
179 if ( ! ai1wm_is_filename_supported( $params['archive'] ) ) {
180 throw new Ai1wm_Archive_Exception(
181 wp_kses(
182 __( 'Invalid archive file type. Only .wpress files are allowed. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-file-type/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
183 ai1wm_allowed_html_tags()
184 )
185 );
186 }
187
188 // Get archive path
189 if ( empty( $params['ai1wm_manual_restore'] ) ) {
190 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . $params['archive'];
191 }
192
193 return ai1wm_backup_path( $params );
194 }
195
196 /**
197 * Get multipart.list absolute path
198 *
199 * @param array $params Request parameters
200 * @return string
201 */
202 function ai1wm_multipart_path( $params ) {
203 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_MULTIPART_NAME;
204 }
205
206 /**
207 * Get content.list absolute path
208 *
209 * @param array $params Request parameters
210 * @return string
211 */
212 function ai1wm_content_list_path( $params ) {
213 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_CONTENT_LIST_NAME;
214 }
215
216 /**
217 * Get media.list absolute path
218 *
219 * @param array $params Request parameters
220 * @return string
221 */
222 function ai1wm_media_list_path( $params ) {
223 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_MEDIA_LIST_NAME;
224 }
225
226 /**
227 * Get plugins.list absolute path
228 *
229 * @param array $params Request parameters
230 * @return string
231 */
232 function ai1wm_plugins_list_path( $params ) {
233 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_PLUGINS_LIST_NAME;
234 }
235
236 /**
237 * Get themes.list absolute path
238 *
239 * @param array $params Request parameters
240 * @return string
241 */
242 function ai1wm_themes_list_path( $params ) {
243 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_THEMES_LIST_NAME;
244 }
245
246 /**
247 * Get tables.list absolute path
248 *
249 * @param array $params Request parameters
250 * @return string
251 */
252 function ai1wm_tables_list_path( $params ) {
253 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_TABLES_LIST_NAME;
254 }
255
256 /**
257 * Get incremental.content.list absolute path
258 *
259 * @param array $params Request parameters
260 * @return string
261 */
262 function ai1wm_incremental_content_list_path( $params ) {
263 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_INCREMENTAL_CONTENT_LIST_NAME;
264 }
265
266 /**
267 * Get incremental.media.list absolute path
268 *
269 * @param array $params Request parameters
270 * @return string
271 */
272 function ai1wm_incremental_media_list_path( $params ) {
273 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_INCREMENTAL_MEDIA_LIST_NAME;
274 }
275
276 /**
277 * Get incremental.plugins.list absolute path
278 *
279 * @param array $params Request parameters
280 * @return string
281 */
282 function ai1wm_incremental_plugins_list_path( $params ) {
283 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_INCREMENTAL_PLUGINS_LIST_NAME;
284 }
285
286 /**
287 * Get incremental.themes.list absolute path
288 *
289 * @param array $params Request parameters
290 * @return string
291 */
292 function ai1wm_incremental_themes_list_path( $params ) {
293 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_INCREMENTAL_THEMES_LIST_NAME;
294 }
295
296 /**
297 * Get incremental.backups.list absolute path
298 *
299 * @param array $params Request parameters
300 * @return string
301 */
302 function ai1wm_incremental_backups_list_path( $params ) {
303 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_INCREMENTAL_BACKUPS_LIST_NAME;
304 }
305
306 /**
307 * Get package.json absolute path
308 *
309 * @param array $params Request parameters
310 * @return string
311 */
312 function ai1wm_package_path( $params ) {
313 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_PACKAGE_NAME;
314 }
315
316 /**
317 * Get multisite.json absolute path
318 *
319 * @param array $params Request parameters
320 * @return string
321 */
322 function ai1wm_multisite_path( $params ) {
323 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_MULTISITE_NAME;
324 }
325
326 /**
327 * Get blogs.json absolute path
328 *
329 * @param array $params Request parameters
330 * @return string
331 */
332 function ai1wm_blogs_path( $params ) {
333 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_BLOGS_NAME;
334 }
335
336 /**
337 * Get settings.json absolute path
338 *
339 * @param array $params Request parameters
340 * @return string
341 */
342 function ai1wm_settings_path( $params ) {
343 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_SETTINGS_NAME;
344 }
345
346 /**
347 * Get database.sql absolute path
348 *
349 * @param array $params Request parameters
350 * @return string
351 */
352 function ai1wm_database_path( $params ) {
353 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_DATABASE_NAME;
354 }
355
356 /**
357 * Get cookies.txt absolute path
358 *
359 * @param array $params Request parameters
360 * @return string
361 */
362 function ai1wm_cookies_path( $params ) {
363 return ai1wm_storage_path( $params ) . DIRECTORY_SEPARATOR . AI1WM_COOKIES_NAME;
364 }
365
366 /**
367 * Get error log absolute path
368 *
369 * @param string $nonce Log nonce
370 * @return string
371 */
372 function ai1wm_error_path( $nonce ) {
373 return AI1WM_STORAGE_PATH . DIRECTORY_SEPARATOR . sprintf( AI1WM_ERROR_NAME, $nonce );
374 }
375
376 /**
377 * Get archive name
378 *
379 * @param array $params Request parameters
380 * @return string
381 */
382 function ai1wm_archive_name( $params ) {
383 return basename( $params['archive'] );
384 }
385
386 /**
387 * Get backup URL address
388 *
389 * @param array $params Request parameters
390 * @return string
391 */
392 function ai1wm_backup_url( $params ) {
393 static $backups_base_url = '';
394 if ( empty( $backups_base_url ) ) {
395 if ( Ai1wm_Backups::are_in_wp_content_folder() ) {
396 $backups_base_url = str_replace( untrailingslashit( WP_CONTENT_DIR ), '', AI1WM_BACKUPS_PATH );
397 $backups_base_url = content_url(
398 ai1wm_replace_directory_separator_with_forward_slash( $backups_base_url )
399 );
400 } else {
401 $backups_base_url = str_replace( untrailingslashit( ABSPATH ), '', AI1WM_BACKUPS_PATH );
402 $backups_base_url = site_url(
403 ai1wm_replace_directory_separator_with_forward_slash( $backups_base_url )
404 );
405 }
406 }
407
408 return $backups_base_url . '/' . ai1wm_replace_directory_separator_with_forward_slash( $params['archive'] );
409 }
410
411 /**
412 * Get archive size in bytes
413 *
414 * @param array $params Request parameters
415 * @return integer
416 */
417 function ai1wm_archive_bytes( $params ) {
418 return filesize( ai1wm_archive_path( $params ) );
419 }
420
421 /**
422 * Get archive modified time in seconds
423 *
424 * @param array $params Request parameters
425 * @return integer
426 */
427 function ai1wm_archive_mtime( $params ) {
428 return filemtime( ai1wm_archive_path( $params ) );
429 }
430
431 /**
432 * Get backup size in bytes
433 *
434 * @param array $params Request parameters
435 * @return integer
436 */
437 function ai1wm_backup_bytes( $params ) {
438 return filesize( ai1wm_backup_path( $params ) );
439 }
440
441 /**
442 * Get database size in bytes
443 *
444 * @param array $params Request parameters
445 * @return integer
446 */
447 function ai1wm_database_bytes( $params ) {
448 return filesize( ai1wm_database_path( $params ) );
449 }
450
451 /**
452 * Get package size in bytes
453 *
454 * @param array $params Request parameters
455 * @return integer
456 */
457 function ai1wm_package_bytes( $params ) {
458 return filesize( ai1wm_package_path( $params ) );
459 }
460
461 /**
462 * Get multisite size in bytes
463 *
464 * @param array $params Request parameters
465 * @return integer
466 */
467 function ai1wm_multisite_bytes( $params ) {
468 return filesize( ai1wm_multisite_path( $params ) );
469 }
470
471 /**
472 * Get archive size as text
473 *
474 * @param array $params Request parameters
475 * @return string
476 */
477 function ai1wm_archive_size( $params ) {
478 return ai1wm_size_format( filesize( ai1wm_archive_path( $params ) ) );
479 }
480
481 /**
482 * Get backup size as text
483 *
484 * @param array $params Request parameters
485 * @return string
486 */
487 function ai1wm_backup_size( $params ) {
488 return ai1wm_size_format( filesize( ai1wm_backup_path( $params ) ) );
489 }
490
491 /**
492 * Parse file size
493 *
494 * @param string $size File size
495 * @param string $default Default size
496 * @return string
497 */
498 function ai1wm_parse_size( $size, $default = null ) {
499 $suffixes = array(
500 '' => 1,
501 'k' => 1000,
502 'm' => 1000000,
503 'g' => 1000000000,
504 );
505
506 // Parse size format
507 if ( preg_match( '/([0-9]+)\s*(k|m|g)?(b?(ytes?)?)/i', $size, $matches ) ) {
508 return $matches[1] * $suffixes[ strtolower( $matches[2] ) ];
509 }
510
511 return $default;
512 }
513
514 /**
515 * Format file size into human-readable string
516 *
517 * Fixes the WP size_format bug: size_format( '0' ) => false
518 *
519 * @param int|string $bytes Number of bytes. Note max integer size for integers.
520 * @param int $decimals Optional. Precision of number of decimal places. Default 0.
521 * @return string|false False on failure. Number string on success.
522 */
523 function ai1wm_size_format( $bytes, $decimals = 0 ) {
524 if ( strval( $bytes ) === '0' ) {
525 return size_format( 0, $decimals );
526 }
527
528 return size_format( $bytes, $decimals );
529 }
530
531 /**
532 * Get current site name
533 *
534 * @param integer $blog_id Blog ID
535 * @return string
536 */
537 function ai1wm_site_name( $blog_id = null ) {
538 return parse_url( get_site_url( $blog_id ), PHP_URL_HOST );
539 }
540
541 /**
542 * Get archive file name
543 *
544 * @param integer $blog_id Blog ID
545 * @return string
546 */
547 function ai1wm_archive_file( $blog_id = null ) {
548 $name = array();
549
550 // Add domain
551 if ( defined( 'AI1WM_KEEP_DOMAIN_NAME' ) ) {
552 $name[] = parse_url( get_site_url( $blog_id ), PHP_URL_HOST );
553 } elseif ( ( $domain = explode( '.', parse_url( get_site_url( $blog_id ), PHP_URL_HOST ) ) ) ) {
554 foreach ( $domain as $subdomain ) {
555 if ( ( $subdomain = strtolower( $subdomain ) ) ) {
556 $name[] = $subdomain;
557 }
558 }
559 }
560
561 // Add path
562 if ( ( $path = parse_url( get_site_url( $blog_id ), PHP_URL_PATH ) ) ) {
563 foreach ( explode( '/', $path ) as $directory ) {
564 if ( ( $directory = strtolower( preg_replace( '/[^A-Za-z0-9\-]/', '', $directory ) ) ) ) {
565 $name[] = $directory;
566 }
567 }
568 }
569
570 // Add year, month and day
571 $name[] = current_time( 'Ymd' );
572
573 // Add hours, minutes and seconds
574 $name[] = current_time( 'His' );
575
576 // Add unique identifier
577 $name[] = ai1wm_generate_random_string( 12, false );
578
579 return sprintf( '%s.wpress', strtolower( implode( '-', $name ) ) );
580 }
581
582 /**
583 * Get archive folder name
584 *
585 * @param integer $blog_id Blog ID
586 * @return string
587 */
588 function ai1wm_archive_folder( $blog_id = null ) {
589 $name = array();
590
591 // Add domain
592 if ( defined( 'AI1WM_KEEP_DOMAIN_NAME' ) ) {
593 $name[] = parse_url( get_site_url( $blog_id ), PHP_URL_HOST );
594 } elseif ( ( $domain = explode( '.', parse_url( get_site_url( $blog_id ), PHP_URL_HOST ) ) ) ) {
595 foreach ( $domain as $subdomain ) {
596 if ( ( $subdomain = strtolower( $subdomain ) ) ) {
597 $name[] = $subdomain;
598 }
599 }
600 }
601
602 // Add path
603 if ( ( $path = parse_url( get_site_url( $blog_id ), PHP_URL_PATH ) ) ) {
604 foreach ( explode( '/', $path ) as $directory ) {
605 if ( ( $directory = strtolower( preg_replace( '/[^A-Za-z0-9\-]/', '', $directory ) ) ) ) {
606 $name[] = $directory;
607 }
608 }
609 }
610
611 return strtolower( implode( '-', $name ) );
612 }
613
614 /**
615 * Get archive bucket name
616 *
617 * @param integer $blog_id Blog ID
618 * @return string
619 */
620 function ai1wm_archive_bucket( $blog_id = null ) {
621 $name = array();
622
623 // Add domain
624 if ( ( $domain = explode( '.', parse_url( get_site_url( $blog_id ), PHP_URL_HOST ) ) ) ) {
625 foreach ( $domain as $subdomain ) {
626 if ( ( $subdomain = strtolower( $subdomain ) ) ) {
627 $name[] = $subdomain;
628 }
629 }
630 }
631
632 // Add path
633 if ( ( $path = parse_url( get_site_url( $blog_id ), PHP_URL_PATH ) ) ) {
634 foreach ( explode( '/', $path ) as $directory ) {
635 if ( ( $directory = strtolower( preg_replace( '/[^A-Za-z0-9\-]/', '', $directory ) ) ) ) {
636 $name[] = $directory;
637 }
638 }
639 }
640
641 return strtolower( implode( '-', $name ) );
642 }
643
644 /**
645 * Get archive vault name
646 *
647 * @param integer $blog_id Blog ID
648 * @return string
649 */
650 function ai1wm_archive_vault( $blog_id = null ) {
651 $name = array();
652
653 // Add domain
654 if ( ( $domain = explode( '.', parse_url( get_site_url( $blog_id ), PHP_URL_HOST ) ) ) ) {
655 foreach ( $domain as $subdomain ) {
656 if ( ( $subdomain = strtolower( $subdomain ) ) ) {
657 $name[] = $subdomain;
658 }
659 }
660 }
661
662 // Add path
663 if ( ( $path = parse_url( get_site_url( $blog_id ), PHP_URL_PATH ) ) ) {
664 foreach ( explode( '/', $path ) as $directory ) {
665 if ( ( $directory = strtolower( preg_replace( '/[^A-Za-z0-9\-]/', '', $directory ) ) ) ) {
666 $name[] = $directory;
667 }
668 }
669 }
670
671 return strtolower( implode( '-', $name ) );
672 }
673
674 /**
675 * Get archive project name
676 *
677 * @param integer $blog_id Blog ID
678 * @return string
679 */
680 function ai1wm_archive_project( $blog_id = null ) {
681 $name = array();
682
683 // Add domain
684 if ( ( $domain = explode( '.', parse_url( get_site_url( $blog_id ), PHP_URL_HOST ) ) ) ) {
685 foreach ( $domain as $subdomain ) {
686 if ( ( $subdomain = strtolower( $subdomain ) ) ) {
687 $name[] = $subdomain;
688 }
689 }
690 }
691
692 // Add path
693 if ( ( $path = parse_url( get_site_url( $blog_id ), PHP_URL_PATH ) ) ) {
694 foreach ( explode( '/', $path ) as $directory ) {
695 if ( ( $directory = strtolower( preg_replace( '/[^A-Za-z0-9\-]/', '', $directory ) ) ) ) {
696 $name[] = $directory;
697 }
698 }
699 }
700
701 return strtolower( implode( '-', $name ) );
702 }
703
704 /**
705 * Get archive share name
706 *
707 * @param integer $blog_id Blog ID
708 * @return string
709 */
710 function ai1wm_archive_share( $blog_id = null ) {
711 $name = array();
712
713 // Add domain
714 if ( ( $domain = explode( '.', parse_url( get_site_url( $blog_id ), PHP_URL_HOST ) ) ) ) {
715 foreach ( $domain as $subdomain ) {
716 if ( ( $subdomain = strtolower( $subdomain ) ) ) {
717 $name[] = $subdomain;
718 }
719 }
720 }
721
722 // Add path
723 if ( ( $path = parse_url( get_site_url( $blog_id ), PHP_URL_PATH ) ) ) {
724 foreach ( explode( '/', $path ) as $directory ) {
725 if ( ( $directory = strtolower( preg_replace( '/[^A-Za-z0-9\-]/', '', $directory ) ) ) ) {
726 $name[] = $directory;
727 }
728 }
729 }
730
731 return strtolower( implode( '-', $name ) );
732 }
733
734 /**
735 * Generate random string
736 *
737 * @param integer $length String length
738 * @param boolean $mixed_chars Whether to include mixed characters
739 * @param boolean $special_chars Whether to include special characters
740 * @param boolean $extra_special_chars Whether to include extra special characters
741 * @return string
742 */
743 function ai1wm_generate_random_string( $length = 12, $mixed_chars = true, $special_chars = false, $extra_special_chars = false ) {
744 $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
745 if ( $mixed_chars ) {
746 $chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
747 }
748
749 if ( $special_chars ) {
750 $chars .= '!@#$%^&*()';
751 }
752
753 if ( $extra_special_chars ) {
754 $chars .= '-_ []{}<>~`+=,.;:/?|';
755 }
756
757 $str = '';
758 for ( $i = 0; $i < $length; $i++ ) {
759 $str .= substr( $chars, wp_rand( 0, strlen( $chars ) - 1 ), 1 );
760 }
761
762 return $str;
763 }
764
765 /**
766 * Get storage folder name
767 *
768 * @return string
769 */
770 function ai1wm_storage_folder() {
771 return uniqid();
772 }
773
774 /**
775 * Check whether blog ID is main site
776 *
777 * @param integer $blog_id Blog ID
778 * @return boolean
779 */
780 function ai1wm_is_mainsite( $blog_id = null ) {
781 return $blog_id === null || $blog_id === 0 || $blog_id === 1;
782 }
783
784 /**
785 * Get files absolute path by blog ID
786 *
787 * @param integer $blog_id Blog ID
788 * @return string
789 */
790 function ai1wm_blog_files_abspath( $blog_id = null ) {
791 if ( ai1wm_is_mainsite( $blog_id ) ) {
792 return ai1wm_get_uploads_dir();
793 }
794
795 return WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . $blog_id . DIRECTORY_SEPARATOR . 'files';
796 }
797
798 /**
799 * Get blogs.dir absolute path by blog ID
800 *
801 * @param integer $blog_id Blog ID
802 * @return string
803 */
804 function ai1wm_blog_blogsdir_abspath( $blog_id = null ) {
805 if ( ai1wm_is_mainsite( $blog_id ) ) {
806 return ai1wm_get_uploads_dir();
807 }
808
809 return WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . $blog_id;
810 }
811
812 /**
813 * Get sites absolute path by blog ID
814 *
815 * @param integer $blog_id Blog ID
816 * @return string
817 */
818 function ai1wm_blog_sites_abspath( $blog_id = null ) {
819 if ( ai1wm_is_mainsite( $blog_id ) ) {
820 return ai1wm_get_uploads_dir();
821 }
822
823 return ai1wm_get_uploads_dir() . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . $blog_id;
824 }
825
826 /**
827 * Get files relative path by blog ID
828 *
829 * @param integer $blog_id Blog ID
830 * @return string
831 */
832 function ai1wm_blog_files_relpath( $blog_id = null ) {
833 if ( ai1wm_is_mainsite( $blog_id ) ) {
834 return 'uploads';
835 }
836
837 return 'blogs.dir' . DIRECTORY_SEPARATOR . $blog_id . DIRECTORY_SEPARATOR . 'files';
838 }
839
840 /**
841 * Get blogs.dir relative path by blog ID
842 *
843 * @param integer $blog_id Blog ID
844 * @return string
845 */
846 function ai1wm_blog_blogsdir_relpath( $blog_id = null ) {
847 if ( ai1wm_is_mainsite( $blog_id ) ) {
848 return 'uploads';
849 }
850
851 return 'blogs.dir' . DIRECTORY_SEPARATOR . $blog_id;
852 }
853
854 /**
855 * Get sites relative path by blog ID
856 *
857 * @param integer $blog_id Blog ID
858 * @return string
859 */
860 function ai1wm_blog_sites_relpath( $blog_id = null ) {
861 if ( ai1wm_is_mainsite( $blog_id ) ) {
862 return 'uploads';
863 }
864
865 return 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . $blog_id;
866 }
867
868 /**
869 * Get files URL by blog ID
870 *
871 * @param integer $blog_id Blog ID
872 * @return string
873 */
874 function ai1wm_blog_files_url( $blog_id = null ) {
875 if ( ai1wm_is_mainsite( $blog_id ) ) {
876 return '/wp-content/uploads/';
877 }
878
879 return sprintf( '/wp-content/blogs.dir/%d/files/', $blog_id );
880 }
881
882 /**
883 * Get blogs.dir URL by blog ID
884 *
885 * @param integer $blog_id Blog ID
886 * @return string
887 */
888 function ai1wm_blog_blogsdir_url( $blog_id = null ) {
889 if ( ai1wm_is_mainsite( $blog_id ) ) {
890 return '/wp-content/uploads/';
891 }
892
893 return sprintf( '/wp-content/blogs.dir/%d/', $blog_id );
894 }
895
896 /**
897 * Get sites URL by blog ID
898 *
899 * @param integer $blog_id Blog ID
900 * @return string
901 */
902 function ai1wm_blog_sites_url( $blog_id = null ) {
903 if ( ai1wm_is_mainsite( $blog_id ) ) {
904 return '/wp-content/uploads/';
905 }
906
907 return sprintf( '/wp-content/uploads/sites/%d/', $blog_id );
908 }
909
910 /**
911 * Get uploads URL by blog ID
912 *
913 * @param integer $blog_id Blog ID
914 * @return string
915 */
916 function ai1wm_blog_uploads_url( $blog_id = null ) {
917 if ( ai1wm_is_mainsite( $blog_id ) ) {
918 return sprintf( '/%s/', ai1wm_get_uploads_path() );
919 }
920
921 return sprintf( '/%s/sites/%d/', ai1wm_get_uploads_path(), $blog_id );
922 }
923
924 /**
925 * Get ServMask table prefix by blog ID
926 *
927 * @param integer $blog_id Blog ID
928 * @return string
929 */
930 function ai1wm_servmask_prefix( $blog_id = null ) {
931 if ( ai1wm_is_mainsite( $blog_id ) ) {
932 return AI1WM_TABLE_PREFIX;
933 }
934
935 return AI1WM_TABLE_PREFIX . $blog_id . '_';
936 }
937
938 /**
939 * Get WordPress table prefix by blog ID
940 *
941 * @param integer $blog_id Blog ID
942 * @return string
943 */
944 function ai1wm_table_prefix( $blog_id = null ) {
945 global $wpdb;
946
947 // Set base table prefix
948 if ( ai1wm_is_mainsite( $blog_id ) ) {
949 return $wpdb->base_prefix;
950 }
951
952 return $wpdb->base_prefix . $blog_id . '_';
953 }
954
955 /**
956 * Get default config filters
957 *
958 * @param array $filters List of files and directories
959 * @return array
960 */
961 function ai1wm_config_filters( $filters = array() ) {
962 return array_merge(
963 $filters,
964 array(
965 AI1WM_PACKAGE_NAME,
966 AI1WM_MULTISITE_NAME,
967 )
968 );
969 }
970
971 /**
972 * Get default content filters
973 *
974 * @param array $filters List of files and directories
975 * @return array
976 */
977 function ai1wm_content_filters( $filters = array() ) {
978 return array_merge(
979 $filters,
980 array(
981 AI1WM_BACKUPS_PATH,
982 AI1WM_BACKUPS_NAME,
983 AI1WM_PACKAGE_NAME,
984 AI1WM_MULTISITE_NAME,
985 AI1WM_DATABASE_NAME,
986 AI1WM_W3TC_CONFIG_FILE,
987 )
988 );
989 }
990
991 /**
992 * Get default media filters
993 *
994 * @param array $filters List of files and directories
995 * @return array
996 */
997 function ai1wm_media_filters( $filters = array() ) {
998 return array_merge(
999 $filters,
1000 array(
1001 AI1WM_BACKUPS_PATH,
1002 )
1003 );
1004 }
1005
1006 /**
1007 * Get default plugin filters
1008 *
1009 * @param array $filters List of plugins
1010 * @return array
1011 */
1012 function ai1wm_plugin_filters( $filters = array() ) {
1013 return array_merge(
1014 $filters,
1015 array(
1016 AI1WM_BACKUPS_PATH,
1017 AI1WM_PLUGIN_BASEDIR,
1018 AI1WMZE_PLUGIN_BASEDIR,
1019 AI1WMAE_PLUGIN_BASEDIR,
1020 AI1WMVE_PLUGIN_BASEDIR,
1021 AI1WMBE_PLUGIN_BASEDIR,
1022 AI1WMIE_PLUGIN_BASEDIR,
1023 AI1WMXE_PLUGIN_BASEDIR,
1024 AI1WMDE_PLUGIN_BASEDIR,
1025 AI1WMTE_PLUGIN_BASEDIR,
1026 AI1WMFE_PLUGIN_BASEDIR,
1027 AI1WMCE_PLUGIN_BASEDIR,
1028 AI1WMGE_PLUGIN_BASEDIR,
1029 AI1WMRE_PLUGIN_BASEDIR,
1030 AI1WMEE_PLUGIN_BASEDIR,
1031 AI1WMME_PLUGIN_BASEDIR,
1032 AI1WMOE_PLUGIN_BASEDIR,
1033 AI1WMPE_PLUGIN_BASEDIR,
1034 AI1WMKE_PLUGIN_BASEDIR,
1035 AI1WMNE_PLUGIN_BASEDIR,
1036 AI1WMSE_PLUGIN_BASEDIR,
1037 AI1WMUE_PLUGIN_BASEDIR,
1038 AI1WMLE_PLUGIN_BASEDIR,
1039 AI1WMWE_PLUGIN_BASEDIR,
1040 )
1041 );
1042 }
1043
1044 /**
1045 * Get default theme filters
1046 *
1047 * @param array $filters List of files and directories
1048 * @return array
1049 */
1050 function ai1wm_theme_filters( $filters = array() ) {
1051 return array_merge(
1052 $filters,
1053 array(
1054 AI1WM_BACKUPS_PATH,
1055 )
1056 );
1057 }
1058
1059 /**
1060 * Get active ServMask plugins
1061 *
1062 * @return array
1063 */
1064 function ai1wm_active_servmask_plugins( $plugins = array() ) {
1065 // WP Migration Plugin
1066 if ( defined( 'AI1WM_PLUGIN_BASENAME' ) ) {
1067 $plugins[] = AI1WM_PLUGIN_BASENAME;
1068 }
1069
1070 // Microsoft Azure Extension
1071 if ( defined( 'AI1WMZE_PLUGIN_BASENAME' ) ) {
1072 $plugins[] = AI1WMZE_PLUGIN_BASENAME;
1073 }
1074
1075 // Backblaze B2 Extension
1076 if ( defined( 'AI1WMAE_PLUGIN_BASENAME' ) ) {
1077 $plugins[] = AI1WMAE_PLUGIN_BASENAME;
1078 }
1079
1080 // Backup Plugin
1081 if ( defined( 'AI1WMVE_PLUGIN_BASENAME' ) ) {
1082 $plugins[] = AI1WMVE_PLUGIN_BASENAME;
1083 }
1084
1085 // Box Extension
1086 if ( defined( 'AI1WMBE_PLUGIN_BASENAME' ) ) {
1087 $plugins[] = AI1WMBE_PLUGIN_BASENAME;
1088 }
1089
1090 // DigitalOcean Spaces Extension
1091 if ( defined( 'AI1WMIE_PLUGIN_BASENAME' ) ) {
1092 $plugins[] = AI1WMIE_PLUGIN_BASENAME;
1093 }
1094
1095 // Direct Extension
1096 if ( defined( 'AI1WMXE_PLUGIN_BASENAME' ) ) {
1097 $plugins[] = AI1WMXE_PLUGIN_BASENAME;
1098 }
1099
1100 // Dropbox Extension
1101 if ( defined( 'AI1WMDE_PLUGIN_BASENAME' ) ) {
1102 $plugins[] = AI1WMDE_PLUGIN_BASENAME;
1103 }
1104
1105 // File Extension
1106 if ( defined( 'AI1WMTE_PLUGIN_BASENAME' ) ) {
1107 $plugins[] = AI1WMTE_PLUGIN_BASENAME;
1108 }
1109
1110 // FTP Extension
1111 if ( defined( 'AI1WMFE_PLUGIN_BASENAME' ) ) {
1112 $plugins[] = AI1WMFE_PLUGIN_BASENAME;
1113 }
1114
1115 // Google Cloud Storage Extension
1116 if ( defined( 'AI1WMCE_PLUGIN_BASENAME' ) ) {
1117 $plugins[] = AI1WMCE_PLUGIN_BASENAME;
1118 }
1119
1120 // Google Drive Extension
1121 if ( defined( 'AI1WMGE_PLUGIN_BASENAME' ) ) {
1122 $plugins[] = AI1WMGE_PLUGIN_BASENAME;
1123 }
1124
1125 // Amazon Glacier Extension
1126 if ( defined( 'AI1WMRE_PLUGIN_BASENAME' ) ) {
1127 $plugins[] = AI1WMRE_PLUGIN_BASENAME;
1128 }
1129
1130 // Mega Extension
1131 if ( defined( 'AI1WMEE_PLUGIN_BASENAME' ) ) {
1132 $plugins[] = AI1WMEE_PLUGIN_BASENAME;
1133 }
1134
1135 // Multisite Extension
1136 if ( defined( 'AI1WMME_PLUGIN_BASENAME' ) ) {
1137 $plugins[] = AI1WMME_PLUGIN_BASENAME;
1138 }
1139
1140 // OneDrive Extension
1141 if ( defined( 'AI1WMOE_PLUGIN_BASENAME' ) ) {
1142 $plugins[] = AI1WMOE_PLUGIN_BASENAME;
1143 }
1144
1145 // pCloud Extension
1146 if ( defined( 'AI1WMPE_PLUGIN_BASENAME' ) ) {
1147 $plugins[] = AI1WMPE_PLUGIN_BASENAME;
1148 }
1149
1150 // Pro Plugin
1151 if ( defined( 'AI1WMKE_PLUGIN_BASENAME' ) ) {
1152 $plugins[] = AI1WMKE_PLUGIN_BASENAME;
1153 }
1154
1155 // S3 Client Extension
1156 if ( defined( 'AI1WMNE_PLUGIN_BASENAME' ) ) {
1157 $plugins[] = AI1WMNE_PLUGIN_BASENAME;
1158 }
1159
1160 // Amazon S3 Extension
1161 if ( defined( 'AI1WMSE_PLUGIN_BASENAME' ) ) {
1162 $plugins[] = AI1WMSE_PLUGIN_BASENAME;
1163 }
1164
1165 // Unlimited Extension
1166 if ( defined( 'AI1WMUE_PLUGIN_BASENAME' ) ) {
1167 $plugins[] = AI1WMUE_PLUGIN_BASENAME;
1168 }
1169
1170 // URL Extension
1171 if ( defined( 'AI1WMLE_PLUGIN_BASENAME' ) ) {
1172 $plugins[] = AI1WMLE_PLUGIN_BASENAME;
1173 }
1174
1175 // WebDAV Extension
1176 if ( defined( 'AI1WMWE_PLUGIN_BASENAME' ) ) {
1177 $plugins[] = AI1WMWE_PLUGIN_BASENAME;
1178 }
1179
1180 return $plugins;
1181 }
1182
1183 /**
1184 * Get active sitewide plugins
1185 *
1186 * @return array
1187 */
1188 function ai1wm_active_sitewide_plugins() {
1189 return array_keys( get_site_option( AI1WM_ACTIVE_SITEWIDE_PLUGINS, array() ) );
1190 }
1191
1192 /**
1193 * Get active plugins
1194 *
1195 * @return array
1196 */
1197 function ai1wm_active_plugins() {
1198 return array_values( get_option( AI1WM_ACTIVE_PLUGINS, array() ) );
1199 }
1200
1201 /**
1202 * Set active sitewide plugins (inspired by WordPress activate_plugins() function)
1203 *
1204 * @param array $plugins List of plugins
1205 * @return boolean
1206 */
1207 function ai1wm_activate_sitewide_plugins( $plugins ) {
1208 $current = get_site_option( AI1WM_ACTIVE_SITEWIDE_PLUGINS, array() );
1209
1210 // Add plugins
1211 foreach ( $plugins as $plugin ) {
1212 if ( ! isset( $current[ $plugin ] ) && ! is_wp_error( validate_plugin( $plugin ) ) ) {
1213 $current[ $plugin ] = time();
1214 }
1215 }
1216
1217 return update_site_option( AI1WM_ACTIVE_SITEWIDE_PLUGINS, $current );
1218 }
1219
1220 /**
1221 * Set active plugins (inspired by WordPress activate_plugins() function)
1222 *
1223 * @param array $plugins List of plugins
1224 * @return boolean
1225 */
1226 function ai1wm_activate_plugins( $plugins ) {
1227 $current = get_option( AI1WM_ACTIVE_PLUGINS, array() );
1228
1229 // Add plugins
1230 foreach ( $plugins as $plugin ) {
1231 if ( ! in_array( $plugin, $current ) && ! is_wp_error( validate_plugin( $plugin ) ) ) {
1232 $current[] = $plugin;
1233 }
1234 }
1235
1236 return update_option( AI1WM_ACTIVE_PLUGINS, $current );
1237 }
1238
1239 /**
1240 * Get active template
1241 *
1242 * @return string
1243 */
1244 function ai1wm_active_template() {
1245 return get_option( AI1WM_ACTIVE_TEMPLATE );
1246 }
1247
1248 /**
1249 * Get active stylesheet
1250 *
1251 * @return string
1252 */
1253 function ai1wm_active_stylesheet() {
1254 return get_option( AI1WM_ACTIVE_STYLESHEET );
1255 }
1256
1257 /**
1258 * Set active template
1259 *
1260 * @param string $template Template name
1261 * @return boolean
1262 */
1263 function ai1wm_activate_template( $template ) {
1264 return update_option( AI1WM_ACTIVE_TEMPLATE, $template );
1265 }
1266
1267 /**
1268 * Set active stylesheet
1269 *
1270 * @param string $stylesheet Stylesheet name
1271 * @return boolean
1272 */
1273 function ai1wm_activate_stylesheet( $stylesheet ) {
1274 return update_option( AI1WM_ACTIVE_STYLESHEET, $stylesheet );
1275 }
1276
1277 /**
1278 * Set inactive sitewide plugins (inspired by WordPress deactivate_plugins() function)
1279 *
1280 * @param array $plugins List of plugins
1281 * @return boolean
1282 */
1283 function ai1wm_deactivate_sitewide_plugins( $plugins ) {
1284 $current = get_site_option( AI1WM_ACTIVE_SITEWIDE_PLUGINS, array() );
1285
1286 // Add plugins
1287 foreach ( $plugins as $plugin ) {
1288 if ( isset( $current[ $plugin ] ) ) {
1289 unset( $current[ $plugin ] );
1290 }
1291 }
1292
1293 return update_site_option( AI1WM_ACTIVE_SITEWIDE_PLUGINS, $current );
1294 }
1295
1296
1297 /**
1298 * Set inactive plugins (inspired by WordPress deactivate_plugins() function)
1299 *
1300 * @param array $plugins List of plugins
1301 * @return boolean
1302 */
1303 function ai1wm_deactivate_plugins( $plugins ) {
1304 $current = get_option( AI1WM_ACTIVE_PLUGINS, array() );
1305
1306 // Remove plugins
1307 foreach ( $plugins as $plugin ) {
1308 if ( ( $key = array_search( $plugin, $current ) ) !== false ) {
1309 unset( $current[ $key ] );
1310 }
1311 }
1312
1313 return update_option( AI1WM_ACTIVE_PLUGINS, $current );
1314 }
1315
1316 /**
1317 * Deactivate Jetpack modules
1318 *
1319 * @param array $modules List of modules
1320 * @return boolean
1321 */
1322 function ai1wm_deactivate_jetpack_modules( $modules ) {
1323 $current = get_option( AI1WM_JETPACK_ACTIVE_MODULES, array() );
1324
1325 // Remove modules
1326 foreach ( $modules as $module ) {
1327 if ( ( $key = array_search( $module, $current ) ) !== false ) {
1328 unset( $current[ $key ] );
1329 }
1330 }
1331
1332 return update_option( AI1WM_JETPACK_ACTIVE_MODULES, $current );
1333 }
1334
1335 /**
1336 * Deactivate Swift Optimizer rules
1337 *
1338 * @param array $rules List of rules
1339 * @return boolean
1340 */
1341 function ai1wm_deactivate_swift_optimizer_rules( $rules ) {
1342 $current = get_option( AI1WM_SWIFT_OPTIMIZER_PLUGIN_ORGANIZER, array() );
1343
1344 // Remove rules
1345 foreach ( $rules as $rule ) {
1346 unset( $current['rules'][ $rule ] );
1347 }
1348
1349 return update_option( AI1WM_SWIFT_OPTIMIZER_PLUGIN_ORGANIZER, $current );
1350 }
1351
1352 /**
1353 * Deactivate sitewide Revolution Slider
1354 *
1355 * @param string $basename Plugin basename
1356 * @return boolean
1357 */
1358 function ai1wm_deactivate_sitewide_revolution_slider( $basename ) {
1359 if ( ( $plugins = get_plugins() ) ) {
1360 if ( isset( $plugins[ $basename ]['Version'] ) && ( $version = $plugins[ $basename ]['Version'] ) ) {
1361 if ( version_compare( PHP_VERSION, '7.3', '>=' ) && version_compare( $version, '5.4.8.3', '<' ) ) {
1362 return ai1wm_deactivate_sitewide_plugins( array( $basename ) );
1363 }
1364
1365 if ( version_compare( PHP_VERSION, '7.2', '>=' ) && version_compare( $version, '5.4.6', '<' ) ) {
1366 return ai1wm_deactivate_sitewide_plugins( array( $basename ) );
1367 }
1368
1369 if ( version_compare( PHP_VERSION, '7.1', '>=' ) && version_compare( $version, '5.4.1', '<' ) ) {
1370 return ai1wm_deactivate_sitewide_plugins( array( $basename ) );
1371 }
1372
1373 if ( version_compare( PHP_VERSION, '7.0', '>=' ) && version_compare( $version, '4.6.5', '<' ) ) {
1374 return ai1wm_deactivate_sitewide_plugins( array( $basename ) );
1375 }
1376 }
1377 }
1378
1379 return false;
1380 }
1381
1382 /**
1383 * Deactivate Revolution Slider
1384 *
1385 * @param string $basename Plugin basename
1386 * @return boolean
1387 */
1388 function ai1wm_deactivate_revolution_slider( $basename ) {
1389 if ( ( $plugins = get_plugins() ) ) {
1390 if ( isset( $plugins[ $basename ]['Version'] ) && ( $version = $plugins[ $basename ]['Version'] ) ) {
1391 if ( version_compare( PHP_VERSION, '7.3', '>=' ) && version_compare( $version, '5.4.8.3', '<' ) ) {
1392 return ai1wm_deactivate_plugins( array( $basename ) );
1393 }
1394
1395 if ( version_compare( PHP_VERSION, '7.2', '>=' ) && version_compare( $version, '5.4.6', '<' ) ) {
1396 return ai1wm_deactivate_plugins( array( $basename ) );
1397 }
1398
1399 if ( version_compare( PHP_VERSION, '7.1', '>=' ) && version_compare( $version, '5.4.1', '<' ) ) {
1400 return ai1wm_deactivate_plugins( array( $basename ) );
1401 }
1402
1403 if ( version_compare( PHP_VERSION, '7.0', '>=' ) && version_compare( $version, '4.6.5', '<' ) ) {
1404 return ai1wm_deactivate_plugins( array( $basename ) );
1405 }
1406 }
1407 }
1408
1409 return false;
1410 }
1411
1412 /**
1413 * Initial DB version
1414 *
1415 * @return boolean
1416 */
1417 function ai1wm_initial_db_version() {
1418 if ( ! get_option( AI1WM_DB_VERSION ) ) {
1419 return update_option( AI1WM_DB_VERSION, get_option( AI1WM_INITIAL_DB_VERSION ) );
1420 }
1421
1422 return false;
1423 }
1424
1425 /**
1426 * Discover plugin basename
1427 *
1428 * @param string $basename Plugin basename
1429 * @return string
1430 */
1431 function ai1wm_discover_plugin_basename( $basename ) {
1432 if ( ( $plugins = get_plugins() ) ) {
1433 foreach ( $plugins as $plugin => $info ) {
1434 if ( strpos( dirname( $plugin ), dirname( $basename ) ) !== false ) {
1435 if ( basename( $plugin ) === basename( $basename ) ) {
1436 return $plugin;
1437 }
1438 }
1439 }
1440 }
1441
1442 return $basename;
1443 }
1444
1445 /**
1446 * Validate plugin basename
1447 *
1448 * @param string $basename Plugin basename
1449 * @return boolean
1450 */
1451 function ai1wm_validate_plugin_basename( $basename ) {
1452 if ( ( $plugins = get_plugins() ) ) {
1453 foreach ( $plugins as $plugin => $info ) {
1454 if ( $plugin === $basename ) {
1455 return true;
1456 }
1457 }
1458 }
1459
1460 return false;
1461 }
1462
1463 /**
1464 * Validate theme basename
1465 *
1466 * @param string $basename Theme basename
1467 * @return boolean
1468 */
1469 function ai1wm_validate_theme_basename( $basename ) {
1470 if ( ( $themes = search_theme_directories() ) ) {
1471 foreach ( $themes as $theme => $info ) {
1472 if ( $info['theme_file'] === $basename ) {
1473 return true;
1474 }
1475 }
1476 }
1477
1478 return false;
1479 }
1480
1481 /**
1482 * Flush WP options cache
1483 *
1484 * @return void
1485 */
1486 function ai1wm_cache_flush() {
1487 wp_cache_init();
1488 wp_cache_flush();
1489
1490 // Reset WP options cache
1491 wp_cache_set( 'alloptions', array(), 'options' );
1492 wp_cache_set( 'notoptions', array(), 'options' );
1493
1494 // Reset WP sitemeta cache
1495 wp_cache_set( '1:notoptions', array(), 'site-options' );
1496 wp_cache_set( '1:ms_files_rewriting', false, 'site-options' );
1497 wp_cache_set( '1:active_sitewide_plugins', false, 'site-options' );
1498
1499 // Delete WP options cache
1500 wp_cache_delete( 'alloptions', 'options' );
1501 wp_cache_delete( 'notoptions', 'options' );
1502
1503 // Delete WP sitemeta cache
1504 wp_cache_delete( '1:notoptions', 'site-options' );
1505 wp_cache_delete( '1:ms_files_rewriting', 'site-options' );
1506 wp_cache_delete( '1:active_sitewide_plugins', 'site-options' );
1507
1508 // Remove WP options filter
1509 remove_all_filters( 'sanitize_option_home' );
1510 remove_all_filters( 'sanitize_option_siteurl' );
1511 remove_all_filters( 'default_site_option_ms_files_rewriting' );
1512 }
1513
1514 /**
1515 * Flush Elementor cache
1516 *
1517 * @return void
1518 */
1519 function ai1wm_elementor_cache_flush() {
1520 delete_post_meta_by_key( '_elementor_css' );
1521 delete_post_meta_by_key( '_elementor_element_cache' );
1522 delete_post_meta_by_key( '_elementor_page_assets' );
1523
1524 delete_option( '_elementor_global_css' );
1525 delete_option( '_elementor_assets_data' );
1526 delete_option( 'elementor-custom-breakpoints-files' );
1527 }
1528
1529 /**
1530 * Set WooCommerce Force SSL checkout
1531 *
1532 * @param boolean $yes Force SSL checkout
1533 * @return void
1534 */
1535 function ai1wm_woocommerce_force_ssl( $yes = true ) {
1536 if ( get_option( 'woocommerce_force_ssl_checkout' ) ) {
1537 if ( $yes ) {
1538 update_option( 'woocommerce_force_ssl_checkout', 'yes' );
1539 } else {
1540 update_option( 'woocommerce_force_ssl_checkout', 'no' );
1541 }
1542 }
1543 }
1544
1545 /**
1546 * Set URL scheme
1547 *
1548 * @param string $url URL value
1549 * @param string $scheme URL scheme
1550 * @return string
1551 */
1552 function ai1wm_url_scheme( $url, $scheme = '' ) {
1553 if ( empty( $scheme ) ) {
1554 return preg_replace( '#^\w+://#', '//', $url );
1555 }
1556
1557 return preg_replace( '#^\w+://#', $scheme . '://', $url );
1558 }
1559
1560 /**
1561 * Opens a file in specified mode
1562 *
1563 * @param string $file Path to the file to open
1564 * @param string $mode Mode in which to open the file
1565 * @return resource
1566 * @throws Ai1wm_Not_Accessible_Exception
1567 */
1568 function ai1wm_open( $file, $mode ) {
1569 $file_handle = @fopen( $file, $mode );
1570 if ( false === $file_handle ) {
1571 throw new Ai1wm_Not_Accessible_Exception(
1572 wp_kses(
1573 /* translators: 1: File path, 2: mode */
1574 sprintf( __( 'Could not open %1$s with mode %2$s. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-file-permissions/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), $file, $mode ),
1575 ai1wm_allowed_html_tags()
1576 )
1577 );
1578 }
1579
1580 return $file_handle;
1581 }
1582
1583 /**
1584 * Opens a gzipped file in specified mode
1585 *
1586 * @param string $file Path to the file to open
1587 * @param string $mode Mode in which to open the file
1588 * @return resource
1589 * @throws Ai1wm_Not_Accessible_Exception
1590 */
1591 function ai1wm_gzopen( $file, $mode ) {
1592 $file_handle = @fopen( "compress.zlib://{$file}", $mode );
1593 if ( false === $file_handle ) {
1594 throw new Ai1wm_Not_Accessible_Exception(
1595 wp_kses(
1596 /* translators: 1: File path, 2: mode */
1597 sprintf( __( 'Could not open %1$s with mode %2$s. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-file-permissions/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), $file, $mode ),
1598 ai1wm_allowed_html_tags()
1599 )
1600 );
1601 }
1602
1603 return $file_handle;
1604 }
1605
1606 /**
1607 * Write contents to a file
1608 *
1609 * @param resource $handle File handle to write to
1610 * @param string $content Contents to write to the file
1611 * @return integer
1612 * @throws Ai1wm_Not_Writable_Exception
1613 * @throws Ai1wm_Quota_Exceeded_Exception
1614 */
1615 function ai1wm_write( $handle, $content ) {
1616 $write_result = @fwrite( $handle, $content );
1617 if ( false === $write_result ) {
1618 if ( ( $meta = stream_get_meta_data( $handle ) ) ) {
1619 throw new Ai1wm_Not_Writable_Exception(
1620 wp_kses(
1621 /* translators: 1: Meta data stream URI. */
1622 sprintf( __( 'Could not write to: %s. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-file-permissions/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), $meta['uri'] ),
1623 ai1wm_allowed_html_tags()
1624 )
1625 );
1626 }
1627 } elseif ( null === $write_result ) {
1628 return strlen( $content );
1629 } elseif ( strlen( $content ) !== $write_result ) {
1630 if ( ( $meta = stream_get_meta_data( $handle ) ) ) {
1631 throw new Ai1wm_Quota_Exceeded_Exception(
1632 wp_kses(
1633 /* translators: 1: Meta data stream URI. */
1634 sprintf( __( 'Out of disk space. Could not write to: %s. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/out-of-disk-space/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), $meta['uri'] ),
1635 ai1wm_allowed_html_tags()
1636 )
1637 );
1638 }
1639 }
1640
1641 return $write_result;
1642 }
1643
1644 /**
1645 * Read contents from a file
1646 *
1647 * @param resource $handle File handle to read from
1648 * @param integer $length Up to length number of bytes read
1649 * @return string
1650 * @throws Ai1wm_Not_Readable_Exception
1651 */
1652 function ai1wm_read( $handle, $length ) {
1653 if ( $length > 0 ) {
1654 $read_result = @fread( $handle, $length );
1655 if ( false === $read_result ) {
1656 if ( ( $meta = stream_get_meta_data( $handle ) ) ) {
1657 throw new Ai1wm_Not_Readable_Exception(
1658 wp_kses(
1659 /* translators: 1: Meta data stream URI. */
1660 sprintf( __( 'Could not read file: %s. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-file-permissions/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), $meta['uri'] ),
1661 ai1wm_allowed_html_tags()
1662 )
1663 );
1664 }
1665 }
1666
1667 return $read_result;
1668 }
1669
1670 return false;
1671 }
1672
1673 /**
1674 * Seeks on a file pointer
1675 *
1676 * @param resource $handle File handle
1677 * @param integer $offset File offset
1678 * @param integer $mode Offset mode
1679 * @return integer
1680 */
1681 function ai1wm_seek( $handle, $offset, $mode = SEEK_SET ) {
1682 $seek_result = @fseek( $handle, $offset, $mode );
1683 if ( -1 === $seek_result ) {
1684 if ( ( $meta = stream_get_meta_data( $handle ) ) ) {
1685 throw new Ai1wm_Not_Seekable_Exception(
1686 wp_kses(
1687 /* translators: 1: File offset, 2: Meta data stream URI. */
1688 sprintf( __( 'Could not seek to offset %1$d on %2$s. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/php-32bit/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), $offset, $meta['uri'] ),
1689 ai1wm_allowed_html_tags()
1690 )
1691 );
1692 }
1693 }
1694
1695 return $seek_result;
1696 }
1697
1698 /**
1699 * Returns the current position of the file read/write pointer
1700 *
1701 * @param resource $handle File handle
1702 * @return integer
1703 */
1704 function ai1wm_tell( $handle ) {
1705 $tell_result = @ftell( $handle );
1706 if ( false === $tell_result ) {
1707 if ( ( $meta = stream_get_meta_data( $handle ) ) ) {
1708 throw new Ai1wm_Not_Tellable_Exception(
1709 wp_kses(
1710 /* translators: 1: Meta data stream URI. */
1711 sprintf( __( 'Could not get current pointer position of %s. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/php-32bit/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), $meta['uri'] ),
1712 ai1wm_allowed_html_tags()
1713 )
1714 );
1715 }
1716 }
1717
1718 return $tell_result;
1719 }
1720
1721 /**
1722 * Write fields to a file
1723 *
1724 * @param resource $handle File handle to write to
1725 * @param array $fields Fields to write to the file
1726 * @param string $separator
1727 * @param string $enclosure
1728 * @param string $escape
1729 *
1730 * @return integer
1731 * @throws Ai1wm_Not_Writable_Exception
1732 */
1733 function ai1wm_putcsv( $handle, $fields, $separator = ',', $enclosure = '"', $escape = '\\' ) {
1734 if ( PHP_MAJOR_VERSION >= 7 ) {
1735 // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters
1736 $write_result = @fputcsv( $handle, $fields, $separator, $enclosure, $escape );
1737 } else {
1738 $write_result = @fputcsv( $handle, $fields, $separator, $enclosure );
1739 }
1740
1741 if ( false === $write_result ) {
1742 if ( ( $meta = stream_get_meta_data( $handle ) ) ) {
1743 throw new Ai1wm_Not_Writable_Exception(
1744 wp_kses(
1745 /* translators: 1: Meta data stream URI. */
1746 sprintf( __( 'Could not write to: %s. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-file-permissions/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), $meta['uri'] ),
1747 ai1wm_allowed_html_tags()
1748 )
1749 );
1750 }
1751 }
1752
1753 return $write_result;
1754 }
1755
1756 /**
1757 * Read fields from a file
1758 *
1759 * @param resource $handle File handle to read from
1760 * @param int $length
1761 * @param string $separator
1762 * @param string $enclosure
1763 * @param string $escape
1764 *
1765 * @return array|false|null
1766 */
1767 function ai1wm_getcsv( $handle, $length = null, $separator = ',', $enclosure = '"', $escape = '\\' ) {
1768 return fgetcsv( $handle, $length, $separator, $enclosure, $escape );
1769 }
1770
1771 /**
1772 * Closes a file handle
1773 *
1774 * @param resource $handle File handle to close
1775 * @return boolean
1776 */
1777 function ai1wm_close( $handle ) {
1778 return @fclose( $handle );
1779 }
1780
1781 /**
1782 * Deletes a file
1783 *
1784 * @param string $file Path to file to delete
1785 * @return boolean
1786 */
1787 function ai1wm_unlink( $file ) {
1788 return @unlink( $file );
1789 }
1790
1791 /**
1792 * Sets modification time of a file
1793 *
1794 * @param string $file Path to file to change modification time
1795 * @param integer $time File modification time
1796 * @return boolean
1797 */
1798 function ai1wm_touch( $file, $mtime ) {
1799 return @touch( $file, $mtime );
1800 }
1801
1802 /**
1803 * Changes file mode
1804 *
1805 * @param string $file Path to file to change mode
1806 * @param integer $time File mode
1807 * @return boolean
1808 */
1809 function ai1wm_chmod( $file, $mode ) {
1810 return @chmod( $file, $mode );
1811 }
1812
1813 /**
1814 * Copies one file's contents to another
1815 *
1816 * @param string $target_file File to copy the contents from
1817 * @param string $output_file File to copy the contents to
1818 * @param integer $output_file_offset Output file offset bytes
1819 * @return void
1820 */
1821 function ai1wm_copy( $target_file, $output_file, $output_file_offset = 0 ) {
1822 $target_handle = ai1wm_open( $target_file, 'rb' );
1823 $output_handle = ai1wm_open( $output_file, 'cb' );
1824 if ( ai1wm_seek( $output_handle, $output_file_offset, SEEK_SET ) !== -1 ) {
1825 while ( ( $file_buffer = ai1wm_read( $target_handle, 4096 ) ) ) {
1826 ai1wm_write( $output_handle, $file_buffer );
1827 }
1828 }
1829
1830 ai1wm_close( $target_handle );
1831 ai1wm_close( $output_handle );
1832 }
1833
1834 /**
1835 * Copies gzipped file's contents while uncompressing to another
1836 *
1837 * @param string $target_file File to copy the contents from
1838 * @param string $output_file File to copy the contents to
1839 * @param integer $output_file_offset Output file offset bytes
1840 * @return void
1841 */
1842 function ai1wm_copy_gz( $target_file, $output_file, $output_file_offset = 0 ) {
1843 $target_handle = ai1wm_gzopen( $target_file, 'rb' );
1844 $output_handle = ai1wm_open( $output_file, 'cb' );
1845 if ( ai1wm_seek( $output_handle, $output_file_offset, SEEK_SET ) !== -1 ) {
1846 while ( ( $file_buffer = ai1wm_read( $target_handle, 4096 ) ) ) {
1847 ai1wm_write( $output_handle, $file_buffer );
1848 }
1849 }
1850
1851 ai1wm_close( $target_handle );
1852 ai1wm_close( $output_handle );
1853 }
1854
1855
1856 /**
1857 * Check whether file size is supported by current PHP version
1858 *
1859 * @param string $file Path to file
1860 * @param integer $php_int_size Size of PHP integer
1861 * @return boolean $php_int_max Max value of PHP integer
1862 */
1863 function ai1wm_is_filesize_supported( $file, $php_int_size = PHP_INT_SIZE, $php_int_max = PHP_INT_MAX ) {
1864 $size_result = true;
1865
1866 // Check whether file size is less than 2GB in PHP 32bits
1867 if ( $php_int_size === 4 ) {
1868 if ( ( $file_handle = @fopen( $file, 'rb' ) ) ) {
1869 if ( @fseek( $file_handle, $php_int_max, SEEK_SET ) !== -1 ) {
1870 if ( @fgetc( $file_handle ) !== false ) {
1871 $size_result = false;
1872 }
1873 }
1874
1875 @fclose( $file_handle );
1876 }
1877 }
1878
1879 return $size_result;
1880 }
1881
1882 /**
1883 * Check whether file name is supported by All-in-One WP Migration
1884 *
1885 * @param string $file Path to file
1886 * @param array $extensions File extensions
1887 * @return boolean
1888 */
1889 function ai1wm_is_filename_supported( $file, $extensions = array( 'wpress' ) ) {
1890 if ( in_array( pathinfo( $file, PATHINFO_EXTENSION ), $extensions ) ) {
1891 return true;
1892 }
1893
1894 return false;
1895 }
1896
1897 /**
1898 * Check whether file data is supported by All-in-One WP Migration
1899 *
1900 * @param string $file Path to file
1901 * @return boolean
1902 */
1903 function ai1wm_is_filedata_supported( $file ) {
1904 if ( ( $file_handle = @fopen( $file, 'rb' ) ) ) {
1905 if ( ( $file_buffer = @fread( $file_handle, Ai1wm_Archiver::HEADER_SIZE ) ) ) {
1906 if ( ( $file_data = @unpack( 'a255filename/a14size/a12mtime/a4088path/a8crc32', $file_buffer ) ) !== false ) {
1907 if ( AI1WM_PACKAGE_NAME === trim( $file_data['filename'] ) ) {
1908 return true;
1909 }
1910 }
1911 }
1912
1913 @fclose( $file_handle );
1914 }
1915
1916 return false;
1917 }
1918
1919 /**
1920 * Check whether gzipped file data is supported by All-in-One WP Migration
1921 *
1922 * @param string $file Path to file
1923 * @return boolean
1924 */
1925 function ai1wm_is_gzipped_filedata_supported( $file ) {
1926 if ( ( $file_handle = @gzopen( $file, 'rb' ) ) ) {
1927 if ( ( $file_buffer = @gzread( $file_handle, Ai1wm_Archiver::HEADER_SIZE ) ) ) {
1928 if ( ( $file_data = @unpack( 'a255filename/a14size/a12mtime/a4088path/a8crc32', $file_buffer ) ) !== false ) {
1929 if ( AI1WM_PACKAGE_NAME === trim( $file_data['filename'] ) ) {
1930 return true;
1931 }
1932 }
1933 }
1934
1935 @gzclose( $file_handle );
1936 }
1937
1938 return false;
1939 }
1940
1941 /**
1942 * Verify secret key
1943 *
1944 * @param string $secret_key Secret key
1945 * @return boolean
1946 * @throws Ai1wm_Not_Valid_Secret_Key_Exception
1947 */
1948 function ai1wm_verify_secret_key( $secret_key ) {
1949 if ( $secret_key !== get_option( AI1WM_SECRET_KEY ) ) {
1950 throw new Ai1wm_Not_Valid_Secret_Key_Exception(
1951 wp_kses(
1952 __( 'Could not authenticate the secret key. The process cannot continue. <a href="https://help.servmask.com/knowledgebase/invalid-secret-key/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ),
1953 ai1wm_allowed_html_tags()
1954 )
1955 );
1956 }
1957
1958 return true;
1959 }
1960
1961 /**
1962 * Is scheduled backup?
1963 *
1964 * @return boolean
1965 */
1966 function ai1wm_is_scheduled_backup() {
1967 if ( isset( $_GET['ai1wm_manual_export'] ) || isset( $_POST['ai1wm_manual_export'] ) ) {
1968 return false;
1969 }
1970
1971 if ( isset( $_GET['ai1wm_manual_import'] ) || isset( $_POST['ai1wm_manual_import'] ) ) {
1972 return false;
1973 }
1974
1975 if ( isset( $_GET['ai1wm_manual_restore'] ) || isset( $_POST['ai1wm_manual_restore'] ) ) {
1976 return false;
1977 }
1978
1979 if ( isset( $_GET['ai1wm_manual_reset'] ) || isset( $_POST['ai1wm_manual_reset'] ) ) {
1980 return false;
1981 }
1982
1983 return true;
1984 }
1985
1986 /**
1987 * PHP setup environment
1988 *
1989 * @return void
1990 */
1991 function ai1wm_setup_environment() {
1992 // Set whether a client disconnect should abort script execution
1993 @ignore_user_abort( true );
1994
1995 // Set maximum execution time
1996 @set_time_limit( 0 );
1997
1998 // Set maximum time in seconds a script is allowed to parse input data
1999 @ini_set( 'max_input_time', '-1' );
2000
2001 // Set maximum backtracking steps
2002 @ini_set( 'pcre.backtrack_limit', PHP_INT_MAX );
2003
2004 // Set binary safe encoding
2005 // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives
2006 if ( @function_exists( 'mb_internal_encoding' ) && ( @ini_get( 'mbstring.func_overload' ) & 2 ) ) {
2007 @mb_internal_encoding( 'ISO-8859-1' );
2008 }
2009
2010 // Clean (erase) the output buffer and turn off output buffering
2011 if ( @ob_get_length() ) {
2012 @ob_end_clean();
2013 }
2014 }
2015
2016 /**
2017 * PHP register error handlers
2018 *
2019 * @return void
2020 */
2021 function ai1wm_setup_errors() {
2022 @set_error_handler( 'Ai1wm_Handler::error' );
2023 @register_shutdown_function( 'Ai1wm_Handler::shutdown' );
2024 }
2025
2026 /**
2027 * Get WordPress time zone string
2028 *
2029 * @return string
2030 */
2031 function ai1wm_get_timezone_string() {
2032 if ( ( $timezone_string = get_option( 'timezone_string' ) ) ) {
2033 return $timezone_string;
2034 }
2035
2036 if ( ( $gmt_offset = get_option( 'gmt_offset' ) ) ) {
2037 if ( $gmt_offset > 0 ) {
2038 return sprintf( 'UTC+%s', abs( $gmt_offset ) );
2039 } elseif ( $gmt_offset < 0 ) {
2040 return sprintf( 'UTC-%s', abs( $gmt_offset ) );
2041 }
2042 }
2043
2044 return 'UTC';
2045 }
2046
2047 /**
2048 * Get WordPress filter hooks
2049 *
2050 * @param string $tag The name of the filter hook
2051 * @return array
2052 */
2053 function ai1wm_get_filters( $tag ) {
2054 global $wp_filter;
2055
2056 // Get WordPress filter hooks
2057 $filters = array();
2058 if ( isset( $wp_filter[ $tag ] ) ) {
2059 if ( ( $filters = $wp_filter[ $tag ] ) ) {
2060 // WordPress 4.7 introduces new class for working with filters/actions called WP_Hook
2061 // which adds another level of abstraction and we need to address it.
2062 if ( isset( $filters->callbacks ) ) {
2063 $filters = $filters->callbacks;
2064 }
2065 }
2066
2067 ksort( $filters );
2068 }
2069
2070 return $filters;
2071 }
2072
2073 /**
2074 * Get WordPress plugins directories
2075 *
2076 * @return array
2077 */
2078 function ai1wm_get_themes_dirs() {
2079 $theme_dirs = array();
2080 foreach ( search_theme_directories() as $theme_name => $theme_info ) {
2081 if ( isset( $theme_info['theme_root'] ) ) {
2082 if ( ! in_array( $theme_info['theme_root'], $theme_dirs ) ) {
2083 $theme_dirs[] = untrailingslashit( $theme_info['theme_root'] );
2084 }
2085 }
2086 }
2087
2088 return $theme_dirs;
2089 }
2090
2091 /**
2092 * Get WordPress plugins directory
2093 *
2094 * @return string
2095 */
2096 function ai1wm_get_plugins_dir() {
2097 return untrailingslashit( WP_PLUGIN_DIR );
2098 }
2099
2100 /**
2101 * Get WordPress uploads directory
2102 *
2103 * @return string
2104 */
2105 function ai1wm_get_uploads_dir() {
2106 if ( ( $upload_dir = wp_upload_dir() ) ) {
2107 if ( isset( $upload_dir['basedir'] ) ) {
2108 return untrailingslashit( $upload_dir['basedir'] );
2109 }
2110 }
2111 }
2112
2113 /**
2114 * Get WordPress uploads URL
2115 *
2116 * @return string
2117 */
2118 function ai1wm_get_uploads_url() {
2119 if ( ( $upload_dir = wp_upload_dir() ) ) {
2120 if ( isset( $upload_dir['baseurl'] ) ) {
2121 return trailingslashit( $upload_dir['baseurl'] );
2122 }
2123 }
2124 }
2125
2126 /**
2127 * Get WordPress uploads path
2128 *
2129 * @return string
2130 */
2131 function ai1wm_get_uploads_path() {
2132 if ( ( $upload_dir = wp_upload_dir() ) ) {
2133 if ( isset( $upload_dir['basedir'] ) ) {
2134 return str_replace( ABSPATH, '', $upload_dir['basedir'] );
2135 }
2136 }
2137 }
2138
2139 /**
2140 * i18n friendly version of basename()
2141 *
2142 * @param string $path File path
2143 * @param string $suffix If the filename ends in suffix this will also be cut off
2144 * @return string
2145 */
2146 function ai1wm_basename( $path, $suffix = '' ) {
2147 return urldecode( basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) );
2148 }
2149
2150 /**
2151 * i18n friendly version of dirname()
2152 *
2153 * @param string $path File path
2154 * @return string
2155 */
2156 function ai1wm_dirname( $path ) {
2157 return urldecode( dirname( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ) ) );
2158 }
2159
2160 /**
2161 * Replace forward slash with current directory separator
2162 *
2163 * @param string $path Path
2164 * @return string
2165 */
2166 function ai1wm_replace_forward_slash_with_directory_separator( $path ) {
2167 return str_replace( '/', DIRECTORY_SEPARATOR, $path );
2168 }
2169
2170 /**
2171 * Replace current directory separator with forward slash
2172 *
2173 * @param string $path Path
2174 * @return string
2175 */
2176 function ai1wm_replace_directory_separator_with_forward_slash( $path ) {
2177 return str_replace( DIRECTORY_SEPARATOR, '/', $path );
2178 }
2179
2180 /**
2181 * Escape Windows directory separator
2182 *
2183 * @param string $path Path
2184 * @return string
2185 */
2186 function ai1wm_escape_windows_directory_separator( $path ) {
2187 return preg_replace( '/[\\\\]+/', '\\\\\\\\', $path );
2188 }
2189
2190 /**
2191 * Should reset WordPress permalinks?
2192 *
2193 * @param array $params Request parameters
2194 * @return boolean
2195 */
2196 function ai1wm_should_reset_permalinks( $params ) {
2197 global $wp_rewrite, $is_apache;
2198
2199 // Permalinks are not supported
2200 if ( empty( $params['using_permalinks'] ) ) {
2201 if ( $wp_rewrite->using_permalinks() ) {
2202 if ( $is_apache ) {
2203 if ( ! apache_mod_loaded( 'mod_rewrite', false ) ) {
2204 return true;
2205 }
2206 }
2207 }
2208 }
2209
2210 return false;
2211 }
2212
2213 /**
2214 * Get .htaccess file content
2215 *
2216 * @return string
2217 */
2218 function ai1wm_get_htaccess() {
2219 if ( is_file( AI1WM_WORDPRESS_HTACCESS ) ) {
2220 return @file_get_contents( AI1WM_WORDPRESS_HTACCESS );
2221 }
2222
2223 return '';
2224 }
2225
2226 /**
2227 * Get web.config file content
2228 *
2229 * @return string
2230 */
2231 function ai1wm_get_webconfig() {
2232 if ( is_file( AI1WM_WORDPRESS_WEBCONFIG ) ) {
2233 return @file_get_contents( AI1WM_WORDPRESS_WEBCONFIG );
2234 }
2235
2236 return '';
2237 }
2238
2239 /**
2240 * Get available space on filesystem or disk partition
2241 *
2242 * @param string $path Directory of the filesystem or disk partition
2243 * @return mixed
2244 */
2245 function ai1wm_disk_free_space( $path ) {
2246 if ( function_exists( 'disk_free_space' ) ) {
2247 return @disk_free_space( $path );
2248 }
2249 }
2250
2251 /**
2252 * Set response header to json end echo data
2253 *
2254 * @param array $data
2255 * @param int $options
2256 * @param int $depth
2257 * @return void
2258 */
2259 function ai1wm_json_response( $data, $options = 0 ) {
2260 if ( ! headers_sent() ) {
2261 header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset', 'utf-8' ) );
2262 }
2263
2264 echo json_encode( $data, $options );
2265 }
2266
2267 /**
2268 * Determines if the server can encrypt backups
2269 *
2270 * @return boolean
2271 */
2272 function ai1wm_can_encrypt() {
2273 if ( ! function_exists( 'openssl_encrypt' ) ) {
2274 return false;
2275 }
2276
2277 if ( ! function_exists( 'openssl_random_pseudo_bytes' ) ) {
2278 return false;
2279 }
2280
2281 if ( ! function_exists( 'openssl_cipher_iv_length' ) ) {
2282 return false;
2283 }
2284
2285 if ( ! function_exists( 'sha1' ) ) {
2286 return false;
2287 }
2288
2289 if ( ! in_array( AI1WM_CIPHER_NAME, array_map( 'strtoupper', openssl_get_cipher_methods() ) ) ) {
2290 return false;
2291 }
2292
2293 return true;
2294 }
2295
2296 /**
2297 * Determines if the server can decrypt backups
2298 *
2299 * @return boolean
2300 */
2301 function ai1wm_can_decrypt() {
2302 if ( ! function_exists( 'openssl_decrypt' ) ) {
2303 return false;
2304 }
2305
2306 if ( ! function_exists( 'openssl_random_pseudo_bytes' ) ) {
2307 return false;
2308 }
2309
2310 if ( ! function_exists( 'openssl_cipher_iv_length' ) ) {
2311 return false;
2312 }
2313
2314 if ( ! function_exists( 'sha1' ) ) {
2315 return false;
2316 }
2317
2318 if ( ! in_array( AI1WM_CIPHER_NAME, array_map( 'strtoupper', openssl_get_cipher_methods() ) ) ) {
2319 return false;
2320 }
2321
2322 return true;
2323 }
2324
2325 /**
2326 * Encrypts a string with a key
2327 *
2328 * @param string $string String to encrypt
2329 * @param string $key Key to encrypt the string with
2330 * @return string
2331 * @throws Ai1wm_Not_Encryptable_Exception
2332 */
2333 function ai1wm_encrypt_string( $string, $key ) {
2334 $iv_length = ai1wm_crypt_iv_length();
2335 $key = substr( sha1( $key, true ), 0, $iv_length );
2336
2337 $iv = openssl_random_pseudo_bytes( $iv_length );
2338 if ( $iv === false ) {
2339 throw new Ai1wm_Not_Encryptable_Exception( esc_html__( 'Could not generate random bytes. The process cannot continue.', 'all-in-one-wp-migration' ) );
2340 }
2341
2342 // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters, PHPCompatibility.Constants.NewConstants
2343 $encrypted_string = openssl_encrypt( $string, AI1WM_CIPHER_NAME, $key, OPENSSL_RAW_DATA, $iv );
2344 if ( $encrypted_string === false ) {
2345 throw new Ai1wm_Not_Encryptable_Exception( esc_html__( 'Could not encrypt data. The process cannot continue.', 'all-in-one-wp-migration' ) );
2346 }
2347
2348 return sprintf( '%s%s', $iv, $encrypted_string );
2349 }
2350
2351 /**
2352 * Returns encrypt/decrypt iv length
2353 *
2354 * @return int
2355 * @throws Ai1wm_Not_Encryptable_Exception
2356 */
2357 function ai1wm_crypt_iv_length() {
2358 $iv_length = openssl_cipher_iv_length( AI1WM_CIPHER_NAME );
2359 if ( $iv_length === false ) {
2360 throw new Ai1wm_Not_Encryptable_Exception( esc_html__( 'Could not obtain cipher length. The process cannot continue.', 'all-in-one-wp-migration' ) );
2361 }
2362
2363 return $iv_length;
2364 }
2365
2366 /**
2367 * Decrypts a string with a key
2368 *
2369 * @param string $encrypted_string String to decrypt
2370 * @param string $key Key to decrypt the string with
2371 * @return string
2372 * @throws Ai1wm_Not_Encryptable_Exception
2373 * @throws Ai1wm_Not_Decryptable_Exception
2374 */
2375 function ai1wm_decrypt_string( $encrypted_string, $key ) {
2376 $iv_length = ai1wm_crypt_iv_length();
2377 $key = substr( sha1( $key, true ), 0, $iv_length );
2378 $iv = substr( $encrypted_string, 0, $iv_length );
2379
2380 // phpcs:ignore PHPCompatibility.Constants.NewConstants, PHPCompatibility.FunctionUse.NewFunctionParameters
2381 $decrypted_string = openssl_decrypt( substr( $encrypted_string, $iv_length ), AI1WM_CIPHER_NAME, $key, OPENSSL_RAW_DATA, $iv );
2382 if ( $decrypted_string === false ) {
2383 throw new Ai1wm_Not_Decryptable_Exception( esc_html__( 'Could not decrypt data. The process cannot continue.', 'all-in-one-wp-migration' ) );
2384 }
2385
2386 return $decrypted_string;
2387 }
2388
2389 /**
2390 * Checks if decryption password is valid
2391 *
2392 * @param string $encrypted_signature
2393 * @param string $password
2394 * @return bool
2395 */
2396 function ai1wm_is_decryption_password_valid( $encrypted_signature, $password ) {
2397 try {
2398 $encrypted_signature = base64_decode( $encrypted_signature );
2399
2400 return ai1wm_decrypt_string( $encrypted_signature, $password ) === AI1WM_SIGN_TEXT;
2401 } catch ( Ai1wm_Not_Decryptable_Exception $exception ) {
2402 return false;
2403 }
2404 }
2405
2406 function ai1wm_populate_roles() {
2407 if ( ! function_exists( 'populate_roles' ) && ! function_exists( 'populate_options' ) && ! function_exists( 'populate_network' ) ) {
2408 require_once ABSPATH . 'wp-admin/includes/schema.php';
2409 }
2410
2411 if ( function_exists( 'populate_roles' ) ) {
2412 populate_roles();
2413 }
2414 }
2415
2416 /**
2417 * Set basic auth header to request
2418 *
2419 * @param array $headers
2420 *
2421 * @return array
2422 */
2423 function ai1wm_auth_headers( $headers = array() ) {
2424 if ( $hash = get_option( AI1WM_AUTH_HEADER ) ) {
2425 $headers['Authorization'] = sprintf( 'Basic %s', $hash );
2426 }
2427
2428 if ( ( $user = get_option( AI1WM_AUTH_USER ) ) && ( $password = get_option( AI1WM_AUTH_PASSWORD ) ) ) {
2429 if ( ! isset( $headers['Authorization'] ) && ( $hash = base64_encode( sprintf( '%s:%s', $user, $password ) ) ) ) {
2430 update_option( AI1WM_AUTH_HEADER, $hash );
2431 $headers['Authorization'] = sprintf( 'Basic %s', $hash );
2432 }
2433 delete_option( AI1WM_AUTH_USER );
2434 delete_option( AI1WM_AUTH_PASSWORD );
2435 }
2436
2437 return $headers;
2438 }
2439
2440 /**
2441 * Check if direct download of backup supported
2442 *
2443 * @return bool
2444 */
2445 function ai1wm_direct_download_supported() {
2446 return ! ( $_SERVER['SERVER_NAME'] === 'playground.wordpress.net' || $_SERVER['SERVER_SOFTWARE'] === 'PHP.wasm' );
2447 }
2448
2449 /**
2450 * Get allowed HTML tags when output with `wp_kses()`
2451 *
2452 * @return array
2453 */
2454 function ai1wm_allowed_html_tags() {
2455 return array(
2456 'a' => array(
2457 'href' => array(),
2458 'title' => array(),
2459 'target' => array(),
2460 'id' => array(),
2461 'name' => array(),
2462 'aria-label' => array(),
2463 'class' => array(),
2464 'style' => array(),
2465 'disabled' => array(),
2466 'download' => array(),
2467 ),
2468 'p' => array(
2469 'class' => array(),
2470 'style' => array(),
2471 ),
2472 'br' => array(),
2473 'em' => array(),
2474 'strong' => array(),
2475 'input' => array(
2476 'type' => array(),
2477 'name' => array(),
2478 'aria-label' => array(),
2479 'style' => array(),
2480 'id' => array(),
2481 'value' => array(),
2482 'class' => array(),
2483 'disabled' => array(),
2484 ),
2485 );
2486 }
2487
2488 /**
2489 * Wrapper for wp_register_style function
2490 *
2491 * @param string $handle Name of the stylesheet
2492 * @param string $src Path of the stylesheet
2493 * @param array $deps An array of registered stylesheet handles this stylesheet depends on
2494 * @param mixed $ver String specifying stylesheet version number
2495 * @param string $media The media for which this stylesheet has been defined
2496 *
2497 * @return bool
2498 */
2499 function ai1wm_register_style( $handle, $src, $deps = array(), $ver = false, $media = 'all' ) {
2500 if ( is_rtl() ) {
2501 $src = str_replace( '.min.css', '.min.rtl.css', $src );
2502 }
2503
2504 return wp_register_style( $handle, $src, $deps, $ver, $media );
2505 }
2506
2507 /**
2508 * Wrapper for wp_enqueue_style function
2509 *
2510 * @param string $handle Name of the stylesheet
2511 * @param string $src Path of the stylesheet
2512 * @param array $deps An array of registered stylesheet handles this stylesheet depends on
2513 * @param mixed $ver String specifying stylesheet version number
2514 * @param string $media The media for which this stylesheet has been defined
2515 *
2516 * @return void
2517 */
2518 function ai1wm_enqueue_style( $handle, $src = '', $deps = array(), $ver = false, $media = 'all' ) {
2519 if ( is_rtl() ) {
2520 $src = str_replace( '.min.css', '.min.rtl.css', $src );
2521 }
2522
2523 wp_enqueue_style( $handle, $src, $deps, $ver, $media );
2524 }
2525
2526 /**
2527 * Wrapper for wp_register_script function
2528 *
2529 * @param string $handle Name of the script
2530 * @param string $src Path of the script
2531 * @param array $deps An array of registered script handles this script depends on
2532 * @param mixed $ver String specifying script version number
2533 * @param mixed $args An array of additional script loading strategies
2534 *
2535 * @return bool
2536 */
2537 function ai1wm_register_script( $handle, $src, $deps = array(), $ver = false, $args = array() ) {
2538 return wp_register_script( $handle, $src, $deps, $ver, $args );
2539 }
2540
2541 /**
2542 * Wrapper for wp_enqueue_script function
2543 *
2544 * @param string $handle Name of the script
2545 * @param string $src Path of the script
2546 * @param array $deps An array of registered script handles this script depends on
2547 * @param mixed $ver String specifying script version number
2548 * @param mixed $args An array of additional script loading strategies
2549 *
2550 * @return void
2551 */
2552 function ai1wm_enqueue_script( $handle, $src = '', $deps = array(), $ver = false, $args = array() ) {
2553 wp_enqueue_script( $handle, $src, $deps, $ver, $args );
2554 }
2555
2556 /**
2557 * Check for compression type availability
2558 *
2559 * @param string $name Compression type
2560 * @return boolean
2561 */
2562 function ai1wm_has_compression_type( $name ) {
2563 switch ( strtolower( $name ) ) {
2564 case 'gzip':
2565 return function_exists( 'gzcompress' );
2566
2567 case 'bzip2':
2568 return function_exists( 'bzcompress' );
2569
2570 default:
2571 return false;
2572 }
2573 }
2574