Duplicator – WordPress Migration Plugin - Version 1.3.2

Version Description

Download this release

Release Info

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

Code changes from version 1.3.0 to 1.3.2

assets/js/javascript.php CHANGED
@@ -91,7 +91,7 @@ Duplicator.OpenLogWindow = function(target)
91
  {
92
  var target = "log-win" || null;
93
  if (target != null) {
94
- window.open('?page=duplicator-tools', 'log-win');
95
  } else {
96
  window.open('<?php echo esc_js(DUPLICATOR_SSDIR_URL); ?>' + '/' + log)
97
  }
91
  {
92
  var target = "log-win" || null;
93
  if (target != null) {
94
+ window.open('?page=duplicator-tools&tab=diagnostics&section=log', 'log-win');
95
  } else {
96
  window.open('<?php echo esc_js(DUPLICATOR_SSDIR_URL); ?>' + '/' + log)
97
  }
classes/class.io.php CHANGED
@@ -75,7 +75,6 @@ class DUP_IO
75
  {
76
  if (self::createDir($dest_dir, 0755, true) === false)
77
  {
78
- DUP_PRO_LOG::traceError("Error creating $dest_dir.");
79
  return false;
80
  }
81
  }
75
  {
76
  if (self::createDir($dest_dir, 0755, true) === false)
77
  {
 
78
  return false;
79
  }
80
  }
classes/class.logging.php CHANGED
@@ -276,7 +276,7 @@ class DUP_Log
276
 
277
  if (file_exists($backup_log_filepath)) {
278
  if (@unlink($backup_log_filepath) === false) {
279
- DUP_PRO_Low_U::errLog("Couldn't delete backup log $backup_log_filepath");
280
  }
281
  }
282
 
276
 
277
  if (file_exists($backup_log_filepath)) {
278
  if (@unlink($backup_log_filepath) === false) {
279
+ self::errLog("Couldn't delete backup log $backup_log_filepath");
280
  }
281
  }
282
 
classes/package/class.pack.archive.php CHANGED
@@ -489,63 +489,78 @@ class DUP_Archive
489
  */
490
  private function getFileLists($path)
491
  {
492
- $handle = @opendir($path);
493
 
494
- if ($handle) {
495
- while (($file = readdir($handle)) !== false) {
496
 
497
- if ($file == '.' || $file == '..') {
498
- continue;
499
- }
500
 
501
- $fullPath = str_replace("\\", '/', "{$path}/{$file}");
 
502
 
503
- // @todo: Don't leave it like this. Convert into an option on the package to not follow symbolic links
504
- // if (is_dir($fullPath) && (is_link($fullPath) == false))
505
- if (is_dir($fullPath)) {
 
 
 
 
 
 
 
 
506
 
507
- $add = true;
508
- if(!is_link($fullPath)){
509
- foreach ($this->tmpFilterDirsAll as $key => $val) {
510
- $trimmedFilterDir = rtrim($val, '/');
511
- if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) {
512
- $add = false;
 
 
 
 
513
  unset($this->tmpFilterDirsAll[$key]);
514
- break;
515
  }
516
  }
517
- }else{
518
- //Convert relative path of link to absolute path
519
- chdir($fullPath);
520
- $link_path = realpath(readlink($fullPath));
521
- chdir(dirname(__FILE__));
522
-
523
- $link_pos = strpos($fullPath,$link_path);
524
- if($link_pos === 0 && (strlen($link_path) < strlen($fullPath))){
525
- $add = false;
526
- $this->RecursiveLinks[] = $fullPath;
527
- $this->FilterDirsAll[] = $fullPath;
528
- }
529
  }
530
 
531
- if ($add) {
532
- $this->getFileLists($fullPath);
533
- $this->Dirs[] = $fullPath;
 
 
 
 
 
534
  }
535
- } else {
536
- if ( ! (in_array(pathinfo($file, PATHINFO_EXTENSION), $this->FilterExtsAll)
537
- || in_array($fullPath, $this->FilterFilesAll)
538
- || in_array($file, $this->FilterFilesAll))) {
539
- $this->Files[] = $fullPath;
540
- }
541
- }
542
- }
543
- closedir($handle);
544
- }
545
- return $this->Dirs;
546
- }
 
 
 
 
 
 
 
 
 
547
 
548
- /**
549
  * Builds a tree for both file size warnings and name check warnings
550
  * The trees are used to apply filters from the scan screen
551
  *
@@ -582,7 +597,7 @@ class DUP_Archive
582
  $this->FilterInfo->TreeSize[] = array(
583
  'size' => DUP_Util::byteSize($sum, 0),
584
  'dir' => $dir,
585
- 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
586
  'iscore' => $iscore,
587
  'files' => $files
588
  );
@@ -612,7 +627,7 @@ class DUP_Archive
612
 
613
  $this->FilterInfo->TreeWarning[] = array(
614
  'dir' => $dir,
615
- 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
616
  'iscore' => $iscore,
617
  'count' => count($files),
618
  'files' => $files);
@@ -646,7 +661,7 @@ class DUP_Archive
646
 
647
  $this->FilterInfo->TreeWarning[] = array(
648
  'dir' => $dir,
649
- 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
650
  'iscore' => $iscore,
651
  'count' => 0);
652
  }
489
  */
490
  private function getFileLists($path)
491
  {
492
+ $handle = @opendir($path);
493
 
494
+ if ($handle) {
495
+ while (($file = readdir($handle)) !== false) {
496
 
497
+ if ($file == '.' || $file == '..') {
498
+ continue;
499
+ }
500
 
501
+ $fullPath = str_replace("\\", '/', "{$path}/{$file}");
502
+ $relative_path = $fullPath;
503
 
504
+ if (is_link($relative_path)) {
505
+ $is_link = true;
506
+
507
+ //Convert relative path of link to absolute path
508
+ chdir($relative_path);
509
+ $real_path = realpath(readlink($relative_path));
510
+ chdir(dirname(__FILE__));
511
+ } else {
512
+ $is_link = false;
513
+ $real_path = realpath($relative_path);
514
+ }
515
 
516
+ $exclude_check = array_unique(array($real_path, $relative_path));
517
+
518
+ if (is_dir($real_path)) {
519
+ $exclude = false;
520
+
521
+ foreach ($this->tmpFilterDirsAll as $key => $val) {
522
+ $trimmedFilterDir = rtrim($val, '/');
523
+ foreach ($exclude_check as $c_check) {
524
+ if ($c_check == $trimmedFilterDir || strpos($c_check, $trimmedFilterDir.'/') !== false) {
525
+ $exclude = true;
526
  unset($this->tmpFilterDirsAll[$key]);
527
+ break 2;
528
  }
529
  }
 
 
 
 
 
 
 
 
 
 
 
 
530
  }
531
 
532
+ if (!$exclude) {
533
+ if ($is_link) {
534
+ $this->RecursiveLinks[] = $relative_path;
535
+ /* $this->FilterDirsAll[] = $relative_path; */
536
+ }
537
+
538
+ $this->getFileLists($relative_path);
539
+ $this->Dirs[] = $relative_path;
540
  }
541
+ } else {
542
+ $exclude = false;
543
+ if (in_array(pathinfo($file, PATHINFO_EXTENSION), $this->FilterExtsAll) || in_array($file, $this->FilterFilesAll)) {
544
+ $exclude = true;
545
+ } else {
546
+ foreach ($exclude_check as $c_check) {
547
+ if (in_array($c_check, $this->FilterFilesAll)) {
548
+ $exclude = true;
549
+ break;
550
+ }
551
+ }
552
+ }
553
+ if (!$exclude) {
554
+ $this->Files[] = $relative_path;
555
+ }
556
+ }
557
+ }
558
+ closedir($handle);
559
+ }
560
+ return $this->Dirs;
561
+ }
562
 
563
+ /**
564
  * Builds a tree for both file size warnings and name check warnings
565
  * The trees are used to apply filters from the scan screen
566
  *
597
  $this->FilterInfo->TreeSize[] = array(
598
  'size' => DUP_Util::byteSize($sum, 0),
599
  'dir' => $dir,
600
+ 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '/', $dir),
601
  'iscore' => $iscore,
602
  'files' => $files
603
  );
627
 
628
  $this->FilterInfo->TreeWarning[] = array(
629
  'dir' => $dir,
630
+ 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '/', $dir),
631
  'iscore' => $iscore,
632
  'count' => count($files),
633
  'files' => $files);
661
 
662
  $this->FilterInfo->TreeWarning[] = array(
663
  'dir' => $dir,
664
+ 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '/', $dir),
665
  'iscore' => $iscore,
666
  'count' => 0);
667
  }
classes/package/class.pack.archive.zip.php CHANGED
@@ -177,8 +177,10 @@ class DUP_Zip extends DUP_Archive
177
  $error_message = "ZipArchive close failure.";
178
 
179
  DUP_Log::Error($error_message,
180
- "This hosted server may have a disk quota limit.\nCheck to make sure this archive file can be stored.",
181
- Dup_ErrorBehavior::LogOnly);
 
 
182
 
183
  $buildProgress->set_failed($error_message);
184
  return;
177
  $error_message = "ZipArchive close failure.";
178
 
179
  DUP_Log::Error($error_message,
180
+ "The ZipArchive engine is having issues zipping up the files on this server. For more details visit the FAQ\n"
181
+ . "I'm getting a ZipArchive close failure when building. How can I resolve this?\n"
182
+ . "[https://snapcreek.com/duplicator/docs/faqs-tech/#faq-package-165-q]",
183
+ Dup_ErrorBehavior::LogOnly);
184
 
185
  $buildProgress->set_failed($error_message);
186
  return;
classes/package/class.pack.php CHANGED
@@ -312,15 +312,18 @@ class DUP_Package
312
  )
313
  );
314
 
315
- $validator->filter_var($this->Installer->OptsDBHost, FILTER_VALIDATE_URL , array(
316
- 'valkey' => 'OptsDBHost' ,
317
- 'errmsg' => __('MySQL Server Host: <b>%1$s</b> isn\'t a valid host', 'duplicator'),
318
- 'acc_vals' => array(
319
- '' ,
320
- 'localhost'
321
- )
322
- )
323
- );
 
 
 
324
 
325
  $validator->filter_var($this->Installer->OptsDBPort, FILTER_VALIDATE_INT , array(
326
  'valkey' => 'OptsDBPort' ,
@@ -337,6 +340,14 @@ class DUP_Package
337
  return $validator;
338
  }
339
 
 
 
 
 
 
 
 
 
340
  /**
341
  * Saves the active package to the package table
342
  *
@@ -440,6 +451,43 @@ class DUP_Package
440
  }
441
  }
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  /**
444
  * Get all packages with status conditions
445
  * @global wpdb $wpdb
@@ -450,11 +498,15 @@ class DUP_Package
450
  * [ 'op' => '<' ,
451
  * 'status' => DUP_PackageStatus::COMPLETED ]
452
  * ]
453
- * @return DUP_Package[]
 
 
454
  */
455
- public static function get_all_by_status($conditions = array())
456
  {
457
  global $wpdb;
 
 
458
  $tablePrefix = DUP_Util::getTablePrefix();
459
  $table = $tablePrefix . "duplicator_packages";
460
 
@@ -475,23 +527,30 @@ class DUP_Package
475
  $where = ' WHERE '.implode($relation, $str_conds).' ';
476
  }
477
 
478
- $packages = array();
479
- $rows = $wpdb->get_results("SELECT * FROM `{$table}` {$where} ORDER BY id DESC", ARRAY_A);
480
 
481
  if ($rows != null) {
482
- foreach ($rows as $row) {
483
- $Package = unserialize($row['package']);
484
- if ($Package) {
485
- // We was not storing Status in Lite 1.2.52, so it is for backward compatibility
486
- if (!isset($Package->Status)) {
487
- $Package->Status = $row['status'];
 
 
 
 
 
 
 
 
488
  }
489
-
490
- $packages[] = $Package;
491
  }
492
  }
493
  }
494
- return $packages;
 
495
  }
496
 
497
  /**
@@ -729,13 +788,8 @@ class DUP_Package
729
  return;
730
  }
731
 
732
- $iterator = new FilesystemIterator(DUPLICATOR_SSDIR_PATH_TMP);
733
-
734
- // if tmp is empty return
735
- if (!$iterator->valid()) {
736
- return;
737
- }
738
-
739
  // RUNNING PACKAGES
740
  $active_pack = self::get_all_by_status(array(
741
  'relation' => 'AND',
@@ -743,8 +797,9 @@ class DUP_Package
743
  array('op' => '<' , 'status' => DUP_PackageStatus::COMPLETE )
744
  ));
745
  $active_files = array();
746
- foreach($active_pack as $package) {
747
- $active_files[] = $package->NameHash;
 
748
  }
749
 
750
  // ERRORS PACKAGES
@@ -762,39 +817,43 @@ class DUP_Package
762
  // Calculate delta time for old files
763
  $oldTimeToClean = time() - DUPLICATOR_TEMP_CLEANUP_SECONDS;
764
 
765
- foreach ($iterator as $fileinfo) {
 
766
  // Don't remove sub dir
767
- if ($fileinfo->isDir()) {
 
768
  continue;
769
  }
770
 
 
771
  // skip all active packages
772
  foreach ($active_files as $c_nameHash) {
773
- if (strpos($fileinfo->getFilename(), $c_nameHash) === 0) {
774
  continue 2;
775
  }
776
  }
777
 
778
  // Remove all old files
779
- if ($fileinfo->getCTime() <= $oldTimeToClean) {
780
- @unlink($fileinfo->getRealPath());
781
  continue;
782
  }
783
 
784
  // remove all error packages files
785
  foreach ($force_del_files as $c_nameHash) {
786
- if (strpos($fileinfo->getFilename(), $c_nameHash) === 0) {
787
- @unlink($fileinfo->getRealPath());
788
  continue 2;
789
  }
790
  }
791
 
 
792
  // skip json file for pre build packages
793
- if (in_array($fileinfo->getExtension(),$extension_filter) || in_array($fileinfo->getFilename() , $active_files)) {
794
  continue;
795
  }
796
 
797
- @unlink($fileinfo->getRealPath());
798
  }
799
  }
800
 
@@ -1211,7 +1270,7 @@ class DUP_Package
1211
  *
1212
  * @param int $id A valid package id form the duplicator_packages table
1213
  *
1214
- * @return obj A copy of the DUP_Package object
1215
  */
1216
  public static function getByID($id)
1217
  {
312
  )
313
  );
314
 
