Duplicator – WordPress Migration Plugin - Version 1.3.6

Version Description

Download this release

Release Info

Developer cory@lamle.org
Plugin Icon 128x128 Duplicator – WordPress Migration Plugin
Version 1.3.6
Comparing to
See all releases

Code changes from version 1.3.4 to 1.3.6

classes/package/class.pack.archive.php CHANGED
@@ -21,30 +21,31 @@ require_once (DUPLICATOR_PLUGIN_PATH.'lib/forceutf8/Encoding.php');
21
  */
22
  class DUP_Archive
23
  {
24
- //PUBLIC
25
- public $FilterDirs;
26
- public $FilterFiles;
27
- public $FilterExts;
28
- public $FilterDirsAll = array();
29
- public $FilterFilesAll = array();
30
- public $FilterExtsAll = array();
31
- public $FilterOn;
32
- public $ExportOnlyDB;
33
- public $File;
34
- public $Format;
35
- public $PackDir;
36
- public $Size = 0;
37
- public $Dirs = array();
38
- public $Files = array();
39
- public $FilterInfo;
40
- public $RecursiveLinks = array();
41
- //PROTECTED
42
- protected $Package;
43
- private $tmpFilterDirsAll = array();
44
- private $wpCorePaths = array();
45
- private $wpCoreExactPaths = array();
46
-
47
- /**
 
48
  * Init this object
49
  */
50
  public function __construct($package)
@@ -126,7 +127,28 @@ class DUP_Archive
126
  }
127
  }
128
 
129
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  * Builds a list of files and directories to be included in the archive
131
  *
132
  * Get the directory size recursively, but don't calc the snapshot directory, exclusion directories
@@ -140,6 +162,7 @@ class DUP_Archive
140
  $rootPath = DUP_Util::safePath(rtrim(DUPLICATOR_WPROOTPATH, '//'));
141
  $rootPath = (trim($rootPath) == '') ? '/' : $rootPath;
142
 
 
143
  //If the root directory is a filter then skip it all
144
  if (in_array($this->PackDir, $this->FilterDirsAll) || $this->Package->Archive->ExportOnlyDB) {
145
  $this->Dirs = array();
@@ -509,8 +532,7 @@ class DUP_Archive
509
  *
510
  * @return array Returns an array of directories to include in the archive
511
  */
512
- private function getFileLists($path)
513
- {
514
  $handle = @opendir($path);
515
 
516
  if ($handle) {
@@ -520,59 +542,54 @@ class DUP_Archive
520
  continue;
521
  }
522
 
523
- $fullPath = str_replace("\\", '/', "{$path}/{$file}");
524
- $relative_path = $fullPath;
525
-
526
- if (is_link($relative_path)) {
527
- $is_link = true;
528
-
529
- //Convert relative path of link to absolute path
530
- chdir($relative_path);
531
- $real_path = realpath(readlink($relative_path));
532
- chdir(dirname(__FILE__));
533
- } else {
534
- $is_link = false;
535
- $real_path = realpath($relative_path);
536
- }
537
-
538
- $exclude_check = array_unique(array($real_path, $relative_path));
539
-
540
- if (is_dir($real_path)) {
541
- $exclude = false;
542
-
543
- foreach ($this->tmpFilterDirsAll as $key => $val) {
544
- $trimmedFilterDir = rtrim($val, '/');
545
- foreach ($exclude_check as $c_check) {
546
- if ($c_check == $trimmedFilterDir || strpos($c_check, $trimmedFilterDir.'/') !== false) {
547
- $exclude = true;
548
- unset($this->tmpFilterDirsAll[$key]);
549
- break 2;
 
 
 
 
 
 
 
 
550
  }
551
  }
552
- }
553
-
554
- if (!$exclude) {
555
- if ($is_link) {
556
- $this->RecursiveLinks[] = $relative_path;
557
- }
558
 
559
- $this->getFileLists($relative_path);
560
- $this->Dirs[] = $relative_path;
561
- }
 
562
  } else {
563
- $exclude = false;
564
- if (in_array(pathinfo($file, PATHINFO_EXTENSION), $this->FilterExtsAll) || in_array($file, $this->FilterFilesAll)) {
565
- $exclude = true;
566
- } else {
567
- foreach ($exclude_check as $c_check) {
568
- if (in_array($c_check, $this->FilterFilesAll)) {
569
- $exclude = true;
570
- break;
571
- }
572
- }
573
- }
574
- if (!$exclude) {
575
- $this->Files[] = $relative_path;
576
  }
577
  }
578
  }
21
  */
22
  class DUP_Archive
23
  {
24
+ //PUBLIC
25
+ public $FilterDirs;
26
+ public $FilterFiles;
27
+ public $FilterExts;
28
+ public $FilterDirsAll = array();
29
+ public $FilterFilesAll = array();
30
+ public $FilterExtsAll = array();
31
+ public $FilterOn;
32
+ public $ExportOnlyDB;
33
+ public $File;
34
+ public $Format;
35
+ public $PackDir;
36
+ public $Size = 0;
37
+ public $Dirs = array();
38
+ public $Files = array();
39
+ public $FilterInfo;
40
+ public $RecursiveLinks = array();
41
+ public $file_count = -1;
42
+ //PROTECTED
43
+ protected $Package;
44
+ private $tmpFilterDirsAll = array();
45
+ private $wpCorePaths = array();
46
+ private $wpCoreExactPaths = array();
47
+
48
+ /**
49
  * Init this object
50
  */
51
  public function __construct($package)
127
  }
128
  }
129
 
130
+ /**
131
+ *
132
+ * @return int return DUP_Archive_Build_Mode
133
+ */
134
+ public function getBuildMode()
135
+ {
136
+ switch ($this->Format) {
137
+ case 'TAR': break;
138
+ case 'TAR-GZIP': break;
139
+ case 'DAF':
140
+ return DUP_Archive_Build_Mode::DupArchive;
141
+ default:
142
+ if (class_exists('ZipArchive')) {
143
+ return DUP_Archive_Build_Mode::ZipArchive;
144
+ } else {
145
+ return DUP_Archive_Build_Mode::Unconfigured;
146
+ }
147
+ break;
148
+ }
149
+ }
150
+
151
+ /**
152
  * Builds a list of files and directories to be included in the archive
153
  *
154
  * Get the directory size recursively, but don't calc the snapshot directory, exclusion directories
162
  $rootPath = DUP_Util::safePath(rtrim(DUPLICATOR_WPROOTPATH, '//'));
163
  $rootPath = (trim($rootPath) == '') ? '/' : $rootPath;
164
 
165
+ $this->RecursiveLinks = array();
166
  //If the root directory is a filter then skip it all
167
  if (in_array($this->PackDir, $this->FilterDirsAll) || $this->Package->Archive->ExportOnlyDB) {
168
  $this->Dirs = array();
532
  *
533
  * @return array Returns an array of directories to include in the archive
534
  */
535
+ private function getFileLists($path) {
 
536
  $handle = @opendir($path);
537
 
538
  if ($handle) {
542
  continue;
543
  }
544
 
545
+ $fullPath = str_replace("\\", '/', "{$path}/{$file}");
546
+
547
+ // @todo: Don't leave it like this. Convert into an option on the package to not follow symbolic links
548
+ // if (is_dir($fullPath) && (is_link($fullPath) == false))
549
+ if (is_dir($fullPath)) {
550
+
551
+ $add = true;
552
+ if (!is_link($fullPath)){
553
+ foreach ($this->tmpFilterDirsAll as $key => $val) {
554
+ $trimmedFilterDir = rtrim($val, '/');
555
+ if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) {
556
+ $add = false;
557
+ unset($this->tmpFilterDirsAll[$key]);
558
+ break;
559
+ }
560
+ }
561
+ } else{
562
+ //Convert relative path of link to absolute path
563
+ chdir($fullPath);
564
+ $link_path = str_replace("\\", '/', realpath(readlink($fullPath)));
565
+ chdir(dirname(__FILE__));
566
+
567
+ $link_pos = strpos($fullPath,$link_path);
568
+ if($link_pos === 0 && (strlen($link_path) < strlen($fullPath))){
569
+ $add = false;
570
+ $this->RecursiveLinks[] = $fullPath;
571
+ $this->FilterDirsAll[] = $fullPath;
572
+ } else {
573
+ foreach ($this->tmpFilterDirsAll as $key => $val) {
574
+ $trimmedFilterDir = rtrim($val, '/');
575
+ if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) {
576
+ $add = false;
577
+ unset($this->tmpFilterDirsAll[$key]);
578
+ break;
579
+ }
580
  }
581
  }
582
+ }
 
 
 
 
 
583
 
584
+ if ($add) {
585
+ $this->getFileLists($fullPath);
586
+ $this->Dirs[] = $fullPath;
587
+ }
588
  } else {
589
+ if ( ! (in_array(pathinfo($file, PATHINFO_EXTENSION), $this->FilterExtsAll)
590
+ || in_array($fullPath, $this->FilterFilesAll)
591
+ || in_array($file, $this->FilterFilesAll))) {
592
+ $this->Files[] = $fullPath;
 
 
 
 
 
 
 
 
 
593
  }
594
  }
595
  }
classes/package/class.pack.archive.zip.php CHANGED
@@ -73,6 +73,7 @@ class DUP_Zip extends DUP_Archive
73
  //ADD SQL
74
  $sql_ark_file_path = $archive->Package->getSqlArkFilePath();
75
  $isSQLInZip = self::$zipArchive->addFile(self::$sqlPath, $sql_ark_file_path);
 
76
  if ($isSQLInZip) {
77
  DUP_Log::Info("SQL ADDED: ".basename(self::$sqlPath));
78
  } else {
@@ -109,6 +110,11 @@ class DUP_Zip extends DUP_Archive
109
  DUP_Log::Info($info);
110
  }
111
 
 
 
 
 
 
112
  /* ZIP FILES: Network Flush
113
  * This allows the process to not timeout on fcgi
114
  * setups that need a response every X seconds */
@@ -127,7 +133,6 @@ class DUP_Zip extends DUP_Archive
127
  }
128
  //Trigger a flush to the web server after so many files have been loaded.
129
  if (self::$limitItems > DUPLICATOR_ZIP_FLUSH_TRIGGER) {
130
- $sumItems = (self::$countDirs + self::$countFiles);
131
  self::$zipArchive->close();
132
  self::$zipArchive->open(self::$zipPath);
133
  self::$limitItems = 0;
@@ -170,6 +175,13 @@ class DUP_Zip extends DUP_Archive
170
 
171
  DUP_Log::Info(print_r(self::$zipArchive, true));
172
 
 
 
 
 
 
 
 
173
  //--------------------------------
174
  //LOG FINAL RESULTS
175
  DUP_Util::fcgiFlush();
@@ -196,6 +208,9 @@ class DUP_Zip extends DUP_Archive
196
  DUP_Log::Info("COMPRESSED SIZE: ".DUP_Util::byteSize(self::$zipFileSize));
197
  DUP_Log::Info("ARCHIVE RUNTIME: {$timerAllSum}");
198
  DUP_Log::Info("MEMORY STACK: ".DUP_Server::getPHPMemory());
 
 
 
199
  } catch (Exception $e) {
200
  $error_message = "Runtime error in class.pack.archive.zip.php constructor.";
201
  DUP_Log::Error($error_message, "Exception: {$e}", Dup_ErrorBehavior::LogOnly);
73
  //ADD SQL
74
  $sql_ark_file_path = $archive->Package->getSqlArkFilePath();
75
  $isSQLInZip = self::$zipArchive->addFile(self::$sqlPath, $sql_ark_file_path);
76
+
77
  if ($isSQLInZip) {
78
  DUP_Log::Info("SQL ADDED: ".basename(self::$sqlPath));
79
  } else {
110
  DUP_Log::Info($info);
111
  }
112
 
113
+ /**
114
+ * count update for integrity check
115
+ */
116
+ $sumItems = (self::$countDirs + self::$countFiles);
117
+
118
  /* ZIP FILES: Network Flush
119
  * This allows the process to not timeout on fcgi
120
  * setups that need a response every X seconds */
133
  }
