PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.3.1
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.3.1
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 / Backend / Modules / Jobs / Scan.php
wp-staging / Backend / Modules / Jobs Last commit date
Cleaners 5 years ago Exceptions 5 years ago Cancel.php 2 years ago CancelUpdate.php 2 years ago Cloning.php 2 years ago CloningProcess.php 2 years ago Data.php 2 years ago Database.php 2 years ago Delete.php 2 years ago Directories.php 2 years ago Files.php 2 years ago Finish.php 2 years ago Job.php 2 years ago JobExecutable.php 2 years ago Logs.php 3 years ago PreserveDataFirstStep.php 3 years ago PreserveDataSecondStep.php 3 years ago ProcessLock.php 2 years ago Scan.php 2 years ago SearchReplace.php 2 years ago TotalStepsAreNumberOfTables.php 5 years ago Updating.php 2 years ago
Scan.php
751 lines
1 <?php
2
3 namespace WPStaging\Backend\Modules\Jobs;
4
5 use DirectoryIterator;
6 use Exception;
7 use RuntimeException;
8 use UnexpectedValueException;
9 use WPStaging\Backend\Optimizer\Optimizer;
10 use WPStaging\Core\Utils\Directories as DirectoriesUtil;
11 use WPStaging\Core\WPStaging;
12 use WPStaging\Framework\Adapter\Directory;
13 use WPStaging\Framework\Filesystem\DiskWriteCheck;
14 use WPStaging\Framework\Filesystem\Scanning\ScanConst;
15 use WPStaging\Framework\Staging\Sites;
16 use WPStaging\Framework\Utils\Sanitize;
17 use WPStaging\Framework\Utils\Strings;
18 use WPStaging\Framework\Utils\WpDefaultDirectories;
19 use WPStaging\Backup\Exceptions\DiskNotWritableException;
20 use WPStaging\Framework\Filesystem\PathChecker;
21 use WPStaging\Framework\SiteInfo;
22 use WPStaging\Framework\TemplateEngine\TemplateEngine;
23 use WPStaging\Framework\Filesystem\PathIdentifier;
24
25 /**
26 * Class Scan
27 * @package WPStaging\Backend\Modules\Jobs
28 */
29 class Scan extends Job
30 {
31 /**
32 * CSS class name to use for WordPress core directories like wp-content, wp-admin, wp-includes
33 * This doesn't contains class selector prefix
34 *
35 * @var string
36 */
37 const WP_CORE_DIR = "wpstg-wp-core-dir";
38
39 /**
40 * CSS class name to use for WordPress non core directories
41 * This doesn't contains class selector prefix
42 *
43 * @var string
44 */
45 const WP_NON_CORE_DIR = "wpstg-wp-non-core-dir";
46
47 /** @var array */
48 private $directories = [];
49
50 /** @var DirectoriesUtil */
51 private $objDirectories;
52
53 /** @var string|null */
54 private $directoryToScanOnly;
55
56 /**
57 * @var string Path to gif loader for directory loading
58 */
59 private $gifLoaderPath;
60
61 /**
62 * @var Strings
63 */
64 private $strUtils;
65
66 /**
67 * @var Directory
68 */
69 protected $dirAdapter;
70
71 /**
72 * @var DiskWriteCheck
73 */
74 private $diskWriteCheck;
75
76 /**
77 * @var Sanitize
78 */
79 private $sanitize;
80
81 /**
82 * @var string Path to the info icon
83 */
84 private $infoIconPath;
85
86 /**
87 * @var string
88 */
89 private $basePath;
90
91 /**
92 * @var string
93 */
94 private $pathIdentifier;
95
96 /**
97 * @var TemplateEngine
98 */
99 private $templateEngine;
100
101 /** @var PathIdentifier */
102 private $pathAdapter;
103
104 /** @var PathChecker */
105 private $pathChecker;
106
107 /** @var string */
108 protected $absPath = ABSPATH;
109
110 /** @var string */
111 protected $wpContentPath = WP_CONTENT_DIR;
112
113 public function __construct($directoryToScanOnly = null)
114 {
115 // Accept both the absolute path or relative path with respect to wp root
116 // Santized the path to make comparing works for windows platform too.
117 $this->directoryToScanOnly = null;
118 if ($directoryToScanOnly !== null) {
119 $this->directoryToScanOnly = $directoryToScanOnly;
120 }
121
122 // TODO: inject using DI when available
123 $this->strUtils = new Strings();
124 $this->pathAdapter = WPStaging::make(PathIdentifier::class);
125 $this->pathChecker = WPStaging::make(PathChecker::class);
126 $this->dirAdapter = WPStaging::make(Directory::class);
127 $this->diskWriteCheck = WPStaging::make(DiskWriteCheck::class);
128 $this->sanitize = WPStaging::make(Sanitize::class);
129 $this->templateEngine = WPStaging::make(TemplateEngine::class);
130 parent::__construct();
131 }
132
133 /**
134 * @param string $gifLoaderPath
135 */
136 public function setGifLoaderPath($gifLoaderPath)
137 {
138 $this->gifLoaderPath = $gifLoaderPath;
139 }
140
141 /**
142 * @param string $infoIconPath
143 */
144 public function setInfoIcon($infoIconPath)
145 {
146 $this->infoIconPath = $infoIconPath;
147 }
148
149 /**
150 * Return the path of info icon
151 *
152 * @return string
153 */
154 public function getInfoIcon()
155 {
156 return $this->infoIconPath;
157 }
158
159 /**
160 * @param string $directoryToScanOnly
161 */
162 public function setDirectoryToScanOnly($directoryToScanOnly)
163 {
164 $this->directoryToScanOnly = $directoryToScanOnly;
165 }
166
167 /** @param string $basePath */
168 public function setBasePath($basePath)
169 {
170 $this->basePath = rtrim(wp_normalize_path($basePath), '/');
171 }
172
173 /** @return string */
174 public function getBasePath()
175 {
176 return $this->basePath;
177 }
178
179 /** @param string $pathIdentifier */
180 public function setPathIdentifier($pathIdentifier)
181 {
182 $this->pathIdentifier = $pathIdentifier;
183 }
184
185 /** @return string */
186 public function getPathIdentifier()
187 {
188 return $this->pathIdentifier;
189 }
190
191 /**
192 * Upon class initialization
193 */
194 public function initialize()
195 {
196 $this->objDirectories = new DirectoriesUtil();
197
198 $this->options->existingClones = get_option(Sites::STAGING_SITES_OPTION, []);
199 $this->options->existingClones = is_array($this->options->existingClones) ? $this->options->existingClones : [];
200
201 $this->directories = [];
202 if (!empty($this->directoryToScanOnly)) {
203 return;
204 }
205
206 $this->getTables();
207
208 $this->setBasePath($this->absPath);
209 $this->setPathIdentifier(PathIdentifier::IDENTIFIER_ABSPATH);
210 $this->getDirectories($this->absPath);
211
212 // If wp-content is outside ABSPATH, then scan it too
213 if ($this->isWpContentOutsideAbspath()) {
214 $this->setBasePath($this->wpContentPath);
215 $this->setPathIdentifier(PathIdentifier::IDENTIFIER_WP_CONTENT);
216 $this->getDirectories(dirname($this->wpContentPath));
217 }
218
219 $this->installOptimizer();
220 }
221
222 /**
223 * Start Module
224 * @return $this|object
225 * @throws Exception
226 */
227 public function start()
228 {
229 // Basic Options
230 $this->options->root = str_replace(["\\", '/'], DIRECTORY_SEPARATOR, ABSPATH);
231 $this->options->current = null;
232 $this->options->currentClone = $this->getCurrentClone();
233
234 if ($this->options->currentClone !== null) {
235 // Make sure no warning is shown when updating/resetting an old clone having no exclude rules options
236 $this->options->currentClone['excludeSizeRules'] = isset($this->options->currentClone['excludeSizeRules']) ? $this->options->currentClone['excludeSizeRules'] : [];
237 $this->options->currentClone['excludeGlobRules'] = isset($this->options->currentClone['excludeGlobRules']) ? $this->options->currentClone['excludeGlobRules'] : [];
238 // Make sure no warning is shown when updating/resetting an old clone having emails allowed option
239 $this->options->currentClone['emailsAllowed'] = isset($this->options->currentClone['emailsAllowed']) ? $this->options->currentClone['emailsAllowed'] : true;
240 }
241
242 // Tables
243 $this->options->clonedTables = [];
244
245 // Files
246 $this->options->totalFiles = 0;
247 $this->options->totalFileSize = 0;
248 $this->options->copiedFiles = 0;
249
250
251 // Directories
252 $this->options->includedDirectories = [];
253 $this->options->includedExtraDirectories = [];
254 $this->options->excludedDirectories = [];
255 $this->options->extraDirectories = [];
256 $this->options->scannedDirectories = [];
257
258 // Job
259 $this->options->currentJob = "PreserveDataFirstStep";
260 $this->options->currentStep = 0;
261 $this->options->totalSteps = 0;
262
263 // Define mainJob to differentiate between cloning, updating and pushing
264 $this->options->mainJob = Job::STAGING;
265 $job = '';
266 if (isset($_POST["job"])) {
267 $job = $this->sanitize->sanitizeString($_POST['job']);
268 }
269
270 if ($this->options->current !== null && $job === 'resetting') {
271 $this->options->mainJob = Job::RESET;
272 } elseif ($this->options->current !== null) {
273 $this->options->mainJob = Job::UPDATE;
274 }
275
276 // Delete previous cached files
277 $this->cloneOptionCache->delete();
278 $this->filesIndexCache->delete();
279
280 $this->saveOptions();
281
282 return $this;
283 }
284
285 /**
286 * Make sure the Optimizer mu plugin is installed before cloning or pushing
287 */
288 private function installOptimizer()
289 {
290 $optimizer = new Optimizer();
291 $optimizer->installOptimizer();
292 }
293
294 /**
295 * @param null|bool $parentChecked Is parent folder selected
296 * @param bool $forceDefault Default false. Set it to true,
297 * when default button on ui is clicked,
298 * to ignore previous selected option for UPDATE and RESET process.
299 * @param null|array $directories to list
300 *
301 * @return string
302 */
303 public function directoryListing($parentChecked = null, $forceDefault = false, $directories = null)
304 {
305 if ($directories === null) {
306 $directories = $this->directories;
307 }
308
309 uksort($directories, 'strcasecmp');
310
311 $excludedDirectories = [];
312 $extraDirectories = [];
313
314 if ($this->isUpdateOrResetJob()) {
315 $currentClone = json_decode(json_encode($this->options->currentClone));
316 $extraDirectories = isset($currentClone->extraDirectories) ? $currentClone->extraDirectories : [];
317 $excludedDirectories = isset($currentClone->excludedDirectories) ? array_map(function ($directory) {
318 // Exception is thrown when directory doesn't have identifier, so we will return directory as it is
319 try {
320 return $this->pathAdapter->transformIdentifiableToPath($directory);
321 } catch (UnexpectedValueException $ex) {
322 return $directory;
323 }
324 }, $currentClone->excludedDirectories) : [];
325 }
326
327 $output = '';
328 foreach ($directories as $dirName => $directory) {
329 // Not a directory, possibly a symlink, therefore we will skip it
330 if (!is_array($directory)) {
331 continue;
332 }
333
334 // Need to preserve keys so no array_shift()
335 $data = reset($directory);
336 unset($directory[key($directory)]);
337
338 $output .= $this->getDirectoryHtml($data['dirName'], $data, $excludedDirectories, $extraDirectories, $parentChecked, $forceDefault);
339 }
340
341 return $output;
342 }
343
344 /**
345 * Checks if there is enough free disk space to create staging site according to selected directories
346 * Returns null when can't run disk_free_space function one way or another
347 * @param string $excludedDirectories
348 * @param string $extraDirectories
349 *
350 * @return bool|null
351 */
352 public function hasFreeDiskSpace($excludedDirectories, $extraDirectories)
353 {
354 $dirUtils = new WpDefaultDirectories();
355 $selectedDirectories = $dirUtils->getWpCoreDirectories();
356 $excludedDirectories = $dirUtils->getExcludedDirectories($excludedDirectories);
357
358 $size = 0;
359 // Scan WP Root path for size (only files)
360 $size += $this->getDirectorySizeExcludingSubdirs($this->absPath);
361 // Scan selected directories for size (wp-core)
362 foreach ($selectedDirectories as $directory) {
363 if ($this->isPathInDirectories($directory, $excludedDirectories)) {
364 continue;
365 }
366
367 $size += $this->getDirectorySizeInclSubdirs($directory, $excludedDirectories);
368 }
369
370 if (!empty($extraDirectories) && $extraDirectories !== '') {
371 $extraDirectories = wpstg_urldecode(explode(ScanConst::DIRECTORIES_SEPARATOR, $extraDirectories));
372 foreach ($extraDirectories as $directory) {
373 $size += $this->getDirectorySizeInclSubdirs($this->absPath . $directory, $excludedDirectories);
374 }
375 }
376
377 $errorMessage = null;
378 try {
379 $this->diskWriteCheck->checkPathCanStoreEnoughBytes($this->absPath, $size);
380 } catch (RuntimeException $ex) {
381 $errorMessage = $ex->getMessage();
382 } catch (DiskNotWritableException $ex) {
383 $errorMessage = $ex->getMessage();
384 }
385
386 $data = [
387 'requiredSpace' => $this->utilsMath->formatSize($size),
388 'errorMessage' => $errorMessage
389 ];
390
391 echo json_encode($data);
392 die();
393 }
394
395 /**
396 * Get Database Tables
397 */
398 protected function getTables()
399 {
400 $db = WPStaging::getInstance()->get("wpdb");
401 $dbPrefix = WPStaging::getTablePrefix();
402
403 $sql = "SHOW TABLE STATUS";
404
405 $tables = $db->get_results($sql);
406
407 $currentTables = [];
408
409 $currentClone = $this->getCurrentClone();
410 $networkClone = is_multisite() && is_main_site() && is_array($currentClone) && (array_key_exists('networkClone', $currentClone) ? $this->sanitize->sanitizeBool($currentClone['networkClone']) : false);
411
412 // Reset excluded Tables than loop through all tables
413 $this->options->excludedTables = [];
414 foreach ($tables as $table) {
415 // Create array of unchecked tables
416 // On the main website of a multisite installation, do not select network site tables beginning with wp_1_, wp_2_ etc.
417 // (On network sites, the correct tables are selected anyway)
418 if (
419 ( ! empty($dbPrefix) && strpos($table->Name, $dbPrefix) !== 0)
420 || (is_multisite() && is_main_site() && !$networkClone && preg_match('/^' . $dbPrefix . '\d+_/', $table->Name))
421 ) {
422 $this->options->excludedTables[] = $table->Name;
423 }
424
425 if ($table->Comment !== "VIEW") {
426 $currentTables[] = [
427 "name" => $table->Name,
428 "size" => ($table->Data_length + $table->Index_length)
429 ];
430 }
431 }
432
433 $this->options->tables = json_decode(json_encode($currentTables));
434 }
435
436 /**
437 * Get directories and main meta data about given directory path
438 * @param string $dirPath - Optional - Default ABSPATH
439 * @param bool $shouldReturn - Optional - Default false
440 *
441 * @return void|array Depend upon value of $shouldReturn
442 */
443 public function getDirectories($dirPath = ABSPATH, $shouldReturn = false)
444 {
445 if (!is_dir($dirPath)) {
446 return;
447 }
448
449 try {
450 $directories = new DirectoryIterator($dirPath);
451 } catch (UnexpectedValueException $ex) {
452 $errorMessage = $ex->getMessage();
453 if ($ex->getCode() === 5) {
454 $errorMessage = esc_html__('Access Denied: No read permission to scan the root directory for cloning. Alternatively you can try the WP STAGING backup feature!', 'wp-staging');
455 }
456
457 echo json_encode([
458 'success' => false,
459 'type' => '',
460 // TODO: Create a Swal Response Class and Js library to handle that response or, Implement own Swal alternative
461 'swalOptions' => [
462 'title' => esc_html__('Error!', 'wp-staging'),
463 'html' => $errorMessage,
464 'cancelButtonText' => esc_html__('Ok', 'wp-staging'),
465 'showCancelButton' => true,
466 'showConfirmButton' => false,
467 ],
468 ]);
469
470 exit();
471 }
472
473 $result = [];
474
475 foreach ($directories as $directory) {
476 if ($directory->isDot() || $directory->isFile()) {
477 continue;
478 }
479
480 // Not a valid directory
481 if (($path = $this->getPath($directory)) === false) {
482 continue;
483 }
484
485 $fullPath = trailingslashit($this->getBasePath()) . ltrim($path, '/');
486 $size = $this->getDirectorySize($fullPath);
487
488 // If filename is int, then it is treated as a numeric index in key and start with 0
489 $result[$directory->getFilename()]['metaData'] = [
490 'dirName' => $directory->getFilename(),
491 "size" => $size,
492 "path" => $fullPath,
493 "basePath" => $this->getBasePath(),
494 "prefix" => $this->getPathIdentifier()
495 ];
496 }
497
498 if ($shouldReturn) {
499 return $result;
500 }
501
502 $this->directories = array_merge($this->directories, $result);
503 }
504
505 /**
506 * Get Path from $directory
507 * @param DirectoryIterator $directory
508 * @return bool|string
509 */
510 protected function getPath($directory)
511 {
512 $basePath = $this->getBasePath();
513 $realPath = WPStaging::make('WPSTG_ALLOW_VFS') === true && strpos($directory->getPathname(), 'vfs://') === 0 ? $directory->getPathname() : $directory->getRealPath();
514 $realPath = wp_normalize_path($realPath);
515
516 /*
517 * Do not follow root path like src/web/..
518 * This must be done before \SplFileInfo->isDir() is used!
519 * Prevents open base dir restriction fatal errors
520 */
521 if (strpos($realPath, $basePath) !== 0) {
522 return false;
523 }
524
525 $path = str_replace($basePath, '', $realPath);
526 // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
527 if (!$directory->isDir() || (strlen($path) < 1 && $this->pathIdentifier !== PathIdentifier::IDENTIFIER_WP_CONTENT)) {
528 return false;
529 }
530
531 return $path;
532 }
533
534 /**
535 * @param string $dirName
536 * @param array $dirInfo contains information about the directory
537 * @param array $excludedDirectories
538 * @param array $extraDirectories
539 * @param bool $parentChecked
540 * @param bool $forceDefault
541 * @return string
542 */
543 protected function getDirectoryHtml($dirName, $dirInfo, $excludedDirectories, $extraDirectories, $parentChecked = false, $forceDefault = false)
544 {
545 $data = $dirInfo;
546 $dataPath = isset($data["path"]) ? $data["path"] : '';
547 $dataSize = isset($data["size"]) ? $data["size"] : '';
548 $path = wp_normalize_path($dataPath);
549 $basePath = isset($data["basePath"]) ? $data["basePath"] : wp_normalize_path($this->absPath);
550 $prefix = isset($data["prefix"]) ? $data["prefix"] : PathIdentifier::IDENTIFIER_ABSPATH;
551 $relPath = str_replace($basePath, '', $path);
552 $relPath = ltrim($relPath, '/');
553
554 // Check if directory name or directory path is not WP core folder
555 $isNotWPCoreDir = $this->isNonWpCoreDirectory($dirName, $path);
556
557 $class = $isNotWPCoreDir ? self::WP_NON_CORE_DIR : self::WP_CORE_DIR;
558 $dirType = 'other';
559
560 if ($this->strUtils->startsWith($path, $this->dirAdapter->getPluginsDirectory()) !== false) {
561 $pluginPath = $this->strUtils->strReplaceFirst($this->dirAdapter->getPluginsDirectory(), '', $path);
562 $dirType = strpos($pluginPath, '/') === false ? 'plugin' : 'other';
563 } elseif ($this->strUtils->startsWith($path, $this->dirAdapter->getActiveThemeParentDirectory()) !== false) {
564 $themePath = $this->strUtils->strReplaceFirst($this->dirAdapter->getActiveThemeParentDirectory(), '', $path);
565 $dirType = strpos($themePath, '/') === false ? 'theme' : 'other';
566 }
567
568 $isScanned = 'false';
569 if (
570 trailingslashit($path) === $this->dirAdapter->getWpContentDirectory()
571 || trailingslashit($path) === $this->dirAdapter->getPluginsDirectory()
572 || trailingslashit($path) === $this->dirAdapter->getActiveThemeParentDirectory()
573 ) {
574 $isScanned = 'true';
575 }
576
577 // Make wp-includes and wp-admin directory items not expandable
578 $isNavigateable = 'true';
579 if ($this->strUtils->startsWith($path, $basePath . "/wp-admin") !== false || $this->strUtils->startsWith($path, $basePath . "/wp-includes") !== false) {
580 $isNavigateable = 'false';
581 }
582
583 // Decide if item checkbox is active or not
584 $shouldBeChecked = $parentChecked !== null ? $parentChecked : !$isNotWPCoreDir;
585 if (!$forceDefault && $this->isUpdateOrResetJob() && (!$this->isPathInDirectories($path, $excludedDirectories))) {
586 $shouldBeChecked = true;
587 } elseif (!$forceDefault && $this->isUpdateOrResetJob()) {
588 $shouldBeChecked = false;
589 }
590
591 if (!$forceDefault && $this->isUpdateOrResetJob() && $class === self::WP_NON_CORE_DIR && !$this->isPathInDirectories($path, $extraDirectories)) {
592 $shouldBeChecked = false;
593 }
594
595 $isDisabledDir = $dirName === 'wp-admin' || $dirName === 'wp-includes';
596
597 return $this->templateEngine->render('Backend/views/clone/ajax/directory-navigation.php', [
598 'scan' => $this,
599 'prefix' => $prefix,
600 'relPath' => $relPath,
601 'class' => $class,
602 'dirType' => $dirType,
603 'isScanned' => $isScanned,
604 'isNavigateable' => $isNavigateable,
605 'shouldBeChecked' => $shouldBeChecked,
606 'parentChecked' => $parentChecked,
607 'directoryDisabled' => $isNotWPCoreDir || $isDisabledDir,
608 'dirName' => $dirName,
609 'gifLoaderPath' => $this->gifLoaderPath,
610 'formattedSize' => $this->utilsMath->formatSize($dataSize),
611 'isDebugMode' => $this->utilsMath->formatSize($dataSize),
612 'dataPath' => $dataPath,
613 'basePath' => $basePath,
614 'forceDefault' => $forceDefault,
615 'dirPath' => $path,
616 ]);
617 }
618
619 /**
620 * Gets size of given directory
621 * @param string $path
622 * @return int|null
623 */
624 protected function getDirectorySize($path)
625 {
626 if (!isset($this->settings->checkDirectorySize) || $this->settings->checkDirectorySize !== '1') {
627 return null;
628 }
629
630 return $this->objDirectories->size($path);
631 }
632
633 /**
634 * Get total size of a directory including all its subdirectories
635 * @param string $dir
636 * @param array $excludedDirectories
637 * @return int
638 */
639 protected function getDirectorySizeInclSubdirs($dir, $excludedDirectories)
640 {
641 $size = 0;
642 foreach (glob(rtrim($dir, '/') . '/*', GLOB_NOSORT) as $each) {
643 if (is_file($each)) {
644 $size += filesize($each);
645 continue;
646 }
647
648 if ($this->isPathInDirectories($each, $excludedDirectories)) {
649 continue;
650 }
651
652 $size += $this->getDirectorySizeInclSubdirs($each, $excludedDirectories);
653 }
654
655 return $size;
656 }
657
658 /**
659 * Get total size of a directory excluding all its subdirectories
660 * @param string $dir
661 * @return int
662 */
663 protected function getDirectorySizeExcludingSubdirs($dir)
664 {
665 $size = 0;
666 foreach (glob(rtrim($dir, '/') . '/*', GLOB_NOSORT) as $each) {
667 $size += is_file($each) ? filesize($each) : 0;
668 }
669
670 return $size;
671 }
672
673 /**
674 * Is the path present is given list of directories
675 * @param string $path
676 * @param array $directories List of directories relative to ABSPATH with leading slash
677 *
678 * @return bool
679 */
680 protected function isPathInDirectories($path, $directories)
681 {
682 return $this->pathChecker->isPathInPathsList($path, $directories, true);
683 }
684
685 /**
686 * Get clone from $_POST['clone'] and set it as current clone
687 * If clone is not found, then set current clone to null
688 *
689 * @return array|null
690 */
691 protected function getCurrentClone()
692 {
693 $cloneID = isset($_POST["clone"]) ? $this->sanitize->sanitizeString($_POST['clone']) : '';
694
695 if (array_key_exists($cloneID, $this->options->existingClones)) {
696 $this->options->current = $cloneID;
697 return $this->options->existingClones[$this->options->current];
698 }
699
700 return null;
701 }
702
703 /**
704 * @return bool
705 */
706 protected function isWpContentOutsideAbspath()
707 {
708 /** @var SiteInfo $siteInfo */
709 $siteInfo = WPStaging::make(SiteInfo::class);
710 return $siteInfo->isWpContentOutsideAbspath();
711 }
712
713 /**
714 * Check if directory name or directory path is not WP core folder
715 *
716 * @param string $dirname
717 * @param string $path
718 * @return bool
719 */
720 protected function isNonWpCoreDirectory($dirname, $path)
721 {
722 $coreDirectories = [
723 'wp-admin',
724 'wp-content',
725 'wp-includes'
726 ];
727
728 foreach ($coreDirectories as $coreDirectory) {
729 if ($dirname === $coreDirectory) {
730 return false;
731 }
732 }
733
734 $wpDirectories = [
735 $this->dirAdapter->getWpContentDirectory(),
736 $this->dirAdapter->getPluginsDirectory(),
737 $this->dirAdapter->getActiveThemeParentDirectory(),
738 $this->dirAdapter->getUploadsDirectory(),
739 $this->dirAdapter->getMuPluginsDirectory()
740 ];
741
742 foreach ($wpDirectories as $wpDirectory) {
743 if (strpos(trailingslashit($path), $wpDirectory) !== false) {
744 return false;
745 }
746 }
747
748 return true;
749 }
750 }
751