315
+ //FILTER_VALIDATE_DOMAIN throws notice message on PHP 5.6
316
+ if (defined('FILTER_VALIDATE_DOMAIN')) {
317
+ $validator->filter_var($this->Installer->OptsDBHost, FILTER_VALIDATE_DOMAIN , array(
318
+ 'valkey' => 'OptsDBHost' ,
319
+ 'errmsg' => __('MySQL Server Host: <b>%1$s</b> isn\'t a valid host', 'duplicator'),
320
+ 'acc_vals' => array(
321
+ '' ,
322
+ 'localhost'
323
+ )
324
+ )
325
+ );
326
+ }
327
 
328
  $validator->filter_var($this->Installer->OptsDBPort, FILTER_VALIDATE_INT , array(
329
  'valkey' => 'OptsDBPort' ,
340
  return $validator;
341
  }
342
 
343
+ /**
344
+ *
345
+ * @return bool return true if package is a active_package_id and status is bewteen 0 and 100
346
+ */
347
+ public function isRunning() {
348
+ return DUP_Settings::Get('active_package_id') == $this->ID && $this->Status >= 0 && $this->Status < 100;
349
+ }
350
+
351
  /**
352
  * Saves the active package to the package table
353
  *
451
  }
452
  }
453
 
454
+ /**
455
+ * Get package archive size.
456
+ * If package isn't complete it get size from sum of temp files.
457
+ *
458
+ * @return int size in byte
459
+ */
460
+ public function getArchiveSize() {
461
+ $size = 0;
462
+
463
+ if ($this->Status >= 100) {
464
+ $size = $this->Archive->Size;
465
+ } else {
466
+ $tmpSearch = glob(DUPLICATOR_SSDIR_PATH_TMP . "/{$this->NameHash}_*");
467
+ if (is_array($tmpSearch)) {
468
+ $result = array_map('filesize', $tmpSearch);
469
+ $size = array_sum($result);
470
+ }
471
+ }
472
+
473
+ return $size;
474
+ }
475
+
476
+ /**
477
+ * Return true if active package exist and have an active status
478
+ *
479
+ * @return bool
480
+ */
481
+ public static function is_active_package_present()
482
+ {
483
+ $activePakcs = self::get_all_by_status(array(
484
+ array('op' => '>=', 'status' => DUP_PackageStatus::CREATED),
485
+ array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE)
486
+ ), true);
487
+
488
+ return in_array( DUP_Settings::Get('active_package_id') , $activePakcs);
489
+ }
490
+
491
  /**
492
  * Get all packages with status conditions
493
  * @global wpdb $wpdb
498
  * [ 'op' => '<' ,
499
  * 'status' => DUP_PackageStatus::COMPLETED ]
500
  * ]
501
+ * @param bool $getIds if true return array of id
502
+ *
503
+ * @return DUP_Package[]|int[]
504
  */
505
+ public static function get_all_by_status($conditions = array(),$getIds = false)
506
  {
507
  global $wpdb;
508
+ $result = array();
509
+
510
  $tablePrefix = DUP_Util::getTablePrefix();
511
  $table = $tablePrefix . "duplicator_packages";
512
 
527
  $where = ' WHERE '.implode($relation, $str_conds).' ';
528
  }
529
 
530
+ $cols = $getIds ? 'id' : '*';
531
+ $rows = $wpdb->get_results("SELECT {$cols} FROM `{$table}` {$where} ORDER BY id DESC", ARRAY_A);
532
 
533
  if ($rows != null) {
534
+ if ($getIds) {
535
+ foreach ($rows as $row) {
536
+ $result[] = (int) $row['id'];
537
+ }
538
+ } else {
539
+ foreach ($rows as $row) {
540
+ $Package = unserialize($row['package']);
541
+ if ($Package) {
542
+ // We was not storing Status in Lite 1.2.52, so it is for backward compatibility
543
+ if (!isset($Package->Status)) {
544
+ $Package->Status = $row['status'];
545
+ }
546
+
547
+ $result[] = $Package;
548
  }
 
 
549
  }
550
  }
551
  }
552
+
553
+ return $result;
554
  }
555
 
556
  /**
788
  return;
789
  }
790
 
791
+ $globs = glob(DUPLICATOR_SSDIR_PATH_TMP.'/*.*');
792
+
 
 
 
 
 
793
  // RUNNING PACKAGES
794
  $active_pack = self::get_all_by_status(array(
795
  'relation' => 'AND',
797
  array('op' => '<' , 'status' => DUP_PackageStatus::COMPLETE )
798
  ));
799
  $active_files = array();
800
+
801
+ foreach($active_pack as $package) {
802
+ $active_files[] = $package->NameHash; // 20181221_dup_c0b2f1198a92f4f6c47a621494adc5cb_20181221173955
803
  }
804
 
805
  // ERRORS PACKAGES
817
  // Calculate delta time for old files
818
  $oldTimeToClean = time() - DUPLICATOR_TEMP_CLEANUP_SECONDS;
819
 
820
+ // foreach ($iterator as $fileinfo) {
821
+ foreach ($globs as $glob_full_path) {
822
  // Don't remove sub dir
823
+ // if ($fileinfo->isDir()) {
824
+ if (is_dir($glob_full_path)) {
825
  continue;
826
  }
827
 
828
+ $file_name = basename($glob_full_path);
829
  // skip all active packages
830
  foreach ($active_files as $c_nameHash) {
831
+ if (strpos($file_name, $c_nameHash) === 0) {
832
  continue 2;
833
  }
834
  }
835
 
836
  // Remove all old files
837
+ if (filemtime($glob_full_path) <= $oldTimeToClean) {
838
+ @unlink($glob_full_path);
839
  continue;
840
  }
841
 
842
  // remove all error packages files
843
  foreach ($force_del_files as $c_nameHash) {
844
+ if (strpos($file_name, $c_nameHash) === 0) {
845
+ @unlink($glob_full_path);
846
  continue 2;
847
  }
848
  }
849
 
850
+ $file_info = pathinfo($glob_full_path);
851
  // skip json file for pre build packages
852
+ if (in_array($file_info['extension'], $extension_filter) || in_array($file_name, $active_files)) {
853
  continue;
854
  }
855
 
856
+ @unlink($glob_full_path);
857
  }
858
  }
859
 
1270
  *
1271
  * @param int $id A valid package id form the duplicator_packages table
1272
  *
1273
+ * @return DUP_Package A copy of the DUP_Package object
1274
  */
1275
  public static function getByID($id)
1276
  {
classes/utilities/class.u.multisite.php CHANGED
@@ -35,19 +35,4 @@ class DUP_MU
35
  return 0;
36
  }
37
  }
38
-
39
- public static function getGeneration()
40
- {
41
- if (self::getMode() == 0) {
42
- return DUP_PRO_MU_Generations::NotMultisite;
43
- } else {
44
- $sitesDir = WP_CONTENT_DIR.'/uploads/sites';
45
-
46
- if (file_exists($sitesDir)) {
47
- return DUP_PRO_MU_Generations::ThreeFivePlus;
48
- } else {
49
- return DUP_PRO_MU_Generations::PreThreeFive;
50
- }
51
- }
52
- }
53
  }
35
  return 0;
36
  }
37
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
classes/utilities/class.u.php CHANGED
@@ -37,6 +37,13 @@ class DUP_Util
37
  */
38
  public static $PHP7_plus;
39
 
 
 
 
 
 
 
 
40
  /**
41
  * Initialized on load (see end of file)
42
  */
@@ -506,19 +513,28 @@ class DUP_Util
506
  $path_ssdir = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH);
507
  $path_plugin = DUP_Util::safePath(DUPLICATOR_PLUGIN_PATH);
508
 
509
- //--------------------------------
510
- //CHMOD DIRECTORY ACCESS
511
- //wordpress root directory
512
- @chmod($path_wproot, 0755);
513
 
514
- //snapshot directory
515
- @mkdir($path_ssdir, 0755);
516
- @chmod($path_ssdir, 0755);
 
 
 
 
 
 
 
 
 
517
 
518
- //snapshot tmp directory
519
  $path_ssdir_tmp = $path_ssdir.'/tmp';
520
- @mkdir($path_ssdir_tmp, 0755);
521
- @chmod($path_ssdir_tmp, 0755);
 
 
 
522
 
523
  //plugins dir/files
524
  @chmod($path_plugin.'files', 0755);
@@ -526,38 +542,51 @@ class DUP_Util
526
  //--------------------------------
527
  //FILE CREATION
528
  //SSDIR: Create Index File
529
- $ssfile = @fopen($path_ssdir.'/index.php', 'w');
530
- @fwrite($ssfile,
531
- '<?php error_reporting(0); if (stristr(php_sapi_name(), "fcgi")) { $url = "http://" . $_SERVER["HTTP_HOST"]; header("Location: {$url}/404.html");} else { header("HTTP/1.1 404 Not Found", true, 404);} exit(); ?>');
532
- @fclose($ssfile);
 
 
 
533
 
534
  //SSDIR: Create token file in snapshot
535
- $tokenfile = @fopen($path_ssdir.'/dtoken.php', 'w');
536
- @fwrite($tokenfile,
537
- '<?php error_reporting(0); if (stristr(php_sapi_name(), "fcgi")) { $url = "http://" . $_SERVER["HTTP_HOST"]; header("Location: {$url}/404.html");} else { header("HTTP/1.1 404 Not Found", true, 404);} exit(); ?>');
538
- @fclose($tokenfile);
 
 
 
539
 
540
  //SSDIR: Create .htaccess
541
  $storage_htaccess_off = DUP_Settings::Get('storage_htaccess_off');
 
542
  if ($storage_htaccess_off) {
543
- @unlink($path_ssdir.'/.htaccess');
544
- } else {
545
- $htfile = @fopen($path_ssdir.'/.htaccess', 'w');
546
  $htoutput = "Options -Indexes";
547
  @fwrite($htfile, $htoutput);
548
  @fclose($htfile);
549
  }
550
 
551
  //SSDIR: Robots.txt file
552
- $robotfile = @fopen($path_ssdir.'/robots.txt', 'w');
553
- @fwrite($robotfile, "User-agent: * \nDisallow: /".DUPLICATOR_SSDIR_NAME.'/');
554
- @fclose($robotfile);
 
 
 
555
 
556
  //PLUG DIR: Create token file in plugin
557
- $tokenfile2 = @fopen($path_plugin.'installer/dtoken.php', 'w');
558
- @fwrite($tokenfile2,
 
 
559
  '<?php @error_reporting(0); @require_once("../../../../wp-admin/admin.php"); global $wp_query; $wp_query->set_404(); header("HTTP/1.1 404 Not Found", true, 404); header("Status: 404 Not Found"); @include(get_template_directory () . "/404.php"); ?>');
560
- @fclose($tokenfile2);
 
561
  }
562
 
563
  /**
@@ -676,5 +705,33 @@ class DUP_Util
676
  $tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? $wpdb->base_prefix : $wpdb->prefix;
677
  return $tablePrefix;
678
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
  }
680
  DUP_Util::init();
37
  */
38
  public static $PHP7_plus;
39
 
40
+ /**
41
+ * array of ini disable functions
42
+ *
43
+ * @var array
44
+ */
45
+ private static $iniDisableFuncs = null;
46
+
47
  /**
48
  * Initialized on load (see end of file)
49
  */
513
  $path_ssdir = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH);
514
  $path_plugin = DUP_Util::safePath(DUPLICATOR_PLUGIN_PATH);
515
 
516
+ if (!file_exists($path_ssdir)) {
517
+ $old_root_perm = @fileperms($path_wproot);
 
 
518
 
519
+ //--------------------------------
520
+ //CHMOD DIRECTORY ACCESS
521
+ //wordpress root directory
522
+ @chmod($path_wproot, 0755);
523
+
524
+ //snapshot directory
525
+ @mkdir($path_ssdir, 0755);
526
+ @chmod($path_ssdir, 0755);
527
+
528
+ // restore original root perms
529
+ @chmod($path_wproot, $old_root_perm );
530
+ }
531
 
 
532
  $path_ssdir_tmp = $path_ssdir.'/tmp';
533
+ if (!file_exists($path_ssdir_tmp)) {
534
+ //snapshot tmp directory
535
+ @mkdir($path_ssdir_tmp, 0755);
536
+ @chmod($path_ssdir_tmp, 0755);
537
+ }
538
 
539
  //plugins dir/files
540
  @chmod($path_plugin.'files', 0755);
542
  //--------------------------------
543
  //FILE CREATION
544
  //SSDIR: Create Index File
545
+ $fileName = $path_ssdir.'/index.php';
546
+ if (!file_exists($fileName)) {
547
+ $ssfile = @fopen($fileName, 'w');
548
+ @fwrite($ssfile,
549
+ '<?php error_reporting(0); if (stristr(php_sapi_name(), "fcgi")) { $url = "http://" . $_SERVER["HTTP_HOST"]; header("Location: {$url}/404.html");} else { header("HTTP/1.1 404 Not Found", true, 404);} exit(); ?>');
550
+ @fclose($ssfile);
551
+ }
552
 
553
  //SSDIR: Create token file in snapshot
554
+ $fileName = $path_ssdir.'/dtoken.php';
555
+ if (!file_exists($fileName)) {
556
+ $tokenfile = @fopen($fileName, 'w');
557
+ @fwrite($tokenfile,
558
+ '<?php error_reporting(0); if (stristr(php_sapi_name(), "fcgi")) { $url = "http://" . $_SERVER["HTTP_HOST"]; header("Location: {$url}/404.html");} else { header("HTTP/1.1 404 Not Found", true, 404);} exit(); ?>');
559
+ @fclose($tokenfile);
560
+ }
561
 
562
  //SSDIR: Create .htaccess
563
  $storage_htaccess_off = DUP_Settings::Get('storage_htaccess_off');
564
+ $fileName = $path_ssdir.'/.htaccess';
565
  if ($storage_htaccess_off) {
566
+ @unlink($fileName);
567
+ } else if (!file_exists($fileName)) {
568
+ $htfile = @fopen($fileName, 'w');
569
  $htoutput = "Options -Indexes";
570
  @fwrite($htfile, $htoutput);
571
  @fclose($htfile);
572
  }
573
 
574
  //SSDIR: Robots.txt file
575
+ $fileName = $path_ssdir.'/robots.txt';
576
+ if (!file_exists($fileName)) {
577
+ $robotfile = @fopen($fileName, 'w');
578
+ @fwrite($robotfile, "User-agent: * \nDisallow: /".DUPLICATOR_SSDIR_NAME.'/');
579
+ @fclose($robotfile);
580
+ }
581
 
582
  //PLUG DIR: Create token file in plugin