134
  //Trigger a flush to the web server after so many files have been loaded.
135
  if (self::$limitItems > DUPLICATOR_ZIP_FLUSH_TRIGGER) {
 
136
  self::$zipArchive->close();
137
  self::$zipArchive->open(self::$zipPath);
138
  self::$limitItems = 0;
175
 
176
  DUP_Log::Info(print_r(self::$zipArchive, true));
177
 
178
+ /**
179
+ * count update for integrity check
180
+ */
181
+ $archive->file_count = self::$countDirs + self::$countFiles;
182
+ DUP_Log::Info("FILE ADDED TO ZIP: ".$archive->file_count);
183
+
184
+
185
  //--------------------------------
186
  //LOG FINAL RESULTS
187
  DUP_Util::fcgiFlush();
208
  DUP_Log::Info("COMPRESSED SIZE: ".DUP_Util::byteSize(self::$zipFileSize));
209
  DUP_Log::Info("ARCHIVE RUNTIME: {$timerAllSum}");
210
  DUP_Log::Info("MEMORY STACK: ".DUP_Server::getPHPMemory());
211
+
212
+
213
+
214
  } catch (Exception $e) {
215
  $error_message = "Runtime error in class.pack.archive.zip.php constructor.";
216
  DUP_Log::Error($error_message, "Exception: {$e}", Dup_ErrorBehavior::LogOnly);
classes/package/class.pack.php CHANGED
@@ -26,13 +26,25 @@ class DUP_Build_Progress
26
  public $build_failures = array();
27
  public $validation_failures = array();
28
 
 
 
 
 
29
  private $package;
30
 
 
 
 
 
31
  public function __construct($package)
32
  {
33
  $this->package = $package;
34
  }
35
 
 
 
 
 
36
  public function has_completed()
37
  {
38
  return $this->failed || ($this->installer_built && $this->archive_built && $this->database_script_built);
@@ -272,8 +284,11 @@ class DUP_Package
272
  $report['RPT']['ScanTime'] = DUP_Util::elapsedTime(DUP_Util::getMicrotime(), $timerStart);
273
  $fp = fopen(DUPLICATOR_SSDIR_PATH_TMP."/{$this->ScanFile}", 'w');
274
 
275
-
276
- fwrite($fp, json_encode($report));
 
 
 
277
  fclose($fp);
278
 
279
  return $report;
@@ -610,6 +625,7 @@ class DUP_Package
610
 
611
  $error_text = "ERROR: SQL file not complete. The file {$sql_temp_path} looks too small ($sql_temp_size bytes) or the end of file marker was not found.";
612
  $this->BuildProgress->set_failed($error_text);
 
613
  $this->update();
614
  //$this->setStatus(DUP_PackageStatus::ERROR);
615
  DUP_Log::Error("$error_text", '', Dup_ErrorBehavior::LogOnly);
@@ -633,8 +649,8 @@ class DUP_Package
633
  $error_message = 'ERROR: Installer file not complete. The end of file marker was not found. Please try to re-create the package.';
634
 
635
  $this->BuildProgress->set_failed($error_message);
 
636
  $this->update();
637
- //$this->setStatus(DUP_PackageStatus::ERROR);
638
  DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly);
639
  return;
640
  }
@@ -651,6 +667,7 @@ class DUP_Package
651
  $error_message = "ERROR: The archive file contains no size.";
652
 
653
  $this->BuildProgress->set_failed($error_message);
 
654
  $this->update();
655
  //$this->setStatus(DUP_PackageStatus::ERROR);
656
  DUP_Log::error($error_message, "Archive Size: {$zip_easy_size}", Dup_ErrorBehavior::LogOnly);
@@ -667,8 +684,9 @@ class DUP_Package
667
  $error_message = sprintf(__("Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name.", 'duplicator'), $scan_filepath);
668
 
669
  //$this->BuildProgress->failed = true;
670
- $this->setStatus(DUP_PackageStatus::ERROR);
671
  $this->BuildProgress->set_failed($error_message);
 
672
  $this->update();
673
 
674
  DUP_Log::Error($error_message, '', Dup_ErrorBehavior::LogOnly);
@@ -710,20 +728,63 @@ class DUP_Package
710
  if (($straight_ratio < 0.90) || ($straight_ratio > 1.01)) {
711
  // Has to exceed both the straight as well as the warning ratios
712
  if (($warning_ratio < 0.90) || ($warning_ratio > 1.01)) {
713
-
714
- $error_message = sprintf('ERROR: File count in archive vs expected suggests a bad archive (%1$d vs %2$d).', $archive_file_count, $expected_filecount);
715
  $this->BuildProgress->set_failed($error_message);
 
716
  $this->update();
717
- $archive_file_count = $this->Archive->file_count;
718
- DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly);
719
  return;
720
  }
721
  }
722
  }
723
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
  }
725
 
726
- public function getLocalPackageFile($file_type)
727
  {
728
  $file_path = null;
729
 
@@ -995,13 +1056,15 @@ class DUP_Package
995
  $this->Installer->build($this);
996
 
997
  //INTEGRITY CHECKS
998
- DUP_Log::Info("\n********************************************************************************");
999
  DUP_Log::Info("INTEGRITY CHECKS:");
1000
- DUP_Log::Info("********************************************************************************");
 
1001
  $dbSizeRead = DUP_Util::byteSize($this->Database->Size);
1002
  $zipSizeRead = DUP_Util::byteSize($this->Archive->Size);
1003
  $exeSizeRead = DUP_Util::byteSize($this->Installer->Size);
1004
 
 
1005
  DUP_Log::Info("SQL File: {$dbSizeRead}");
1006
  DUP_Log::Info("Installer File: {$exeSizeRead}");
1007
  DUP_Log::Info("Archive File: {$zipSizeRead} ");
@@ -1015,7 +1078,8 @@ class DUP_Package
1015
  $sql_complete_txt = DUP_Util::tailFile($sql_tmp_path, 3);
1016
  if (!strstr($sql_complete_txt, 'DUPLICATOR_MYSQLDUMP_EOF')) {
1017
  DUP_Log::Error("ERROR: SQL file not complete. The end of file marker was not found. Please try to re-create the package.");
1018
- }
 
1019
 
1020
  $timerEnd = DUP_Util::getMicrotime();
1021
  $timerSum = DUP_Util::elapsedTime($timerEnd, $timerStart);
@@ -1024,6 +1088,7 @@ class DUP_Package
1024
  $this->ExeSize = $exeSizeRead;
1025
  $this->ZipSize = $zipSizeRead;
1026
 
 
1027
  $this->buildCleanup();
1028
 
1029
  //FINAL REPORT
@@ -1033,6 +1098,7 @@ class DUP_Package
1033
  $info .= "PEAK PHP MEMORY USED: ".DUP_Server::getPHPMemory(true)."\n";
1034
  $info .= "DONE PROCESSING => {$this->Name} ".@date(get_option('date_format')." ".get_option('time_format'))."\n";
1035
 
 
1036
  DUP_Log::Info($info);
1037
  DUP_Log::Close();
1038
 
26
  public $build_failures = array();
27
  public $validation_failures = array();
28
 
29
+ /**
30
+ *
31
+ * @var DUP_Package
32
+ */
33
  private $package;
34
 
35
+ /**
36
+ *
37
+ * @param DUP_Package $package
38
+ */
39
  public function __construct($package)
40
  {
41
  $this->package = $package;
42
  }
43
 
44
+ /**
45
+ *
46
+ * @return bool
47
+ */
48
  public function has_completed()
49
  {
50
  return $this->failed || ($this->installer_built && $this->archive_built && $this->database_script_built);
284
  $report['RPT']['ScanTime'] = DUP_Util::elapsedTime(DUP_Util::getMicrotime(), $timerStart);
285
  $fp = fopen(DUPLICATOR_SSDIR_PATH_TMP."/{$this->ScanFile}", 'w');
286
 
287
+ if (function_exists('wp_json_encode')) {
288
+ fwrite($fp, wp_json_encode($report));
289
+ } else {
290
+ fwrite($fp, json_encode($report));
291
+ }
292
  fclose($fp);
293
 
294
  return $report;
625
 
626
  $error_text = "ERROR: SQL file not complete. The file {$sql_temp_path} looks too small ($sql_temp_size bytes) or the end of file marker was not found.";
627
  $this->BuildProgress->set_failed($error_text);
628
+ $this->Status = DUP_PackageStatus::ERROR;
629
  $this->update();
630
  //$this->setStatus(DUP_PackageStatus::ERROR);
631
  DUP_Log::Error("$error_text", '', Dup_ErrorBehavior::LogOnly);
649
  $error_message = 'ERROR: Installer file not complete. The end of file marker was not found. Please try to re-create the package.';
650
 
651
  $this->BuildProgress->set_failed($error_message);
652
+ $this->Status = DUP_PackageStatus::ERROR;
653
  $this->update();
 
654
  DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly);
655
  return;
656
  }
667
  $error_message = "ERROR: The archive file contains no size.";
668
 
669
  $this->BuildProgress->set_failed($error_message);
670
+ $this->Status = DUP_PackageStatus::ERROR;
671
  $this->update();
672
  //$this->setStatus(DUP_PackageStatus::ERROR);
673
  DUP_Log::error($error_message, "Archive Size: {$zip_easy_size}", Dup_ErrorBehavior::LogOnly);
684
  $error_message = sprintf(__("Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name.", 'duplicator'), $scan_filepath);
685
 
686
  //$this->BuildProgress->failed = true;
687
+ //$this->setStatus(DUP_PackageStatus::ERROR);
688
  $this->BuildProgress->set_failed($error_message);
689
+ $this->Status = DUP_PackageStatus::ERROR;
690
  $this->update();
691
 
692
  DUP_Log::Error($error_message, '', Dup_ErrorBehavior::LogOnly);
728
  if (($straight_ratio < 0.90) || ($straight_ratio > 1.01)) {
729
  // Has to exceed both the straight as well as the warning ratios
730
  if (($warning_ratio < 0.90) || ($warning_ratio > 1.01)) {
731
+ $error_message = sprintf('ERROR: File count in archive vs expected suggests a bad archive (%1$d vs %2$d).', $this->Archive->file_count, $expected_filecount);
 
732
  $this->BuildProgress->set_failed($error_message);
733
+ $this->Status = DUP_PackageStatus::ERROR;
734
  $this->update();
735
+
736
+ DUP_Log::error($error_message, '');
737
  return;
738
  }
739
  }
740
  }
741
  }