583
+ $fileName = $path_plugin.'installer/dtoken.php';
584
+ if (!file_exists($fileName)) {
585
+ $tokenfile2 = @fopen($fileName, 'w');
586
+ @fwrite($tokenfile2,
587
  '<?php @error_reporting(0); @require_once("../../../../wp-admin/admin.php"); global $wp_query; $wp_query->set_404(); header("HTTP/1.1 404 Not Found", true, 404); header("Status: 404 Not Found"); @include(get_template_directory () . "/404.php"); ?>');
588
+ @fclose($tokenfile2);
589
+ }
590
  }
591
 
592
  /**
705
  $tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? $wpdb->base_prefix : $wpdb->prefix;
706
  return $tablePrefix;
707
  }
708
+
709
+ /**
710
+ * return ini disable functions array
711
+ *
712
+ * @return array
713
+ */
714
+ public static function getIniDisableFuncs() {
715
+ if (is_null(self::$iniDisableFuncs)) {
716
+ $tmpFuncs = ini_get ( 'disable_functions' );
717
+ $tmpFuncs = explode(',',$tmpFuncs);
718
+ self::$iniDisableFuncs = array();
719
+ foreach ($tmpFuncs as $cFunc) {
720
+ self::$iniDisableFuncs[] = trim($cFunc);
721
+ }
722
+ }
723
+
724
+ return self::$iniDisableFuncs;
725
+ }
726
+
727
+ /**
728
+ * Check if functione exists and isn't in ini disable_functions
729
+ *
730
+ * @param string $function_name
731
+ * @return bool
732
+ */
733
+ public static function isIniFunctionEnalbe($function_name) {
734
+ return function_exists($function_name) && !in_array($function_name, self::getIniDisableFuncs());
735
+ }
736
  }
737
  DUP_Util::init();
classes/utilities/class.u.shell.php CHANGED
@@ -27,12 +27,19 @@ class DUP_Shell_U
27
  return escapeshellarg($string);
28
  }
29
 
30
- public static function isPopenEnabled() {
31
- if (!function_exists('popen') || !function_exists('proc_open')) {
 
 
 
 
 
 
32
  $ret = false;
33
  } else {
34
  $ret = true;
35
- }
 
36
  $ret = apply_filters('duplicator_pro_is_popen_enabled', $ret);
37
  return $ret;
38
  }
27
  return escapeshellarg($string);
28
  }
29
 
30
+ /**
31
+ *
32
+ * @return boolean
33
+ *
34
+ */
35
+ public static function isPopenEnabled() {
36
+
37
+ if (!DUP_Util::isIniFunctionEnalbe('popen') || !DUP_Util::isIniFunctionEnalbe('proc_open')) {
38
  $ret = false;
39
  } else {
40
  $ret = true;
41
+ }
42
+
43
  $ret = apply_filters('duplicator_pro_is_popen_enabled', $ret);
44
  return $ret;
45
  }
classes/utilities/class.u.validator.php CHANGED
@@ -20,8 +20,10 @@ class DUP_Validator
20
  * @var array $patterns
21
  */
22
  private static $patterns = array(
23
- 'fdir' => '/^([a-zA-Z]:|\/|\\\\\\\\)[\p{L}\s0-9-_!%&()=\[\]#@,.;+\\\\\/]+$/',
24
- 'ffile' => '/^([a-zA-Z]:|\/|\\\\\\\\)[\p{L}\s0-9-_!%&()=\[\]#@,.;+\\\\\/]+\.[A-Za-z0-9]{2,4}$/',
 
 
25
  'fext' => '/^\.?[A-Za-z0-9]{2,4}$/',
26
  'email' => '[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+',
27
  'empty' => '/^$/',
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]+\.[A-Za-z0-9]{2,4}$/',
27
  'fext' => '/^\.?[A-Za-z0-9]{2,4}$/',
28
  'email' => '[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+',
29
  'empty' => '/^$/',
ctrls/ctrl.package.php CHANGED
@@ -270,6 +270,60 @@ function duplicator_package_delete()
270
  die();
271
  }
272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  /**
274
  * Controller for Tools
275
  * @package Duplicator\ctrls
@@ -376,6 +430,12 @@ class DUP_CTRL_Package extends DUP_CTRL_Base
376
 
377
  //OUTPUT: Installer, Archive, SQL File
378
  if ($isBinary) {
 
 
 
 
 
 
379
  header("Pragma: public");
380
  header("Expires: 0");
381
  header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
@@ -392,17 +452,18 @@ class DUP_CTRL_Package extends DUP_CTRL_Base
392
  $fileName = basename($filePath);
393
  }
394
 
395
- header("Content-Type: application/octet-stream");
396
- header("Content-Disposition: attachment; filename=\"{$fileName}\";");
397
 
398
- @ob_end_clean(); // required or large files wont work
399
- DUP_Log::Trace("streaming $filePath");
 
 
 
 
400
 
401
- if (fpassthru($fp) === false) {
402
- DUP_Log::Trace("Error with fpassthru for {$filePath}");
403
- }
404
  fclose($fp);
405
- die(); //Supress additional ouput
406
  } else {
407
  header("Content-Type: text/plain");
408
  header("Content-Disposition: attachment; filename=\"error.txt\";");
@@ -483,4 +544,4 @@ class DUP_CTRL_Package extends DUP_CTRL_Base
483
  }
484
  }
485
 
486
- }
270
  die();
271
  }
272
 
273
+ /**
274
+ * Active package info
275
+ * Returns a JSON scan report active package info or
276
+ * active_package_present == false if no active package is present.
277
+ *
278
+ * @return json
279
+ */
280
+ function duplicator_active_package_info()
281
+ {
282
+ ob_start();
283
+ try {
284
+ global $wpdb;
285
+
286
+ $error = false;
287
+ $result = array(
288
+ 'active_package' => array(
289
+ 'present' => false,
290
+ 'status' => 0,
291
+ 'size' => 0
292
+ ),
293
+ 'html' => '',
294
+ 'message' => ''
295
+ );
296
+
297
+ $nonce = sanitize_text_field($_POST['nonce']);
298
+ if (!wp_verify_nonce($nonce, 'duplicator_active_package_info')) {
299
+ throw new Exception(__('An unathorized security request was made to this page. Please try again!','duplicator'));
300
+ }
301
+
302
+ $result['active_package']['present'] = DUP_Package::is_active_package_present();
303
+
304
+ if ($result['active_package']['present']) {
305
+ $id = DUP_Settings::Get('active_package_id');
306
+ $package = DUP_Package::getByID($id);
307
+ if (is_null($package)) {
308
+ throw new Exception(__('Active package object error','duplicator'));
309
+ }
310
+ $result['active_package']['status'] = $package->Status;
311
+ $result['active_package']['size'] = $package->getArchiveSize();
312
+ $result['active_package']['size_format'] = DUP_Util::byteSize($package->getArchiveSize());
313
+ }
314
+ } catch (Exception $e) {
315
+ $error = true;
316
+ $result['message'] = $e->getMessage();
317
+ }
318
+
319
+ $result['html'] = ob_get_clean();
320
+ if ($error) {
321
+ wp_send_json_error($result);
322
+ } else {
323
+ wp_send_json_success($result);
324
+ }
325
+ }
326
+
327
  /**
328
  * Controller for Tools
329
  * @package Duplicator\ctrls
430
 
431
  //OUTPUT: Installer, Archive, SQL File
432
  if ($isBinary) {
433
+ @session_write_close();
434
+ @ob_flush();
435
+ //flush seems to cause issues on some PHP version where the download prompt
436
+ //is no longer called but the contents of the installer are dumped to the browser.
437
+ //@flush();
438
+
439
  header("Pragma: public");
440
  header("Expires: 0");
441
  header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
452
  $fileName = basename($filePath);
453
  }
454
 
455
+ header("Content-Type: application/octet-stream");
456
+ header("Content-Disposition: attachment; filename=\"{$fileName}\";");
457
 
458
+ DUP_LOG::trace("streaming $filePath");
459
+
460
+ while(!feof($fp)) {
461
+ $buffer = fread($fp, 2048);
462
+ print $buffer;
463
+ }
464
 
 
 
 
465
  fclose($fp);
466
+ exit;
467
  } else {
468
  header("Content-Type: text/plain");
469
  header("Content-Disposition: attachment; filename=\"error.txt\";");
544
  }
545
  }
546
 
547
+ }
define.php CHANGED
@@ -2,7 +2,8 @@
2
  //Prevent directly browsing to the file
3
  if (function_exists('plugin_dir_url'))
4
  {
5
- define('DUPLICATOR_VERSION', '1.3.0');
 
6
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
7
  define('DUPLICATOR_SITE_URL', get_site_url());
8
 
2
  //Prevent directly browsing to the file
3
  if (function_exists('plugin_dir_url'))
4
  {
5
+ define('DUPLICATOR_VERSION', '1.3.2');
6
+ define('DUPLICATOR_VERSION_BUILD', '2018-12-29_10:15');
7
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
8
  define('DUPLICATOR_SITE_URL', get_site_url());
9
 
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.0
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
9
  Text Domain: duplicator
@@ -209,6 +209,7 @@ if (is_admin() == true)
209
  add_action('admin_notices', array('DUP_UI_Notice', 'showReservedFilesNotice'));
210
 
211
  //CTRL ACTIONS
 
212
  add_action('wp_ajax_duplicator_package_scan', 'duplicator_package_scan');
213
  add_action('wp_ajax_duplicator_package_build', 'duplicator_package_build');
214
  add_action('wp_ajax_duplicator_package_delete', 'duplicator_package_delete');
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.2
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
9
  Text Domain: duplicator
209
  add_action('admin_notices', array('DUP_UI_Notice', 'showReservedFilesNotice'));
210
 
211
  //CTRL ACTIONS
212
+ add_action('wp_ajax_duplicator_active_package_info', 'duplicator_active_package_info');
213
  add_action('wp_ajax_duplicator_package_scan', 'duplicator_package_scan');
214
  add_action('wp_ajax_duplicator_package_build', 'duplicator_package_build');
215
  add_action('wp_ajax_duplicator_package_delete', 'duplicator_package_delete');
installer/dup-installer/classes/class.db.php CHANGED
@@ -20,11 +20,10 @@ class DUPX_DB
20
  * @param string $username The server DB user name
21
  * @param string $password The server DB password
22
  * @param string $dbname The server DB name
23
- * @param int $port The server DB port
24
  *
25
  * @return database connection handle
26
  */
27
- public static function connect($host, $username, $password, $dbname = '', $port = null)
28
  {
29
  //sock connections
30
  if ('sock' === substr($host, -4)) {
@@ -349,8 +348,8 @@ class DUPX_DB
349
  if (function_exists('mysqli_set_charset') && self::hasAbility($dbh, 'set_charset')) {
350
  return mysqli_set_charset($dbh, $charset);
351
  } else {
352
- $sql = " SET NAMES ".mysqli_real_escape_string($this->dbh, $charset);
353
- if (!empty($collate)) $sql .= " COLLATE ".mysqli_real_escape_string($this->dbh, $collate);
354
  return mysqli_query($dbh, $sql);
355
  }
356
  }
20
  * @param string $username The server DB user name
21
  * @param string $password The server DB password
22
  * @param string $dbname The server DB name
 
23
  *
24
  * @return database connection handle
25
  */
26
+ public static function connect($host, $username, $password, $dbname = '')
27
  {
28
  //sock connections
29
  if ('sock' === substr($host, -4)) {
348
  if (function_exists('mysqli_set_charset') && self::hasAbility($dbh, 'set_charset')) {
349
  return mysqli_set_charset($dbh, $charset);
350
  } else {
351
+ $sql = " SET NAMES ".mysqli_real_escape_string($dbh, $charset);
352
+ if (!empty($collate)) $sql .= " COLLATE ".mysqli_real_escape_string($dbh, $collate);
353
  return mysqli_query($dbh, $sql);
354
  }
355
  }
installer/dup-installer/classes/class.engine.php CHANGED
@@ -188,7 +188,7 @@ class DUPX_UpdateEngine
188
  if (!$fullsearch) {
189
  $colList = self::getTextColumns($conn, $table);
190
  if ($colList != null && is_array($colList)) {
191
- array_walk($colList, set_sql_column_safe);
192
  $colList = implode(',', $colList);
193
  }
194
  $colMsg = (empty($colList)) ? '*' : '~';
@@ -230,6 +230,7 @@ class DUPX_UpdateEngine
230
  //Loops every cell
231
  foreach ($columns as $column => $primary_key) {
232
  $report['scan_cells']++;
 
233
  $edited_data = $data_to_fix = $row[$column];
234
  $base64converted = false;
235
  $txt_found = false;
188
  if (!$fullsearch) {
189
  $colList = self::getTextColumns($conn, $table);
190
  if ($colList != null && is_array($colList)) {
191
+ array_walk($colList, 'set_sql_column_safe');
192
  $colList = implode(',', $colList);
193
  }
194
  $colMsg = (empty($colList)) ? '*' : '~';
230
  //Loops every cell
231
  foreach ($columns as $column => $primary_key) {
232
  $report['scan_cells']++;
233
+ if (!isset($row[$column])) continue;
234
  $edited_data = $data_to_fix = $row[$column];
235
  $base64converted = false;
236
  $txt_found = false;
installer/dup-installer/classes/class.logging.php CHANGED
@@ -55,7 +55,7 @@ class DUPX_Log
55
  $log_msg = strip_tags($log_msg);
56
  @fwrite($GLOBALS["LOG_FILE_HANDLE"], "\nINSTALLER ERROR:\n{$log_msg}\n");
57
  @fclose($GLOBALS["LOG_FILE_HANDLE"]);
58
- die("<div class='dupx-ui-error'><hr size='1' /><b style='color:#B80000;'>INSTALL ERROR!</b><br/>{$errorMessage}</div>");
59
  }
60
 
61
  }
55
  $log_msg = strip_tags($log_msg);
56
  @fwrite($GLOBALS["LOG_FILE_HANDLE"], "\nINSTALLER ERROR:\n{$log_msg}\n");
57
  @fclose($GLOBALS["LOG_FILE_HANDLE"]);
58
+ die("<div class='dupx-ui-error'><hr size='1' /><b style='color:#B80000;'><i class='fa fa-exclamation-circle'></i> INSTALL ERROR!</b><br/>{$errorMessage}</div>");
59
  }
60
 
61
  }
installer/dup-installer/classes/config/class.wp.config.tranformer.php CHANGED
@@ -149,6 +149,23 @@ class WPConfigTransformer {
149
  $separator = (string) $separator;
150
  $placement = (string) $placement;
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  if ( false === strpos( $this->wp_config_src, $anchor ) ) {
153
  throw new Exception( 'Unable to locate placement anchor.' );
154
  }
149
  $separator = (string) $separator;
150
  $placement = (string) $placement;
151
 
152
+ // Custom code by the SnapCreek Team
153
+ if ( false === strpos( $this->wp_config_src, $anchor ) ) {
154
+ $other_anchor_points = array(
155
+ '/** Absolute path to the WordPress directory',
156
+ "if ( !defined('ABSPATH') )",
157
+ '/** Sets up WordPress vars and included files',
158
+ 'require_once(ABSPATH',
159
+ );
160
+ foreach ($other_anchor_points as $anchor_point) {
161
+ $anchor_point = (string) $anchor_point;
162
+ if ( false !== strpos( $this->wp_config_src, $anchor_point ) ) {
163
+ $anchor = $anchor_point;
164
+ break;
165
+ }
166
+ }
167
+ }
168
+
169
  if ( false === strpos( $this->wp_config_src, $anchor ) ) {
170
  throw new Exception( 'Unable to locate placement anchor.' );
171
  }
installer/dup-installer/classes/utilities/class.u.php CHANGED
@@ -61,7 +61,34 @@ class DUPX_U
61
  }
62
  }
63
 
64
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  * Does one string contain other
66
  *
67
  * @param string $haystack The full string to search
@@ -145,7 +172,7 @@ class DUPX_U
145
  return false;
146
  }