742
+
743
+ /* ------ ZIP CONSISTENCY CHECK ------ */
744
+ if ($this->Archive->getBuildMode() == DUP_Archive_Build_Mode::ZipArchive) {
745
+ DUP_LOG::trace("Running ZipArchive consistency check");
746
+ $zipPath = DUP_Util::safePath("{$this->StorePath}/{$this->Archive->File}");
747
+
748
+ $zip = new ZipArchive();
749
+
750
+ // ZipArchive::CHECKCONS will enforce additional consistency checks
751
+ $res = $zip->open($zipPath, ZipArchive::CHECKCONS);
752
+
753
+ if ($res !== TRUE) {
754
+ $consistency_error = sprintf(__('ERROR: Cannot open created archive. Error code = %1$s', 'duplicator'), $res);
755
+
756
+ DUP_LOG::trace($consistency_error);
757
+ switch ($res) {
758
+ case ZipArchive::ER_NOZIP :
759
+ $consistency_error = __('ERROR: Archive is not valid zip archive.', 'duplicator');
760
+ break;
761
+
762
+ case ZipArchive::ER_INCONS :
763
+ $consistency_error = __("ERROR: Archive doesn't pass consistency check.", 'duplicator');
764
+ break;
765
+
766
+
767
+ case ZipArchive::ER_CRC :
768
+ $consistency_error = __("ERROR: Archive checksum is bad.", 'duplicator');
769
+ break;
770
+ }
771
+
772
+ $this->BuildProgress->set_failed($consistency_error);
773
+ $this->Status = DUP_PackageStatus::ERROR;
774
+ $this->update();
775
+
776
+ DUP_LOG::trace($consistency_error);
777
+ DUP_Log::error($consistency_error, '');
778
+ } else {
779
+ DUP_Log::info(__('ARCHIVE CONSISTENCY TEST: Pass', 'duplicator'));
780
+ DUP_LOG::trace("Zip for package $this->ID passed consistency test");
781
+ }
782
+
783
+ $zip->close();
784
+ }
785
  }
786
 
787
+ public function getLocalPackageFile($file_type)
788
  {
789
  $file_path = null;
790
 
1056
  $this->Installer->build($this);
1057
 
1058
  //INTEGRITY CHECKS
1059
+ /*DUP_Log::Info("\n********************************************************************************");
1060
  DUP_Log::Info("INTEGRITY CHECKS:");
1061
+ DUP_Log::Info("********************************************************************************");*/
1062
+ $this->runDupArchiveBuildIntegrityCheck();
1063
  $dbSizeRead = DUP_Util::byteSize($this->Database->Size);
1064
  $zipSizeRead = DUP_Util::byteSize($this->Archive->Size);
1065
  $exeSizeRead = DUP_Util::byteSize($this->Installer->Size);
1066
 
1067
+ /*
1068
  DUP_Log::Info("SQL File: {$dbSizeRead}");
1069
  DUP_Log::Info("Installer File: {$exeSizeRead}");
1070
  DUP_Log::Info("Archive File: {$zipSizeRead} ");
1078
  $sql_complete_txt = DUP_Util::tailFile($sql_tmp_path, 3);
1079
  if (!strstr($sql_complete_txt, 'DUPLICATOR_MYSQLDUMP_EOF')) {
1080
  DUP_Log::Error("ERROR: SQL file not complete. The end of file marker was not found. Please try to re-create the package.");
1081
+ }*/
1082
+
1083
 
1084
  $timerEnd = DUP_Util::getMicrotime();
1085
  $timerSum = DUP_Util::elapsedTime($timerEnd, $timerStart);
1088
  $this->ExeSize = $exeSizeRead;
1089
  $this->ZipSize = $zipSizeRead;
1090
 
1091
+
1092
  $this->buildCleanup();
1093
 
1094
  //FINAL REPORT
1098
  $info .= "PEAK PHP MEMORY USED: ".DUP_Server::getPHPMemory(true)."\n";
1099
  $info .= "DONE PROCESSING => {$this->Name} ".@date(get_option('date_format')." ".get_option('time_format'))."\n";
1100
 
1101
+
1102
  DUP_Log::Info($info);
1103
  DUP_Log::Close();
1104
 
classes/utilities/class.u.json.php CHANGED
@@ -34,8 +34,11 @@ class DUP_JSON
34
  public static function customEncode($value, $iteration = 1)
35
  {
36
  if (DUP_Util::$on_php_53_plus) {
37
-
38
- $encoded = json_encode($value);
 
 
 
39
 
40
  switch (json_last_error()) {
41
  case JSON_ERROR_NONE:
34
  public static function customEncode($value, $iteration = 1)
35
  {
36
  if (DUP_Util::$on_php_53_plus) {
37
+ if (function_exists('wp_json_encode')) {
38
+ $encoded = wp_json_encode($value);
39
+ } else {
40
+ $encoded = json_encode($value);
41
+ }
42
 
43
  switch (json_last_error()) {
44
  case JSON_ERROR_NONE:
classes/utilities/class.u.validator.php CHANGED
@@ -10,9 +10,10 @@
10
  * @copyright (c) 2017, Snapcreek LLC
11
  *
12
  */
13
-
14
  // Exit if accessed directly
15
- if (! defined('DUPLICATOR_VERSION')) exit;
 
 
16
 
17
  class DUP_Validator
18
  {
@@ -20,21 +21,20 @@ class DUP_Validator
20
  * @var array $patterns
21
  */
22
  private static $patterns = array(
23
- //'fdir' => '/^([a-zA-Z]:|\/|\\\\\\\\)[\\p{L}\s0-9-_!%&()=\[\]#@,.;+\\\\\/]+$/u',
24
- //'ffile' => '/^([a-zA-Z]:|\/|\\\\\\\\)[\\p{L}\s0-9-_!%&()=\[\]#@,.;+\\\\\/]+\.[A-Za-z0-9]{2,4}$/u',
25
  'fdir' => '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/',
26
- 'ffile' => '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/',
27
- 'fext' => '/^\.?[A-Za-z0-9]{2,4}$/',
28
- 'email' => '[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+',
29
  'empty' => '/^$/',
30
  'nempty' => '/^.+$/',
31
  );
32
 
33
- const FILTER_VALIDATE_IS_EMPTY = 'empty';
34
  const FILTER_VALIDATE_NOT_EMPTY = 'nempty';
35
- const FILTER_VALIDATE_FILE = 'ffile';
36
- const FILTER_VALIDATE_FOLDER = 'fdir';
37
- const FILTER_VALIDATE_FILE_EXT = 'fext';
 
38
 
39
  /**
40
  * @var array $errors [ ['key' => string field key,
@@ -142,7 +142,7 @@ class DUP_Validator
142
  $success = true;
143
  $result = null;
144
 
145
- if (isset($options['acc_vals']) && in_array($variable , $options['acc_vals'])) {
146
  return $variable;
147
  }
148
 
@@ -212,19 +212,19 @@ class DUP_Validator
212
  * @param string $filter
213
  * @param array $options
214
  */
215
- public function explode_filter_custom($variable, $delimiter , $filter, $options = array()) {
 
216
  if (empty($variable)) {
217
  return array();
218
  }
219
 
220
  $vals = explode($delimiter, trim($variable, $delimiter));
221
- $res = array();
222
 
223
- foreach ($vals as $val) {
224
- $res[] = $this->filter_custom($val, $filter, $options);
225
- }
226
 
227
  return $res;
228
  }
229
-
230
  }
10
  * @copyright (c) 2017, Snapcreek LLC
11
  *
12
  */
 
13
  // Exit if accessed directly
14
+ if (!defined('DUPLICATOR_VERSION')) {
15
+ exit;
16
+ }
17
 
18
  class DUP_Validator
19
  {
21
  * @var array $patterns
22
  */
23
  private static $patterns = array(
 
 
24
  'fdir' => '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/',
25
+ 'ffile' => '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/',
26
+ 'fext' => '/^\.?[^\\\\\/*:<>\0?"|\s\.]+$/',
27
+ 'email' => '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_\`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/',
28
  'empty' => '/^$/',
29
  'nempty' => '/^.+$/',
30
  );
31
 
32
+ const FILTER_VALIDATE_IS_EMPTY = 'empty';
33
  const FILTER_VALIDATE_NOT_EMPTY = 'nempty';
34
+ const FILTER_VALIDATE_FILE = 'ffile';
35
+ const FILTER_VALIDATE_FOLDER = 'fdir';
36
+ const FILTER_VALIDATE_FILE_EXT = 'fext';
37
+ const FILTER_VALIDATE_EMAIL = 'email';
38
 
39
  /**
40
  * @var array $errors [ ['key' => string field key,
142
  $success = true;
143
  $result = null;
144
 
145
+ if (isset($options['acc_vals']) && in_array($variable, $options['acc_vals'])) {
146
  return $variable;
147
  }
148
 
212
  * @param string $filter
213
  * @param array $options
214
  */
215
+ public function explode_filter_custom($variable, $delimiter, $filter, $options = array())
216
+ {
217
  if (empty($variable)) {
218
  return array();
219
  }
220
 
221
  $vals = explode($delimiter, trim($variable, $delimiter));
222
+ $res = array();
223
 
224
+ foreach ($vals as $val) {
225
+ $res[] = $this->filter_custom($val, $filter, $options);
226
+ }
227
 
228
  return $res;
229
  }
 
230
  }
ctrls/ctrl.base.php CHANGED
@@ -123,16 +123,11 @@ class DUP_CTRL_Result
123
  case 'JSON' :
124
  return json_encode($this);
125
  break;
126
-
127
  case 'PHP' :
128
  return $this;
129
  break;
130
-
131
  default:
132
- if (!headers_sent()) {
133
- header('Content-Type: application/json');
134
- }
135
- return die(json_encode($this));
136
  break;
137
  }
138
  }
123
  case 'JSON' :
124
  return json_encode($this);
125
  break;
 
126
  case 'PHP' :
127
  return $this;
128
  break;
 
129
  default:
130
+ wp_send_json($this);
 
 
 
131
  break;
132
  }
133
  }
ctrls/ctrl.package.php CHANGED
@@ -23,9 +23,11 @@ function duplicator_package_scan()
23
  die('An unathorized security request was made to this page. Please try again!');
24
  }
25
 
26
- header('Content-Type: application/json;');
27
  DUP_Util::hasCapability('export');
28
 
 
 
 
29
  @set_time_limit(0);
30
  $errLevel = error_reporting();
31
  error_reporting(E_ERROR);
@@ -427,7 +429,7 @@ class DUP_CTRL_Package extends DUP_CTRL_Base
427
  //OUTPUT: Installer, Archive, SQL File
428
  if ($isBinary) {
429
  @session_write_close();
430
- @ob_flush();
431
  //flush seems to cause issues on some PHP version where the download prompt
432
  //is no longer called but the contents of the installer are dumped to the browser.
433
  //@flush();
23
  die('An unathorized security request was made to this page. Please try again!');
24
  }
25
 
 
26
  DUP_Util::hasCapability('export');
27
 
28
+ header('Content-Type: application/json;');
29
+ @ob_flush();
30
+
31
  @set_time_limit(0);
32
  $errLevel = error_reporting();
33
  error_reporting(E_ERROR);
429
  //OUTPUT: Installer, Archive, SQL File
430
  if ($isBinary) {
431
  @session_write_close();
432
+ // @ob_flush();
433
  //flush seems to cause issues on some PHP version where the download prompt
434
  //is no longer called but the contents of the installer are dumped to the browser.
435
  //@flush();
define.php CHANGED
@@ -2,8 +2,8 @@
2
  //Prevent directly browsing to the file
3
  if (function_exists('plugin_dir_url'))
4
  {
5
- define('DUPLICATOR_VERSION', '1.3.4');
6
- define('DUPLICATOR_VERSION_BUILD', '2019-01-16_13:00');
7
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
8
  define('DUPLICATOR_SITE_URL', get_site_url());
9
 
@@ -33,7 +33,7 @@ if (function_exists('plugin_dir_url'))
33
  define('DUPLICATOR_INSTALL_SITE_OVERWRITE_ON', false);
34
 
35
  //GENERAL CONSTRAINTS
36
- define('DUPLICATOR_PHP_MAX_MEMORY', '2048M');
37
  define('DUPLICATOR_DB_MAX_TIME', 5000);
38
  define('DUPLICATOR_DB_EOF_MARKER', 'DUPLICATOR_MYSQLDUMP_EOF');
39
  //SCANNER CONSTRAINTS
2
  //Prevent directly browsing to the file
3
  if (function_exists('plugin_dir_url'))
4
  {
5
+ define('DUPLICATOR_VERSION', '1.3.6');
6
+ define('DUPLICATOR_VERSION_BUILD', '2019-02-20_8:40');
7
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
8
  define('DUPLICATOR_SITE_URL', get_site_url());
9
 
33
  define('DUPLICATOR_INSTALL_SITE_OVERWRITE_ON', false);
34
 
35
  //GENERAL CONSTRAINTS
36
+ define('DUPLICATOR_PHP_MAX_MEMORY', 4294967296); // 4096MB
37
  define('DUPLICATOR_DB_MAX_TIME', 5000);
38
  define('DUPLICATOR_DB_EOF_MARKER', 'DUPLICATOR_MYSQLDUMP_EOF');
39
  //SCANNER CONSTRAINTS
duplicator.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Duplicator
4
  Plugin URI: https://snapcreek.com/duplicator/duplicator-free/
5
  Description: Migrate and backup a copy of your WordPress files and database. Duplicate and move a site from one location to another quickly.
6
- Version: 1.3.4
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
9
  Text Domain: duplicator
3
  Plugin Name: Duplicator
4
  Plugin URI: https://snapcreek.com/duplicator/duplicator-free/
5
  Description: Migrate and backup a copy of your WordPress files and database. Duplicate and move a site from one location to another quickly.
6
+ Version: 1.3.6
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
9
  Text Domain: duplicator
installer/dup-installer/classes/class.db.php CHANGED
@@ -42,7 +42,9 @@ class DUPX_DB
42
  }
43
 
44
  }
45
- $dbh->options(MYSQLI_OPT_LOCAL_INFILE, false);
 
 
46
  return $dbh;
47
  }
48
 
42
  }
43
 
44
  }