147
  }
148
-
149
  /**
150
  * A safe method used to copy larger files
151
  *
@@ -489,8 +516,8 @@ class DUPX_U
489
  public static function unsetSafePath($path)
490
  {
491
  return str_replace("/", "\\", $path);
492
- }
493
-
494
  /**
495
  * Check PHP version
496
  *
@@ -502,7 +529,7 @@ class DUPX_U
502
  {
503
  return (version_compare(PHP_VERSION, $version) >= 0);
504
  }
505
-
506
  // START ESCAPING AND SANITIZATION
507
  /**
508
  * Escaping for HTML blocks.
@@ -584,7 +611,7 @@ class DUPX_U
584
  */
585
  public static function esc_textarea( $text )
586
  {
587
- $safe_text = htmlspecialchars( $text, ENT_QUOTES, 'UTF-8' );
588
  /**
589
  * Filters a string cleaned and escaped for output in a textarea element.
590
  *
@@ -911,7 +938,7 @@ class DUPX_U
911
  return ( ! in_array( $i, $allowedentitynames ) ) ? "&amp;$i;" : "&$i;";
912
  }
913
 
914
-
915
  /**
916
  * Helper function to determine if a Unicode value is valid.
917
  *
@@ -924,7 +951,7 @@ class DUPX_U
924
  ($i >= 0xe000 && $i <= 0xfffd) ||
925
  ($i >= 0x10000 && $i <= 0x10ffff) );
926
  }
927
-
928
  /**
929
  * Callback for wp_kses_normalize_entities() regular expression.
930
  *
@@ -1104,7 +1131,7 @@ class DUPX_U
1104
  return $good_protocol_url;
1105
  }
1106
 
1107
-
1108
  /**
1109
  * Removes any invalid control characters in $string.
1110
  *
@@ -1263,7 +1290,7 @@ class DUPX_U
1263
  }
1264
 
1265
  // SANITIZE Functions
1266
-
1267
  /**
1268
  * Normalize EOL characters and strip duplicate whitespace.
1269
  *
@@ -1420,7 +1447,7 @@ class DUPX_U
1420
  return $matches[0];
1421
  }
1422
 
1423
-
1424
  /**
1425
  * Remove slashes from a string or array of strings.
1426
  *
@@ -1486,7 +1513,7 @@ class DUPX_U
1486
  return is_string($value) ? stripslashes($value) : $value;
1487
  }
1488
 
1489
-
1490
  /**
1491
  * Normalize a filesystem path.
1492
  *
61
  }
62
  }
63
 
64
+ /**
65
+ * Add replace strings to substitute old url to new url
66
+ * 1) no protocol old url to no protocol new url (es. //www.hold.url => //www.new.url)
67
+ * 2) wrong protocol new url to right protocol new url (es. http://www.new.url => https://www.new.url)
68
+ *
69
+ * @param string $old
70
+ * @param string $new
71
+ */
72
+ public static function replacmentUrlOldToNew($old, $new)
73
+ {
74
+ //SEARCH WITH NO PROTOCOL: RAW "//"
75
+ $url_old_raw = str_ireplace(array('http://', 'https://'), '//', $old);
76
+ $url_new_raw = str_ireplace(array('http://', 'https://'), '//', $new);
77
+ DUPX_U::queueReplacementWithEncodings($url_old_raw, $url_new_raw);
78
+
79
+ //FORCE NEW PROTOCOL "//"
80
+ $url_new_info = parse_url($new);
81
+ $url_new_domain = $url_new_info['scheme'].'://'.$url_new_info['host'];
82
+
83
+ if ($url_new_info['scheme'] == 'http') {
84
+ $url_new_wrong_protocol = 'https://'.$url_new_info['host'];
85
+ } else {
86
+ $url_new_wrong_protocol = 'http://'.$url_new_info['host'];
87
+ }
88
+ DUPX_U::queueReplacementWithEncodings($url_new_wrong_protocol, $url_new_domain);
89
+ }
90
+
91
+ /**
92
  * Does one string contain other
93
  *
94
  * @param string $haystack The full string to search
172
  return false;
173
  }
174
  }
175
+
176
  /**
177
  * A safe method used to copy larger files
178
  *
516
  public static function unsetSafePath($path)
517
  {
518
  return str_replace("/", "\\", $path);
519
+ }
520
+
521
  /**
522
  * Check PHP version
523
  *
529
  {
530
  return (version_compare(PHP_VERSION, $version) >= 0);
531
  }
532
+
533
  // START ESCAPING AND SANITIZATION
534
  /**
535
  * Escaping for HTML blocks.
611
  */
612
  public static function esc_textarea( $text )
613
  {
614
+ $safe_text = htmlspecialchars( $text, ENT_QUOTES, 'UTF-8' );
615
  /**
616
  * Filters a string cleaned and escaped for output in a textarea element.
617
  *
938
  return ( ! in_array( $i, $allowedentitynames ) ) ? "&amp;$i;" : "&$i;";
939
  }
940
 
941
+
942
  /**
943
  * Helper function to determine if a Unicode value is valid.
944
  *
951
  ($i >= 0xe000 && $i <= 0xfffd) ||
952
  ($i >= 0x10000 && $i <= 0x10ffff) );
953
  }
954
+
955
  /**
956
  * Callback for wp_kses_normalize_entities() regular expression.
957
  *
1131
  return $good_protocol_url;
1132
  }
1133
 
1134
+
1135
  /**
1136
  * Removes any invalid control characters in $string.
1137
  *
1290
  }
1291
 
1292
  // SANITIZE Functions
1293
+
1294
  /**
1295
  * Normalize EOL characters and strip duplicate whitespace.
1296
  *
1447
  return $matches[0];
1448
  }
1449
 
1450
+
1451
  /**
1452
  * Remove slashes from a string or array of strings.
1453
  *
1513
  return is_string($value) ? stripslashes($value) : $value;
1514
  }
1515
 
1516
+
1517
  /**
1518
  * Normalize a filesystem path.
1519
  *
installer/dup-installer/ctrls/ctrl.s3.php CHANGED
@@ -36,13 +36,12 @@ if (isset($_POST['url_new'])) {
36
  $_POST['url_new'] = null;
37
  }
38
 
39
-
40
  $_POST['ssl_admin'] = isset($_POST['ssl_admin']) ? true : false;
41
  $_POST['exe_safe_mode'] = isset($_POST['exe_safe_mode']) ? $_POST['exe_safe_mode'] : 0;
42
  $_POST['config_mode'] = (isset($_POST['config_mode'])) ? $_POST['config_mode'] : 'NEW';
43
 
44
  //MYSQL CONNECTION
45
- $dbh = DUPX_DB::connect($_POST['dbhost'], $_POST['dbuser'], html_entity_decode($_POST['dbpass']), $_POST['dbname'], $_POST['dbport']);
46
  $dbConnError = (mysqli_connect_error()) ? 'Error: '.mysqli_connect_error() : 'Unable to Connect';
47
 
48
  if (!$dbh) {
@@ -84,11 +83,11 @@ $log .= print_r($POST_LOG, true);
84
  $log .= "--------------------------------------\n";
85
  $log .= "TABLES TO SCAN\n";
86
  $log .= "--------------------------------------\n";
87
- $log .= (isset($_POST['tables']) && count($_POST['tables'] > 0)) ? print_r($_POST['tables'], true) : 'No tables selected to update';
88
  $log .= "--------------------------------------\n";
89
  $log .= "KEEP PLUGINS ACTIVE\n";
90
  $log .= "--------------------------------------\n";
91
- $log .= (isset($_POST['plugins']) && count($_POST['plugins'] > 0)) ? print_r($_POST['plugins'], true) : 'No plugins selected for activation';
92
  DUPX_Log::info($log, 2);
93
 
94
 
@@ -103,6 +102,20 @@ $log .= "[^] no searchable columns\n";
103
  $log .= "--------------------------------------";
104
  DUPX_Log::info($log);
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  //CUSTOM REPLACE -> REPLACE LIST
107
  if (isset($_POST['search'])) {
108
  $search_count = count($_POST['search']);
@@ -118,30 +131,39 @@ if (isset($_POST['search'])) {
118
  }
119
  }
120
 
121
- //DIRS PATHS
122
  DUPX_U::queueReplacementWithEncodings($_POST['path_old'] , $_POST['path_new'] );
123
  $path_old_unsetSafe = rtrim(DUPX_U::unsetSafePath($_POST['path_old']), '\\');
124
  $path_new_unsetSafe = rtrim($_POST['path_new'], '/');
125
  DUPX_U::queueReplacementWithEncodings($path_old_unsetSafe , $path_new_unsetSafe );
126
 
127
- //SEARCH WITH NO PROTOCAL: RAW "//"
128
- $url_old_raw = str_ireplace(array('http://', 'https://'), '//', $_POST['url_old']);
129
- $url_new_raw = str_ireplace(array('http://', 'https://'), '//', $_POST['url_new']);
130
-
131
- DUPX_U::queueReplacementWithEncodings($url_old_raw , $url_new_raw);
132
 
133
- //FORCE NEW PROTOCOL "//"
134
- $url_new_info = parse_url($_POST['url_new']);
135
- $url_new_domain = $url_new_info['scheme'].'://'.$url_new_info['host'];
 
 
136
 
137
- if ($url_new_info['scheme'] == 'http') {
138
- $url_new_wrong_protocol = 'https://'.$url_new_info['host'];
139
- } else {
140
- $url_new_wrong_protocol = 'http://'.$url_new_info['host'];
141
  }
142
 
143
- DUPX_U::queueReplacementWithEncodings($url_new_wrong_protocol , $url_new_domain);
 
 
 
 
144
 
 
 
 
 
145
 
146
  /*=============================================================
147
  * REMOVE TRAILING SLASH LOGIC:
@@ -185,7 +207,7 @@ DUPX_UpdateEngine::logErrors($report);
185
  //CREATE NEW ADMIN USER
186
  //===============================================
187
  if (strlen($_POST['wp_username']) >= 4 && strlen($_POST['wp_password']) >= 6) {
188
-
189
  $post_wp_username = $_POST['wp_username'];
190
  $post_wp_password = $_POST['wp_password'];
191
  $post_wp_mail = $_POST['wp_mail'];
@@ -234,7 +256,7 @@ if (strlen($_POST['wp_username']) >= 4 && strlen($_POST['wp_password']) >= 6) {
234
  @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'nickname', '{$post_wp_nickname}')");
235
  @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'first_name', '{$post_wp_first_name}')");
236
  @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'last_name', '{$post_wp_last_name}')");
237
-
238
  DUPX_Log::info("\nNEW WP-ADMIN USER:");
239
  if ($newuser1 && $newuser_test2 && $newuser3) {
240
  DUPX_Log::info("- New username '{$post_wp_username}' was created successfully allong with MU usermeta.");
@@ -259,8 +281,6 @@ DUPX_Log::info("\n====================================");
259
  DUPX_Log::info('CONFIGURATION FILE UPDATES:');
260
  DUPX_Log::info("====================================\n");
261
 
262
- $root_path = $GLOBALS['DUPX_ROOT'];
263
- $wpconfig_ark_path = ($GLOBALS['DUPX_AC']->installSiteOverwriteOn) ? "{$root_path}/dup-wp-config-arc__{$GLOBALS['DUPX_AC']->package_hash}.txt" : "{$root_path}/wp-config.php";
264
  if (!is_writable($wpconfig_ark_path)) {
265
  $err_log = "\nWARNING: Unable to update file permissions and write to dup-wp-config-arc__[HASH].txt. ";
266
  $err_log .= "Check that the wp-config.php is in the archive.zip and check with your host or administrator to enable PHP to write to the wp-config.php file. ";
@@ -268,25 +288,24 @@ if (!is_writable($wpconfig_ark_path)) {
268
  chmod($wpconfig_ark_path, 0644) ? DUPX_Log::info("File Permission Update: dup-wp-config-arc__[HASH].txt set to 0644") : DUPX_Log::error("{$err_log}");
269
  }
270
 
271
- $config_transformer = new WPConfigTransformer($wpconfig_ark_path);
272
  $config_transformer->update('constant', 'WP_HOME', $_POST['url_new'], array('normalize' => true, 'add' => false));
273
  $config_transformer->update('constant', 'WP_SITEURL', $_POST['url_new'], array('normalize' => true, 'add' => false));
274
 
275
  //SSL CHECKS
276
- if ($_POST['ssl_admin']) {
277
- $config_transformer->update('constant', 'FORCE_SSL_ADMIN', 'true', array('raw' => true, 'normalize' => true));
278
  } else {
279
  $config_transformer->update('constant', 'FORCE_SSL_ADMIN', 'false', array('raw' => true, 'add' => false, 'normalize' => true));
280
  }
281
 
282
- if ($_POST['cache_wp']) {
283
  $config_transformer->update('constant', 'WP_CACHE', 'true', array('raw' => true, 'normalize' => true));
284
  } else {
285
  $config_transformer->update('constant', 'WP_CACHE', 'false', array('raw' => true, 'add' => false, 'normalize' => true));
286
  }
287
 
288
  // Cache: [ ] Keep Home Path
289
- if ($_POST['cache_path']) {
290
  if ($config_transformer->exists('constant', 'WPCACHEHOME')) {
291
  $wpcachehome_const_val = $config_transformer->get_value('constant', 'WPCACHEHOME');
292
  $wpcachehome_const_val = DUPX_U::wp_normalize_path($wpcachehome_const_val);
@@ -323,7 +342,7 @@ if ($config_transformer->exists('constant', 'WP_TEMP_DIR')) {
323
  $wp_temp_dir_const_val = $config_transformer->get_value('constant', 'WP_TEMP_DIR');
324
  $wp_temp_dir_const_val = DUPX_U::wp_normalize_path($wp_temp_dir_const_val);
325
  $new_path = str_replace($_POST['path_old'], $_POST['path_new'], $wp_temp_dir_const_val, $count);
326
- if ($count > 0) {
327
  $config_transformer->update('constant', 'WP_TEMP_DIR', $new_path, array('normalize' => true));
328
  }
329
  }
@@ -368,7 +387,7 @@ if ($config_transformer->exists('constant', 'WPMU_PLUGIN_URL')) {
368
 
369
  // COOKIE_DOMAIN
370
  if ($config_transformer->exists('constant', 'COOKIE_DOMAIN')) {
371
-
372
  $post_url_old = DUPX_U::sanitize_text_field($_POST['url_old']);
373
  $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
374
 
@@ -386,12 +405,11 @@ if ($config_transformer->exists('constant', 'COOKIE_DOMAIN')) {
386
  }
387
  }
388
 
389
- $db_port = is_int($_POST['dbport']) ? DUPX_U::sanitize_text_field($_POST['dbport']) : 3306;
390
- $db_host = ($db_port == 3306) ? DUPX_U::sanitize_text_field($_POST['dbhost']) : DUPX_U::sanitize_text_field($_POST['dbhost']).':'.DUPX_U::sanitize_text_field($db_port);
391
  $db_name = isset($_POST['dbname']) ? DUPX_U::sanitize_text_field($_POST['dbname']) : '';
392
  $db_user = isset($_POST['dbuser']) ? DUPX_U::sanitize_text_field($_POST['dbuser']) : '';
393
  $db_pass = isset($_POST['dbpass']) ? trim(DUPX_U::wp_unslash($_POST['dbpass'])) : '';
394
-
395
  $config_transformer->update('constant', 'DB_NAME', $db_name);
396
  $config_transformer->update('constant', 'DB_USER', $db_user);
397
  $config_transformer->update('constant', 'DB_PASSWORD', $db_pass);
@@ -453,6 +471,7 @@ DUPX_Log::info("\n====================================");
453
  DUPX_Log::info("NOTICES");
454
  DUPX_Log::info("====================================\n");
455
  $config_vars = array('WPCACHEHOME', 'COOKIE_DOMAIN', 'WP_SITEURL', 'WP_HOME', 'WP_TEMP_DIR');
 
456
  $config_found = DUPX_U::getListValues($config_vars, $wpconfig_ark_contents);
457
 
458
  //Files
36
  $_POST['url_new'] = null;
37
  }
38
 
 
39
  $_POST['ssl_admin'] = isset($_POST['ssl_admin']) ? true : false;
40
  $_POST['exe_safe_mode'] = isset($_POST['exe_safe_mode']) ? $_POST['exe_safe_mode'] : 0;
41
  $_POST['config_mode'] = (isset($_POST['config_mode'])) ? $_POST['config_mode'] : 'NEW';
42
 
43
  //MYSQL CONNECTION
44
+ $dbh = DUPX_DB::connect($_POST['dbhost'], $_POST['dbuser'], html_entity_decode($_POST['dbpass']), $_POST['dbname']);
45
  $dbConnError = (mysqli_connect_error()) ? 'Error: '.mysqli_connect_error() : 'Unable to Connect';
46
 
47
  if (!$dbh) {
83
  $log .= "--------------------------------------\n";
84
  $log .= "TABLES TO SCAN\n";
85
  $log .= "--------------------------------------\n";
86
+ $log .= (isset($_POST['tables']) && count($_POST['tables']) > 0) ? print_r($_POST['tables'], true) : 'No tables selected to update';
87
  $log .= "--------------------------------------\n";
88
  $log .= "KEEP PLUGINS ACTIVE\n";
89
  $log .= "--------------------------------------\n";
90
+ $log .= (isset($_POST['plugins']) && count($_POST['plugins']) > 0) ? print_r($_POST['plugins'], true) : 'No plugins selected for activation';
91
  DUPX_Log::info($log, 2);
92
 
93
 
102
  $log .= "--------------------------------------";
103
  DUPX_Log::info($log);
104
 
105
+ //===============================================
106
+ // INIZIALIZE WP_CONFIG TRANSFORMER
107
+ //===============================================
108
+ $root_path = $GLOBALS['DUPX_ROOT'];
109
+ $wpconfig_ark_path = ($GLOBALS['DUPX_AC']->installSiteOverwriteOn) ? "{$root_path}/dup-wp-config-arc__{$GLOBALS['DUPX_AC']->package_hash}.txt" : "{$root_path}/wp-config.php";
110
+ $config_transformer = null;
111
+ if (is_readable($wpconfig_ark_path)) {
112
+ $config_transformer = new WPConfigTransformer($wpconfig_ark_path);
113
+ }
114
+
115
+ //===============================================
116
+ // SEARCH AND REPLACE STRINGS
117
+ //===============================================
118
+
119
  //CUSTOM REPLACE -> REPLACE LIST
120
  if (isset($_POST['search'])) {
121
  $search_count = count($_POST['search']);
131
  }
132
  }
133
 
134
+ // DIRS PATHS
135
  DUPX_U::queueReplacementWithEncodings($_POST['path_old'] , $_POST['path_new'] );
136
  $path_old_unsetSafe = rtrim(DUPX_U::unsetSafePath($_POST['path_old']), '\\');
137
  $path_new_unsetSafe = rtrim($_POST['path_new'], '/');
138
  DUPX_U::queueReplacementWithEncodings($path_old_unsetSafe , $path_new_unsetSafe );
139
 
140
+ // URLS
141
+ // url from _POST
142
+ $old_urls_list = array(
143
+ $_POST['url_old']
144
+ );
145
 
146
+ // urls from wp-config
147
+ if (!is_null($config_transformer)) {
148
+ if ($config_transformer->exists('constant', 'WP_HOME')) {
149
+ $old_urls_list[] = $config_transformer->get_value('constant', 'WP_HOME');
150
+ }
151
 
152
+ if ($config_transformer->exists('constant', 'WP_SITEURL')) {
153
+ $old_urls_list[] = $config_transformer->get_value('constant', 'WP_SITEURL');
154
+ }
 
155
  }
156
 
157
+ // urls from db
158
+ $dbUrls = mysqli_query($dbh, 'SELECT * FROM `'.mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix).'options` where option_name IN (\'siteurl\',\'home\')');
159
+ while ($row = $dbUrls->fetch_object()) {
160
+ $old_urls_list[] = $row->option_value;
161
+ }
162
 
163
+ $old_urls_list = array_unique ($old_urls_list);
164
+ foreach ($old_urls_list as $old_url) {
165
+ DUPX_U::replacmentUrlOldToNew($old_url, $_POST['url_new']);
166
+ }
167
 
168
  /*=============================================================
169
  * REMOVE TRAILING SLASH LOGIC:
207
  //CREATE NEW ADMIN USER
208
  //===============================================
209
  if (strlen($_POST['wp_username']) >= 4 && strlen($_POST['wp_password']) >= 6) {
210
+
211
  $post_wp_username = $_POST['wp_username'];
212
  $post_wp_password = $_POST['wp_password'];
213
  $post_wp_mail = $_POST['wp_mail'];
256
  @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'nickname', '{$post_wp_nickname}')");
257
  @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'first_name', '{$post_wp_first_name}')");
258
  @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'last_name', '{$post_wp_last_name}')");
259
+
260
  DUPX_Log::info("\nNEW WP-ADMIN USER:");
261
  if ($newuser1 && $newuser_test2 && $newuser3) {
262
  DUPX_Log::info("- New username '{$post_wp_username}' was created successfully allong with MU usermeta.");
281
  DUPX_Log::info('CONFIGURATION FILE UPDATES:');
282
  DUPX_Log::info("====================================\n");
283
 
 
 
284
  if (!is_writable($wpconfig_ark_path)) {
285
  $err_log = "\nWARNING: Unable to update file permissions and write to dup-wp-config-arc__[HASH].txt. ";
286
  $err_log .= "Check that the wp-config.php is in the archive.zip and check with your host or administrator to enable PHP to write to the wp-config.php file. ";
288
  chmod($wpconfig_ark_path, 0644) ? DUPX_Log::info("File Permission Update: dup-wp-config-arc__[HASH].txt set to 0644") : DUPX_Log::error("{$err_log}");
289
  }
290
 
 
291
  $config_transformer->update('constant', 'WP_HOME', $_POST['url_new'], array('normalize' => true, 'add' => false));
292
  $config_transformer->update('constant', 'WP_SITEURL', $_POST['url_new'], array('normalize' => true, 'add' => false));
293
 
294
  //SSL CHECKS
295
+ if (isset($_POST['ssl_admin']) && $_POST['ssl_admin']) {
296
+ $config_transformer->update('constant', 'FORCE_SSL_ADMIN', 'true', array('raw' => true, 'normalize' => true));
297
  } else {
298
  $config_transformer->update('constant', 'FORCE_SSL_ADMIN', 'false', array('raw' => true, 'add' => false, 'normalize' => true));
299
  }
300
 
301
+ if (isset($_POST['cache_wp']) && $_POST['cache_wp']) {
302
  $config_transformer->update('constant', 'WP_CACHE', 'true', array('raw' => true, 'normalize' => true));
303
  } else {
304
  $config_transformer->update('constant', 'WP_CACHE', 'false', array('raw' => true, 'add' => false, 'normalize' => true));
305
  }
306
 
307
  // Cache: [ ] Keep Home Path
308
+ if (isset($_POST['cache_path']) && $_POST['cache_path']) {
309
  if ($config_transformer->exists('constant', 'WPCACHEHOME')) {
310
  $wpcachehome_const_val = $config_transformer->get_value('constant', 'WPCACHEHOME');
311
  $wpcachehome_const_val = DUPX_U::wp_normalize_path($wpcachehome_const_val);
342
  $wp_temp_dir_const_val = $config_transformer->get_value('constant', 'WP_TEMP_DIR');
343
  $wp_temp_dir_const_val = DUPX_U::wp_normalize_path($wp_temp_dir_const_val);
344
  $new_path = str_replace($_POST['path_old'], $_POST['path_new'], $wp_temp_dir_const_val, $count);
345
+ if ($count > 0) {
346
  $config_transformer->update('constant', 'WP_TEMP_DIR', $new_path, array('normalize' => true));
347
  }
348
  }
387
 
388
  // COOKIE_DOMAIN
389
  if ($config_transformer->exists('constant', 'COOKIE_DOMAIN')) {
390
+
391
  $post_url_old = DUPX_U::sanitize_text_field($_POST['url_old']);
392
  $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
393
 
405
  }
406
  }
407
 
408
+ $db_host = isset($_POST['dbhost']) ? DUPX_U::sanitize_text_field($_POST['dbhost']) : '';
 
409
  $db_name = isset($_POST['dbname']) ? DUPX_U::sanitize_text_field($_POST['dbname']) : '';
410
  $db_user = isset($_POST['dbuser']) ? DUPX_U::sanitize_text_field($_POST['dbuser']) : '';
411
  $db_pass = isset($_POST['dbpass']) ? trim(DUPX_U::wp_unslash($_POST['dbpass'])) : '';
412
+
413
  $config_transformer->update('constant', 'DB_NAME', $db_name);
414
  $config_transformer->update('constant', 'DB_USER', $db_user);
415
  $config_transformer->update('constant', 'DB_PASSWORD', $db_pass);
471
  DUPX_Log::info("NOTICES");
472
  DUPX_Log::info("====================================\n");
473
  $config_vars = array('WPCACHEHOME', 'COOKIE_DOMAIN', 'WP_SITEURL', 'WP_HOME', 'WP_TEMP_DIR');
474
+ $wpconfig_ark_contents = file_get_contents($wpconfig_ark_path);
475
  $config_found = DUPX_U::getListValues($config_vars, $wpconfig_ark_contents);
476
 
477
  //Files
installer/dup-installer/main.installer.php CHANGED
@@ -28,6 +28,9 @@ 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
 
32
  ob_start();
33
  $GLOBALS['DUPX_DEBUG'] = (isset($_GET['debug']) && $_GET['debug'] == 1) ? true : false;
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
  $GLOBALS['DUPX_DEBUG'] = (isset($_GET['debug']) && $_GET['debug'] == 1) ? true : false;
installer/dup-installer/views/view.s1.base.php CHANGED
@@ -343,7 +343,8 @@ VALIDATION
343
  <b>Options:</b>
344
  <ul style="margin-bottom: 0">
345
  <li>If the archive was already manually extracted then <a href="javascript:void(0)" onclick="DUPX.getManaualArchiveOpt()">[Enable Manual Archive Extraction]</a></li>
346
- <li>If the wp-config file is not needed then remove it.</li>
 
347
  </ul>
348
  <?php
349
  }
343
  <b>Options:</b>
344
  <ul style="margin-bottom: 0">
345
  <li>If the archive was already manually extracted then <a href="javascript:void(0)" onclick="DUPX.getManaualArchiveOpt()">[Enable Manual Archive Extraction]</a></li>
346
+ <li>Empty the directory of all files, except for the installer.php and archive.zip/daf files.</li>
347
+ <li>Advanced Users: Can attempt to manually remove the wp-config file only if the archive was manually extracted.</li>
348
  </ul>
349
  <?php
350
  }
installer/dup-installer/views/view.s3.php CHANGED
@@ -253,10 +253,18 @@ VIEW: STEP 3- INPUT -->
253
  </div><br style="clear:both" />
254
  <select id="plugins" name="plugins[]" multiple="multiple" style="width:315px; height:100px" <?php echo ($_POST['exe_safe_mode'] > 0) ? 'disabled="true"' : ''; ?>>
255
  <?php
 
 
 
 
256
  $selected_string = ($_POST['exe_safe_mode'] > 0) ? '' : 'selected="selected"';
257
  foreach ($active_plugins as $plugin) {
258
- $plugin_dirname = dirname($plugin);
259
- echo "<option {$selected_string} value='" . DUPX_U::esc_attr( $plugin ) . "'>" . DUPX_U::esc_attr($plugin_dirname) . '</option>';
 
 
 
 
260
  }
261
  ?>
262
  </select>
@@ -465,9 +473,9 @@ DUPX.runUpdate = function()
465
  } catch(err) {
466
  console.error(err);
467
  console.error('JSON parse failed for response data: ' + respData);
468
- var status = "<b>Server Code:</b> " + xhr.status + "<br/>";
469
  status += "<b>Status:</b> " + textStatus + "<br/>";
470
- status += "<b>Response:</b> " + xhr.responseText + "<hr/>";
471
  status += "<b>Additional Troubleshooting Tips:</b><br/>";
472
  status += "- Check the <a href='./<?php echo DUPX_U::esc_attr($GLOBALS["LOG_FILE_NAME"]);?>' target='dup-installer'>dup-installer-log.txt</a> file for warnings or errors.<br/>";
473
  status += "- Check the web server and PHP error logs. <br/>";
253
  </div><br style="clear:both" />
254
  <select id="plugins" name="plugins[]" multiple="multiple" style="width:315px; height:100px" <?php echo ($_POST['exe_safe_mode'] > 0) ? 'disabled="true"' : ''; ?>>
255
  <?php
256
+ $exclude_plugins = array(
257
+ 'really-simple-ssl/rlrsssl-really-simple-ssl.php',
258
+ 'simple-google-recaptcha/simple-google-recaptcha.php',
259
+ );
260
  $selected_string = ($_POST['exe_safe_mode'] > 0) ? '' : 'selected="selected"';
261
  foreach ($active_plugins as $plugin) {
262
+ $label = dirname($plugin) == '.' ? $plugin : dirname($plugin);
263
+ if (in_array($plugin, $exclude_plugins)) {
264
+ echo "<option value='" . DUPX_U::esc_attr($plugin) . "'>" . DUPX_U::esc_html($label) . '</option>';
265
+ } else {
266
+ echo "<option {$selected_string} value='" . DUPX_U::esc_attr( $plugin ) . "'>" . DUPX_U::esc_html($label) . '</option>';
267
+ }
268
  }
269
  ?>
270
  </select>
473
  } catch(err) {
474
  console.error(err);
475
  console.error('JSON parse failed for response data: ' + respData);
476
+ var status = "<b>Server Code:</b> " + xHr.status + "<br/>";
477
  status += "<b>Status:</b> " + textStatus + "<br/>";
478
+ status += "<b>Response:</b> " + xHr.responseText + "<hr/>";
479
  status += "<b>Additional Troubleshooting Tips:</b><br/>";
480
  status += "- Check the <a href='./<?php echo DUPX_U::esc_attr($GLOBALS["LOG_FILE_NAME"]);?>' target='dup-installer'>dup-installer-log.txt</a> file for warnings or errors.<br/>";
481
  status += "- Check the web server and PHP error logs. <br/>";
installer/installer.tpl CHANGED
@@ -378,9 +378,14 @@ class DUPX_Bootstrap
378
 
379
  public function postExtractProcessing()
380
  {
381
- $dproInstallerDir = dirname(__FILE__) . '/dup-installer';
382
  $libDir = $dproInstallerDir . '/lib';
383
  $fileopsDir = $libDir . '/fileops';
 
 
 
 
 
384
 
385
  $sourceFilepath = "{$fileopsDir}/fileops.ppp";
386
  $destFilepath = "{$fileopsDir}/fileops.php";
@@ -389,7 +394,7 @@ class DUPX_Bootstrap
389
  if(@rename($sourceFilepath, $destFilepath) === false) {
390
  return "Error renaming {$sourceFilepath}";
391
  }
392
- }
393
  }
394
 
395
  /**
378
 
379
  public function postExtractProcessing()
380
  {
381
+ $dproInstallerDir = dirname(__FILE__) . '/dup-installer';
382
  $libDir = $dproInstallerDir . '/lib';
383
  $fileopsDir = $libDir . '/fileops';
384
+
385
+ if(!file_exists($dproInstallerDir)) {
386
+
387
+ return 'Can\'t extract installer directory. See <a target="_blank" href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-022-q">this FAQ item</a> for details on how to resolve.</a>';
388
+ }
389
 
390
  $sourceFilepath = "{$fileopsDir}/fileops.ppp";
391
  $destFilepath = "{$fileopsDir}/fileops.php";
394
  if(@rename($sourceFilepath, $destFilepath) === false) {
395
  return "Error renaming {$sourceFilepath}";
396
  }
397
+ }
398
  }
399
 
400
  /**
lib/dup_archive/classes/class.duparchive.engine.php CHANGED
@@ -464,20 +464,14 @@ class DupArchiveEngine
464
  // Single-threaded file expansion
465
  public static function expandFiles($archiveFilePath, $relativeFilePaths, $destPath)
466
  {
467
- DUP_PRO_LOG::trace("Opening archive: {$archiveFilePath}");
468
-
469
  // Not setting timeout timestamp so it will never timeout
470
  DupArchiveUtil::tlog("opening archive {$archiveFilePath}");
471
 
472
  $archiveHandle = SnapLibIOU::fopen($archiveFilePath, 'r');
473
 
474
- DUP_PRO_LOG::trace("archiveHandle: ".var_export($archiveHandle,true));
475
-
476
  /* @var $expandState DupArchiveSimpleExpandState */
477
  $expandState = new DupArchiveSimpleExpandState();
478
 
479
- DUP_PRO_LOG::trace("Initialize class DupArchiveSimpleExpandState(): ".var_export($expandState,true));
480
-
481
  $expandState->archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle);
482
  $expandState->isCompressed = $expandState->archiveHeader->isCompressed;
483
  $expandState->archiveOffset = SnapLibIOU::ftell($archiveHandle);
@@ -487,8 +481,6 @@ class DupArchiveEngine
487
  // $expandState->basePath = $destPath . '/tempExtract'; // RSR remove once extract works
488
  $expandState->basePath = $destPath; // RSR remove once extract works
489
 
490
- DUP_PRO_LOG::trace("expandState Setup: ".var_export($expandState,true));
491
-
492
  // TODO: Filter out all directories/files except those in the list
493
  self::expandItems($expandState, $archiveHandle);
494
 
464
  // Single-threaded file expansion
465
  public static function expandFiles($archiveFilePath, $relativeFilePaths, $destPath)
466
  {
 
 
467
  // Not setting timeout timestamp so it will never timeout
468
  DupArchiveUtil::tlog("opening archive {$archiveFilePath}");
469
 
470
  $archiveHandle = SnapLibIOU::fopen($archiveFilePath, 'r');
471
 
 
 
472
  /* @var $expandState DupArchiveSimpleExpandState */
473
  $expandState = new DupArchiveSimpleExpandState();
474
 
 
 
475
  $expandState->archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle);
476
  $expandState->isCompressed = $expandState->archiveHeader->isCompressed;
477
  $expandState->archiveOffset = SnapLibIOU::ftell($archiveHandle);
481
  // $expandState->basePath = $destPath . '/tempExtract'; // RSR remove once extract works
482
  $expandState->basePath = $destPath; // RSR remove once extract works
483
 
 
 
484
  // TODO: Filter out all directories/files except those in the list
485
  self::expandItems($expandState, $archiveHandle);
486
 
lib/dup_archive/classes/util/class.duparchive.u.json.php CHANGED
@@ -14,38 +14,33 @@ 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()) {
24
- case JSON_ERROR_NONE:
25
- // DUP_PRO_LOG::trace("#### no json errors so returning");
26
- return $encoded;
27
- case JSON_ERROR_DEPTH:
28
- throw new RuntimeException('Maximum stack depth exceeded'); // or trigger_error() or throw new Exception()
29
- case JSON_ERROR_STATE_MISMATCH:
30
- throw new RuntimeException('Underflow or the modes mismatch'); // or trigger_error() or throw new Exception()
31
- case JSON_ERROR_CTRL_CHAR:
32
- throw new RuntimeException('Unexpected control character found');
33
- case JSON_ERROR_SYNTAX:
34
- throw new RuntimeException('Syntax error, malformed JSON'); // or trigger_error() or throw new Exception()
35
- case JSON_ERROR_UTF8:
36
- if ($iteration == 1) {
37
- // DUP_PRO_LOG::trace("#### utf8 error so redoing");
38
- $clean = self::makeUTF8($value);
39
- return self::customEncode($clean, $iteration + 1);
40
- } else {
41
- throw new RuntimeException('UTF-8 error loop');
42
- }
43
- default:
44
- throw new RuntimeException('Unknown error'); // or trigger_error() or throw new Exception()
45
- }
46
- // } else {
47
- // return self::oldCustomEncode($value);
48
- // }
49
  }
50
 
51
  public static function encode($value, $options = 0)
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()) {
24
+ case JSON_ERROR_NONE:
25
+ return $encoded;
26
+ case JSON_ERROR_DEPTH:
27
+ throw new RuntimeException('Maximum stack depth exceeded'); // or trigger_error() or throw new Exception()
28
+ case JSON_ERROR_STATE_MISMATCH:
29
+ throw new RuntimeException('Underflow or the modes mismatch'); // or trigger_error() or throw new Exception()
30
+ case JSON_ERROR_CTRL_CHAR:
31
+ throw new RuntimeException('Unexpected control character found');
32
+ case JSON_ERROR_SYNTAX:
33
+ throw new RuntimeException('Syntax error, malformed JSON'); // or trigger_error() or throw new Exception()
34
+ case JSON_ERROR_UTF8:
35
+ if ($iteration == 1) {
36
+ $clean = self::makeUTF8($value);
37
+ return self::customEncode($clean, $iteration + 1);
38
+ } else {
39
+ throw new RuntimeException('UTF-8 error loop');
40
+ }
41
+ default:
42
+ throw new RuntimeException('Unknown error'); // or trigger_error() or throw new Exception()
43
+ }
 
 
 
 
 
44
  }
45
 
46
  public static function encode($value, $options = 0)
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.0
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.2
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.
uninstall.php CHANGED
@@ -24,6 +24,7 @@ if (DUP_Settings::Get('uninstall_files')) {
24
 
25
  $ssdir = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH);