45
+ if (method_exists($dbh, 'options')) {
46
+ $dbh->options(MYSQLI_OPT_LOCAL_INFILE, false);
47
+ }
48
  return $dbh;
49
  }
50
 
installer/dup-installer/classes/class.engine.php CHANGED
@@ -277,23 +277,28 @@ class DUPX_UpdateEngine
277
  }
278
  }
279
 
280
- //Replace logic - level 1: simple check on any string or serlized strings
281
- foreach ($list as $item) {
282
- $objArr = array();
283
- $edited_data = self::recursiveUnserializeReplace($item['search'], $item['replace'], $edited_data, false, $objArr);
284
- }
285
-
286
- //Replace logic - level 2: repair serialized strings that have become broken
287
- $serial_check = self::fixSerialString($edited_data);
288
- if ($serial_check['fixed']) {
289
- $edited_data = $serial_check['data'];
290
- } elseif ($serial_check['tried'] && !$serial_check['fixed']) {
291
  $serial_err++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  }
293
  }
294
 
295
  //Change was made
296
- if ($edited_data != $data_to_fix || $serial_err > 0) {
297
  $report['updt_cells']++;
298
  //Base 64 encode
299
  if ($base64converted) {
277
  }
278
  }
279
 
280
+ if (self::isSerialized($edited_data) && strlen($edited_data) > MAX_STRLEN_SERIALIZED_CHECK) {
281
+ // skip search and replace for too big serialized string
 
 
 
 
 
 
 
 
 
282
  $serial_err++;
283
+ } else {
284
+ //Replace logic - level 1: simple check on any string or serlized strings
285
+ foreach ($list as $item) {
286
+ $objArr = array();
287
+ $edited_data = self::recursiveUnserializeReplace($item['search'], $item['replace'], $edited_data, false, $objArr);
288
+ }
289
+
290
+ //Replace logic - level 2: repair serialized strings that have become broken
291
+ $serial_check = self::fixSerialString($edited_data);
292
+ if ($serial_check['fixed']) {
293
+ $edited_data = $serial_check['data'];
294
+ } elseif ($serial_check['tried'] && !$serial_check['fixed']) {
295
+ $serial_err++;
296
+ }
297
  }
298
  }
299
 
300
  //Change was made
301
+ if ($serial_err > 0 || $edited_data != $data_to_fix) {
302
  $report['updt_cells']++;
303
  //Base 64 encode
304
  if ($base64converted) {
installer/dup-installer/classes/config/class.constants.php CHANGED
@@ -48,7 +48,7 @@ class DUPX_Constants
48
  //PHP INI SETUP: all time in seconds
49
  if (!$GLOBALS['DUPX_ENFORCE_PHP_INI']) {
50
  @ini_set('mysql.connect_timeout', '5000');
51
- @ini_set('memory_limit', '5000M');
52
  @ini_set("max_execution_time", '5000');
53
  @ini_set("max_input_time", '5000');
54
  @ini_set('default_socket_timeout', '5000');
@@ -85,6 +85,8 @@ class DUPX_Constants
85
  : @fopen($GLOBALS['LOG_FILE_PATH'], "a+");
86
 
87
  $GLOBALS['HOST_NAME'] = strlen($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
 
 
88
  }
89
  }
90
 
48
  //PHP INI SETUP: all time in seconds
49
  if (!$GLOBALS['DUPX_ENFORCE_PHP_INI']) {
50
  @ini_set('mysql.connect_timeout', '5000');
51
+ @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY);
52
  @ini_set("max_execution_time", '5000');
53
  @ini_set("max_input_time", '5000');
54
  @ini_set('default_socket_timeout', '5000');
85
  : @fopen($GLOBALS['LOG_FILE_PATH'], "a+");
86
 
87
  $GLOBALS['HOST_NAME'] = strlen($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
88
+
89
+ if (!defined('MAX_STRLEN_SERIALIZED_CHECK')) { define('MAX_STRLEN_SERIALIZED_CHECK', 2000000); }
90
  }
91
  }
92
 
installer/dup-installer/classes/config/class.wp.config.tranformer.php CHANGED
@@ -68,6 +68,10 @@ class WPConfigTransformer {
68
  throw new Exception( 'wp-config.php file is empty.' );
69
  }
70
 
 
 
 
 
71
  $this->wp_config_src = $wp_config_src;
72
  $this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
73
 
@@ -91,11 +95,15 @@ class WPConfigTransformer {
91
  */
92
  public function get_value( $type, $name ) {
93
  $wp_config_src = file_get_contents( $this->wp_config_path );
94
-
95
  if ( ! trim( $wp_config_src ) ) {
96
  throw new Exception( 'wp-config.php file is empty.' );
97
  }
98
 
 
 
 
 
 
99
  $this->wp_config_src = $wp_config_src;
100
  $this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
101
 
68
  throw new Exception( 'wp-config.php file is empty.' );
69
  }
70
 
71
+ // SnapCreek custom change
72
+ // Normalize the newline to prevent an issue coming from OSX
73
+ $wp_config_src = str_replace(array("\n\r", "\r"), array("\n", "\n"), $wp_config_src);
74
+
75
  $this->wp_config_src = $wp_config_src;
76
  $this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
77
 
95
  */
96
  public function get_value( $type, $name ) {
97
  $wp_config_src = file_get_contents( $this->wp_config_path );
 
98
  if ( ! trim( $wp_config_src ) ) {
99
  throw new Exception( 'wp-config.php file is empty.' );
100
  }
101
 
102
+ // SnapCreek custom change
103
+ // Normalize the newline to prevent an issue coming from OSX
104
+ $wp_config_src = str_replace(array("\n\r", "\r"), array("\n", "\n"), $wp_config_src);
105
+
106
+
107
  $this->wp_config_src = $wp_config_src;
108
  $this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
109
 
installer/dup-installer/classes/utilities/class.u.php CHANGED
@@ -183,7 +183,91 @@ class DUPX_U
183
  return $exists;
184
  }
185
 
186
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  * A safe method used to copy larger files
188
  *
189
  * @param string $source The path to the file being copied
@@ -206,42 +290,67 @@ class DUPX_U
206
  }
207
 
208
  /**
209
- * Safely remove a directory and recursively if needed
210
- *
211
- * @param string $directory The full path to the directory to remove
212
- * @param string $recursive recursively remove all items
213
- *
214
- * @return bool Returns true if all content was removed
215
- */
216
- public static function deleteDirectory($directory, $recursive)
217
- {
218
- $success = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
220
- if ($excepted_subdirectories = null) {
221
- $excepted_subdirectories = array();
222
- }
 
 
223
 
224
- $filenames = array_diff(scandir($directory), array('.', '..'));
 
225
 
226
- foreach ($filenames as $filename) {
227
- if (is_dir("$directory/$filename")) {
228
- if ($recursive) {
229
- $success = self::deleteDirectory("$directory/$filename", true);
230
- }
231
- } else {
232
- $success = @unlink("$directory/$filename");
233
- }
 
 
234
 
235
- if ($success === false) {
236
- //self::log("Problem deleting $directory/$filename");
237
- break;
238
- }
239
- }
240
 
241
- return $success && rmdir($directory);
242
- }
 
 
243
 
244
- /**
 
 
 
245
  * Dumps a variable for debugging
246
  *
247
  * @param string $var The variable to view
@@ -542,23 +651,30 @@ class DUPX_U
542
 
543
  /**
544
  * @param $url string The URL whichs domain you want to get
545
- * @return bool|string The domain part of the given URL
 
 
 
 
 
546
  */
547
  public static function getDomain($url)
548
  {
549
  $pieces = parse_url($url);
550
  $domain = isset($pieces['host']) ? $pieces['host'] : '';
551
- if(strpos($domain,".") !== false){
552
  if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) {
553
  return $regs['domain'];
 
 
 
554
  }
555
- }else{
556
  return $domain;
557
  }
 
558
 
559
- return false;
560
- }
561
- // START ESCAPING AND SANITIZATION
562
  /**
563
  * Escaping for HTML blocks.
564
  *
183
  return $exists;
184
  }
185
 
186
+ /**
187
+ * move all folder content up to parent
188
+ *
189
+ * @param string $subFolderName full path
190
+ * @param boolean $deleteSubFolder if true delete subFolder after moved all
191
+ * @return boolean
192
+ *
193
+ */
194
+ public static function moveUpfromSubFolder($subFolderName, $deleteSubFolder = false)
195
+ {
196
+ if (!is_dir($subFolderName)) {
197
+ return false;
198
+ }
199
+
200
+ $parentFolder = dirname($subFolderName);
201
+ if (!is_writable($parentFolder)) {
202
+ return false;
203
+ }
204
+
205
+ $success = true;
206
+ if (($subList = glob(rtrim($subFolderName, '/').'/*', GLOB_NOSORT)) === false) {
207
+ DUPX_Log::info("Problem glob folder ".$subFolderName);
208
+ return false;
209
+ } else {
210
+ foreach ($subList as $cName) {
211
+ $destination = $parentFolder.'/'.basename($cName);
212
+ if (file_exists($destination)) {
213
+ $success = self::deletePath($destination);
214
+ }
215
+
216
+ if ($success) {
217
+ $success = rename($cName, $destination);
218
+ } else {
219
+ break;
220
+ }
221
+ }
222
+
223
+ if ($success && $deleteSubFolder) {
224
+ $success = self::deleteDirectory($subFolderName, true);
225
+ }
226
+ }
227
+
228
+ if (!$success) {
229
+ DUPX_Log::info("Problem om moveUpfromSubFolder subFolder:".$subFolderName);
230
+ }
231
+
232
+ return $success;
233
+ }
234
+
235
+ /**
236
+ * @param string $archive_filepath full path of zip archive
237
+ *
238
+ * @return boolean|string path of dup-installer folder of false if not found
239
+ */
240
+ public static function findDupInstallerFolder($archive_filepath)
241
+ {
242
+ $zipArchive = new ZipArchive();
243
+ $result = false;
244
+
245
+ if ($zipArchive->open($archive_filepath) === true) {
246
+ for ($i = 0; $i < $zipArchive->numFiles; $i++) {
247
+ $stat = $zipArchive->statIndex($i);
248
+ $safePath = rtrim(self::setSafePath($stat['name']), '/');
249
+ if (substr_count($safePath, '/') > 1) {
250
+ continue;
251
+ }
252
+
253
+ if (basename($safePath) === 'dup-installer') {
254
+ $result = ($safePath === 'dup-installer') ? '' : dirname($safePath);
255
+ break;
256
+ }
257
+ }
258
+ if ($zipArchive->close() !== true) {
259
+ DUPX_Log::info("Can't close ziparchive:".$archive_filepath);
260
+ $result = false;
261
+ }
262
+ } else {
263
+ DUPX_Log::info("Can't open zip archive:".$archive_filepath);
264
+ $result = false;
265
+ }
266
+
267
+ return $result;
268
+ }
269
+
270
+ /**
271
  * A safe method used to copy larger files
272
  *
273
  * @param string $source The path to the file being copied
290
  }
291
 
292
  /**
293
+ * Safely remove a directory and recursively if needed
294
+ *
295
+ * @param string $directory The full path to the directory to remove
296
+ * @param string $recursive recursively remove all items
297
+ *
298
+ * @return bool Returns true if all content was removed
299
+ */
300
+ public static function deleteDirectory($directory, $recursive)
301
+ {
302
+ $success = true;
303
+
304
+ $filenames = array_diff(scandir($directory), array('.', '..'));
305
+
306
+ foreach ($filenames as $filename) {
307
+ $fullPath = $directory.'/'.$filename;
308
+
309
+ if (is_dir($fullPath)) {
310
+ if ($recursive) {
311
+ $success = self::deleteDirectory($fullPath, true);
312
+ }
313
+ } else {
314
+ $success = @unlink($fullPath);
315
+ if ($success === false) {
316
+ DUPX_Log::info( __FUNCTION__.": Problem deleting file:".$fullPath);
317
+ }
318
+ }
319
 
320
+ if ($success === false) {
321
+ DUPX_Log::info("Problem deleting dir:".$directory);
322
+ break;
323
+ }
324
+ }
325
 
326
+ return $success && rmdir($directory);
327
+ }
328
 
329
+ /**
330
+ * Safely remove a file or directory and recursively if needed
331
+ *
332
+ * @param string $directory The full path to the directory to remove
333
+ *
334
+ * @return bool Returns true if all content was removed
335
+ */
336
+ public static function deletePath($path)
337
+ {
338
+ $success = true;
339
 
340
+ if (is_dir($path)) {
341
+ $success = self::deleteDirectory($path, true);
342
+ } else {
343
+ $success = @unlink($path);
 
344
 
345
+ if ($success === false) {
346
+ DUPX_Log::info( __FUNCTION__.": Problem deleting file:".$path);
347
+ }
348
+ }
349
 
350
+ return $success;
351
+ }
352
+
353
+ /**
354
  * Dumps a variable for debugging
355
  *
356
  * @param string $var The variable to view
651
 
652
  /**
653
  * @param $url string The URL whichs domain you want to get
654
+ * @return string The domain part of the given URL
655
+ * www.myurl.co.uk => myurl.co.uk
656
+ * www.google.com => google.com
657
+ * my.test.myurl.co.uk => myurl.co.uk
658
+ * www.myurl.localweb => myurl.localweb
659
+ *
660
  */
661
  public static function getDomain($url)
662
  {
663
  $pieces = parse_url($url);
664
  $domain = isset($pieces['host']) ? $pieces['host'] : '';
665
+ if (strpos($domain, ".") !== false) {
666
  if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) {
667
  return $regs['domain'];
668
+ } else {
669
+ $exDomain = explode('.', $domain);
670
+ return implode('.', array_slice($exDomain, -2, 2));
671
  }
672
+ } else {
673
  return $domain;
674
  }
675
+ }
676
 
677
+ // START ESCAPING AND SANITIZATION
 
 
678
  /**
679
  * Escaping for HTML blocks.
680
  *
installer/dup-installer/ctrls/ctrl.s1.php CHANGED
@@ -154,22 +154,45 @@ switch ($post_archive_engine) {
154
  DUPX_Log::error(ERR_ZIPARCHIVE);
155
  }
156
 
 
 
 
 
 
 
 
157
  $zip = new ZipArchive();
158
 
159
  if ($zip->open($archive_path) === TRUE) {
160
  for($i = 0; $i < $zip->numFiles; $i++) {
161
  $extract_filename = $zip->getNameIndex($i);
 
 
 
 
 
 
 
 
 
 
 
162
  try {
163
- //rsr uncomment if debugging DUPX_Log::info("Attempting to extract {$extract_filename}. Time:". time());
164
  if (!$zip->extractTo($target , $extract_filename)) {
165
  DUPX_Log::info("FILE EXTRACION ERROR: ".$extract_filename);
166
  } else {
167
  DUPX_Log::info("DONE: ".$extract_filename,2);
168
  }
 
169
  } catch (Exception $ex) {
170
  DUPX_Log::info("FILE EXTRACION ERROR: {$extract_filename} | MSG:" . $ex->getMessage());
171
  }
172
  }
 
 
 
 
 
173
  /*
174
  if (!$zip->extractTo($target)) {
175
  $zip_err_msg = ERR_ZIPEXTRACTION;
154
  DUPX_Log::error(ERR_ZIPARCHIVE);
155
  }
156
 
157
+ $dupInstallerFolder = DUPX_U::findDupInstallerFolder($archive_path);
158
+ if (!empty($dupInstallerFolder)) {
159
+ DUPX_Log::info("ARCHIVE dup-installer SUBFOLDER:\"".$dupInstallerFolder."\"");
160
+ }
161
+
162
+ $dupInstallerZipPath = $dupInstallerFolder.'/dup-installer';
163
+
164
  $zip = new ZipArchive();
165
 
166
  if ($zip->open($archive_path) === TRUE) {
167
  for($i = 0; $i < $zip->numFiles; $i++) {
168
  $extract_filename = $zip->getNameIndex($i);
169
+
170
+ // skip dup-installer folder. Alrady extracted in bootstrap
171
+ if (strpos($extract_filename , $dupInstallerZipPath) === 0) {
172
+ continue;
173
+ }
174
+
175
+ // skip no dupInstallerFolder files
176
+ if (!empty($dupInstallerFolder) && strpos($extract_filename , $dupInstallerFolder) !== 0) {
177
+ continue;
178
+ }
179
+
180
  try {
 
181
  if (!$zip->extractTo($target , $extract_filename)) {
182
  DUPX_Log::info("FILE EXTRACION ERROR: ".$extract_filename);
183
  } else {
184
  DUPX_Log::info("DONE: ".$extract_filename,2);
185
  }
186
+
187
  } catch (Exception $ex) {
188
  DUPX_Log::info("FILE EXTRACION ERROR: {$extract_filename} | MSG:" . $ex->getMessage());
189
  }
190
  }
191
+
192
+ if (!empty($dupInstallerFolder)) {
193
+ DUPX_U::moveUpfromSubFolder($target.'/'.$dupInstallerFolder , true);
194
+ }
195
+
196
  /*
197
  if (!$zip->extractTo($target)) {
198
  $zip_err_msg = ERR_ZIPEXTRACTION;
installer/dup-installer/ctrls/ctrl.s3.php CHANGED
@@ -168,7 +168,7 @@ try {
168
 
169
  // urls from db
170
  $dbUrls = mysqli_query($dbh, 'SELECT * FROM `'.mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix).'options` where option_name IN (\'siteurl\',\'home\')');
171
- if ($dbUrls) {
172
  while ($row = $dbUrls->fetch_object()) {
173
  $old_urls_list[] = $row->option_value;
174
  }
168
 
169
  // urls from db
170
  $dbUrls = mysqli_query($dbh, 'SELECT * FROM `'.mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix).'options` where option_name IN (\'siteurl\',\'home\')');
171
+ if ($dbUrls instanceof mysqli_result) {
172
  while ($row = $dbUrls->fetch_object()) {
173
  $old_urls_list[] = $row->option_value;
174
  }
installer/dup-installer/main.installer.php CHANGED
@@ -27,10 +27,18 @@
27
  if ( !defined('ABSPATH') )
28
  define('ABSPATH', dirname(__FILE__) . '/');
29
 
 
 
 
 
 
30
  date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here.
31
- @ignore_user_abort(true);
32
- @set_time_limit(1800);
33
- @ini_set('memory_limit', '2048M');
 
 
 
34
 
35
  ob_start();
36
  try {
27
  if ( !defined('ABSPATH') )
28
  define('ABSPATH', dirname(__FILE__) . '/');
29
 
30
+ if (!defined('KB_IN_BYTES')) { define('KB_IN_BYTES', 1024); }
31
+ if (!defined('MB_IN_BYTES')) { define('MB_IN_BYTES', 1024 * KB_IN_BYTES); }
32
+ if (!defined('GB_IN_BYTES')) { define('GB_IN_BYTES', 1024 * MB_IN_BYTES); }
33
+ if (!defined('DUPLICATOR_PHP_MAX_MEMORY')) { define('DUPLICATOR_PHP_MAX_MEMORY', 4096 * MB_IN_BYTES); }
34
+
35
  date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here.
36
+ @ignore_user_abort(true);
37
+ @set_time_limit(3600);
38
+ @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY);
39
+ @ini_set('max_input_time', '-1');
40
+ @ini_set('pcre.backtrack_limit', PHP_INT_MAX);
41
+ @ini_set('default_socket_timeout', 3600);
42
 
43
  ob_start();
44
  try {
installer/dup-installer/php.ini ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ max_execution_time = 3600
2
+ max_input_time = -1
3
+ ignore_user_abort = On
4
+ post_max_size = 4096M
5
+ upload_max_filesize = 4096M
6
+ memory_limit = 4096M
7
+ default_socket_timeout = 3600
8
+ pcre.backtrack_limit = 99999999999
installer/dup-installer/views/view.s1.base.php CHANGED
@@ -457,7 +457,7 @@ VALIDATION
457
  <b>Open BaseDir:</b> <i><?php echo $notice['50'] == 'Good' ? "<i class='dupx-pass'>Disabled</i>" : "<i class='dupx-fail'>Enabled</i>"; ?></i>
458
  <br/><br/>
459
 
460
- If <a href="http://www.php.net/manual/en/ini.core.php#ini.open-basedir" target="_blank">open_basedir</a> is enabled and your
461
  having issues getting your site to install properly; please work with your host and follow these steps to prevent issues:
462
  <ol style="margin:7px; line-height:19px">
463
  <li>Disable the open_basedir setting in the php.ini file</li>
@@ -1373,8 +1373,15 @@ $(document).ready(function ()
1373
  $("*[data-type='toggle']").click(DUPX.toggleClick);
1374
  $("#tabs").tabs();
1375
  DUPX.acceptWarning();
1376
- $('#set_file_perms').trigger("click");
1377
- $('#set_dir_perms').trigger("click");
 
 
 
 
 
 
 
1378
  DUPX.toggleSetupType();
1379
 
1380
  <?php echo ($arcCheck == 'Fail') ? "$('#s1-area-archive-file-link').trigger('click');" : ""; ?>
457
  <b>Open BaseDir:</b> <i><?php echo $notice['50'] == 'Good' ? "<i class='dupx-pass'>Disabled</i>" : "<i class='dupx-fail'>Enabled</i>"; ?></i>
458
  <br/><br/>
459
 
460
+ If <a href="http://php.net/manual/en/ini.core.php#ini.open-basedir" target="_blank">open_basedir</a> is enabled and your
461
  having issues getting your site to install properly; please work with your host and follow these steps to prevent issues:
462
  <ol style="margin:7px; line-height:19px">
463
  <li>Disable the open_basedir setting in the php.ini file</li>
1373
  $("*[data-type='toggle']").click(DUPX.toggleClick);
1374
  $("#tabs").tabs();
1375
  DUPX.acceptWarning();
1376
+ <?php
1377
+ $isWindows = DUPX_U::isWindows();
1378
+ if (!$isWindows) {
1379
+ ?>
1380
+ $('#set_file_perms').trigger("click");
1381
+ $('#set_dir_perms').trigger("click");
1382
+ <?php
1383
+ }
1384
+ ?>
1385
  DUPX.toggleSetupType();
1386
 
1387
  <?php echo ($arcCheck == 'Fail') ? "$('#s1-area-archive-file-link').trigger('click');" : ""; ?>
installer/installer.tpl CHANGED
@@ -1,5 +1,17 @@
1
  <?php
 
 
 
 
 
 
2
  date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here.
 
 
 
 
 
 
3
 
4
  class DUPX_CSRF {
5
 
@@ -178,8 +190,14 @@ class DUPX_Bootstrap
178
 
179
  //$archive_extension = strtolower(pathinfo($archive_filepath)['extension']);
180
  $archive_extension = strtolower(pathinfo($archive_filepath, PATHINFO_EXTENSION));
181
- $manual_extract_found = file_exists($installer_directory."/main.installer.php");
182
-
 
 
 
 
 
 
183
  $isZip = ($archive_extension == 'zip');
184
 
185
  //MANUAL EXTRACTION NOT FOUND
@@ -211,6 +229,29 @@ class DUPX_Bootstrap
211
  return $error;
212
  }
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  //SIZE CHECK ERROR
215
  if (($this->archiveRatio < 90) && ($this->archiveActualSize > 0) && ($this->archiveExpectedSize > 0)) {
216
  $this->log("ERROR: The expected archive size should be around [{$archiveExpectedEasy}]. The actual size is currently [{$archiveActualEasy}].");
@@ -228,20 +269,26 @@ class DUPX_Bootstrap
228
 
229
  }
230
 
231
- // INSTALL DIRECTORY: Check if its setup correctly AND we are not in overwrite mode
232
- // disable extract installer mode by passing GET var like installer.php?extract-installer=0 or installer.php?extract-installer=disable
233
- if ((isset($_GET['extract-installer']) && ('0' == $_GET['extract-installer'] || 'disable' == $_GET['extract-installer'] || 'false' == $_GET['extract-installer'])) && file_exists($installer_directory)) {
234
- //RSR for testing if (file_exists($installer_directory)) {
235
 
236
- self::log("$installer_directory already exists");
237
- $extract_installer = !file_exists($installer_directory."/main.installer.php");
 
 
 
 
 
 
238
 
239
- ($extract_installer)
240
- ? self::log("But main.installer.php doesn't so extracting anyway")
241
- : self::log("main.installer.php also exists so not going to extract installer directory");
242
 
 
 
 
 
243
  } else {
244
- self::log("Going to overwrite installer directory since either in overwrite mode or installer directory doesn't exist");
 
245
  }
246
 
247
  if ($extract_installer && file_exists($installer_directory)) {
@@ -293,8 +340,14 @@ class DUPX_Bootstrap
293
  if ($extract_success) {
294
  self::log('Successfully extracted with ZipArchive');
295
  } else {
296
- $error = 'Error extracting with ZipArchive. ';
297
- self::log($error);
 
 
 
 
 
 
298
  }
299
  } else {
300
  self::log("WARNING: ZipArchive is not enabled.");
@@ -340,6 +393,73 @@ class DUPX_Bootstrap
340
  throw $ex;
341
  }
342
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  } else {
344
  self::log("Didn't need to extract the installer.");
345
  }
@@ -530,10 +650,11 @@ class DUPX_Bootstrap
530
  *
531
  * @return bool Returns true if the data was properly extracted
532
  */