26
  $ssdir_tmp = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP);
 
27
 
28
  //Sanity check for strange setup
29
  $check = glob("{$ssdir}/wp-config.php");
@@ -42,6 +43,10 @@ if (DUP_Settings::Get('uninstall_files')) {
42
  if (strstr($file, '_archive.zip'))
43
  @unlink("{$file}");
44
  }
 
 
 
 
45
  foreach (glob("{$ssdir}/*_scan.json") as $file) {
46
  if (strstr($file, '_scan.json'))
47
  @unlink("{$file}");
@@ -64,8 +69,18 @@ if (DUP_Settings::Get('uninstall_files')) {
64
  @unlink("{$file}");
65
  }
66
  @unlink("{$ssdir}/.htaccess");
67
- @rmdir($ssdir_tmp);
68
- @rmdir($ssdir);
 
 
 
 
 
 
 
 
 
 
69
  }
70
  }
71
  }
24
 
25
  $ssdir = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH);
26
  $ssdir_tmp = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP);
27
+ $ssdir_installer = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . '/installer');
28
 
29
  //Sanity check for strange setup
30
  $check = glob("{$ssdir}/wp-config.php");
43
  if (strstr($file, '_archive.zip'))
44
  @unlink("{$file}");
45
  }
46
+ foreach (glob("{$ssdir}/*_archive.daf") as $file) {
47
+ if (strstr($file, '_archive.daf'))
48
+ @unlink("{$file}");
49
+ }
50
  foreach (glob("{$ssdir}/*_scan.json") as $file) {
51
  if (strstr($file, '_scan.json'))
52
  @unlink("{$file}");
69
  @unlink("{$file}");
70
  }
71
  @unlink("{$ssdir}/.htaccess");
72
+
73
+ //installer log from previous install
74
+ foreach (glob("{$ssdir_installer}/*.txt") as $file) {
75
+ if (strstr($file, '.txt'))
76
+ @unlink("{$file}");
77
+ }
78
+
79
+ if (strstr($ssdir, 'wp-snapshots')) {
80
+ @rmdir($ssdir_installer);
81
+ @rmdir($ssdir_tmp);
82
+ @rmdir($ssdir);
83
+ }
84
  }
85
  }
86
  }
views/packages/main/packages.php CHANGED
@@ -4,6 +4,7 @@
4
  $packages = DUP_Package::get_all();
5
  $totalElements = count($packages);
6
  $statusCount = 0; // total packages completed
 
7
 
8
  $package_debug = DUP_Settings::Get('package_debug');
9
  $ajax_nonce = wp_create_nonce('package_list');
@@ -23,16 +24,27 @@
23
  input#dup-bulk-action-all {margin:0px;padding:0px 0px 0px 5px;}