533
- private function extractInstallerZipArchive($archive_filepath)
534
  {
535
  $success = true;
536
  $zipArchive = new ZipArchive();
 
537
 
538
  if ($zipArchive->open($archive_filepath) === true) {
539
  self::log("Successfully opened $archive_filepath");
@@ -541,14 +662,35 @@ class DUPX_Bootstrap
541
  $folder_prefix = self::INSTALLER_DIR_NAME.'/';
542
  self::log("Extracting all files from archive within ".self::INSTALLER_DIR_NAME);
543
 
544
- $installer_files_found = 0;
545
 
546
  for ($i = 0; $i < $zipArchive->numFiles; $i++) {
547
  $stat = $zipArchive->statIndex($i);
548
- $filename = $stat['name'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
549
 
550
- if ($this->startsWith($filename, $folder_prefix)) {
551
- $installer_files_found++;
 
552
 
553
  if ($zipArchive->extractTo($destination, $filename) === true) {
554
  self::log("Success: {$filename} >>> {$destination}");
@@ -560,32 +702,41 @@ class DUPX_Bootstrap
560
  }
561
  }
562
 
563
- $lib_directory = dirname(__FILE__).'/'.self::INSTALLER_DIR_NAME.'/lib';
564
- $snaplib_directory = $lib_directory.'/snaplib';
 
 
 
 
 
565
 
566
- // If snaplib files aren't present attempt to extract and copy those
567
- if(!file_exists($snaplib_directory))
568
- {
569
- $folder_prefix = 'snaplib/';
570
- $destination = $lib_directory;
571
-
572
- for ($i = 0; $i < $zipArchive->numFiles; $i++) {
573
- $stat = $zipArchive->statIndex($i);
574
- $filename = $stat['name'];
575
-
576
- if ($this->startsWith($filename, $folder_prefix)) {
577
- $installer_files_found++;
578
-
579
- if ($zipArchive->extractTo($destination, $filename) === true) {
580
- self::log("Success: {$filename} >>> {$destination}");
581
- } else {
582
- self::log("Error extracting {$filename} from archive archive file");
583
- $success = false;
584
- break;
585
- }
586
- }
587
- }
588
- }
 
 
 
 
589
 
590
  if ($zipArchive->close() === true) {
591
  self::log("Successfully closed archive file");
@@ -593,18 +744,72 @@ class DUPX_Bootstrap
593
  self::log("Problem closing archive file");
594
  $success = false;
595
  }
596
-
597
- if ($installer_files_found < 10) {
598
- self::log("Couldn't find the installer directory in the archive!");
599
-
600
- $success = false;
 
 
 
 
601
  }
602
  } else {
603
  self::log("Couldn't open archive archive file with ZipArchive");
604
  $success = false;
605
  }
 
606
  return $success;
607
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
608
 
609
  /**
610
  * Extracts only the 'dup-installer' files using Shell-Exec Unzip
@@ -747,7 +952,13 @@ class DUPX_Bootstrap
747
  } else {
748
  $possible_paths = array(
749
  '/usr/bin/unzip',
750
- '/opt/local/bin/unzip'// RSR TODO put back in when we support shellexec on windows,
 
 
 
 
 
 
751
  );
752
 
753
  foreach ($possible_paths as $path) {
@@ -813,6 +1024,83 @@ class DUPX_Bootstrap
813
 
814
  return $files;
815
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
816
  }
817
 
818
  try {
1
  <?php
2
+
3
+ if (!defined('KB_IN_BYTES')) { define('KB_IN_BYTES', 1024); }
4
+ if (!defined('MB_IN_BYTES')) { define('MB_IN_BYTES', 1024 * KB_IN_BYTES); }
5
+ if (!defined('GB_IN_BYTES')) { define('GB_IN_BYTES', 1024 * MB_IN_BYTES); }
6
+ if (!defined('DUPLICATOR_PHP_MAX_MEMORY')) { define('DUPLICATOR_PHP_MAX_MEMORY', 4096 * MB_IN_BYTES); }
7
+
8
  date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here.
9
+ @ignore_user_abort(true);
10
+ @set_time_limit(3600);
11
+ @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY);
12
+ @ini_set('max_input_time', '-1');
13
+ @ini_set('pcre.backtrack_limit', PHP_INT_MAX);
14
+ @ini_set('default_socket_timeout', 3600);
15
 
16
  class DUPX_CSRF {
17
 
190
 
191
  //$archive_extension = strtolower(pathinfo($archive_filepath)['extension']);
192
  $archive_extension = strtolower(pathinfo($archive_filepath, PATHINFO_EXTENSION));
193
+ $manual_extract_found = (
194
+ file_exists($installer_directory."/main.installer.php")
195
+ &&
196
+ file_exists($installer_directory."/dup-archive__".self::PACKAGE_HASH.".txt")
197
+ &&
198
+ file_exists($installer_directory."/dup-database__".self::PACKAGE_HASH.".sql")
199
+ );
200
+
201
  $isZip = ($archive_extension == 'zip');
202
 
203
  //MANUAL EXTRACTION NOT FOUND
229
  return $error;
230
  }
231
 
232
+ if (!filter_var(self::ARCHIVE_SIZE, FILTER_VALIDATE_INT) || self::ARCHIVE_SIZE > 2147483647) {
233
+
234
+ $os_first_three_chars = substr(PHP_OS, 0, 3);
235
+ $os_first_three_chars = strtoupper($os_first_three_chars);
236
+ $no_of_bits = PHP_INT_SIZE * 8;
237
+
238
+ if ($no_of_bits == 32) {
239
+ if ($isZip) { // ZIP
240
+ if ('WIN' === $os_first_three_chars) {
241
+ $error = "This package is currently {$archiveExpectedEasy} and it's on a Windows OS. PHP on Windows does not support files larger than 2GB. Please use the file filters to get your package lower to support this server or try the package on a Linux server.";
242
+ return $error;
243
+ }
244
+ } else { // DAF
245
+ if ('WIN' === $os_first_three_chars) {
246
+ $error = 'Windows PHP limitations prevents extraction of archives larger than 2GB. Please do the following: <ol><li>Download and use the <a target="_blank" href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-052-q">Windows DupArchive extractor</a> to extract all files from the archive.</li><li>Perform a <a target="_blank" href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q">Manual Extract Install</a> starting at step 4.</li></ol>';
247
+ } else {
248
+ $error = 'This archive is too large for 32-bit PHP. Ask your host to upgrade the server to 64-bit PHP or install on another system has 64-bit PHP.';
249
+ }
250
+ return $error;
251
+ }
252
+ }
253
+ }
254
+
255
  //SIZE CHECK ERROR
256
  if (($this->archiveRatio < 90) && ($this->archiveActualSize > 0) && ($this->archiveExpectedSize > 0)) {
257
  $this->log("ERROR: The expected archive size should be around [{$archiveExpectedEasy}]. The actual size is currently [{$archiveActualEasy}].");
269
 
270
  }
271
 
 
 
 
 
272
 
273
+ // OLD COMPATIBILITY MODE
274
+ if (isset($_GET['extract-installer']) && !isset($_GET['force-extract-installer'])) {
275
+ $_GET['force-extract-installer'] = $_GET['extract-installer'];
276
+ }
277
+
278
+ if ($manual_extract_found) {
279
+ // INSTALL DIRECTORY: Check if its setup correctly AND we are not in overwrite mode
280
+ if (isset($_GET['force-extract-installer']) && ('1' == $_GET['force-extract-installer'] || 'enable' == $_GET['force-extract-installer'] || 'false' == $_GET['force-extract-installer'])) {
281
 
282
+ self::log("Manual extract found with force extract installer get parametr");
283
+ $extract_installer = true;
 
284
 
285
+ } else {
286
+ $extract_installer = false;
287
+ self::log("Manual extract found so not going to extract dup-installer dir");
288
+ }
289
  } else {
290
+ $extract_installer = true;
291
+ self::log("Manual extract didn't found so going to extract dup-installer dir");
292
  }
293
 
294
  if ($extract_installer && file_exists($installer_directory)) {
340
  if ($extract_success) {
341
  self::log('Successfully extracted with ZipArchive');
342
  } else {
343
+ if (0 == $this->installer_files_found) {
344
+ $error = "This archive is not properly formatted and does not contain a dup-installer directory. Please make sure you are attempting to install the original archive and not one that has been reconstructed.";
345
+ self::log($error);
346
+ return $error;
347
+ } else {
348
+ $error = 'Error extracting with ZipArchive. ';
349
+ self::log($error);
350
+ }
351
  }
352
  } else {
353
  self::log("WARNING: ZipArchive is not enabled.");
393
  throw $ex;
394
  }
395
  }
396
+
397
+ $is_apache = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false);
398
+ $is_nginx = (strpos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false);
399
+
400
+ $sapi_type = php_sapi_name();
401
+ $php_ini_data = array(
402
+ 'max_execution_time' => 3600,
403
+ 'max_input_time' => -1,
404
+ 'ignore_user_abort' => 'On',
405
+ 'post_max_size' => '4096M',
406
+ 'upload_max_filesize' => '4096M',
407
+ 'memory_limit' => DUPLICATOR_PHP_MAX_MEMORY,
408
+ 'default_socket_timeout' => 3600,
409
+ 'pcre.backtrack_limit' => 99999999999,
410
+ );
411
+ $sapi_type_first_three_chars = substr($sapi_type, 0, 3);
412
+ if ('fpm' === $sapi_type_first_three_chars) {
413
+ self::log("SAPI: FPM");
414
+ if ($is_apache) {
415
+ self::log('Server: Apache');
416
+ } elseif ($is_nginx) {
417
+ self::log('Server: Nginx');
418
+ }
419
+
420
+ if ($is_apache || $is_nginx) {
421
+ $htaccess_data = array();
422
+ foreach ($php_ini_data as $php_ini_key=>$php_ini_val) {
423
+ if ($is_apache) {
424
+ $htaccess_data[] = 'SetEnv PHP_VALUE "'.$php_ini_key.' = '.$php_ini_val.'"';
425
+ } elseif ($is_nginx) {
426
+ if ('On' == $php_ini_val || 'Off' == $php_ini_val) {
427
+ $htaccess_data[] = 'php_flag '.$php_ini_key.' '.$php_ini_val;
428
+ } else {
429
+ $htaccess_data[] = 'php_value '.$php_ini_key.' '.$php_ini_val;
430
+ }
431
+ }
432
+ }
433
+
434
+ $htaccess_text = implode("\n", $htaccess_data);
435
+ $htaccess_file_path = dirname(__FILE__).'/dup-installer/.htaccess';
436
+ self::log("creating {$htaccess_file_path} with the content:");
437
+ self::log($htaccess_text);
438
+ @file_put_contents($htaccess_file_path, $htaccess_text);
439
+ }
440
+ } elseif ('cgi' === $sapi_type_first_three_chars || 'litespeed' === $sapi_type) {
441
+ if ('cgi' === $sapi_type_first_three_chars) {
442
+ self::log("SAPI: CGI");
443
+ } else {
444
+ self::log("SAPI: litespeed");
445
+ }
446
+ if (version_compare(phpversion(), 5.5) >= 0 && (!$is_apache || 'litespeed' === $sapi_type)) {
447
+ $ini_data = array();
448
+ foreach ($php_ini_data as $php_ini_key=>$php_ini_val) {
449
+ $ini_data[] = $php_ini_key.' = '.$php_ini_val;
450
+ }
451
+ $ini_text = implode("\n", $ini_data);
452
+ $ini_file_path = dirname(__FILE__).'/dup-installer/.user.ini';
453
+ self::log("creating {$ini_file_path} with the content:");
454
+ self::log($ini_text);
455
+ @file_put_contents($ini_file_path, $ini_text);
456
+ } else{
457
+ self::log("No need to create dup-installer/.htaccess or dup-installer/.user.ini");
458
+ }
459
+ } else {
460
+ self::log("No need to create dup-installer/.htaccess or dup-installer/.user.ini");
461
+ self::log("SAPI: Unrecognized");
462
+ }
463
  } else {
464
  self::log("Didn't need to extract the installer.");
465
  }
650
  *
651
  * @return bool Returns true if the data was properly extracted
652
  */
653
+ private function extractInstallerZipArchive($archive_filepath, $checkSubFolder = false)
654
  {
655
  $success = true;
656
  $zipArchive = new ZipArchive();
657
+ $subFolderArchiveList = array();
658
 
659
  if ($zipArchive->open($archive_filepath) === true) {
660
  self::log("Successfully opened $archive_filepath");
662
  $folder_prefix = self::INSTALLER_DIR_NAME.'/';
663
  self::log("Extracting all files from archive within ".self::INSTALLER_DIR_NAME);
664
 
665
+ $this->installer_files_found = 0;
666
 
667
  for ($i = 0; $i < $zipArchive->numFiles; $i++) {
668
  $stat = $zipArchive->statIndex($i);
669
+ if ($checkSubFolder == false) {
670
+ $filenameCheck = $stat['name'];
671
+ $filename = $stat['name'];
672
+ $tmpSubFolder = null;
673
+ } else {
674
+ $safePath = rtrim(self::setSafePath($stat['name']) , '/');
675
+ $tmpArray = explode('/' , $safePath);
676
+
677
+ if (count($tmpArray) < 2) {
678
+ continue;
679
+ }
680
+
681
+ $tmpSubFolder = $tmpArray[0];
682
+ array_shift($tmpArray);
683
+ $filenameCheck = implode('/' , $tmpArray);
684
+ $filename = $stat['name'];
685
+ }
686
+
687
+
688
+ if ($this->startsWith($filenameCheck , $folder_prefix)) {
689
+ $this->installer_files_found++;
690
 
691
+ if (!empty($tmpSubFolder) && !in_array($tmpSubFolder , $subFolderArchiveList)) {
692
+ $subFolderArchiveList[] = $tmpSubFolder;
693
+ }
694
 
695
  if ($zipArchive->extractTo($destination, $filename) === true) {
696
  self::log("Success: {$filename} >>> {$destination}");
702
  }
703
  }
704
 
705
+ if ($checkSubFolder && count($subFolderArchiveList) !== 1) {
706
+ self::log("Error: Multiple dup subfolder archive");
707
+ $success = false;
708
+ } else {
709
+ if ($checkSubFolder) {
710
+ $this->moveUpfromSubFolder(dirname(__FILE__).'/'.$subFolderArchiveList[0] , true);
711
+ }
712
 
713
+ $lib_directory = dirname(__FILE__).'/'.self::INSTALLER_DIR_NAME.'/lib';
714
+ $snaplib_directory = $lib_directory.'/snaplib';
715
+
716
+ // If snaplib files aren't present attempt to extract and copy those
717
+ if(!file_exists($snaplib_directory))
718
+ {
719
+ $folder_prefix = 'snaplib/';
720
+ $destination = $lib_directory;
721
+
722
+ for ($i = 0; $i < $zipArchive->numFiles; $i++) {
723
+ $stat = $zipArchive->statIndex($i);
724
+ $filename = $stat['name'];
725
+
726
+ if ($this->startsWith($filename, $folder_prefix)) {
727
+ $this->installer_files_found++;
728
+
729
+ if ($zipArchive->extractTo($destination, $filename) === true) {
730
+ self::log("Success: {$filename} >>> {$destination}");
731
+ } else {
732
+ self::log("Error extracting {$filename} from archive archive file");
733
+ $success = false;
734
+ break;
735
+ }
736
+ }
737
+ }
738
+ }
739
+ }
740
 
741
  if ($zipArchive->close() === true) {
742
  self::log("Successfully closed archive file");
744
  self::log("Problem closing archive file");
745
  $success = false;
746
  }
747
+
748
+ if ($success != false && $this->installer_files_found < 10) {
749
+ if ($checkSubFolder) {
750
+ self::log("Couldn't find the installer directory in the archive!");
751
+ $success = false;
752
+ } else {
753
+ self::log("Couldn't find the installer directory in archive root! Check subfolder");
754
+ $this->extractInstallerZipArchive($archive_filepath, true);
755
+ }
756
  }
757
  } else {
758
  self::log("Couldn't open archive archive file with ZipArchive");
759
  $success = false;
760
  }
761
+
762
  return $success;
763
  }
764
+
765
+ /**
766
+ * move all folder content up to parent
767
+ *
768
+ * @param string $subFolderName full path
769
+ * @param boolean $deleteSubFolder if true delete subFolder after moved all
770
+ * @return boolean
771
+ *
772
+ */
773
+ private function moveUpfromSubFolder($subFolderName, $deleteSubFolder = false)
774
+ {
775
+ if (!is_dir($subFolderName)) {
776
+ return false;
777
+ }
778
+
779
+ $parentFolder = dirname($subFolderName);
780
+ if (!is_writable($parentFolder)) {
781
+ return false;
782
+ }
783
+
784
+ $success = true;
785
+ if (($subList = glob(rtrim($subFolderName, '/').'/*', GLOB_NOSORT)) === false) {
786
+ self::log("Problem glob folder ".$subFolderName);
787
+ return false;
788
+ } else {
789
+ foreach ($subList as $cName) {
790
+ $destination = $parentFolder.'/'.basename($cName);
791
+ if (file_exists($destination)) {
792
+ $success = self::deletePath($destination);
793
+ }
794
+
795
+ if ($success) {
796
+ $success = rename($cName, $destination);
797
+ } else {
798
+ break;
799
+ }
800
+ }
801
+
802
+ if ($success && $deleteSubFolder) {
803
+ $success = self::deleteDirectory($subFolderName, true);
804
+ }
805
+ }
806
+
807
+ if (!$success) {
808
+ self::log("Problem om moveUpfromSubFolder subFolder:".$subFolderName);
809
+ }
810
+
811
+ return $success;
812
+ }
813
 
814
  /**
815
  * Extracts only the 'dup-installer' files using Shell-Exec Unzip
952
  } else {
953
  $possible_paths = array(
954
  '/usr/bin/unzip',
955
+ '/opt/local/bin/unzip',
956
+ '/bin/unzip',
957
+ '/usr/local/bin/unzip',
958
+ '/usr/sfw/bin/unzip',
959
+ '/usr/xdg4/bin/unzip',
960
+ '/opt/bin/unzip',
961
+ // RSR TODO put back in when we support shellexec on windows,
962
  );
963
 
964
  foreach ($possible_paths as $path) {
1024
 
1025
  return $files;
1026
  }
1027
+
1028
+ /**
1029
+ * Safely remove a directory and recursively if needed
1030
+ *
1031
+ * @param string $directory The full path to the directory to remove
1032
+ * @param string $recursive recursively remove all items
1033
+ *
1034
+ * @return bool Returns true if all content was removed
1035
+ */
1036
+ public static function deleteDirectory($directory, $recursive)
1037
+ {
1038
+ $success = true;
1039
+
1040
+ $filenames = array_diff(scandir($directory), array('.', '..'));
1041
+
1042
+ foreach ($filenames as $filename) {
1043
+ $fullPath = $directory.'/'.$filename;
1044
+
1045
+ if (is_dir($fullPath)) {
1046
+ if ($recursive) {
1047
+ $success = self::deleteDirectory($fullPath, true);
1048
+ }
1049
+ } else {
1050
+ $success = @unlink($fullPath);
1051
+ if ($success === false) {
1052
+ self::log( __FUNCTION__.": Problem deleting file:".$fullPath);
1053
+ }
1054
+ }
1055
+
1056
+ if ($success === false) {
1057
+ self::log("Problem deleting dir:".$directory);
1058
+ break;
1059
+ }
1060
+ }
1061
+
1062
+ return $success && rmdir($directory);
1063
+ }
1064
+
1065
+ /**
1066
+ * Safely remove a file or directory and recursively if needed
1067
+ *
1068
+ * @param string $directory The full path to the directory to remove
1069
+ *
1070
+ * @return bool Returns true if all content was removed
1071
+ */
1072
+ public static function deletePath($path)
1073
+ {
1074
+ $success = true;
1075
+
1076
+ if (is_dir($path)) {
1077
+ $success = self::deleteDirectory($path, true);
1078
+ } else {
1079
+ $success = @unlink($path);
1080
+
1081
+ if ($success === false) {
1082
+ self::log( __FUNCTION__.": Problem deleting file:".$path);
1083
+ }
1084
+ }
1085
+
1086
+ return $success;
1087
+ }
1088
+
1089
+ /**
1090
+ * Makes path safe for any OS for PHP
1091
+ *
1092
+ * Paths should ALWAYS READ be "/"
1093
+ * uni: /home/path/file.txt
1094
+ * win: D:/home/path/file.txt
1095
+ *
1096
+ * @param string $path The path to make safe
1097
+ *
1098
+ * @return string The original $path with a with all slashes facing '/'.
1099
+ */
1100
+ public static function setSafePath($path)
1101
+ {
1102
+ return str_replace("\\", "/", $path);
1103
+ }
1104
  }
1105
 
1106
  try {
lib/dup_archive/classes/util/class.duparchive.u.json.php CHANGED
@@ -14,10 +14,14 @@ class DupArchiveJsonU
14
 
15
  public static function customEncode($value, $iteration = 1)
16
  {
17
- if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
18
- $encoded = json_encode($value, JSON_PRETTY_PRINT);
19
  } else {
20
- $encoded = json_encode($value);
 
 
 
 
21
  }
22
 
23
  switch (json_last_error()) {
14
 
15
  public static function customEncode($value, $iteration = 1)
16
  {
17
+ if (function_exists('wp_json_encode')) {
18
+ $encoded = wp_json_encode($value);
19
  } else {
20
+ if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
21
+ $encoded = json_encode($value, JSON_PRETTY_PRINT);
22
+ } else {
23
+ $encoded = json_encode($value);
24
+ }
25
  }
26
 
27
  switch (json_last_error()) {
lib/dup_archive/daws/daws.php CHANGED
@@ -8,6 +8,19 @@ error_reporting(E_ALL);
8
  error_reporting(E_ALL);
9
  set_error_handler("terminate_missing_variables");
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  require_once(dirname(__FILE__) . '/class.daws.constants.php');
12
 
13
  require_once(DAWSConstants::$LIB_DIR . '/snaplib/snaplib.all.php');
8
  error_reporting(E_ALL);
9
  set_error_handler("terminate_missing_variables");
10
 
11
+ if (!defined('KB_IN_BYTES')) { define('KB_IN_BYTES', 1024); }
12
+ if (!defined('MB_IN_BYTES')) { define('MB_IN_BYTES', 1024 * KB_IN_BYTES); }
13
+ if (!defined('GB_IN_BYTES')) { define('GB_IN_BYTES', 1024 * MB_IN_BYTES); }
14
+ if (!defined('DUPLICATOR_PHP_MAX_MEMORY')) { define('DUPLICATOR_PHP_MAX_MEMORY', 4096 * MB_IN_BYTES); }
15
+
16
+ date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here.
17
+ @ignore_user_abort(true);
18
+ @set_time_limit(3600);
19
+ @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY);
20
+ @ini_set('max_input_time', '-1');
21
+ @ini_set('pcre.backtrack_limit', PHP_INT_MAX);
22
+ @ini_set('default_socket_timeout', 3600);
23
+
24
  require_once(dirname(__FILE__) . '/class.daws.constants.php');
25
 
26
  require_once(DAWSConstants::$LIB_DIR . '/snaplib/snaplib.all.php');
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: migration, backup, restore, move, migrate, duplicate, transfer, clone, aut
4
  Requires at least: 4.0
5
  Tested up to: 5.0
6
  Requires PHP: 5.2.17
7
- Stable tag: 1.3.4
8
  License: GPLv2
9
 
10
  WordPress migration and backups are much easier with Duplicator! Clone, backup, move and transfer an entire site from one location to another.
4
  Requires at least: 4.0
5
  Tested up to: 5.0
6
  Requires PHP: 5.2.17
7
+ Stable tag: 1.3.6
8
  License: GPLv2
9
 
10
  WordPress migration and backups are much easier with Duplicator! Clone, backup, move and transfer an entire site from one location to another.
views/packages/main/s2.scan2.php CHANGED
@@ -70,7 +70,7 @@ PHP SETTINGS -->
70
  $test = ($test) ? 'ON' : 'OFF';
71
  echo '<hr size="1" /><span id="data-srv-php-openbase"></span>&nbsp;<b>' . esc_html__('PHP Open Base Dir', 'duplicator') . ":</b>&nbsp; '{$test}' <br/>";
72
  _e('Issues might occur when [open_basedir] is enabled. Work with your server admin to disable this value in the php.ini file if you’re having issues building a package.', 'duplicator');
73
- echo "&nbsp;<i><a href='http://www.php.net/manual/en/ini.core.php#ini.open-basedir' target='_blank'>[" . esc_html__('details', 'duplicator') . "]</a></i><br/>";
74
 
75
  //MAX_EXECUTION_TIME
76
  $test = (@set_time_limit(0)) ? 0 : ini_get("max_execution_time");
70
  $test = ($test) ? 'ON' : 'OFF';
71
  echo '<hr size="1" /><span id="data-srv-php-openbase"></span>&nbsp;<b>' . esc_html__('PHP Open Base Dir', 'duplicator') . ":</b>&nbsp; '{$test}' <br/>";
72
  _e('Issues might occur when [open_basedir] is enabled. Work with your server admin to disable this value in the php.ini file if you’re having issues building a package.', 'duplicator');
73
+ echo "&nbsp;<i><a href='http://php.net/manual/en/ini.core.php#ini.open-basedir' target='_blank'>[" . esc_html__('details', 'duplicator') . "]</a></i><br/>";
74
 
75
  //MAX_EXECUTION_TIME
76
  $test = (@set_time_limit(0)) ? 0 : ini_get("max_execution_time");
views/tools/diagnostics/information.php CHANGED
@@ -51,8 +51,10 @@ if ($section == "info" || $section == '') {
51
  if ($_GET['action'] != 'display') : ?>
52
  <div id="message" class="notice notice-success is-dismissible dup-wpnotice-box">
53
  <p><b><?php echo esc_html($action_response); ?></b></p>
54
- <?php if ( $_GET['action'] == 'installer') : ?>
55
- <?php
 
 
56
  // Move installer log before cleanup
57
  $installer_log_path = DUPLICATOR_INSTALLER_DIRECTORY.'/dup-installer-log__'.DUPLICATOR_INSTALLER_HASH_PATTERN.'.txt';
58
  $glob_files = glob($installer_log_path);
@@ -93,9 +95,12 @@ if ($section == "info" || $section == '') {
93
  }
94
 
95
  if (!empty($file_path)) {
96
- echo (file_exists($file_path))
97
- ? "<div class='failed'><i class='fa fa-exclamation-triangle'></i> {$txt_found} - ".esc_html($file_path)." </div>"
98
- : "<div class='success'> <i class='fa fa-check'></i> {$txt_removed} - ".esc_html($file_path)." </div>";
 
 
 
99
  }
100
  }
101
 
@@ -130,6 +135,15 @@ if ($section == "info" || $section == '') {
130
 
131
  echo '<br/><br/>';
132
 
 
 
 
 
 
 
 
 
 
133
  echo '<b><i class="fa fa-thumbs-o-up"></i> ' . esc_html__('Help Support Duplicator', 'duplicator') . ':</b>&nbsp;';
134
  _e('The Duplicator team has worked many years to make moving a WordPress site a much easier process. Show your support with a '
135
  . '<a href="https://wordpress.org/support/plugin/duplicator/reviews/?filter=5" target="_blank">5 star review</a>! We would be thrilled if you could!', 'duplicator');
51
  if ($_GET['action'] != 'display') : ?>
52
  <div id="message" class="notice notice-success is-dismissible dup-wpnotice-box">
53
  <p><b><?php echo esc_html($action_response); ?></b></p>
54
+ <?php
55
+ if ( $_GET['action'] == 'installer') :
56
+ $remove_error = false;
57
+
58
  // Move installer log before cleanup
59
  $installer_log_path = DUPLICATOR_INSTALLER_DIRECTORY.'/dup-installer-log__'.DUPLICATOR_INSTALLER_HASH_PATTERN.'.txt';
60
  $glob_files = glob($installer_log_path);
95
  }
96
 
97
  if (!empty($file_path)) {
98
+ if (file_exists($file_path)) {
99
+ echo "<div class='failed'><i class='fa fa-exclamation-triangle'></i> {$txt_found} - ".esc_html($file_path)." </div>";
100
+ $remove_error = true;
101
+ } else {
102
+ echo "<div class='success'> <i class='fa fa-check'></i> {$txt_removed} - ".esc_html($file_path)." </div>";
103
+ }
104
  }
105
  }
106
 
135
 
136
  echo '<br/><br/>';
137
 
138
+ if ($remove_error) {
139
+ echo __('Some of the installer files did not get removed, ', 'duplicator').
140
+ '<a href="#" onclick="Duplicator.Tools.deleteInstallerFiles(); return false;" >'.
141
+ __('please retry the installer cleanup process', 'duplicator').
142
+ '</a>.'.
143
+ __(' If this process continues please see the previous FAQ link.', 'duplicator').
144
+ '<br><br>';
145
+ }
146
+
147
  echo '<b><i class="fa fa-thumbs-o-up"></i> ' . esc_html__('Help Support Duplicator', 'duplicator') . ':</b>&nbsp;';
148
  _e('The Duplicator team has worked many years to make moving a WordPress site a much easier process. Show your support with a '
149
  . '<a href="https://wordpress.org/support/plugin/duplicator/reviews/?filter=5" target="_blank">5 star review</a>! We would be thrilled if you could!', 'duplicator');