24
  button.dup-button-selected {border:1px solid #000 !important; background-color:#dfdfdf !important;}
25
  div.dup-quick-start {font-style:italic; font-size: 13px; line-height: 18px; margin-top: 15px}
 
 
 
 
 
 
 
26
 
27
  /* Table package details */
28
  table.dup-pack-table {word-break:break-all;}
29
  table.dup-pack-table th {white-space:nowrap !important;}
30
  table.dup-pack-table td.pack-name {text-overflow:ellipsis; white-space:nowrap}
 
31
 
32
  table.dup-pack-table input[name="delete_confirm"] {margin-left:15px}
33
  table.dup-pack-table td.fail {border-left: 4px solid #d54e21;}
34
  table.dup-pack-table td.pass {border-left: 4px solid #2ea2cc;}
35
- tr.dup-pack-info td {white-space:nowrap; padding:12px 30px 0px 7px;}
 
 
 
36
  tr.dup-pack-info td.get-btns {text-align:right; padding:3px 5px 6px 0px !important;}
37
  tr.dup-pack-info td.get-btns button {box-shadow:none}
38
  textarea.dup-pack-debug {width:98%; height:300px; font-size:11px; display:none}
@@ -42,6 +54,13 @@
42
  div#dup-help-dlg i {display: inline-block; width: 15px; padding:2px;line-height:28px; font-size:14px;}
43
  tr.dup-pack-info sup {font-style:italic;font-size:10px; cursor: pointer; vertical-align: baseline; position: relative; top: -0.8em;}
44
  tr#pack-processing {display: none}
 
 
 
 
 
 
 
45
  </style>
46
 
47
  <form id="form-duplicator" method="post">
@@ -68,11 +87,16 @@ TOOL-BAR -->
68
  $package_url = admin_url('admin.php?page=duplicator&tab=new1');
69
  $package_nonce_url = wp_nonce_url($package_url, 'new1-package');
70
  ?>
71
- <a href="<?php echo $package_nonce_url;?>" class="add-new-h2"><?php esc_html_e("Create New", 'duplicator'); ?></a>
 
 
 
 
 
 
72
  </td>
73
  </tr>
74
- </table>
75
-
76
 
77
  <?php if($totalElements == 0 ) : ?>
78
  <!-- ====================
@@ -137,31 +161,36 @@ TOOL-BAR -->
137
  $txt_mode_zip = __('Archive created as zip file', 'duplicator');
138
  $txt_mode_daf = __('Archive created as daf file', 'duplicator');
139
  //$rows = $qryResult;
 
 
140
  foreach ($packages as $Package) {
141
-
 
142
  // Never display incomplete packages and purge those that are no longer active
143
- if($Package->Status >= 0 && $Package->Status < 100) {
144
- if(DUP_Settings::Get('active_package_id') != $Package->ID) {
145
- $Package->delete();
 
 
146
  }
147
 
148
- if ($rowCount <= 1 && $totalElements == 1)
149
- $package_running = true;
150
-
151
- continue;
152
  }
153
 
 
154
  $pack_dbonly = false;
155
 
156
  if (is_object($Package)) {
157
  $pack_name = $Package->Name;
158
- $pack_archive_size = $Package->Archive->Size;
 
159
  $pack_storeurl = $Package->StoreURL;
160
  $pack_namehash = $Package->NameHash;
161
  $pack_dbonly = $Package->Archive->ExportOnlyDB;
162
  $pack_build_mode = ($Package->Archive->Format === 'ZIP') ? true : false;
163
  } else {
164
  $pack_archive_size = 0;
 
165
  $pack_storeurl = 'unknown';
166
  $pack_name = 'unknown';
167
  $pack_namehash = 'unknown';
@@ -183,10 +212,10 @@ TOOL-BAR -->
183
 
184
  <?php
185
 
186
- if ($Package->Status >= 100) :
187
  $statusCount ++;
188
  ?>
189
- <tr class="dup-pack-info <?php echo esc_attr($css_alt); ?>">
190
  <td class="pass"><input name="delete_confirm" type="checkbox" id="<?php echo absint($Package->ID); ?>" /></td>
191
  <td>
192
  <?php
@@ -194,9 +223,10 @@ TOOL-BAR -->
194
  echo ($pack_build_mode) ? " <sup title='{$txt_mode_zip}'>zip</sup>" : " <sup title='{$txt_mode_daf}'>daf</sup>";
195
  ?>
196
  </td>
197
- <td><?php echo DUP_Util::byteSize($pack_archive_size); ?></td>
198
  <td class='pack-name'>
199
  <?php echo ($pack_dbonly) ? "{$pack_name} <sup title='".esc_attr($txt_dbonly)."'>DB</sup>" : esc_html($pack_name); ?>
 
200
  </td>
201
  <td class="get-btns">
202
  <button id="<?php echo esc_attr("{$uniqueid}_installer.php"); ?>" class="button no-select" onclick="Duplicator.Pack.DownloadPackageFile(0, <?php echo absint($Package->ID); ?>); return false;">
@@ -215,19 +245,19 @@ TOOL-BAR -->
215
  <?php else : ?>
216
 
217
  <?php
218
- $size = 0;
219
  $tmpSearch = glob(DUPLICATOR_SSDIR_PATH_TMP . "/{$pack_namehash}_*");
220
  if (is_array($tmpSearch)) {
221
  $result = array_map('filesize', $tmpSearch);
222
  $size = array_sum($result);
223
  }
224
- $pack_archive_size = $size;
225
  $error_url = "?page=duplicator&action=detail&tab=detail&id={$Package->ID}";
226
  ?>
227
  <tr class="dup-pack-info <?php echo esc_attr($css_alt); ?>">
228
  <td class="fail"><input name="delete_confirm" type="checkbox" id="<?php echo absint($Package->ID); ?>" /></td>
229
  <td><?php echo DUP_Package::getCreatedDateFormat($Package->Created, $ui_create_frmt);?></td>
230
- <td><?php echo DUP_Util::byteSize($size); ?></td>
231
  <td class='pack-name'><?php echo esc_html($pack_name); ?></td>
232
  <td class="get-btns error-msg" colspan="2">
233
  <span>
@@ -270,31 +300,36 @@ TOOL-BAR -->
270
  <!-- ==========================================
271
  THICK-BOX DIALOGS: -->
272
  <?php
273
- $alert1 = new DUP_UI_Dialog();
274
- $alert1->title = __('Bulk Action Required', 'duplicator');
275
- $alert1->message = '<i class="fa fa-exclamation-triangle"></i>&nbsp;';
276
- $alert1->message .= __('No selections made! Please select an action from the "Bulk Actions" drop down menu.', 'duplicator');
277
- $alert1->initAlert();
278
-
279
- $alert2 = new DUP_UI_Dialog();
280
- $alert2->title = __('Selection Required', 'duplicator', 'duplicator');
281
- $alert2->message = '<i class="fa fa-exclamation-triangle"></i>&nbsp;';
282
- $alert2->message .= __('No selections made! Please select at least one package to delete.', 'duplicator');
283
- $alert2->initAlert();
284
-
285
- $confirm1 = new DUP_UI_Dialog();
286
- $confirm1->title = __('Delete Packages?', 'duplicator');
287
- $confirm1->message = __('Are you sure, you want to delete the selected package(s)?', 'duplicator');
288
- $confirm1->progressText = __('Removing Packages, Please Wait...', 'duplicator');
289
- $confirm1->jscallback = 'Duplicator.Pack.Delete()';
290
- $confirm1->initConfirm();
291
-
292
- $alert3 = new DUP_UI_Dialog();
293
- $alert3->height = 355;
294
- $alert3->width = 350;
295
- $alert3->title = __('Duplicator Help', 'duplicator');
296
- $alert3->message = "<div id='dup-help-dlg'></div>";
297
- $alert3->initAlert();
 
 
 
 
 
298
  ?>
299
 
300
  <!-- =======================
@@ -317,7 +352,26 @@ DIALOG: HELP DIALOG -->
317
  <script>
318
  jQuery(document).ready(function($)
319
  {
320
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
  /* Creats a comma seperate list of all selected package ids */
322
  Duplicator.Pack.GetDeleteList = function ()
323
  {
@@ -365,6 +419,55 @@ jQuery(document).ready(function($)
365
  });
366
 
367
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
 
369
  /* Toogles the Bulk Action Check boxes */
370
  Duplicator.Pack.SetDeleteAll = function()
@@ -388,10 +491,13 @@ jQuery(document).ready(function($)
388
  <?php $alert3->showAlert(); ?>
389
  }
390
 
391
- <?php if ($package_running) :?>
392
- $('#pack-processing').show();
 
393
 
394
- <?php endif; ?>
 
 
395
 
396
  });
397
  </script>
4
  $packages = DUP_Package::get_all();
5
  $totalElements = count($packages);
6
  $statusCount = 0; // total packages completed
7
+ $active_package_present = DUP_Package::is_active_package_present();
8
 
9
  $package_debug = DUP_Settings::Get('package_debug');
10
  $ajax_nonce = wp_create_nonce('package_list');
24
  input#dup-bulk-action-all {margin:0px;padding:0px 0px 0px 5px;}
25
  button.dup-button-selected {border:1px solid #000 !important; background-color:#dfdfdf !important;}
26
  div.dup-quick-start {font-style:italic; font-size: 13px; line-height: 18px; margin-top: 15px}
27
+
28
+ .add-new-h2.disabled {
29
+ cursor: not-allowed;
30
+ border-color: #ccc !important;
31
+ background: #f7f7f7 !important;
32
+ color: #ccc !important;
33
+ }
34
 
35
  /* Table package details */
36
  table.dup-pack-table {word-break:break-all;}
37
  table.dup-pack-table th {white-space:nowrap !important;}
38
  table.dup-pack-table td.pack-name {text-overflow:ellipsis; white-space:nowrap}
39
+ table.dup-pack-table td.pack-size {min-width: 65px; }
40
 
41
  table.dup-pack-table input[name="delete_confirm"] {margin-left:15px}
42
  table.dup-pack-table td.fail {border-left: 4px solid #d54e21;}
43
  table.dup-pack-table td.pass {border-left: 4px solid #2ea2cc;}
44
+
45
+ .dup-pack-info {height: 45px;}
46
+ .dup-pack-info td {vertical-align: middle; }
47
+ tr.dup-pack-info td {white-space:nowrap; padding:2px 30px 2px 7px;}
48
  tr.dup-pack-info td.get-btns {text-align:right; padding:3px 5px 6px 0px !important;}
49
  tr.dup-pack-info td.get-btns button {box-shadow:none}
50
  textarea.dup-pack-debug {width:98%; height:300px; font-size:11px; display:none}
54
  div#dup-help-dlg i {display: inline-block; width: 15px; padding:2px;line-height:28px; font-size:14px;}
55
  tr.dup-pack-info sup {font-style:italic;font-size:10px; cursor: pointer; vertical-align: baseline; position: relative; top: -0.8em;}
56
  tr#pack-processing {display: none}
57
+
58
+ /* Building package */
59
+
60
+ .dup-pack-info .building-info {display: none;}
61
+ .dup-pack-info.is-running .building-info {display: inline;}
62
+ .dup-pack-info.is-running .get-btns button {display: none;}
63
+
64
  </style>
65
 
66
  <form id="form-duplicator" method="post">
87
  $package_url = admin_url('admin.php?page=duplicator&tab=new1');
88
  $package_nonce_url = wp_nonce_url($package_url, 'new1-package');
89
  ?>
90
+ <a id="dup-create-new"
91
+ onClick="return Duplicator.Pack.CreateNew(this);"
92
+ href="<?php echo $package_nonce_url;?>"
93
+ class="add-new-h2 <?php echo ($active_package_present ? 'disabled' : ''); ?>"
94
+ >
95
+ <?php esc_html_e("Create New", 'duplicator'); ?>
96
+ </a>
97
  </td>
98
  </tr>
99
+ </table>
 
100
 
101
  <?php if($totalElements == 0 ) : ?>
102
  <!-- ====================
161
  $txt_mode_zip = __('Archive created as zip file', 'duplicator');
162
  $txt_mode_daf = __('Archive created as daf file', 'duplicator');
163
  //$rows = $qryResult;
164
+
165
+
166
  foreach ($packages as $Package) {
167
+ $is_running_package = $Package->isRunning();
168
+
169
  // Never display incomplete packages and purge those that are no longer active
170
+ if(!$is_running_package && $Package->Status >= 0 && $Package->Status < 100) {
171
+ $Package->delete();
172
+
173
+ if ($rowCount <= 1 && $totalElements == 1) {
174
+ $package_running = true;
175
  }
176
 
177
+ continue;
 
 
 
178
  }
179
 
180
+
181
  $pack_dbonly = false;
182
 
183
  if (is_object($Package)) {
184
  $pack_name = $Package->Name;
185
+ $pack_archive_size = $Package->getArchiveSize();
186
+ $pack_perc = $Package->Status;
187
  $pack_storeurl = $Package->StoreURL;
188
  $pack_namehash = $Package->NameHash;
189
  $pack_dbonly = $Package->Archive->ExportOnlyDB;
190
  $pack_build_mode = ($Package->Archive->Format === 'ZIP') ? true : false;
191
  } else {
192
  $pack_archive_size = 0;
193
+ $pack_perc = 0;
194
  $pack_storeurl = 'unknown';
195
  $pack_name = 'unknown';
196
  $pack_namehash = 'unknown';
212
 
213
  <?php
214
 
215
+ if ($Package->Status >= 100 || $is_running_package) :
216
  $statusCount ++;
217
  ?>
218
+ <tr class="dup-pack-info <?php echo esc_attr($css_alt); ?> <?php echo $is_running_package ? 'is-running' : ''; ?>">
219
  <td class="pass"><input name="delete_confirm" type="checkbox" id="<?php echo absint($Package->ID); ?>" /></td>
220
  <td>
221
  <?php
223
  echo ($pack_build_mode) ? " <sup title='{$txt_mode_zip}'>zip</sup>" : " <sup title='{$txt_mode_daf}'>daf</sup>";
224
  ?>
225
  </td>
226
+ <td class="pack-size"><?php echo DUP_Util::byteSize($pack_archive_size); ?></td>
227
  <td class='pack-name'>
228
  <?php echo ($pack_dbonly) ? "{$pack_name} <sup title='".esc_attr($txt_dbonly)."'>DB</sup>" : esc_html($pack_name); ?>
229
+ <span class="building-info" ><i class="fa fa-gear fa-spin"></i> <b>Building Package</b> <span class="perc"><?php echo $pack_perc; ?></span>%</span>
230
  </td>
231
  <td class="get-btns">
232
  <button id="<?php echo esc_attr("{$uniqueid}_installer.php"); ?>" class="button no-select" onclick="Duplicator.Pack.DownloadPackageFile(0, <?php echo absint($Package->ID); ?>); return false;">
245
  <?php else : ?>
246
 
247
  <?php
248
+ /*$size = 0;
249
  $tmpSearch = glob(DUPLICATOR_SSDIR_PATH_TMP . "/{$pack_namehash}_*");
250
  if (is_array($tmpSearch)) {
251
  $result = array_map('filesize', $tmpSearch);
252
  $size = array_sum($result);
253
  }
254
+ $pack_archive_size = $size;*/
255
  $error_url = "?page=duplicator&action=detail&tab=detail&id={$Package->ID}";
256
  ?>
257
  <tr class="dup-pack-info <?php echo esc_attr($css_alt); ?>">
258
  <td class="fail"><input name="delete_confirm" type="checkbox" id="<?php echo absint($Package->ID); ?>" /></td>
259
  <td><?php echo DUP_Package::getCreatedDateFormat($Package->Created, $ui_create_frmt);?></td>
260
+ <td class="pack-size"><?php echo DUP_Util::byteSize($pack_archive_size); ?></td>
261
  <td class='pack-name'><?php echo esc_html($pack_name); ?></td>
262
  <td class="get-btns error-msg" colspan="2">
263
  <span>
300
  <!-- ==========================================
301
  THICK-BOX DIALOGS: -->
302
  <?php
303
+ $alert1 = new DUP_UI_Dialog();
304
+ $alert1->title = __('Bulk Action Required', 'duplicator');
305
+ $alert1->message = '<i class="fa fa-exclamation-triangle"></i>&nbsp;';
306
+ $alert1->message .= __('No selections made! Please select an action from the "Bulk Actions" drop down menu.', 'duplicator');
307
+ $alert1->initAlert();
308
+
309
+ $alert2 = new DUP_UI_Dialog();
310
+ $alert2->title = __('Selection Required', 'duplicator', 'duplicator');
311
+ $alert2->message = '<i class="fa fa-exclamation-triangle"></i>&nbsp;';
312
+ $alert2->message .= __('No selections made! Please select at least one package to delete.', 'duplicator');
313
+ $alert2->initAlert();
314
+
315
+ $confirm1 = new DUP_UI_Dialog();
316
+ $confirm1->title = __('Delete Packages?', 'duplicator');
317
+ $confirm1->message = __('Are you sure, you want to delete the selected package(s)?', 'duplicator');
318
+ $confirm1->progressText = __('Removing Packages, Please Wait...', 'duplicator');
319
+ $confirm1->jscallback = 'Duplicator.Pack.Delete()';
320
+ $confirm1->initConfirm();
321
+
322
+ $alert3 = new DUP_UI_Dialog();
323
+ $alert3->height = 355;
324
+ $alert3->width = 350;
325
+ $alert3->title = __('Duplicator Help', 'duplicator');
326
+ $alert3->message = "<div id='dup-help-dlg'></div>";
327
+ $alert3->initAlert();
328
+
329
+ $alertPackRunning = new DUP_UI_Dialog();
330
+ $alertPackRunning->title = __('Alert!', 'duplicator');
331
+ $alertPackRunning->message = __('A package is being processed. Retry later.', 'duplicator');
332
+ $alertPackRunning->initAlert();
333
  ?>
334
 
335
  <!-- =======================
352
  <script>
353
  jQuery(document).ready(function($)
354
  {
355
+ /** Create new package check */
356
+ Duplicator.Pack.CreateNew = function(e){
357
+ var cButton = $(e);
358
+ if (cButton.hasClass('disabled')) {
359
+ <?php $alertPackRunning->showAlert(); ?>
360
+ } else {
361
+ Duplicator.Pack.GetActivePackageInfo(function (info) {
362
+ if (info.present) {
363
+ cButton.addClass('disabled');
364
+ // reloag current page to update packages list
365
+ location.reload(true);
366
+ } else {
367
+ // no active package. Load step1 page.
368
+ window.location = cButton.attr('href');
369
+ }
370
+ });
371
+ }
372
+ return false;
373
+ };
374
+
375
  /* Creats a comma seperate list of all selected package ids */
376
  Duplicator.Pack.GetDeleteList = function ()
377
  {
419
  });
420
 
421
  };
422
+
423
+ Duplicator.Pack.ActivePackageInfo = function (info) {
424
+ $('.dup-pack-info.is-running .pack-size').text(info.size_format);
425
+
426
+ if (info.present) {
427
+ $('.dup-pack-info.is-running .building-info .perc').text(info.status);
428
+
429
+ setTimeout(function(){
430
+ Duplicator.Pack.GetActivePackageInfo(Duplicator.Pack.ActivePackageInfo);
431
+ }, 1000);
432
+
433
+ } else {
434
+ $('.dup-pack-info.is-running').removeClass('is-running');
435
+ $('#dup-create-new.disabled').removeClass('disabled');
436
+ }
437
+ }
438
+
439
+ /* Get active package info
440
+ *
441
+ * */
442
+ Duplicator.Pack.GetActivePackageInfo = function (callbackOnSuccess)
443
+ {
444
+ $.ajax({
445
+ type: "POST",
446
+ cache: false,
447
+ url: ajaxurl,
448
+ dataType: "json",
449
+ timeout: 10000000,
450
+ data: {
451
+ action : 'duplicator_active_package_info',
452
+ nonce: '<?php echo esc_js(wp_create_nonce('duplicator_active_package_info')); ?>'
453
+ },
454
+ complete: function () {},
455
+ success: function (result) {
456
+ console.log(result);
457
+ if (result.success) {
458
+ if ($.isFunction(callbackOnSuccess)) {
459
+ callbackOnSuccess(result.data.active_package);
460
+ }
461
+ } else {
462
+ // @todo manage error
463
+ }
464
+ },
465
+ error: function (result) {
466
+ var result = result || new Object();
467
+ // @todo manage error
468
+ }
469
+ });
470
+ };
471
 
472
  /* Toogles the Bulk Action Check boxes */
473
  Duplicator.Pack.SetDeleteAll = function()
491
  <?php $alert3->showAlert(); ?>
492
  }
493
 
494
+ <?php if ($package_running) : ?>
495
+ $('#pack-processing').show();
496
+ <?php endif;
497
 
498
+ if ($active_package_present) :?>
499
+ Duplicator.Pack.GetActivePackageInfo(Duplicator.Pack.ActivePackageInfo);
500
+ <?php endif; ?>
501
 
502
  });
503
  </script>
views/packages/main/s2.scan1.php CHANGED
@@ -104,6 +104,9 @@
104
  div#data-db-tablelist {max-height:250px; overflow-y:scroll; border:1px solid silver; padding:8px; background: #efefef; border-radius: 4px}
105
  div#data-db-tablelist td{padding:0 5px 3px 20px; min-width:100px}
106
  div#data-db-size1, div#data-ll-totalsize {display:inline-block; font-size:11px; margin-right:1px;}
 
 
 
107
 
108
  /*WARNING-CONTINUE*/
109
  div#dup-scan-warning-continue {display:none; text-align:center; padding:0 0 15px 0}
@@ -250,10 +253,19 @@ TOOL BAR:STEPS -->
250
  </div>
251
  </div>
252
 
 
 
 
 
 
 
 
 
 
253
  <div class="dup-button-footer" style="display:none">
254
  <input type="button" value="&#9664; <?php esc_html_e("Back", 'duplicator') ?>" onclick="window.location.assign('?page=duplicator&tab=new1&_wpnonce=<?php echo wp_create_nonce('new1-package');?>')" class="button button-large" />
255
  <input type="button" value="<?php esc_attr_e("Rescan", 'duplicator') ?>" onclick="Duplicator.Pack.rescan()" class="button button-large" />
256
- <input type="submit" value="<?php esc_attr_e("Build", 'duplicator') ?> &#9654" class="button button-primary button-large" id="dup-build-button" />
257
  </div>
258
  </div>
259
 
@@ -344,7 +356,26 @@ jQuery(document).ready(function($)
344
  Duplicator.Pack.initLiteLimitData(data);
345
  <?php endif; ?>
346
  }
347
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  //Toggles each scan item to hide/show details
349
  Duplicator.Pack.toggleScanItem = function(item)
350
  {
@@ -362,7 +393,7 @@ jQuery(document).ready(function($)
362
  //Returns the scanner without a page refresh
363
  Duplicator.Pack.rescan = function()
364
  {
365
- $('#dup-msg-success,#dup-msg-error,.dup-button-footer').hide();
366
  $('#dup-progress-bar-area').show();
367
  Duplicator.Pack.runScanner();
368
  }
104
  div#data-db-tablelist {max-height:250px; overflow-y:scroll; border:1px solid silver; padding:8px; background: #efefef; border-radius: 4px}
105
  div#data-db-tablelist td{padding:0 5px 3px 20px; min-width:100px}
106
  div#data-db-size1, div#data-ll-totalsize {display:inline-block; font-size:11px; margin-right:1px;}
107
+ /*FILES */
108
+ div#dup-confirm-area {color:maroon; display:none; text-align: center; font-size:14px; line-height:24px; font-weight: bold; margin: -5px 0 10px 0}
109
+ div#dup-confirm-area label {font-size:14px !important}
110
 
111
  /*WARNING-CONTINUE*/
112
  div#dup-scan-warning-continue {display:none; text-align:center; padding:0 0 15px 0}
253
  </div>
254
  </div>
255
 
256
+ <div id="dup-confirm-area">
257
+ <label for="duplicator-confirm-check"><?php esc_html_e('Do you want to continue?', 'duplicator');
258
+ echo '<br/> ';
259
+ esc_html_e('At least one or more checkboxes was checked in "Quick Filters".', 'duplicator') ?><br/>
260
+ <i style="font-weight:normal"><?php esc_html_e('To apply a "Quick Filter" click the "Add Filters & Rescan" button', 'duplicator') ?></i><br/>
261
+ <input type="checkbox" id="duplicator-confirm-check" onclick="jQuery('#dup-build-button').removeAttr('disabled');">
262
+ <?php esc_html_e('Yes. Continue without applying any file filters.', 'duplicator') ?></label><br/>
263
+ </div>
264
+
265
  <div class="dup-button-footer" style="display:none">
266
  <input type="button" value="&#9664; <?php esc_html_e("Back", 'duplicator') ?>" onclick="window.location.assign('?page=duplicator&tab=new1&_wpnonce=<?php echo wp_create_nonce('new1-package');?>')" class="button button-large" />
267
  <input type="button" value="<?php esc_attr_e("Rescan", 'duplicator') ?>" onclick="Duplicator.Pack.rescan()" class="button button-large" />
268
+ <input type="submit" onclick="Duplicator.Pack.startBuild();" value="<?php esc_attr_e("Build", 'duplicator') ?> &#9654" class="button button-primary button-large" id="dup-build-button" />
269
  </div>
270
  </div>
271
 
356
  Duplicator.Pack.initLiteLimitData(data);
357
  <?php endif; ?>
358
  }
359
+
360
+ Duplicator.Pack.startBuild = function()
361
+ {
362
+ if ($('#duplicator-confirm-check').is(":checked")) {
363
+ $('#form-duplicator').submit();
364
+ return true;
365
+ }
366
+
367
+ var sizeChecks = $('#hb-files-large-result input:checked');
368
+ var addonChecks = $('#hb-addon-sites-result input:checked');
369
+ var utf8Checks = $('#hb-files-utf8-result input:checked');
370
+ if (sizeChecks.length > 0 || addonChecks.length > 0 || utf8Checks.length > 0) {
371
+ $('#dup-confirm-area').show();
372
+ $('#dup-build-button').prop('disabled', true);
373
+ return false;
374
+ } else {
375
+ $('#form-duplicator').submit();
376
+ }
377
+ }
378
+
379
  //Toggles each scan item to hide/show details
380
  Duplicator.Pack.toggleScanItem = function(item)
381
  {
393
  //Returns the scanner without a page refresh
394
  Duplicator.Pack.rescan = function()
395
  {
396
+ $('#dup-msg-success,#dup-msg-error, #dup-confirm-area, .dup-button-footer').hide();
397
  $('#dup-progress-bar-area').show();
398
  Duplicator.Pack.runScanner();
399
  }
views/packages/main/s2.scan3.php CHANGED
@@ -108,7 +108,7 @@ TOTAL SIZE -->
108
  <input type="checkbox" name="dir_paths[]" value="{{directory.dir}}" id="lf_dir_{{@index}}" onclick="Duplicator.Pack.filesOff(this)" />
109
  {{/if}}
110
  <label for="lf_dir_{{@index}}" title="{{directory.dir}}">
111
- <i class="size">[{{directory.size}}]</i> /{{directory.sdir}}/
112
  </label> <br/>
113
  <div class="files">
114
  {{#each directory.files as |file|}}
@@ -250,7 +250,7 @@ FILE NAME CHECKS -->
250
 
251
  <label for="nc1_dir_{{@index}}" title="{{directory.dir}}">
252
  <i class="count">({{directory.count}})</i>
253
- /{{directory.sdir}}/
254
  </label> <br/>
255
  <div class="files">
256
  {{#each directory.files}}
@@ -444,7 +444,7 @@ DATABASE -->
444
  echo '</div>';
445
  echo '<br/>';
446
 
447
- $lnk = '<a href="https://snapcreek.com/duplicator/docs/quick-start#quick-060-q" target="_blank">' . esc_html__('covered here.', 'duplicator') . '</a>';
448
  printf(__("- Perform a two part install %s", 'duplicator'), $lnk);
449
  echo '<br/><br/>';
450
 
108
  <input type="checkbox" name="dir_paths[]" value="{{directory.dir}}" id="lf_dir_{{@index}}" onclick="Duplicator.Pack.filesOff(this)" />
109
  {{/if}}
110
  <label for="lf_dir_{{@index}}" title="{{directory.dir}}">
111
+ <i class="size">[{{directory.size}}]</i> {{directory.sdir}}/
112
  </label> <br/>
113
  <div class="files">
114
  {{#each directory.files as |file|}}
250
 
251
  <label for="nc1_dir_{{@index}}" title="{{directory.dir}}">
252
  <i class="count">({{directory.count}})</i>
253
+ {{directory.sdir}}/
254
  </label> <br/>
255
  <div class="files">
256
  {{#each directory.files}}
444
  echo '</div>';
445
  echo '<br/>';
446
 
447
+ $lnk = '<a href="https://snapcreek.com/duplicator/docs/quick-start?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=da_size_two_part&utm_campaign=duplicator_pro#quick-060-q" target="_blank">' . esc_html__('covered here.', 'duplicator') . '</a>';
448
  printf(__("- Perform a two part install %s", 'duplicator'), $lnk);
449
  echo '<br/><br/>';
450
 
views/packages/main/s3.build.php CHANGED
@@ -584,8 +584,8 @@ jQuery(document).ready(function ($)
584
  var seconds = ((millis % 60000) / 1000).toFixed(0);
585
  var status = minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
586
  $('#dup-msg-error-response-time span.data').html(status);
587
- $('#dup-create-area-nolink').hide();
588
- $('#dup-create-area-link').show();
589
  };
590
 
591
  Duplicator.Pack.WireDownloadLinks = function(data)
584
  var seconds = ((millis % 60000) / 1000).toFixed(0);
585
  var status = minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
586
  $('#dup-msg-error-response-time span.data').html(status);
587
+ //$('#dup-create-area-nolink').hide();
588
+ //$('#dup-create-area-link').show();
589
  };
590
 
591
  Duplicator.Pack.WireDownloadLinks = function(data)
views/tools/diagnostics/inc.settings.php CHANGED
@@ -29,7 +29,10 @@ SERVER SETTINGS -->
29
  </tr>
30
  <tr>
31
  <td><?php esc_html_e("Duplicator Version", 'duplicator'); ?></td>
32
- <td><?php echo esc_html(DUPLICATOR_VERSION); ?></td>
 
 
 
33
  </tr>
34
  <tr>
35
  <td><?php esc_html_e("Operating System", 'duplicator'); ?></td>
29
  </tr>
30
  <tr>
31
  <td><?php esc_html_e("Duplicator Version", 'duplicator'); ?></td>
32
+ <td>
33
+ <?php echo esc_html(DUPLICATOR_VERSION); ?> -
34
+ <?php echo esc_html(DUPLICATOR_VERSION_BUILD); ?>
35
+ </td>
36
  </tr>
37
  <tr>
38
  <td><?php esc_html_e("Operating System", 'duplicator'); ?></td>