Duplicator – WordPress Migration Plugin - Version 1.3.16

Version Description

Download this release

Release Info

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

Code changes from version 1.3.14 to 1.3.16

Files changed (61) hide show
  1. classes/class.constants.php +1 -1
  2. classes/class.logging.php +275 -33
  3. classes/class.settings.php +9 -2
  4. classes/host/class.godaddy.host.php +15 -0
  5. classes/host/class.wpengine.host.php +34 -0
  6. classes/package/class.pack.archive.filters.php +8 -0
  7. classes/package/class.pack.archive.php +9 -2
  8. classes/package/class.pack.archive.zip.php +2 -2
  9. classes/package/class.pack.database.php +1 -1
  10. classes/package/class.pack.installer.php +4 -6
  11. classes/package/class.pack.php +14 -3
  12. classes/package/duparchive/class.pack.archive.duparchive.php +2 -5
  13. classes/utilities/class.u.php +41 -42
  14. ctrls/class.web.services.php +81 -76
  15. ctrls/ctrl.package.php +29 -15
  16. ctrls/ctrl.tools.php +2 -0
  17. ctrls/ctrl.ui.php +1 -0
  18. deactivation.php +4 -0
  19. define.php +3 -2
  20. duplicator.php +16 -3
  21. installer/dup-installer/assets/inc.css.php +23 -15
  22. installer/dup-installer/assets/inc.libs.js.php +0 -2
  23. installer/dup-installer/classes/class.db.php +45 -12
  24. installer/dup-installer/classes/class.engine.php +780 -373
  25. installer/dup-installer/classes/class.http.php +7 -1
  26. installer/dup-installer/classes/class.s3.func.php +1319 -0
  27. installer/dup-installer/classes/class.view.php +72 -72
  28. installer/dup-installer/classes/config/class.boot.php +1 -0
  29. installer/dup-installer/classes/config/class.conf.srv.php +92 -177
  30. installer/dup-installer/classes/config/class.constants.php +19 -4
  31. installer/dup-installer/classes/utilities/class.u.php +38 -7
  32. installer/dup-installer/classes/utilities/class.u.search.reaplce.manager.php +611 -0
  33. installer/dup-installer/ctrls/ctrl.base.php +38 -37
  34. installer/dup-installer/ctrls/ctrl.s1.php +74 -71
  35. installer/dup-installer/ctrls/ctrl.s2.base.php +21 -1
  36. installer/dup-installer/ctrls/ctrl.s3.php +34 -655
  37. installer/dup-installer/index.php +7 -1
  38. installer/dup-installer/main.installer.php +17 -12
  39. installer/dup-installer/views/view.help.php +71 -54
  40. installer/dup-installer/views/view.s1.base.php +4 -3
  41. installer/dup-installer/views/view.s3.php +10 -0
  42. installer/dup-installer/views/view.s4.php +1 -0
  43. installer/installer.tpl +989 -210
  44. lib/config/class.wp.config.tranformer.php +37 -14
  45. lib/config/class.wp.config.tranformer.src.php +7 -8
  46. lib/dup_archive/classes/class.duparchive.engine.php +2 -9
  47. lib/dup_archive/classes/class.duparchive.mini.expander.php +11 -14
  48. lib/dup_archive/classes/processors/class.duparchive.processor.file.php +7 -13
  49. lib/dup_archive/daws/daws.php +1 -1
  50. lib/snaplib/class.snaplib.u.io.php +211 -31
  51. lib/snaplib/class.snaplib.u.os.php +32 -6
  52. lib/snaplib/class.snaplib.u.util.php +1 -1
  53. readme.txt +1 -1
  54. views/packages/controller.php +2 -0
  55. views/packages/main/controller.php +2 -0
  56. views/packages/main/packages.php +1 -1
  57. views/packages/main/s1.setup2.php +2 -0
  58. views/packages/main/s3.build.php +1 -1
  59. views/settings/controller.php +1 -0
  60. views/settings/gopro.php +2 -2
  61. views/tools/controller.php +2 -0
classes/class.constants.php CHANGED
@@ -2,5 +2,5 @@
2
  defined("ABSPATH") || exit;
3
  class DUP_Constants
4
  {
5
- const ZIP_STRING_LIMIT = 1048576; // Cutoff for using ZipArchive addtostring vs addfile
6
  }
2
  defined("ABSPATH") || exit;
3
  class DUP_Constants
4
  {
5
+ const ZIP_STRING_LIMIT = 70000; // Cutoff for using ZipArchive addtostring vs addfile
6
  }
classes/class.logging.php CHANGED
@@ -16,15 +16,18 @@ abstract class Dup_ErrorBehavior
16
 
17
  class DUP_Log
18
  {
19
- static $debugging = true;
20
- private static $traceEnabled;
21
-
22
- /**
23
- * The file handle used to write to the log file
24
- * @var file resource
25
- */
26
- public static $logFileHandle = null;
27
-
 
 
 
28
  /**
29
  * Init this static object
30
  */
@@ -33,37 +36,71 @@ class DUP_Log
33
  self::$traceEnabled = (DUP_Settings::Get('trace_log_enabled') == 1);
34
  }
35
 
36
- /**
37
- * Open a log file connection for writing
38
- * @param string $name Name of the log file to create
39
- */
40
- public static function Open($name)
41
- {
42
- if (!isset($name)) throw new Exception("A name value is required to open a file log.");
43
- self::$logFileHandle = @fopen(DUPLICATOR_SSDIR_PATH."/{$name}.log", "a+");
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  /**
47
- * Close the log file connection
48
- */
49
- public static function Close()
50
- {
51
- @fclose(self::$logFileHandle);
52
- }
53
-
54
- /**
55
- * General information logging
56
  * @param string $msg The message to log
57
  *
58
  * REPLACE TO DEBUG: Memory consumption as script runs
59
  * $results = DUP_Util::byteSize(memory_get_peak_usage(true)) . "\t" . $msg;
60
  * @fwrite(self::$logFileHandle, "{$results} \n");
61
- */
62
- public static function Info($msg)
63
- {
64
- self::Trace($msg);
65
- @fwrite(self::$logFileHandle, "{$msg} \n");
66
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  /**
69
  * Does the trace file exists
@@ -134,6 +171,13 @@ class DUP_Log
134
  }
135
  }
136
 
 
 
 
 
 
 
 
137
  public static function errLog($message)
138
  {
139
  $message = 'DUP:'.$message;
@@ -279,4 +323,202 @@ class DUP_Log
279
  }
280
  }
281
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  DUP_Log::Init();
16
 
17
  class DUP_Log
18
  {
19
+ /**
20
+ * The file handle used to write to the package log file
21
+ */
22
+ private static $logFileHandle = null;
23
+
24
+ /**
25
+ * Get the setting which indicates if tracing is enabled
26
+ */
27
+ private static $traceEnabled = false;
28
+
29
+ public static $profileLogs = null;
30
+
31
  /**
32
  * Init this static object
33
  */
36
  self::$traceEnabled = (DUP_Settings::Get('trace_log_enabled') == 1);
37
  }
38
 
39
+ /**
40
+ * Open a log file connection for writing to the package log file
41
+ *
42
+ * @param string $nameHas The Name of the log file to create
43
+ *
44
+ * @return nul
45
+ */
46
+ public static function Open($nameHash)
47
+ {
48
+ if (!isset($nameHash)) {
49
+ throw new Exception("A name value is required to open a file log.");
50
+ }
51
+ self::Close();
52
+ if ((self::$logFileHandle = @fopen(DUPLICATOR_SSDIR_PATH."/{$nameHash}.log", "a+")) === false) {
53
+ self::$logFileHandle = null;
54
+ return false;
55
+ } else {
56
+ /**
57
+ * By initializing the error_handler on opening the log, I am sure that when a package is processed, the handler is active.
58
+ */
59
+ DUP_Handler::init_error_handler();
60
+ return true;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Close the package log file connection if is opened
66
+ *
67
+ * @return bool Returns TRUE on success or FALSE on failure.
68
+ */
69
+ public static function Close()
70
+ {
71
+ if (!is_null(self::$logFileHandle)) {
72
+ $result = @fclose(self::$logFileHandle);
73
+ self::$logFileHandle = null;
74
+ }
75
+ return $result;
76
+ }
77
 
78
  /**
79
+ * General information send to the package log if opened
 
 
 
 
 
 
 
 
80
  * @param string $msg The message to log
81
  *
82
  * REPLACE TO DEBUG: Memory consumption as script runs
83
  * $results = DUP_Util::byteSize(memory_get_peak_usage(true)) . "\t" . $msg;
84
  * @fwrite(self::$logFileHandle, "{$results} \n");
85
+ *
86
+ * @param string $msg The message to log
87
+ *
88
+ * @return null
89
+ */
90
+ public static function Info($msg)
91
+ {
92
+ self::Trace($msg);
93
+ if (!is_null(self::$logFileHandle)) {
94
+ @fwrite(self::$logFileHandle, $msg."\n");
95
+ }
96
+ }
97
+
98
+ public static function print_r_info($val, $name = '')
99
+ {
100
+ $msg = empty($name) ? '' : 'VALUE '.$name.': ';
101
+ $msg .= print_r($val, true);
102
+ self::info($msg);
103
+ }
104
 
105
  /**
106
  * Does the trace file exists
171
  }
172
  }
173
 
174
+ public static function print_r_trace($val, $name = '', $calling_function_override = null)
175
+ {
176
+ $msg = empty($name) ? '' : 'VALUE '.$name.': ';
177
+ $msg .= print_r($val, true);
178
+ self::trace($msg, $calling_function_override);
179
+ }
180
+
181
  public static function errLog($message)
182
  {
183
  $message = 'DUP:'.$message;
323
  }
324
  }
325
  }
326
+
327
+ class DUP_Handler
328
+ {
329
+ const MODE_OFF = 0; // don't write in log
330
+ const MODE_LOG = 1; // write errors in log file
331
+ const MODE_VAR = 2; // put php errors in $varModeLog static var
332
+ const SHUTDOWN_TIMEOUT = 'tm';
333
+
334
+ /**
335
+ *
336
+ * @var bool
337
+ */
338
+ private static $inizialized = false;
339
+
340
+ /**
341
+ *
342
+ * @var array
343
+ */
344
+ private static $shutdownReturns = array(
345
+ 'tm' => 'timeout'
346
+ );
347
+
348
+ /**
349
+ *
350
+ * @var int
351
+ */
352
+ private static $handlerMode = self::MODE_LOG;
353
+
354
+ /**
355
+ *
356
+ * @var bool // print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100]
357
+ */
358
+ private static $codeReference = true;
359
+
360
+ /**
361
+ *
362
+ * @var bool // print prefix in php error line [PHP ERR][WARN] MSG: .....
363
+ */
364
+ private static $errPrefix = true;
365
+
366
+ /**
367
+ *
368
+ * @var string // php errors in MODE_VAR
369
+ */
370
+ private static $varModeLog = '';
371
+
372
+ /**
373
+ * This function only initializes the error handler the first time it is called
374
+ */
375
+ public static function init_error_handler()
376
+ {
377
+ if (!self::$inizialized) {
378
+ @set_error_handler(array(__CLASS__, 'error'));
379
+ @register_shutdown_function(array(__CLASS__, 'shutdown'));
380
+ self::$inizialized = true;
381
+ }
382
+ }
383
+
384
+ /**
385
+ * Error handler
386
+ *
387
+ * @param integer $errno Error level
388
+ * @param string $errstr Error message
389
+ * @param string $errfile Error file
390
+ * @param integer $errline Error line
391
+ * @return void
392
+ */
393
+ public static function error($errno, $errstr, $errfile, $errline)
394
+ {
395
+ switch (self::$handlerMode) {
396
+ case self::MODE_OFF:
397
+ if ($errno == E_ERROR) {
398
+ $log_message = self::getMessage($errno, $errstr, $errfile, $errline);
399
+ DUP_Log::Error($log_message);
400
+ }
401
+ break;
402
+ case self::MODE_VAR:
403
+ self::$varModeLog .= self::getMessage($errno, $errstr, $errfile, $errline)."\n";
404
+ break;
405
+ case self::MODE_LOG:
406
+ default:
407
+ switch ($errno) {
408
+ case E_ERROR :
409
+ $log_message = self::getMessage($errno, $errstr, $errfile, $errline);
410
+ DUP_Log::Error($log_message);
411
+ break;
412
+ case E_NOTICE :
413
+ case E_WARNING :
414
+ default :
415
+ $log_message = self::getMessage($errno, $errstr, $errfile, $errline);
416
+ DUP_Log::Info($log_message);
417
+ break;
418
+ }
419
+ }
420
+ }
421
+
422
+ private static function getMessage($errno, $errstr, $errfile, $errline)
423
+ {
424
+ $result = '';
425
+
426
+ if (self::$errPrefix) {
427
+ $result = '[PHP ERR]';
428
+ switch ($errno) {
429
+ case E_ERROR :
430
+ $result .= '[FATAL]';
431
+ break;
432
+ case E_WARNING :
433
+ $result .= '[WARN]';
434
+ break;
435
+ case E_NOTICE :
436
+ $result .= '[NOTICE]';
437
+ break;
438
+ default :
439
+ $result .= '[ISSUE]';
440
+ break;
441
+ }
442
+ $result .= ' MSG:';
443
+ }
444
+
445
+ $result .= $errstr;
446
+
447
+ if (self::$codeReference) {
448
+ $result .= ' [CODE:'.$errno.'|FILE:'.$errfile.'|LINE:'.$errline.']';
449
+ }
450
+
451
+ return $result;
452
+ }
453
+
454
+ /**
455
+ * if setMode is called without params set as default
456
+ *
457
+ * @param int $mode
458
+ * @param bool $errPrefix // print prefix in php error line [PHP ERR][WARN] MSG: .....
459
+ * @param bool $codeReference // print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100]
460
+ */
461
+ public static function setMode($mode = self::MODE_LOG, $errPrefix = true, $codeReference = true)
462
+ {
463
+ switch ($mode) {
464
+ case self::MODE_OFF:
465
+ case self::MODE_VAR:
466
+ self::$handlerMode = $mode;
467
+ break;
468
+ case self::MODE_LOG:
469
+ default:
470
+ self::$handlerMode = self::MODE_LOG;
471
+ }
472
+
473
+ self::$varModeLog = '';
474
+ self::$errPrefix = $errPrefix;
475
+ self::$codeReference = $codeReference;
476
+ }
477
+
478
+ /**
479
+ *
480
+ * @return string // return var log string in MODE_VAR
481
+ */
482
+ public static function getVarLog()
483
+ {
484
+ return self::$varModeLog;
485
+ }
486
+
487
+ /**
488
+ *
489
+ * @return string // return var log string in MODE_VAR and clean var
490
+ */
491
+ public static function getVarLogClean()
492
+ {
493
+ $result = self::$varModeLog;
494
+ self::$varModeLog = '';
495
+ return $result;
496
+ }
497
+
498
+ /**
499
+ *
500
+ * @param string $status // timeout
501
+ * @param string
502
+ */
503
+ public static function setShutdownReturn($status, $str)
504
+ {
505
+ self::$shutdownReturns[$status] = $str;
506
+ }
507
+
508
+ /**
509
+ * Shutdown handler
510
+ *
511
+ * @return void
512
+ */
513
+ public static function shutdown()
514
+ {
515
+ if (($error = error_get_last())) {
516
+ if (preg_match('/^Maximum execution time (?:.+) exceeded$/i', $error['message'])) {
517
+ echo self::$shutdownReturns[self::SHUTDOWN_TIMEOUT];
518
+ }
519
+ self::error($error['type'], $error['message'], $error['file'], $error['line']);
520
+ }
521
+ }
522
+ }
523
+
524
  DUP_Log::Init();
classes/class.settings.php CHANGED
@@ -89,7 +89,7 @@ class DUP_Settings
89
  public static function SetDefaults()
90
  {
91
  $defaults = self::GetAllDefaults();
92
- self::$Data = $defaults;
93
  return self::Save();
94
  }
95
 
@@ -130,7 +130,14 @@ class DUP_Settings
130
  //Flag for .htaccess file
131
  $default['storage_htaccess_off'] = isset(self::$Data['storage_htaccess_off']) ? self::$Data['storage_htaccess_off'] : false;
132
  // Initial archive build mode
133
- $default['archive_build_mode'] = isset(self::$Data['archive_build_mode']) ? self::$Data['archive_build_mode'] : DUP_Archive_Build_Mode::ZipArchive;
 
 
 
 
 
 
 
134
 
135
  //Skip scan archive
136
  $default['skip_archive_scan'] = isset(self::$Data['skip_archive_scan']) ? self::$Data['skip_archive_scan'] : false;
89
  public static function SetDefaults()
90
  {
91
  $defaults = self::GetAllDefaults();
92
+ self::$Data = apply_filters('duplicator_defaults_settings', $defaults);
93
  return self::Save();
94
  }
95
 
130
  //Flag for .htaccess file
131
  $default['storage_htaccess_off'] = isset(self::$Data['storage_htaccess_off']) ? self::$Data['storage_htaccess_off'] : false;
132
  // Initial archive build mode
133
+ if (isset(self::$Data['archive_build_mode'])) {
134
+ $default['archive_build_mode'] = self::$Data['archive_build_mode'];
135
+ } else {
136
+ $is_ziparchive_available = apply_filters('duplicator_is_ziparchive_available', class_exists('ZipArchive'));
137
+ $default['archive_build_mode'] = $is_ziparchive_available ? DUP_Archive_Build_Mode::ZipArchive : DUP_Archive_Build_Mode::DupArchive;
138
+ }
139
+
140
+ // $default['package_zip_flush'] = apply_filters('duplicator_package_zip_flush_default_setting', '0');
141
 
142
  //Skip scan archive
143
  $default['skip_archive_scan'] = isset(self::$Data['skip_archive_scan']) ? self::$Data['skip_archive_scan'] : false;
classes/host/class.godaddy.host.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined("ABSPATH") or die("");
3
+
4
+ class DUP_GoDaddy_Host {
5
+ public static function init() {
6
+ add_filter('duplicator_defaults_settings', array('DUP_GoDaddy_Host', 'defaultsSettings'));
7
+ }
8
+
9
+ public static function defaultsSettings($defaults) {
10
+ $defaults['archive_build_mode'] = DUP_Archive_Build_Mode::DupArchive;
11
+ return $defaults;
12
+ }
13
+ }
14
+
15
+ DUP_GoDaddy_Host::init();
classes/host/class.wpengine.host.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined("ABSPATH") or die("");
3
+ // New encryption class
4
+
5
+ class DUP_WPEngine_Host {
6
+ public static function init() {
7
+ add_filter('duplicator_installer_file_path', array('DUP_WPEngine_Host', 'installerFilePath'), 10, 1);
8
+ add_filter('duplicator_global_file_filters_on', '__return_true');
9
+ add_filter('duplicator_global_file_filters', array('DUP_WPEngine_Host', 'globalFileFilters'), 10, 1);
10
+ add_filter('duplicator_defaults_settings', array('DUP_WPEngine_Host', 'defaultsSettings'));
11
+ }
12
+
13
+ public static function installerFilePath($path) {
14
+ $path_info = pathinfo($path);
15
+ $newPath = $path;
16
+ if ('php' == $path_info['extension']) {
17
+ $newPath = substr_replace($path, '.txt', -4);
18
+ }
19
+ return $newPath;
20
+ }
21
+
22
+ public static function globalFileFilters($files) {
23
+ $files[] = wp_normalize_path(WP_CONTENT_DIR).'/mysql.sql';
24
+ return $files;
25
+ }
26
+
27
+ public static function defaultsSettings($defaults) {
28
+ $defaults['package_zip_flush'] = '1';
29
+ return $defaults;
30
+ }
31
+
32
+ }
33
+
34
+ DUP_WPEngine_Host::init();
classes/package/class.pack.archive.filters.php CHANGED
@@ -76,6 +76,14 @@ class DUP_Archive_Filter_Info
76
  * Init this object
77
  */
78
  public function __construct()
 
 
 
 
 
 
 
 
79
  {
80
  $this->Dirs = new DUP_Archive_Filter_Scope_Directory();
81
  $this->Files = new DUP_Archive_Filter_Scope_File();
76
  * Init this object
77
  */
78
  public function __construct()
79
+ {
80
+ $this->reset();
81
+ }
82
+
83
+ /**
84
+ * reset and clean all object
85
+ */
86
+ public function reset()
87
  {
88
  $this->Dirs = new DUP_Archive_Filter_Scope_Directory();
89
  $this->Files = new DUP_Archive_Filter_Scope_File();
classes/package/class.pack.archive.php CHANGED
@@ -37,7 +37,12 @@ class DUP_Archive
37
  public $Size = 0;
38
  public $Dirs = array();
39
  public $Files = array();
40
- public $FilterInfo;
 
 
 
 
 
41
  public $RecursiveLinks = array();
42
  public $file_count = -1;
43
  //PROTECTED
@@ -344,8 +349,10 @@ class DUP_Archive
344
  $this->FilterInfo->Dirs->Core[] = $wp_content.'/'.$backwpup_cfg_logfolder;
345
  }
346
  }
 
347
  if ($GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON']) {
348
- $this->FilterInfo->Files->Global = $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS'];
 
349
  }
350
 
351
  // Prevent adding double wp-content dir conflicts
37
  public $Size = 0;
38
  public $Dirs = array();
39
  public $Files = array();
40
+
41
+ /**
42
+ *
43
+ * @var DUP_Archive_Filter_Info
44
+ */
45
+ public $FilterInfo = null;
46
  public $RecursiveLinks = array();
47
  public $file_count = -1;
48
  //PROTECTED
349
  $this->FilterInfo->Dirs->Core[] = $wp_content.'/'.$backwpup_cfg_logfolder;
350
  }
351
  }
352
+ $duplicator_global_file_filters_on = apply_filters('duplicator_global_file_filters_on', $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON']);
353
  if ($GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON']) {
354
+ $duplicator_global_file_filters = apply_filters('duplicator_global_file_filters', $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS']);
355
+ $this->FilterInfo->Files->Global = $duplicator_global_file_filters;
356
  }
357
 
358
  // Prevent adding double wp-content dir conflicts
classes/package/class.pack.archive.zip.php CHANGED
@@ -127,7 +127,7 @@ class DUP_Zip extends DUP_Archive
127
  $localFileName = $archive->getLocalFilePath($file);
128
 
129
  if (is_readable($file)) {
130
- if ($file_size < DUP_Constants::ZIP_STRING_LIMIT && self::$zipArchive->addFromString($localFileName, file_get_contents($file))) {
131
  Dup_Log::Info("Adding {$file} to zip");
132
  self::$limitItems++;
133
  self::$countFiles++;
@@ -164,7 +164,7 @@ class DUP_Zip extends DUP_Archive
164
  $localFileName = $archive->getLocalFilePath($file);
165
 
166
  if (is_readable($file)) {
167
- if ($file_size < DUP_Constants::ZIP_STRING_LIMIT && self::$zipArchive->addFromString($localFileName, file_get_contents($file))) {
168
  self::$countFiles++;
169
  } elseif (self::$zipArchive->addFile($file, $localFileName)) {
170
  self::$countFiles++;
127
  $localFileName = $archive->getLocalFilePath($file);
128
 
129
  if (is_readable($file)) {
130
+ if (defined('DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR') && DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR && $file_size < DUP_Constants::ZIP_STRING_LIMIT && self::$zipArchive->addFromString($localFileName, file_get_contents($file))) {
131
  Dup_Log::Info("Adding {$file} to zip");
132
  self::$limitItems++;
133
  self::$countFiles++;
164
  $localFileName = $archive->getLocalFilePath($file);
165
 
166
  if (is_readable($file)) {
167
+ if (defined('DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR') && DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR && $file_size < DUP_Constants::ZIP_STRING_LIMIT && self::$zipArchive->addFromString($localFileName, file_get_contents($file))) {
168
  self::$countFiles++;
169
  } elseif (self::$zipArchive->addFile($file, $localFileName)) {
170
  self::$countFiles++;
classes/package/class.pack.database.php CHANGED
@@ -640,7 +640,7 @@ class DUP_Database
640
  }
641
 
642
  if ($is_select_error) {
643
- $fix = esc_html__('Please constact your DataBase administrator to fix the error.', 'duplicator');
644
  $errorMessage = $select_last_error.' '.$fix.'.';
645
  $package->BuildProgress->set_failed($errorMessage);
646
  $package->BuildProgress->failed = true;
640
  }
641
 
642
  if ($is_select_error) {
643
+ $fix = esc_html__('Please contact your DataBase administrator to fix the error.', 'duplicator');
644
  $errorMessage = $select_last_error.' '.$fix.'.';
645
  $package->BuildProgress->set_failed($errorMessage);
646
  $package->BuildProgress->failed = true;
classes/package/class.pack.installer.php CHANGED
@@ -76,7 +76,7 @@ class DUP_Installer
76
  {
77
  $success = true;
78
  $archive_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Archive->File}");
79
- $installer_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_installer.php";
80
  $template_filepath = DUPLICATOR_PLUGIN_PATH.'/installer/installer.tpl';
81
  $mini_expander_filepath = DUPLICATOR_PLUGIN_PATH.'/lib/dup_archive/classes/class.duparchive.mini.expander.php';
82
 
@@ -183,7 +183,7 @@ class DUP_Installer
183
  private function add_extra_files($package)
184
  {
185
  $success = false;
186
- $installer_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_installer.php";
187
  $scan_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_scan.json";
188
  $sql_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Database->File}");
189
  $archive_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Archive->File}");
@@ -299,12 +299,10 @@ class DUP_Installer
299
  private function add_installer_files_using_duparchive($archive_filepath, $installer_filepath, $archive_config_filepath)
300
  {
301
  $installer_backup_filename = 'installer-backup.php';
302
- $installer_backup_filepath = dirname($installer_filepath)."/{$installer_backup_filename}";
303
 
304
  DUP_Log::Info('Adding enhanced installer files to archive using DupArchive');
305
- DupLiteSnapLibIOU::copy($installer_filepath, $installer_backup_filepath);
306
- DupArchiveEngine::addFileToArchiveUsingBaseDirST($archive_filepath, dirname($installer_backup_filepath), $installer_backup_filepath);
307
- DupLiteSnapLibIOU::rm($installer_backup_filepath);
308
 
309
  $this->numFilesAdded++;
310
 
76
  {
77
  $success = true;
78
  $archive_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Archive->File}");
79
+ $installer_filepath = apply_filters('duplicator_installer_file_path', DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_installer.php");
80
  $template_filepath = DUPLICATOR_PLUGIN_PATH.'/installer/installer.tpl';
81
  $mini_expander_filepath = DUPLICATOR_PLUGIN_PATH.'/lib/dup_archive/classes/class.duparchive.mini.expander.php';
82
 
183
  private function add_extra_files($package)
184
  {
185
  $success = false;
186
+ $installer_filepath = apply_filters('duplicator_installer_file_path', DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_installer.php");
187
  $scan_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_scan.json";
188
  $sql_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Database->File}");
189
  $archive_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Archive->File}");
299
  private function add_installer_files_using_duparchive($archive_filepath, $installer_filepath, $archive_config_filepath)
300
  {
301
  $installer_backup_filename = 'installer-backup.php';
302
+
303
 
304
  DUP_Log::Info('Adding enhanced installer files to archive using DupArchive');
305
+ DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $installer_filepath, $installer_backup_filename);
 
 
306
 
307
  $this->numFilesAdded++;
308
 
classes/package/class.pack.php CHANGED
@@ -360,6 +360,11 @@ class DUP_Package
360
  return DUP_Settings::Get('active_package_id') == $this->ID && $this->Status >= 0 && $this->Status < 100;
361
  }
362
 
 
 
 
 
 
363
  /**
364
  * Saves the active package to the package table
365
  *
@@ -371,7 +376,7 @@ class DUP_Package
371
 
372
  $this->Archive->Format = strtoupper($extension);
373
  $this->Archive->File = "{$this->NameHash}_archive.{$extension}";
374
- $this->Installer->File = "{$this->NameHash}_installer.php";
375
  $this->Database->File = "{$this->NameHash}_database.sql";
376
  $this->WPUser = isset($current_user->user_login) ? $current_user->user_login : 'unknown';
377
 
@@ -383,6 +388,7 @@ class DUP_Package
383
  $this->writeLogHeader();
384
 
385
  //CREATE DB RECORD
 
386
  $packageObj = serialize($this);
387
  if (!$packageObj) {
388
  DUP_Log::Error("Unable to serialize package object while building record.");
@@ -720,6 +726,9 @@ class DUP_Package
720
  if ($rows != null) {
721
  $Package = @unserialize($rows[0]->package);
722
  if ($Package) {
 
 
 
723
  // We was not storing Status in Lite 1.2.52, so it is for backward compatibility
724
  if (!isset($Package->Status)) {
725
  $Package->Status = $row['status'];
@@ -943,7 +952,7 @@ class DUP_Package
943
 
944
  if ($file_type == DUP_PackageFileType::Installer) {
945
  DUP_Log::Trace("Installer requested");
946
- $file_name = $this->getInstallerFilename();
947
  } else if ($file_type == DUP_PackageFileType::Archive) {
948
  DUP_Log::Trace("Archive requested");
949
  $file_name = $this->getArchiveFilename();
@@ -1365,6 +1374,8 @@ class DUP_Package
1365
  {
1366
  global $wpdb;
1367
 
 
 
1368
  $packageObj = serialize($this);
1369
 
1370
  if (!$packageObj) {
@@ -1500,7 +1511,7 @@ class DUP_Package
1500
  $row = $wpdb->get_row($sql);
1501
  if (is_object($row)) {
1502
  $obj = @unserialize($row->package);
1503
- $obj->Status = $row->status;
1504
  }
1505
  //Incase unserilaize fails
1506
  $obj = (is_object($obj)) ? $obj : null;
360
  return DUP_Settings::Get('active_package_id') == $this->ID && $this->Status >= 0 && $this->Status < 100;
361
  }
362
 
363
+ protected function cleanObjectBeforeSave()
364
+ {
365
+ $this->Archive->FilterInfo->reset();
366
+ }
367
+
368
  /**
369
  * Saves the active package to the package table
370
  *
376
 
377
  $this->Archive->Format = strtoupper($extension);
378
  $this->Archive->File = "{$this->NameHash}_archive.{$extension}";
379
+ $this->Installer->File = apply_filters('duplicator_installer_file_path', "{$this->NameHash}_installer.php");
380
  $this->Database->File = "{$this->NameHash}_database.sql";
381
  $this->WPUser = isset($current_user->user_login) ? $current_user->user_login : 'unknown';
382
 
388
  $this->writeLogHeader();
389
 
390
  //CREATE DB RECORD
391
+ $this->cleanObjectBeforeSave();
392
  $packageObj = serialize($this);
393
  if (!$packageObj) {
394
  DUP_Log::Error("Unable to serialize package object while building record.");
726
  if ($rows != null) {
727
  $Package = @unserialize($rows[0]->package);
728
  if ($Package) {
729
+ if (empty($Package->ID)) {
730
+ $Package->ID = $rows[0]->id;
731
+ }
732
  // We was not storing Status in Lite 1.2.52, so it is for backward compatibility
733
  if (!isset($Package->Status)) {
734
  $Package->Status = $row['status'];
952
 
953
  if ($file_type == DUP_PackageFileType::Installer) {
954
  DUP_Log::Trace("Installer requested");
955
+ $file_name = apply_filters('duplicator_installer_file_path', $this->getInstallerFilename());
956
  } else if ($file_type == DUP_PackageFileType::Archive) {
957
  DUP_Log::Trace("Archive requested");
958
  $file_name = $this->getArchiveFilename();
1374
  {
1375
  global $wpdb;
1376
 
1377
+ $this->Status = number_format($this->Status, 1, '.', '');
1378
+ $this->cleanObjectBeforeSave();
1379
  $packageObj = serialize($this);
1380
 
1381
  if (!$packageObj) {
1511
  $row = $wpdb->get_row($sql);
1512
  if (is_object($row)) {
1513
  $obj = @unserialize($row->package);
1514
+ // $obj->Status = $row->status;
1515
  }
1516
  //Incase unserilaize fails
1517
  $obj = (is_object($obj)) ? $obj : null;
classes/package/duparchive/class.pack.archive.duparchive.php CHANGED
@@ -35,11 +35,8 @@ class DUP_DupArchive
35
 
36
  DUP_LOG::trace("start");
37
  try {
38
- if(DUP_Log::$logFileHandle == null) {
39
- DUP_Log::Open($package->NameHash);
40
- }
41
-
42
- DUP_LOG::trace("c2");
43
 
44
  if ($buildProgress->retries > DUPLICATOR_MAX_BUILD_RETRIES) {
45
  DUP_LOG::trace("c3");
35
 
36
  DUP_LOG::trace("start");
37
  try {
38
+ DUP_Log::Open($package->NameHash);
39
+ DUP_Log::trace("c2");
 
 
 
40
 
41
  if ($buildProgress->retries > DUPLICATOR_MAX_BUILD_RETRIES) {
42
  DUP_LOG::trace("c3");
classes/utilities/class.u.php CHANGED
@@ -466,21 +466,43 @@ class DUP_Util
466
  return base64_encode($string);
467
  }
468
 
469
- /**
470
- * Does the current user have the capability
471
- *
472
- * @return null Dies if user doesn't have the correct capability
473
- */
474
- public static function hasCapability($permission = 'read')
475
- {
476
- $capability = $permission;
477
- $capability = apply_filters('wpfront_user_role_editor_duplicator_translate_capability', $capability);
478
 
479
- if (!current_user_can($capability)) {
480
- wp_die(__('You do not have sufficient permissions to access this page.', 'duplicator'));
481
- return;
482
- }
483
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
 
485
  /**
486
  * Gets the name of the owner of the current PHP script
@@ -539,25 +561,20 @@ class DUP_Util
539
  //--------------------------------
540
  //CHMOD DIRECTORY ACCESS
541
  //wordpress root directory
542
- @chmod($path_wproot, 0755);
543
 
544
  //snapshot directory
545
- @mkdir($path_ssdir, 0755);
546
- @chmod($path_ssdir, 0755);
547
 
548
  // restore original root perms
549
- @chmod($path_wproot, $old_root_perm);
550
  }
551
 
552
  $path_ssdir_tmp = $path_ssdir.'/tmp';
553
- if (!file_exists($path_ssdir_tmp)) {
554
- //snapshot tmp directory
555
- @mkdir($path_ssdir_tmp, 0755);
556
- @chmod($path_ssdir_tmp, 0755);
557
- }
558
 
559
  //plugins dir/files
560
- @chmod($path_plugin.'files', 0755);
561
 
562
  //--------------------------------
563
  //FILE CREATION
@@ -570,15 +587,6 @@ class DUP_Util
570
  @fclose($ssfile);
571
  }
572
 
573
- //SSDIR: Create token file in snapshot
574
- $fileName = $path_ssdir.'/dtoken.php';
575
- if (!file_exists($fileName)) {
576
- $tokenfile = @fopen($fileName, 'w');
577
- @fwrite($tokenfile,
578
- '<?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(); ?>');
579
- @fclose($tokenfile);
580
- }
581
-
582
  //SSDIR: Create .htaccess
583
  $storage_htaccess_off = DUP_Settings::Get('storage_htaccess_off');
584
  $fileName = $path_ssdir.'/.htaccess';
@@ -598,15 +606,6 @@ class DUP_Util
598
  @fwrite($robotfile, "User-agent: * \nDisallow: /".DUPLICATOR_SSDIR_NAME.'/');
599
  @fclose($robotfile);
600
  }
601
-
602
- //PLUG DIR: Create token file in plugin
603
- $fileName = $path_plugin.'installer/dtoken.php';
604
- if (!file_exists($fileName)) {
605
- $tokenfile2 = @fopen($fileName, 'w');
606
- @fwrite($tokenfile2,
607
- '<?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"); ?>');
608
- @fclose($tokenfile2);
609
- }
610
  }
611
 
612
  /**
466
  return base64_encode($string);
467
  }
468
 
469
+ const SECURE_ISSUE_DIE = 'die';
470
+ const SECURE_ISSUE_THROW = 'throw';
471
+ const SECURE_ISSUE_RETURN = 'return';
 
 
 
 
 
 
472
 
473
+ /**
474
+ * Does the current user have the capability
475
+ *
476
+ * @param type $permission
477
+ * @param type $exit // SECURE_ISSUE_DIE die script with die function
478
+ * SECURE_ISSUE_THROW throw an exception if fail
479
+ * SECURE_ISSUE_RETURN return false if fail
480
+ *
481
+ * @return boolean // return false is fail and $exit is SECURE_ISSUE_THROW
482
+ * // true if success
483
+ *
484
+ * @throws Exception // thow exception if $exit is SECURE_ISSUE_THROW
485
+ */
486
+ public static function hasCapability($permission = 'read', $exit = self::SECURE_ISSUE_DIE)
487
+ {
488
+ $capability = apply_filters('wpfront_user_role_editor_duplicator_translate_capability', $permission);
489
+
490
+ if (!current_user_can($capability)) {
491
+ $exitMsg = __('You do not have sufficient permissions to access this page.', 'duplicator');
492
+ DUP_LOG::Trace('You do not have sufficient permissions to access this page. PERMISSION: '.$permission);
493
+
494
+ switch ($exit) {
495
+ case self::SECURE_ISSUE_THROW:
496
+ throw new Exception($exitMsg);
497
+ case self::SECURE_ISSUE_RETURN:
498
+ return false;
499
+ case self::SECURE_ISSUE_DIE:
500
+ default:
501
+ wp_die($exitMsg);
502
+ }
503
+ }
504
+ return true;
505
+ }
506
 
507
  /**
508
  * Gets the name of the owner of the current PHP script
561
  //--------------------------------
562
  //CHMOD DIRECTORY ACCESS
563
  //wordpress root directory
564
+ DupLiteSnapLibIOU::chmod($path_wproot, 'u+rwx');
565
 
566
  //snapshot directory
567
+ DupLiteSnapLibIOU::dirWriteCheckOrMkdir($path_ssdir, 'u+rwx');
 
568
 
569
  // restore original root perms
570
+ DupLiteSnapLibIOU::chmod($path_wproot, $old_root_perm);
571
  }
572
 
573
  $path_ssdir_tmp = $path_ssdir.'/tmp';
574
+ DupLiteSnapLibIOU::dirWriteCheckOrMkdir($path_ssdir_tmp, 'u+rwx');
 
 
 
 
575
 
576
  //plugins dir/files
577
+ DupLiteSnapLibIOU::dirWriteCheckOrMkdir($path_plugin.'files', 'u+rwx');
578
 
579
  //--------------------------------
580
  //FILE CREATION
587
  @fclose($ssfile);
588
  }
589
 
 
 
 
 
 
 
 
 
 
590
  //SSDIR: Create .htaccess
591
  $storage_htaccess_off = DUP_Settings::Get('storage_htaccess_off');
592
  $fileName = $path_ssdir.'/.htaccess';
606
  @fwrite($robotfile, "User-agent: * \nDisallow: /".DUPLICATOR_SSDIR_NAME.'/');
607
  @fclose($robotfile);
608
  }
 
 
 
 
 
 
 
 
 
609
  }
610
 
611
  /**
ctrls/class.web.services.php CHANGED
@@ -1,77 +1,82 @@
1
- <?php
2
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
-
4
- class DUP_Web_Services
5
- {
6
-
7
- /**
8
- * init ajax actions
9
- */
10
- public static function init()
11
- {
12
- add_action('wp_ajax_duplicator_reset_all_settings', array(__CLASS__, 'ajax_reset_all'));
13
- }
14
-
15
- /**
16
- *
17
- * @param DUP_PRO_Package $package
18
- */
19
- public static function package_delete_callback($package)
20
- {
21
- $package->delete();
22
- }
23
-
24
- /**
25
- * reset all ajax action
26
- *
27
- * the output must be json
28
- */
29
- public static function ajax_reset_all()
30
- {
31
- check_ajax_referer('duplicator_reset_all_settings', 'nonce');
32
- DUP_Util::hasCapability('export');
33
-
34
- ob_start();
35
- try {
36
- /** Execute function * */
37
- $error = false;
38
- $result = array(
39
- 'data' => array(),
40
- 'html' => '',
41
- 'message' => ''
42
- );
43
-
44
- $nonce = sanitize_text_field($_POST['nonce']);
45
- if (!wp_verify_nonce($nonce, 'duplicator_reset_all_settings')) {
46
- DUP_Log::trace('Security issue');
47
- throw new Exception('Security issue');
48
- }
49
-
50
- DUP_Package::by_status_callback(array(__CLASS__,'package_delete_callback'),array(
51
- array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE)
52
- ));
53
-
54
- /** reset active package id * */
55
- DUP_Settings::Set('active_package_id', -1);
56
- DUP_Settings::Save();
57
-
58
- /** Clean tmp folder * */
59
- DUP_Package::not_active_files_tmp_cleanup();
60
-
61
- //throw new Exception('force error test');
62
- } catch (Exception $e) {
63
- $error = true;
64
- $result['message'] = $e->getMessage();
65
- }
66
-
67
- /** Intercept output * */
68
- $result['html'] = ob_get_clean();
69
-
70
- /** check error and return json * */
71
- if ($error) {
72
- wp_send_json_error($result);
73
- } else {
74
- wp_send_json_success($result);
75
- }
76
- }
 
 
 
 
 
77
  }
1
+ <?php
2
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+
4
+ class DUP_Web_Services
5
+ {
6
+
7
+ /**
8
+ * init ajax actions
9
+ */
10
+ public static function init()
11
+ {
12
+ add_action('wp_ajax_duplicator_reset_all_settings', array(__CLASS__, 'ajax_reset_all'));
13
+ }
14
+
15
+ /**
16
+ *
17
+ * @param DUP_Package $package
18
+ */
19
+ public static function package_delete_callback($package)
20
+ {
21
+ $package->delete();
22
+ }
23
+
24
+ /**
25
+ * reset all ajax action
26
+ *
27
+ * the output must be json
28
+ */
29
+ public static function ajax_reset_all()
30
+ {
31
+ ob_start();
32
+ try {
33
+ DUP_Handler::init_error_handler();
34
+
35
+ if (!check_ajax_referer('duplicator_reset_all_settings', 'nonce', false)) {
36
+ DUP_LOG::Trace('Security issue');
37
+ throw new Exception('Security issue');
38
+ }
39
+ DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
40
+
41
+ /** Execute function * */
42
+ $error = false;
43
+ $result = array(
44
+ 'data' => array(),
45
+ 'html' => '',
46
+ 'message' => ''
47
+ );
48
+
49
+ $nonce = sanitize_text_field($_POST['nonce']);
50
+ if (!wp_verify_nonce($nonce, 'duplicator_reset_all_settings')) {
51
+ DUP_Log::trace('Security issue');
52
+ throw new Exception('Security issue');
53
+ }
54
+
55
+ DUP_Package::by_status_callback(array(__CLASS__,'package_delete_callback'),array(
56
+ array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE)
57
+ ));
58
+
59
+ /** reset active package id * */
60
+ DUP_Settings::Set('active_package_id', -1);
61
+ DUP_Settings::Save();
62
+
63
+ /** Clean tmp folder * */
64
+ DUP_Package::not_active_files_tmp_cleanup();
65
+
66
+ //throw new Exception('force error test');
67
+ } catch (Exception $e) {
68
+ $error = true;
69
+ $result['message'] = $e->getMessage();
70
+ }
71
+
72
+ /** Intercept output * */
73
+ $result['html'] = ob_get_clean();
74
+
75
+ /** check error and return json * */
76
+ if ($error) {
77
+ wp_send_json_error($result);
78
+ } else {
79
+ wp_send_json_success($result);
80
+ }
81
+ }
82
  }
ctrls/ctrl.package.php CHANGED
@@ -19,6 +19,8 @@ require_once(DUPLICATOR_PLUGIN_PATH.'/classes/package/duparchive/class.pack.arch
19
  */
20
  function duplicator_package_scan()
21
  {
 
 
22
  check_ajax_referer('duplicator_package_scan', 'nonce');
23
  DUP_Util::hasCapability('export');
24
 
@@ -49,6 +51,8 @@ function duplicator_package_scan()
49
  */
50
  function duplicator_package_build()
51
  {
 
 
52
  check_ajax_referer('duplicator_package_build', 'nonce');
53
  DUP_Util::hasCapability('export');
54
 
@@ -95,6 +99,8 @@ function duplicator_package_build()
95
  */
96
  function duplicator_duparchive_package_build()
97
  {
 
 
98
  DUP_LOG::Trace("call to duplicator_duparchive_package_build");
99
 
100
  check_ajax_referer('duplicator_duparchive_package_build', 'nonce');
@@ -199,6 +205,7 @@ function duplicator_duparchive_package_build()
199
  */
200
  function duplicator_package_delete()
201
  {
 
202
  check_ajax_referer('duplicator_package_delete', 'nonce');
203
  DUP_Util::hasCapability('export');
204
 
@@ -233,27 +240,26 @@ function duplicator_package_delete()
233
  $nameHash = "{$row['name']}_{$row['hash']}";
234
  $delResult = $wpdb->query($wpdb->prepare("DELETE FROM `{$tblName}` WHERE id = %d", $id));
235
  if ($delResult != 0) {
 
 
 
 
 
236
 
237
- //TMP FILES
238
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.daf"));
239
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.zip"));
240
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_database.sql"));
241
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_installer.php"));
242
-
243
- //WP-SNAPSHOT FILES
244
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_archive.daf"));
245
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_archive.zip"));
246
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_database.sql"));
247
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_installer.php"));
248
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_scan.json"));
249
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_wp-config.txt"));
250
- _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}.log"));
251
 
252
  //Unfinished Zip files
 
253
  $tmpZip = DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.zip.*";
254
  if ($tmpZip !== false) {
255
  array_map('unlink', glob($tmpZip));
256
  }
 
257
  $delCount++;
258
  }
259
  }
@@ -280,8 +286,10 @@ function duplicator_package_delete()
280
  function duplicator_active_package_info()
281
  {
282
  ob_start();
283
- DUP_Util::hasCapability('export');
284
  try {
 
 
 
285
  if (!check_ajax_referer('duplicator_active_package_info', 'nonce', false)) {
286
  throw new Exception(__('An unathorized security request was made to this page. Please try again!','duplicator'));
287
  }
@@ -350,6 +358,8 @@ class DUP_CTRL_Package extends DUP_CTRL_Base
350
  */
351
  public function addQuickFilters($post)
352
  {
 
 
353
  check_ajax_referer('DUP_CTRL_Package_addQuickFilters', 'nonce');
354
  DUP_Util::hasCapability('export');
355
  $post = $this->postParamMerge($post);
@@ -404,6 +414,8 @@ class DUP_CTRL_Package extends DUP_CTRL_Base
404
  */
405
  function getPackageFile($post)
406
  {
 
 
407
  check_ajax_referer('DUP_CTRL_Package_getPackageFile', 'nonce' );
408
  DUP_Util::hasCapability('export');
409
  $params = $this->postParamMerge($post);
@@ -501,6 +513,8 @@ class DUP_CTRL_Package extends DUP_CTRL_Base
501
  */
502
  public function getActivePackageStatus($post)
503
  {
 
 
504
  check_ajax_referer('DUP_CTRL_Package_getActivePackageStatus', 'nonce');
505
  DUP_Util::hasCapability('export');
506
 
19
  */
20
  function duplicator_package_scan()
21
  {
22
+ DUP_Handler::init_error_handler();
23
+
24
  check_ajax_referer('duplicator_package_scan', 'nonce');
25
  DUP_Util::hasCapability('export');
26
 
51
  */
52
  function duplicator_package_build()
53
  {
54
+ DUP_Handler::init_error_handler();
55
+
56
  check_ajax_referer('duplicator_package_build', 'nonce');
57
  DUP_Util::hasCapability('export');
58
 
99
  */
100
  function duplicator_duparchive_package_build()
101
  {
102
+ DUP_Handler::init_error_handler();
103
+
104
  DUP_LOG::Trace("call to duplicator_duparchive_package_build");
105
 
106
  check_ajax_referer('duplicator_duparchive_package_build', 'nonce');
205
  */
206
  function duplicator_package_delete()
207
  {
208
+ DUP_Handler::init_error_handler();
209
  check_ajax_referer('duplicator_package_delete', 'nonce');
210
  DUP_Util::hasCapability('export');
211
 
240
  $nameHash = "{$row['name']}_{$row['hash']}";
241
  $delResult = $wpdb->query($wpdb->prepare("DELETE FROM `{$tblName}` WHERE id = %d", $id));
242
  if ($delResult != 0) {
243
+ //TMP FILES
244
+ $globTmpFiles = glob(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}*"));
245
+ foreach ($globTmpFiles as $globTmpFile) {
246
+ _unlinkFile($globTmpFile);
247
+ }
248
 
249
+ //WP-SNAPSHOT FILES
250
+ $globSnapshotFiles = glob(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}*"));
251
+ foreach ($globSnapshotFiles as $globSnapshotFile) {
252
+ _unlinkFile($globSnapshotFile);
253
+ }
254
+ // _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}.log"));
 
 
 
 
 
 
 
 
255
 
256
  //Unfinished Zip files
257
+ /*
258
  $tmpZip = DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.zip.*";
259
  if ($tmpZip !== false) {
260
  array_map('unlink', glob($tmpZip));
261
  }
262
+ */
263
  $delCount++;
264
  }
265
  }
286
  function duplicator_active_package_info()
287
  {
288
  ob_start();
 
289
  try {
290
+ DUP_Handler::init_error_handler();
291
+ DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
292
+
293
  if (!check_ajax_referer('duplicator_active_package_info', 'nonce', false)) {
294
  throw new Exception(__('An unathorized security request was made to this page. Please try again!','duplicator'));
295
  }
358
  */
359
  public function addQuickFilters($post)
360
  {
361
+ DUP_Handler::init_error_handler();
362
+
363
  check_ajax_referer('DUP_CTRL_Package_addQuickFilters', 'nonce');
364
  DUP_Util::hasCapability('export');
365
  $post = $this->postParamMerge($post);
414
  */
415
  function getPackageFile($post)
416
  {
417
+ DUP_Handler::init_error_handler();
418
+
419
  check_ajax_referer('DUP_CTRL_Package_getPackageFile', 'nonce' );
420
  DUP_Util::hasCapability('export');
421
  $params = $this->postParamMerge($post);
513
  */
514
  public function getActivePackageStatus($post)
515
  {
516
+ DUP_Handler::init_error_handler();
517
+
518
  check_ajax_referer('DUP_CTRL_Package_getActivePackageStatus', 'nonce');
519
  DUP_Util::hasCapability('export');
520
 
ctrls/ctrl.tools.php CHANGED
@@ -31,6 +31,8 @@ class DUP_CTRL_Tools extends DUP_CTRL_Base
31
  */
32
  public function runScanValidator($post)
33
  {
 
 
34
  check_ajax_referer('DUP_CTRL_Tools_runScanValidator', 'nonce');
35
  DUP_Util::hasCapability('export');
36
 
31
  */
32
  public function runScanValidator($post)
33
  {
34
+ DUP_Handler::init_error_handler();
35
+
36
  check_ajax_referer('DUP_CTRL_Tools_runScanValidator', 'nonce');
37
  DUP_Util::hasCapability('export');
38
 
ctrls/ctrl.ui.php CHANGED
@@ -39,6 +39,7 @@ class DUP_CTRL_UI extends DUP_CTRL_Base
39
  */
40
  public function SaveViewState($post)
41
  {
 
42
  check_ajax_referer('DUP_CTRL_UI_SaveViewState', 'nonce');
43
  DUP_Util::hasCapability('export');
44
 
39
  */
40
  public function SaveViewState($post)
41
  {
42
+ DUP_Handler::init_error_handler();
43
  check_ajax_referer('DUP_CTRL_UI_SaveViewState', 'nonce');
44
  DUP_Util::hasCapability('export');
45
 
deactivation.php CHANGED
@@ -86,12 +86,14 @@ if (!function_exists('duplicator_add_deactivation_feedback_dialog_box')) {
86
  'input_type' => '',
87
  'input_placeholder' => ''
88
  ),
 
89
  array(
90
  'id' => 'OTHER',
91
  'text' => __('Other', 'duplicator'),
92
  'input_type' => 'textarea',
93
  'input_placeholder' => __('Please tell us the reason so we can improve it.', 'duplicator')
94
  )
 
95
  );
96
 
97
  $reasons_list_items_html = '';
@@ -356,6 +358,8 @@ if (!function_exists('duplicator_submit_uninstall_reason_action')) {
356
 
357
  function duplicator_submit_uninstall_reason_action()
358
  {
 
 
359
  if (!wp_verify_nonce($_REQUEST['duplicator_ajax_nonce'], 'duplicator_ajax_nonce')) {
360
  wp_die('Security issue');
361
  }
86
  'input_type' => '',
87
  'input_placeholder' => ''
88
  ),
89
+ /*
90
  array(
91
  'id' => 'OTHER',
92
  'text' => __('Other', 'duplicator'),
93
  'input_type' => 'textarea',
94
  'input_placeholder' => __('Please tell us the reason so we can improve it.', 'duplicator')
95
  )
96
+ */
97
  );
98
 
99
  $reasons_list_items_html = '';
358
 
359
  function duplicator_submit_uninstall_reason_action()
360
  {
361
+ DUP_Handler::init_error_handler();
362
+
363
  if (!wp_verify_nonce($_REQUEST['duplicator_ajax_nonce'], 'duplicator_ajax_nonce')) {
364
  wp_die('Security issue');
365
  }
define.php CHANGED
@@ -4,8 +4,8 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
4
  //Prevent directly browsing to the file
5
  if (function_exists('plugin_dir_url'))
6
  {
7
- define('DUPLICATOR_VERSION', '1.3.14');
8
- define('DUPLICATOR_VERSION_BUILD', '2019-05-20_15:40');
9
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
10
  define('DUPLICATOR_SITE_URL', get_site_url());
11
 
@@ -56,6 +56,7 @@ if (function_exists('plugin_dir_url'))
56
  define('DUPLICATOR_WEBCONFIG_ORIG_FILENAME', 'web.config.orig');
57
  define("DUPLICATOR_INSTALLER_DIRECTORY", DUPLICATOR_WPROOTPATH . 'dup-installer');
58
  define('DUPLICATOR_MAX_LOG_SIZE', 400000); // The higher this is the more overhead
 
59
 
60
  $GLOBALS['DUPLICATOR_SERVER_LIST'] = array('Apache','LiteSpeed', 'Nginx', 'Lighttpd', 'IIS', 'WebServerX', 'uWSGI');
61
  $GLOBALS['DUPLICATOR_OPTS_DELETE'] = array('duplicator_ui_view_state', 'duplicator_package_active', 'duplicator_settings');
4
  //Prevent directly browsing to the file
5
  if (function_exists('plugin_dir_url'))
6
  {
7
+ define('DUPLICATOR_VERSION', '1.3.16');
8
+ define('DUPLICATOR_VERSION_BUILD', '2019-07-07_14:00');
9
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
10
  define('DUPLICATOR_SITE_URL', get_site_url());
11
 
56
  define('DUPLICATOR_WEBCONFIG_ORIG_FILENAME', 'web.config.orig');
57
  define("DUPLICATOR_INSTALLER_DIRECTORY", DUPLICATOR_WPROOTPATH . 'dup-installer');
58
  define('DUPLICATOR_MAX_LOG_SIZE', 400000); // The higher this is the more overhead
59
+ define('DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR', false);
60
 
61
  $GLOBALS['DUPLICATOR_SERVER_LIST'] = array('Apache','LiteSpeed', 'Nginx', 'Lighttpd', 'IIS', 'WebServerX', 'uWSGI');
62
  $GLOBALS['DUPLICATOR_OPTS_DELETE'] = array('duplicator_ui_view_state', 'duplicator_package_active', 'duplicator_settings');
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.14
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
9
  Text Domain: duplicator
@@ -158,6 +158,19 @@ if (is_admin() == true)
158
  require_once 'deactivation.php';
159
  require_once 'lib/snaplib/snaplib.all.php';
160
  require_once 'classes/class.constants.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  require_once 'classes/class.settings.php';
162
  require_once 'classes/class.logging.php';
163
  require_once 'classes/utilities/class.u.php';
@@ -168,7 +181,7 @@ if (is_admin() == true)
168
  require_once 'classes/ui/class.ui.viewstate.php';
169
  require_once 'classes/ui/class.ui.notice.php';
170
  require_once 'classes/package/class.pack.php';
171
- require_once 'views/packages/screen.php';
172
 
173
  //Controllers
174
  require_once 'ctrls/ctrl.package.php';
@@ -206,7 +219,7 @@ if (is_admin() == true)
206
  status INT(11) NOT NULL,
207
  created DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
208
  owner VARCHAR(60) NOT NULL,
209
- package MEDIUMBLOB NOT NULL,
210
  PRIMARY KEY (id),
211
  KEY hash (hash))";
212
 
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.16
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
9
  Text Domain: duplicator
158
  require_once 'deactivation.php';
159
  require_once 'lib/snaplib/snaplib.all.php';
160
  require_once 'classes/class.constants.php';
161
+ $isWPEngineHost = apply_filters('duplicator_wp_engine_host_check', file_exists(WPMU_PLUGIN_DIR.'/wpengine-common/mu-plugin.php'));
162
+ if ($isWPEngineHost) {
163
+ require_once 'classes/host/class.wpengine.host.php';
164
+ }
165
+
166
+ $hostName = gethostname();
167
+ $goDaddyHostNameSuffix = '.secureserver.net';
168
+ $lenGoDaddyHostNameSuffix = strlen($goDaddyHostNameSuffix);
169
+ $isGoDaddyHost = apply_filters('duplicator_godaddy_host_check', (false !== $hostName && substr($hostName, - $lenGoDaddyHostNameSuffix) === $goDaddyHostNameSuffix));
170
+ if ($isGoDaddyHost) {
171
+ require_once 'classes/host/class.godaddy.host.php';
172
+ }
173
+
174
  require_once 'classes/class.settings.php';
175
  require_once 'classes/class.logging.php';
176
  require_once 'classes/utilities/class.u.php';
181
  require_once 'classes/ui/class.ui.viewstate.php';
182
  require_once 'classes/ui/class.ui.notice.php';
183
  require_once 'classes/package/class.pack.php';
184
+ require_once 'views/packages/screen.php';
185
 
186
  //Controllers
187
  require_once 'ctrls/ctrl.package.php';
219
  status INT(11) NOT NULL,
220
  created DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
221
  owner VARCHAR(60) NOT NULL,
222
+ package LONGTEXT NOT NULL,
223
  PRIMARY KEY (id),
224
  KEY hash (hash))";
225
 
installer/dup-installer/assets/inc.css.php CHANGED
@@ -44,9 +44,10 @@
44
  select option {
45
  padding: 2px 5px;
46
  }
47
- select option[disabled] {
48
  text-decoration: line-through;
49
  cursor: not-allowed;
 
50
  }
51
 
52
  select:disabled {background:#EBEBE4}
@@ -400,23 +401,30 @@
400
  pre.s4-diff-viewer {line-height:11px}
401
  div#s4-notice-reports div.section-content div.title {cursor:pointer}
402
 
403
- /* ============================
404
- STEP 5 HELP
405
- ============================ */
 
 
 
 
406
  div.help-target {float:right;}
407
- div.help-target a {float:right; font-size:16px; color:#13659C}
408
- div#main-help sup {font-size:11px; font-weight:normal; font-style:italic; color:blue}
409
- div.help-online {text-align:center; font-size:18px; padding:10px 0 0 0; line-height:24px}
410
- div.help {color:#555; font-style:italic; font-size:11px; padding:4px; border-top:1px solid #dfdfdf}
411
- div.help-page fieldset {margin-bottom:25px}
412
  div#main-help {font-size:13px; line-height:17px}
413
- div#main-help h3 {border-bottom:1px solid silver; padding:8px; margin:4px 0 8px 0; font-size:20px}
414
  div#main-help span.step {color:#DB4B38}
415
- table.help-opt {width: 100%; border: none; border-collapse: collapse; margin:5px 0 0 0;}
416
- table.help-opt td.section {background-color:#dfdfdf;}
417
- table.help-opt td, th {padding:7px; border:1px solid silver;}
418
- table.help-opt td:first-child {font-weight:bold; padding-right:10px; white-space:nowrap}
419
- table.help-opt th {background: #333; color: #fff;border:1px solid #333; padding:3px}
 
 
 
420
 
421
  #main-help section {
422
  border: 1px solid silver;
44
  select option {
45
  padding: 2px 5px;
46
  }
47
+ select option:disabled {
48
  text-decoration: line-through;
49
  cursor: not-allowed;
50
+ color: #A9A9A9;
51
  }
52
 
53
  select:disabled {background:#EBEBE4}
401
  pre.s4-diff-viewer {line-height:11px}
402
  div#s4-notice-reports div.section-content div.title {cursor:pointer}
403
 
404
+ /* ============================
405
+ STEP 5 HELP
406
+ ============================ */
407
+ #body-help div#content {
408
+ width: 100%;
409
+ max-width: 1024px;
410
+ }
411
  div.help-target {float:right;}
412
+ div.help-target a {float:right; font-size:16px; color:#13659C}
413
+ div#main-help sup {font-size:11px; font-weight:normal; font-style:italic; color:blue}
414
+ div.help-online {text-align:center; font-size:18px; padding:10px 0 0 0; line-height:24px}
415
+ div.help {color:#555; font-style:italic; font-size:11px; padding:4px; border-top:1px solid #dfdfdf}
416
+ div.help-page fieldset {margin-bottom:25px}
417
  div#main-help {font-size:13px; line-height:17px}
418
+ div#main-help h3 {border-bottom:1px solid silver; padding:8px; margin:4px 0 8px 0; font-size:20px}
419
  div#main-help span.step {color:#DB4B38}
420
+ .help-opt {width: 100%; border: none; border-collapse: collapse; margin:5px 0 0 0;}
421
+ .help-opt .col-opt {
422
+ width: 250px;
423
+ }
424
+ .help-opt td.section {background-color:#dfdfdf;}
425
+ .help-opt td, .help-opt th {padding:15px 10px; border:1px solid silver;}
426
+ .help-opt td:first-child {font-weight:bold; padding-right:10px; white-space:nowrap}
427
+ .help-opt th {background: #333; color: #fff;border:1px solid #333 }
428
 
429
  #main-help section {
430
  border: 1px solid silver;
installer/dup-installer/assets/inc.libs.js.php CHANGED
@@ -166,7 +166,6 @@ for(var c=0;c<f.length;c++){var e=true;for(var b=0;b<a&&(b+c+a)<f.length;b++){e=
166
  */
167
  function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t<e.length;t++)i[t]=e[t];return i}return Array.from(e)}var _slice=Array.prototype.slice;!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):e.parsley=t(e.jQuery)}(this,function(e){"use strict";function t(e,t){return e.parsleyAdaptedCallback||(e.parsleyAdaptedCallback=function(){var i=Array.prototype.slice.call(arguments,0);i.unshift(this),e.apply(t||A,i)}),e.parsleyAdaptedCallback}function i(e){return 0===e.lastIndexOf(D,0)?e.substr(D.length):e}var n=1,r={},s={attr:function(e,t,i){var n,r,s,a=new RegExp("^"+t,"i");if("undefined"==typeof i)i={};else for(n in i)i.hasOwnProperty(n)&&delete i[n];if("undefined"==typeof e||"undefined"==typeof e[0])return i;for(s=e[0].attributes,n=s.length;n--;)r=s[n],r&&r.specified&&a.test(r.name)&&(i[this.camelize(r.name.slice(t.length))]=this.deserializeValue(r.value));return i},checkAttr:function(e,t,i){return e.is("["+t+i+"]")},setAttr:function(e,t,i,n){e[0].setAttribute(this.dasherize(t+i),String(n))},generateID:function(){return""+n++},deserializeValue:function(t){var i;try{return t?"true"==t||("false"==t?!1:"null"==t?null:isNaN(i=Number(t))?/^[\[\{]/.test(t)?e.parseJSON(t):t:i):t}catch(n){return t}},camelize:function(e){return e.replace(/-+(.)?/g,function(e,t){return t?t.toUpperCase():""})},dasherize:function(e){return e.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()},warn:function(){var e;window.console&&"function"==typeof window.console.warn&&(e=window.console).warn.apply(e,arguments)},warnOnce:function(e){r[e]||(r[e]=!0,this.warn.apply(this,arguments))},_resetWarnings:function(){r={}},trimString:function(e){return e.replace(/^\s+|\s+$/g,"")},namespaceEvents:function(t,i){return t=this.trimString(t||"").split(/\s+/),t[0]?e.map(t,function(e){return e+"."+i}).join(" "):""},objectCreate:Object.create||function(){var e=function(){};return function(t){if(arguments.length>1)throw Error("Second argument not supported");if("object"!=typeof t)throw TypeError("Argument must be an object");e.prototype=t;var i=new e;return e.prototype=null,i}}()},a=s,o={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset], input[type=hidden]",priorityEnabled:!0,multiple:null,group:null,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,triggerAfterFailure:"input",errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(e){},errorsContainer:function(e){},errorsWrapper:'<ul class="parsley-errors-list"></ul>',errorTemplate:"<li></li>"},l=function(){};l.prototype={asyncSupport:!0,actualizeOptions:function(){return a.attr(this.$element,this.options.namespace,this.domOptions),this.parent&&this.parent.actualizeOptions&&this.parent.actualizeOptions(),this},_resetOptions:function(e){this.domOptions=a.objectCreate(this.parent.options),this.options=a.objectCreate(this.domOptions);for(var t in e)e.hasOwnProperty(t)&&(this.options[t]=e[t]);this.actualizeOptions()},_listeners:null,on:function(e,t){this._listeners=this._listeners||{};var i=this._listeners[e]=this._listeners[e]||[];return i.push(t),this},subscribe:function(t,i){e.listenTo(this,t.toLowerCase(),i)},off:function(e,t){var i=this._listeners&&this._listeners[e];if(i)if(t)for(var n=i.length;n--;)i[n]===t&&i.splice(n,1);else delete this._listeners[e];return this},unsubscribe:function(t,i){e.unsubscribeTo(this,t.toLowerCase())},trigger:function(e,t,i){t=t||this;var n,r=this._listeners&&this._listeners[e];if(r)for(var s=r.length;s--;)if(n=r[s].call(t,t,i),n===!1)return n;return this.parent?this.parent.trigger(e,t,i):!0},reset:function(){if("ParsleyForm"!==this.__class__)return this._resetUI(),this._trigger("reset");for(var e=0;e<this.fields.length;e++)this.fields[e].reset();this._trigger("reset")},destroy:function(){if(this._destroyUI(),"ParsleyForm"!==this.__class__)return this.$element.removeData("Parsley"),this.$element.removeData("ParsleyFieldMultiple"),void this._trigger("destroy");for(var e=0;e<this.fields.length;e++)this.fields[e].destroy();this.$element.removeData("Parsley"),this._trigger("destroy")},asyncIsValid:function(e,t){return a.warnOnce("asyncIsValid is deprecated; please use whenValid instead"),this.whenValid({group:e,force:t})},_findRelated:function(){return this.options.multiple?this.parent.$element.find("["+this.options.namespace+'multiple="'+this.options.multiple+'"]'):this.$element}};var u={string:function(e){return e},integer:function(e){if(isNaN(e))throw'Requirement is not an integer: "'+e+'"';return parseInt(e,10)},number:function(e){if(isNaN(e))throw'Requirement is not a number: "'+e+'"';return parseFloat(e)},reference:function(t){var i=e(t);if(0===i.length)throw'No such reference: "'+t+'"';return i},"boolean":function(e){return"false"!==e},object:function(e){return a.deserializeValue(e)},regexp:function(e){var t="";return/^\/.*\/(?:[gimy]*)$/.test(e)?(t=e.replace(/.*\/([gimy]*)$/,"$1"),e=e.replace(new RegExp("^/(.*?)/"+t+"$"),"$1")):e="^"+e+"$",new RegExp(e,t)}},d=function(e,t){var i=e.match(/^\s*\[(.*)\]\s*$/);if(!i)throw'Requirement is not an array: "'+e+'"';var n=i[1].split(",").map(a.trimString);if(n.length!==t)throw"Requirement has "+n.length+" values when "+t+" are needed";return n},h=function(e,t){var i=u[e||"string"];if(!i)throw'Unknown requirement specification: "'+e+'"';return i(t)},p=function(e,t,i){var n=null,r={};for(var s in e)if(s){var a=i(s);"string"==typeof a&&(a=h(e[s],a)),r[s]=a}else n=h(e[s],t);return[n,r]},f=function(t){e.extend(!0,this,t)};f.prototype={validate:function(t,i){if(this.fn)return arguments.length>3&&(i=[].slice.call(arguments,1,-1)),this.fn.call(this,t,i);if(e.isArray(t)){if(!this.validateMultiple)throw"Validator `"+this.name+"` does not handle multiple values";return this.validateMultiple.apply(this,arguments)}if(this.validateNumber)return isNaN(t)?!1:(arguments[0]=parseFloat(arguments[0]),this.validateNumber.apply(this,arguments));if(this.validateString)return this.validateString.apply(this,arguments);throw"Validator `"+this.name+"` only handles multiple values"},parseRequirements:function(t,i){if("string"!=typeof t)return e.isArray(t)?t:[t];var n=this.requirementType;if(e.isArray(n)){for(var r=d(t,n.length),s=0;s<r.length;s++)r[s]=h(n[s],r[s]);return r}return e.isPlainObject(n)?p(n,t,i):[h(n,t)]},requirementType:"string",priority:2};var c=function(e,t){this.__class__="ParsleyValidatorRegistry",this.locale="en",this.init(e||{},t||{})},m={email:/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,number:/^-?(\d*\.)?\d+(e[-+]?\d+)?$/i,integer:/^-?\d+$/,digits:/^\d+$/,alphanum:/^\w+$/i,url:new RegExp("^(?:(?:https?|ftp)://)?(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:/\\S*)?$","i")};m.range=m.number;var g=function(e){var t=(""+e).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);return t?Math.max(0,(t[1]?t[1].length:0)-(t[2]?+t[2]:0)):0};c.prototype={init:function(t,i){this.catalog=i,this.validators=e.extend({},this.validators);for(var n in t)this.addValidator(n,t[n].fn,t[n].priority);window.Parsley.trigger("parsley:validator:init")},setLocale:function(e){if("undefined"==typeof this.catalog[e])throw new Error(e+" is not available in the catalog");return this.locale=e,this},addCatalog:function(e,t,i){return"object"==typeof t&&(this.catalog[e]=t),!0===i?this.setLocale(e):this},addMessage:function(e,t,i){return"undefined"==typeof this.catalog[e]&&(this.catalog[e]={}),this.catalog[e][t]=i,this},addMessages:function(e,t){for(var i in t)this.addMessage(e,i,t[i]);return this},addValidator:function(e,t,i){if(this.validators[e])a.warn('Validator "'+e+'" is already defined.');else if(o.hasOwnProperty(e))return void a.warn('"'+e+'" is a restricted keyword and is not a valid validator name.');return this._setValidator.apply(this,arguments)},updateValidator:function(e,t,i){return this.validators[e]?this._setValidator(this,arguments):(a.warn('Validator "'+e+'" is not already defined.'),this.addValidator.apply(this,arguments))},removeValidator:function(e){return this.validators[e]||a.warn('Validator "'+e+'" is not defined.'),delete this.validators[e],this},_setValidator:function(e,t,i){"object"!=typeof t&&(t={fn:t,priority:i}),t.validate||(t=new f(t)),this.validators[e]=t;for(var n in t.messages||{})this.addMessage(n,e,t.messages[n]);return this},getErrorMessage:function(e){var t;if("type"===e.name){var i=this.catalog[this.locale][e.name]||{};t=i[e.requirements]}else t=this.formatMessage(this.catalog[this.locale][e.name],e.requirements);return t||this.catalog[this.locale].defaultMessage||this.catalog.en.defaultMessage},formatMessage:function(e,t){if("object"==typeof t){for(var i in t)e=this.formatMessage(e,t[i]);return e}return"string"==typeof e?e.replace(/%s/i,t):""},validators:{notblank:{validateString:function(e){return/\S/.test(e)},priority:2},required:{validateMultiple:function(e){return e.length>0},validateString:function(e){return/\S/.test(e)},priority:512},type:{validateString:function(e,t){var i=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],n=i.step,r=void 0===n?"1":n,s=i.base,a=void 0===s?0:s,o=m[t];if(!o)throw new Error("validator type `"+t+"` is not supported");if(!o.test(e))return!1;if("number"===t&&!/^any$/i.test(r||"")){var l=Number(e),u=Math.max(g(r),g(a));if(g(l)>u)return!1;var d=function(e){return Math.round(e*Math.pow(10,u))};if((d(l)-d(a))%d(r)!=0)return!1}return!0},requirementType:{"":"string",step:"string",base:"number"},priority:256},pattern:{validateString:function(e,t){return t.test(e)},requirementType:"regexp",priority:64},minlength:{validateString:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxlength:{validateString:function(e,t){return e.length<=t},requirementType:"integer",priority:30},length:{validateString:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},mincheck:{validateMultiple:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxcheck:{validateMultiple:function(e,t){return e.length<=t},requirementType:"integer",priority:30},check:{validateMultiple:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},min:{validateNumber:function(e,t){return e>=t},requirementType:"number",priority:30},max:{validateNumber:function(e,t){return t>=e},requirementType:"number",priority:30},range:{validateNumber:function(e,t,i){return e>=t&&i>=e},requirementType:["number","number"],priority:30},equalto:{validateString:function(t,i){var n=e(i);return n.length?t===n.val():t===i},priority:256}}};var y={},v=function T(e,t,i){for(var n=[],r=[],s=0;s<e.length;s++){for(var a=!1,o=0;o<t.length;o++)if(e[s].assert.name===t[o].assert.name){a=!0;break}a?r.push(e[s]):n.push(e[s])}return{kept:r,added:n,removed:i?[]:T(t,e,!0).added}};y.Form={_actualizeTriggers:function(){var e=this;this.$element.on("submit.Parsley",function(t){e.onSubmitValidate(t)}),this.$element.on("click.Parsley",'input[type="submit"], button[type="submit"]',function(t){e.onSubmitButton(t)}),!1!==this.options.uiEnabled&&this.$element.attr("novalidate","")},focus:function(){if(this._focusedField=null,!0===this.validationResult||"none"===this.options.focus)return null;for(var e=0;e<this.fields.length;e++){var t=this.fields[e];if(!0!==t.validationResult&&t.validationResult.length>0&&"undefined"==typeof t.options.noFocus&&(this._focusedField=t.$element,"first"===this.options.focus))break}return null===this._focusedField?null:this._focusedField.focus()},_destroyUI:function(){this.$element.off(".Parsley")}},y.Field={_reflowUI:function(){if(this._buildUI(),this._ui){var e=v(this.validationResult,this._ui.lastValidationResult);this._ui.lastValidationResult=this.validationResult,this._manageStatusClass(),this._manageErrorsMessages(e),this._actualizeTriggers(),!e.kept.length&&!e.added.length||this._failedOnce||(this._failedOnce=!0,this._actualizeTriggers())}},getErrorsMessages:function(){if(!0===this.validationResult)return[];for(var e=[],t=0;t<this.validationResult.length;t++)e.push(this.validationResult[t].errorMessage||this._getErrorMessage(this.validationResult[t].assert));return e},addError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.message,n=t.assert,r=t.updateClass,s=void 0===r?!0:r;this._buildUI(),this._addError(e,{message:i,assert:n}),s&&this._errorClass()},updateError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.message,n=t.assert,r=t.updateClass,s=void 0===r?!0:r;this._buildUI(),this._updateError(e,{message:i,assert:n}),s&&this._errorClass()},removeError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.updateClass,n=void 0===i?!0:i;this._buildUI(),this._removeError(e),n&&this._manageStatusClass()},_manageStatusClass:function(){this.hasConstraints()&&this.needsValidation()&&!0===this.validationResult?this._successClass():this.validationResult.length>0?this._errorClass():this._resetClass()},_manageErrorsMessages:function(t){if("undefined"==typeof this.options.errorsMessagesDisabled){if("undefined"!=typeof this.options.errorMessage)return t.added.length||t.kept.length?(this._insertErrorWrapper(),0===this._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&this._ui.$errorsWrapper.append(e(this.options.errorTemplate).addClass("parsley-custom-error-message")),this._ui.$errorsWrapper.addClass("filled").find(".parsley-custom-error-message").html(this.options.errorMessage)):this._ui.$errorsWrapper.removeClass("filled").find(".parsley-custom-error-message").remove();for(var i=0;i<t.removed.length;i++)this._removeError(t.removed[i].assert.name);for(i=0;i<t.added.length;i++)this._addError(t.added[i].assert.name,{message:t.added[i].errorMessage,assert:t.added[i].assert});for(i=0;i<t.kept.length;i++)this._updateError(t.kept[i].assert.name,{message:t.kept[i].errorMessage,assert:t.kept[i].assert})}},_addError:function(t,i){var n=i.message,r=i.assert;this._insertErrorWrapper(),this._ui.$errorsWrapper.addClass("filled").append(e(this.options.errorTemplate).addClass("parsley-"+t).html(n||this._getErrorMessage(r)))},_updateError:function(e,t){var i=t.message,n=t.assert;this._ui.$errorsWrapper.addClass("filled").find(".parsley-"+e).html(i||this._getErrorMessage(n))},_removeError:function(e){this._ui.$errorsWrapper.removeClass("filled").find(".parsley-"+e).remove()},_getErrorMessage:function(e){var t=e.name+"Message";return"undefined"!=typeof this.options[t]?window.Parsley.formatMessage(this.options[t],e.requirements):window.Parsley.getErrorMessage(e)},_buildUI:function(){if(!this._ui&&!1!==this.options.uiEnabled){var t={};this.$element.attr(this.options.namespace+"id",this.__id__),t.$errorClassHandler=this._manageClassHandler(),t.errorsWrapperId="parsley-id-"+(this.options.multiple?"multiple-"+this.options.multiple:this.__id__),t.$errorsWrapper=e(this.options.errorsWrapper).attr("id",t.errorsWrapperId),t.lastValidationResult=[],t.validationInformationVisible=!1,this._ui=t}},_manageClassHandler:function(){if("string"==typeof this.options.classHandler&&e(this.options.classHandler).length)return e(this.options.classHandler);var t=this.options.classHandler.call(this,this);return"undefined"!=typeof t&&t.length?t:!this.options.multiple||this.$element.is("select")?this.$element:this.$element.parent()},_insertErrorWrapper:function(){var t;if(0!==this._ui.$errorsWrapper.parent().length)return this._ui.$errorsWrapper.parent();if("string"==typeof this.options.errorsContainer){if(e(this.options.errorsContainer).length)return e(this.options.errorsContainer).append(this._ui.$errorsWrapper);a.warn("The errors container `"+this.options.errorsContainer+"` does not exist in DOM")}else"function"==typeof this.options.errorsContainer&&(t=this.options.errorsContainer.call(this,this));if("undefined"!=typeof t&&t.length)return t.append(this._ui.$errorsWrapper);var i=this.$element;return this.options.multiple&&(i=i.parent()),i.after(this._ui.$errorsWrapper)},_actualizeTriggers:function(){var e=this,t=this._findRelated();t.off(".Parsley"),this._failedOnce?t.on(a.namespaceEvents(this.options.triggerAfterFailure,"Parsley"),function(){e.validate()}):t.on(a.namespaceEvents(this.options.trigger,"Parsley"),function(t){e._eventValidate(t)})},_eventValidate:function(e){(!/key|input/.test(e.type)||this._ui&&this._ui.validationInformationVisible||!(this.getValue().length<=this.options.validationThreshold))&&this.validate()},_resetUI:function(){this._failedOnce=!1,this._actualizeTriggers(),"undefined"!=typeof this._ui&&(this._ui.$errorsWrapper.removeClass("filled").children().remove(),this._resetClass(),this._ui.lastValidationResult=[],this._ui.validationInformationVisible=!1)},_destroyUI:function(){this._resetUI(),"undefined"!=typeof this._ui&&this._ui.$errorsWrapper.remove(),delete this._ui},_successClass:function(){this._ui.validationInformationVisible=!0,this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass)},_errorClass:function(){this._ui.validationInformationVisible=!0,this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass)},_resetClass:function(){this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass)}};var _=function(t,i,n){this.__class__="ParsleyForm",this.__id__=a.generateID(),this.$element=e(t),this.domOptions=i,this.options=n,this.parent=window.Parsley,this.fields=[],this.validationResult=null},w={pending:null,resolved:!0,rejected:!1};_.prototype={onSubmitValidate:function(e){var t=this;if(!0!==e.parsley){var i=this._$submitSource||this.$element.find('input[type="submit"], button[type="submit"]').first();if(this._$submitSource=null,this.$element.find(".parsley-synthetic-submit-button").prop("disabled",!0),!i.is("[formnovalidate]")){var n=this.whenValidate({event:e});"resolved"===n.state()&&!1!==this._trigger("submit")||(e.stopImmediatePropagation(),e.preventDefault(),"pending"===n.state()&&n.done(function(){t._submit(i)}))}}},onSubmitButton:function(t){this._$submitSource=e(t.target)},_submit:function(t){if(!1!==this._trigger("submit")){if(t){var i=this.$element.find(".parsley-synthetic-submit-button").prop("disabled",!1);0===i.length&&(i=e('<input class="parsley-synthetic-submit-button" type="hidden">').appendTo(this.$element)),i.attr({name:t.attr("name"),value:t.attr("value")})}this.$element.trigger(e.extend(e.Event("submit"),{parsley:!0}))}},validate:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling validate on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1],s=i[2];t={group:n,force:r,event:s}}return w[this.whenValidate(t).state()]},whenValidate:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force,s=i.event;this.submitEvent=s,s&&(this.submitEvent=e.extend({},s,{preventDefault:function(){a.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"),t.validationResult=!1}})),this.validationResult=!0,this._trigger("validate"),this._refreshFields();var o=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValidate({force:r,group:n})})}),l=function(){var i=e.Deferred();return!1===t.validationResult&&i.reject(),i.resolve().promise()};return e.when.apply(e,_toConsumableArray(o)).done(function(){t._trigger("success")}).fail(function(){t.validationResult=!1,t.focus(),t._trigger("error")}).always(function(){t._trigger("validated")}).pipe(l,l)},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={group:n,force:r}}return w[this.whenValid(t).state()]},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force;this._refreshFields();var s=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValid({group:n,force:r})})});return e.when.apply(e,_toConsumableArray(s))},_refreshFields:function(){return this.actualizeOptions()._bindFields()},_bindFields:function(){var t=this,i=this.fields;return this.fields=[],this.fieldsMappedById={},this._withoutReactualizingFormOptions(function(){t.$element.find(t.options.inputs).not(t.options.excluded).each(function(e,i){var n=new window.Parsley.Factory(i,{},t);"ParsleyField"!==n.__class__&&"ParsleyFieldMultiple"!==n.__class__||!0===n.options.excluded||"undefined"==typeof t.fieldsMappedById[n.__class__+"-"+n.__id__]&&(t.fieldsMappedById[n.__class__+"-"+n.__id__]=n,t.fields.push(n))}),e(i).not(t.fields).each(function(e,t){t._trigger("reset")})}),this},_withoutReactualizingFormOptions:function(e){var t=this.actualizeOptions;this.actualizeOptions=function(){return this};var i=e();return this.actualizeOptions=t,i},_trigger:function(e){return this.trigger("form:"+e)}};var b=function(t,i,n,r,s){if(!/ParsleyField/.test(t.__class__))throw new Error("ParsleyField or ParsleyFieldMultiple instance expected");var a=window.Parsley._validatorRegistry.validators[i],o=new f(a);e.extend(this,{validator:o,name:i,requirements:n,priority:r||t.options[i+"Priority"]||o.priority,isDomConstraint:!0===s}),this._parseRequirements(t.options)},F=function(e){var t=e[0].toUpperCase();return t+e.slice(1)};b.prototype={validate:function(e,t){var i=this.requirementList.slice(0);return i.unshift(e),i.push(t),this.validator.validate.apply(this.validator,i)},_parseRequirements:function(e){var t=this;this.requirementList=this.validator.parseRequirements(this.requirements,function(i){return e[t.name+F(i)]})}};var C=function(t,i,n,r){this.__class__="ParsleyField",this.__id__=a.generateID(),this.$element=e(t),"undefined"!=typeof r&&(this.parent=r),this.options=n,this.domOptions=i,this.constraints=[],this.constraintsByName={},this.validationResult=[],this._bindConstraints()},$={pending:null,resolved:!0,rejected:!1};C.prototype={validate:function(t){arguments.length>=1&&!e.isPlainObject(t)&&(a.warnOnce("Calling validate on a parsley field without passing arguments as an object is deprecated."),t={options:t});var i=this.whenValidate(t);if(!i)return!0;switch(i.state()){case"pending":return null;case"resolved":return!0;case"rejected":return this.validationResult}},whenValidate:function(){var e=this,t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],i=t.force,n=t.group;return this.refreshConstraints(),!n||this._isInGroup(n)?(this.value=this.getValue(),this._trigger("validate"),this.whenValid({force:i,value:this.value,_refreshed:!0}).always(function(){e._reflowUI()}).done(function(){e._trigger("success")}).fail(function(){e._trigger("error")}).always(function(){e._trigger("validated")})):void 0},hasConstraints:function(){return 0!==this.constraints.length},needsValidation:function(e){return"undefined"==typeof e&&(e=this.getValue()),e.length||this._isRequired()||"undefined"!=typeof this.options.validateIfEmpty?!0:!1},_isInGroup:function(t){return e.isArray(this.options.group)?-1!==e.inArray(t,this.options.group):this.options.group===t},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley field without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={force:n,value:r}}var s=this.whenValid(t);return s?$[s.state()]:!0},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.force,r=void 0===n?!1:n,s=i.value,a=i.group,o=i._refreshed;if(o||this.refreshConstraints(),!a||this._isInGroup(a)){if(this.validationResult=!0,!this.hasConstraints())return e.when();if(("undefined"==typeof s||null===s)&&(s=this.getValue()),!this.needsValidation(s)&&!0!==r)return e.when();var l=this._getGroupedConstraints(),u=[];return e.each(l,function(i,n){var r=e.when.apply(e,_toConsumableArray(e.map(n,function(e){return t._validateConstraint(s,e)})));return u.push(r),"rejected"===r.state()?!1:void 0}),e.when.apply(e,u)}},_validateConstraint:function(t,i){var n=this,r=i.validate(t,this);return!1===r&&(r=e.Deferred().reject()),e.when(r).fail(function(e){!0===n.validationResult&&(n.validationResult=[]),n.validationResult.push({assert:i,errorMessage:"string"==typeof e&&e})})},getValue:function(){var e;return e="function"==typeof this.options.value?this.options.value(this):"undefined"!=typeof this.options.value?this.options.value:this.$element.val(),"undefined"==typeof e||null===e?"":this._handleWhitespace(e)},refreshConstraints:function(){return this.actualizeOptions()._bindConstraints()},addConstraint:function(e,t,i,n){if(window.Parsley._validatorRegistry.validators[e]){var r=new b(this,e,t,i,n);"undefined"!==this.constraintsByName[r.name]&&this.removeConstraint(r.name),this.constraints.push(r),this.constraintsByName[r.name]=r}return this},removeConstraint:function(e){for(var t=0;t<this.constraints.length;t++)if(e===this.constraints[t].name){this.constraints.splice(t,1);break}return delete this.constraintsByName[e],this},updateConstraint:function(e,t,i){return this.removeConstraint(e).addConstraint(e,t,i)},_bindConstraints:function(){for(var e=[],t={},i=0;i<this.constraints.length;i++)!1===this.constraints[i].isDomConstraint&&(e.push(this.constraints[i]),t[this.constraints[i].name]=this.constraints[i]);this.constraints=e,this.constraintsByName=t;for(var n in this.options)this.addConstraint(n,this.options[n],void 0,!0);return this._bindHtml5Constraints()},_bindHtml5Constraints:function(){(this.$element.hasClass("required")||this.$element.attr("required"))&&this.addConstraint("required",!0,void 0,!0),"string"==typeof this.$element.attr("pattern")&&this.addConstraint("pattern",this.$element.attr("pattern"),void 0,!0),"undefined"!=typeof this.$element.attr("min")&&"undefined"!=typeof this.$element.attr("max")?this.addConstraint("range",[this.$element.attr("min"),this.$element.attr("max")],void 0,!0):"undefined"!=typeof this.$element.attr("min")?this.addConstraint("min",this.$element.attr("min"),void 0,!0):"undefined"!=typeof this.$element.attr("max")&&this.addConstraint("max",this.$element.attr("max"),void 0,!0),"undefined"!=typeof this.$element.attr("minlength")&&"undefined"!=typeof this.$element.attr("maxlength")?this.addConstraint("length",[this.$element.attr("minlength"),this.$element.attr("maxlength")],void 0,!0):"undefined"!=typeof this.$element.attr("minlength")?this.addConstraint("minlength",this.$element.attr("minlength"),void 0,!0):"undefined"!=typeof this.$element.attr("maxlength")&&this.addConstraint("maxlength",this.$element.attr("maxlength"),void 0,!0);var e=this.$element.attr("type");return"undefined"==typeof e?this:"number"===e?this.addConstraint("type",["number",{step:this.$element.attr("step"),base:this.$element.attr("min")||this.$element.attr("value")}],void 0,!0):/^(email|url|range)$/i.test(e)?this.addConstraint("type",e,void 0,!0):this},_isRequired:function(){return"undefined"==typeof this.constraintsByName.required?!1:!1!==this.constraintsByName.required.requirements},_trigger:function(e){return this.trigger("field:"+e)},_handleWhitespace:function(e){return!0===this.options.trimValue&&a.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"'),"squish"===this.options.whitespace&&(e=e.replace(/\s{2,}/g," ")),("trim"===this.options.whitespace||"squish"===this.options.whitespace||!0===this.options.trimValue)&&(e=a.trimString(e)),e},_getGroupedConstraints:function(){if(!1===this.options.priorityEnabled)return[this.constraints];for(var e=[],t={},i=0;i<this.constraints.length;i++){var n=this.constraints[i].priority;t[n]||e.push(t[n]=[]),t[n].push(this.constraints[i])}return e.sort(function(e,t){return t[0].priority-e[0].priority}),e}};var x=C,P=function(){this.__class__="ParsleyFieldMultiple"};P.prototype={addElement:function(e){return this.$elements.push(e),this},refreshConstraints:function(){var t;if(this.constraints=[],this.$element.is("select"))return this.actualizeOptions()._bindConstraints(),this;for(var i=0;i<this.$elements.length;i++)if(e("html").has(this.$elements[i]).length){t=this.$elements[i].data("ParsleyFieldMultiple").refreshConstraints().constraints;for(var n=0;n<t.length;n++)this.addConstraint(t[n].name,t[n].requirements,t[n].priority,t[n].isDomConstraint)}else this.$elements.splice(i,1);return this},getValue:function(){if("function"==typeof this.options.value)value=this.options.value(this);else if("undefined"!=typeof this.options.value)return this.options.value;if(this.$element.is("input[type=radio]"))return this._findRelated().filter(":checked").val()||"";if(this.$element.is("input[type=checkbox]")){var t=[];return this._findRelated().filter(":checked").each(function(){t.push(e(this).val())}),t}return this.$element.is("select")&&null===this.$element.val()?[]:this.$element.val()},_init:function(){return this.$elements=[this.$element],this}};var E=function(t,i,n){this.$element=e(t);var r=this.$element.data("Parsley");if(r)return"undefined"!=typeof n&&r.parent===window.Parsley&&(r.parent=n,r._resetOptions(r.options)),r;if(!this.$element.length)throw new Error("You must bind Parsley on an existing element.");if("undefined"!=typeof n&&"ParsleyForm"!==n.__class__)throw new Error("Parent instance must be a ParsleyForm instance");return this.parent=n||window.Parsley,this.init(i)};E.prototype={init:function(e){return this.__class__="Parsley",this.__version__="2.3.5",this.__id__=a.generateID(),this._resetOptions(e),this.$element.is("form")||a.checkAttr(this.$element,this.options.namespace,"validate")&&!this.$element.is(this.options.inputs)?this.bind("parsleyForm"):this.isMultiple()?this.handleMultiple():this.bind("parsleyField")},isMultiple:function(){return this.$element.is("input[type=radio], input[type=checkbox]")||this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple")},handleMultiple:function(){var t,i,n=this;if(this.options.multiple||("undefined"!=typeof this.$element.attr("name")&&this.$element.attr("name").length?this.options.multiple=t=this.$element.attr("name"):"undefined"!=typeof this.$element.attr("id")&&this.$element.attr("id").length&&(this.options.multiple=this.$element.attr("id"))),this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple"))return this.options.multiple=this.options.multiple||this.__id__,this.bind("parsleyFieldMultiple");if(!this.options.multiple)return a.warn("To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.",this.$element),this;this.options.multiple=this.options.multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g,""),
168
  "undefined"!=typeof t&&e('input[name="'+t+'"]').each(function(t,i){e(i).is("input[type=radio], input[type=checkbox]")&&e(i).attr(n.options.namespace+"multiple",n.options.multiple)});for(var r=this._findRelated(),s=0;s<r.length;s++)if(i=e(r.get(s)).data("Parsley"),"undefined"!=typeof i){this.$element.data("ParsleyFieldMultiple")||i.addElement(this.$element);break}return this.bind("parsleyField",!0),i||this.bind("parsleyFieldMultiple")},bind:function(t,i){var n;switch(t){case"parsleyForm":n=e.extend(new _(this.$element,this.domOptions,this.options),window.ParsleyExtend)._bindFields();break;case"parsleyField":n=e.extend(new x(this.$element,this.domOptions,this.options,this.parent),window.ParsleyExtend);break;case"parsleyFieldMultiple":n=e.extend(new x(this.$element,this.domOptions,this.options,this.parent),new P,window.ParsleyExtend)._init();break;default:throw new Error(t+"is not a supported Parsley type")}return this.options.multiple&&a.setAttr(this.$element,this.options.namespace,"multiple",this.options.multiple),"undefined"!=typeof i?(this.$element.data("ParsleyFieldMultiple",n),n):(this.$element.data("Parsley",n),n._actualizeTriggers(),n._trigger("init"),n)}};var V=e.fn.jquery.split(".");if(parseInt(V[0])<=1&&parseInt(V[1])<8)throw"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.";V.forEach||a.warn("Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim");var M=e.extend(new l,{$element:e(document),actualizeOptions:null,_resetOptions:null,Factory:E,version:"2.3.5"});e.extend(x.prototype,y.Field,l.prototype),e.extend(_.prototype,y.Form,l.prototype),e.extend(E.prototype,l.prototype),e.fn.parsley=e.fn.psly=function(t){if(this.length>1){var i=[];return this.each(function(){i.push(e(this).parsley(t))}),i}return e(this).length?new E(this,t):void a.warn("You must bind Parsley on an existing element.")},"undefined"==typeof window.ParsleyExtend&&(window.ParsleyExtend={}),M.options=e.extend(a.objectCreate(o),window.ParsleyConfig),window.ParsleyConfig=M.options,window.Parsley=window.psly=M,window.ParsleyUtils=a;var O=window.Parsley._validatorRegistry=new c(window.ParsleyConfig.validators,window.ParsleyConfig.i18n);window.ParsleyValidator={},e.each("setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator".split(" "),function(t,i){window.Parsley[i]=e.proxy(O,i),window.ParsleyValidator[i]=function(){var e;return a.warnOnce("Accessing the method '"+i+"' through ParsleyValidator is deprecated. Simply call 'window.Parsley."+i+"(...)'"),(e=window.Parsley)[i].apply(e,arguments)}}),window.Parsley.UI=y,window.ParsleyUI={removeError:function(e,t,i){var n=!0!==i;return a.warnOnce("Accessing ParsleyUI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e.removeError(t,{updateClass:n})},getErrorsMessages:function(e){return a.warnOnce("Accessing ParsleyUI is deprecated. Call 'getErrorsMessages' on the instance directly."),e.getErrorsMessages()}},e.each("addError updateError".split(" "),function(e,t){window.ParsleyUI[t]=function(e,i,n,r,s){var o=!0!==s;return a.warnOnce("Accessing ParsleyUI is deprecated. Call '"+t+"' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e[t](i,{message:n,assert:r,updateClass:o})}}),/firefox/i.test(navigator.userAgent)&&e(document).on("change","select",function(t){e(t.target).trigger("input")}),!1!==window.ParsleyConfig.autoBind&&e(function(){e("[data-parsley-validate]").length&&e("[data-parsley-validate]").parsley()});var A=e({}),R=function(){a.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley")},D="parsley:";e.listen=function(e,n){var r;if(R(),"object"==typeof arguments[1]&&"function"==typeof arguments[2]&&(r=arguments[1],n=arguments[2]),"function"!=typeof n)throw new Error("Wrong parameters");window.Parsley.on(i(e),t(n,r))},e.listenTo=function(e,n,r){if(R(),!(e instanceof x||e instanceof _))throw new Error("Must give Parsley instance");if("string"!=typeof n||"function"!=typeof r)throw new Error("Wrong parameters");e.on(i(n),t(r))},e.unsubscribe=function(e,t){if(R(),"string"!=typeof e||"function"!=typeof t)throw new Error("Wrong arguments");window.Parsley.off(i(e),t.parsleyAdaptedCallback)},e.unsubscribeTo=function(e,t){if(R(),!(e instanceof x||e instanceof _))throw new Error("Must give Parsley instance");e.off(i(t))},e.unsubscribeAll=function(t){R(),window.Parsley.off(i(t)),e("form,input,textarea,select").each(function(){var n=e(this).data("Parsley");n&&n.off(i(t))})},e.emit=function(e,t){var n;R();var r=t instanceof x||t instanceof _,s=Array.prototype.slice.call(arguments,r?2:1);s.unshift(i(e)),r||(t=window.Parsley),(n=t).trigger.apply(n,_toConsumableArray(s))};e.extend(!0,M,{asyncValidators:{"default":{fn:function(e){return e.status>=200&&e.status<300},url:!1},reverse:{fn:function(e){return e.status<200||e.status>=300},url:!1}},addAsyncValidator:function(e,t,i,n){return M.asyncValidators[e]={fn:t,url:i||!1,options:n||{}},this}}),M.addValidator("remote",{requirementType:{"":"string",validator:"string",reverse:"boolean",options:"object"},validateString:function(t,i,n,r){var s,a,o={},l=n.validator||(!0===n.reverse?"reverse":"default");if("undefined"==typeof M.asyncValidators[l])throw new Error("Calling an undefined async validator: `"+l+"`");i=M.asyncValidators[l].url||i,i.indexOf("{value}")>-1?i=i.replace("{value}",encodeURIComponent(t)):o[r.$element.attr("name")||r.$element.attr("id")]=t;var u=e.extend(!0,n.options||{},M.asyncValidators[l].options);s=e.extend(!0,{},{url:i,data:o,type:"GET"},u),r.trigger("field:ajaxoptions",r,s),a=e.param(s),"undefined"==typeof M._remoteCache&&(M._remoteCache={});var d=M._remoteCache[a]=M._remoteCache[a]||e.ajax(s),h=function(){var t=M.asyncValidators[l].fn.call(r,d,i,n);return t||(t=e.Deferred().reject()),e.when(t)};return d.then(h,h)},priority:-1}),M.on("form:submit",function(){M._remoteCache={}}),window.ParsleyExtend.addAsyncValidator=function(){return ParsleyUtils.warnOnce("Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`"),M.addAsyncValidator.apply(M,arguments)},M.addMessages("en",{defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",number:"This value should be a valid number.",integer:"This value should be a valid integer.",digits:"This value should be digits.",alphanum:"This value should be alphanumeric."},notblank:"This value should not be blank.",required:"This value is required.",pattern:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or fewer.",length:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or fewer.",check:"You must select between %s and %s choices.",equalto:"This value should be the same."}),M.setLocale("en");var q=M;return q});
169
- //# sourceMappingURL=parsley.min.js.map
170
  </script>
171
 
172
 
@@ -186,5 +185,4 @@ f.push(" != null ? helper : ",this.aliasable("helpers.helperMissing"))),this.pus
186
 
187
  !function(a,b,c){!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):jQuery&&!jQuery.fn.qtip&&a(jQuery)}(function(d){"use strict";function e(a,b,c,e){this.id=c,this.target=a,this.tooltip=F,this.elements={target:a},this._id=S+"-"+c,this.timers={img:{}},this.options=b,this.plugins={},this.cache={event:{},target:d(),disabled:E,attr:e,onTooltip:E,lastClass:""},this.rendered=this.destroyed=this.disabled=this.waiting=this.hiddenDuringWait=this.positioning=this.triggering=E}function f(a){return a===F||"object"!==d.type(a)}function g(a){return!(d.isFunction(a)||a&&a.attr||a.length||"object"===d.type(a)&&(a.jquery||a.then))}function h(a){var b,c,e,h;return f(a)?E:(f(a.metadata)&&(a.metadata={type:a.metadata}),"content"in a&&(b=a.content,f(b)||b.jquery||b.done?b=a.content={text:c=g(b)?E:b}:c=b.text,"ajax"in b&&(e=b.ajax,h=e&&e.once!==E,delete b.ajax,b.text=function(a,b){var f=c||d(this).attr(b.options.content.attr)||"Loading...",g=d.ajax(d.extend({},e,{context:b})).then(e.success,F,e.error).then(function(a){return a&&h&&b.set("content.text",a),a},function(a,c,d){b.destroyed||0===a.status||b.set("content.text",c+": "+d)});return h?f:(b.set("content.text",f),g)}),"title"in b&&(d.isPlainObject(b.title)&&(b.button=b.title.button,b.title=b.title.text),g(b.title||E)&&(b.title=E))),"position"in a&&f(a.position)&&(a.position={my:a.position,at:a.position}),"show"in a&&f(a.show)&&(a.show=a.show.jquery?{target:a.show}:a.show===D?{ready:D}:{event:a.show}),"hide"in a&&f(a.hide)&&(a.hide=a.hide.jquery?{target:a.hide}:{event:a.hide}),"style"in a&&f(a.style)&&(a.style={classes:a.style}),d.each(R,function(){this.sanitize&&this.sanitize(a)}),a)}function i(a,b){for(var c,d=0,e=a,f=b.split(".");e=e[f[d++]];)d<f.length&&(c=e);return[c||a,f.pop()]}function j(a,b){var c,d,e;for(c in this.checks)for(d in this.checks[c])(e=new RegExp(d,"i").exec(a))&&(b.push(e),("builtin"===c||this.plugins[c])&&this.checks[c][d].apply(this.plugins[c]||this,b))}function k(a){return V.concat("").join(a?"-"+a+" ":" ")}function l(a,b){return b>0?setTimeout(d.proxy(a,this),b):void a.call(this)}function m(a){this.tooltip.hasClass(ab)||(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this.timers.show=l.call(this,function(){this.toggle(D,a)},this.options.show.delay))}function n(a){if(!this.tooltip.hasClass(ab)&&!this.destroyed){var b=d(a.relatedTarget),c=b.closest(W)[0]===this.tooltip[0],e=b[0]===this.options.show.target[0];if(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this!==b[0]&&"mouse"===this.options.position.target&&c||this.options.hide.fixed&&/mouse(out|leave|move)/.test(a.type)&&(c||e))try{a.preventDefault(),a.stopImmediatePropagation()}catch(f){}else this.timers.hide=l.call(this,function(){this.toggle(E,a)},this.options.hide.delay,this)}}function o(a){!this.tooltip.hasClass(ab)&&this.options.hide.inactive&&(clearTimeout(this.timers.inactive),this.timers.inactive=l.call(this,function(){this.hide(a)},this.options.hide.inactive))}function p(a){this.rendered&&this.tooltip[0].offsetWidth>0&&this.reposition(a)}function q(a,c,e){d(b.body).delegate(a,(c.split?c:c.join("."+S+" "))+"."+S,function(){var a=y.api[d.attr(this,U)];a&&!a.disabled&&e.apply(a,arguments)})}function r(a,c,f){var g,i,j,k,l,m=d(b.body),n=a[0]===b?m:a,o=a.metadata?a.metadata(f.metadata):F,p="html5"===f.metadata.type&&o?o[f.metadata.name]:F,q=a.data(f.metadata.name||"qtipopts");try{q="string"==typeof q?d.parseJSON(q):q}catch(r){}if(k=d.extend(D,{},y.defaults,f,"object"==typeof q?h(q):F,h(p||o)),i=k.position,k.id=c,"boolean"==typeof k.content.text){if(j=a.attr(k.content.attr),k.content.attr===E||!j)return E;k.content.text=j}if(i.container.length||(i.container=m),i.target===E&&(i.target=n),k.show.target===E&&(k.show.target=n),k.show.solo===D&&(k.show.solo=i.container.closest("body")),k.hide.target===E&&(k.hide.target=n),k.position.viewport===D&&(k.position.viewport=i.container),i.container=i.container.eq(0),i.at=new A(i.at,D),i.my=new A(i.my),a.data(S))if(k.overwrite)a.qtip("destroy",!0);else if(k.overwrite===E)return E;return a.attr(T,c),k.suppress&&(l=a.attr("title"))&&a.removeAttr("title").attr(cb,l).attr("title",""),g=new e(a,k,c,!!j),a.data(S,g),g}function s(a){return a.charAt(0).toUpperCase()+a.slice(1)}function t(a,b){var d,e,f=b.charAt(0).toUpperCase()+b.slice(1),g=(b+" "+rb.join(f+" ")+f).split(" "),h=0;if(qb[b])return a.css(qb[b]);for(;d=g[h++];)if((e=a.css(d))!==c)return qb[b]=d,e}function u(a,b){return Math.ceil(parseFloat(t(a,b)))}function v(a,b){this._ns="tip",this.options=b,this.offset=b.offset,this.size=[b.width,b.height],this.init(this.qtip=a)}function w(a,b){this.options=b,this._ns="-modal",this.init(this.qtip=a)}function x(a){this._ns="ie6",this.init(this.qtip=a)}var y,z,A,B,C,D=!0,E=!1,F=null,G="x",H="y",I="width",J="height",K="top",L="left",M="bottom",N="right",O="center",P="flipinvert",Q="shift",R={},S="qtip",T="data-hasqtip",U="data-qtip-id",V=["ui-widget","ui-tooltip"],W="."+S,X="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),Y=S+"-fixed",Z=S+"-default",$=S+"-focus",_=S+"-hover",ab=S+"-disabled",bb="_replacedByqTip",cb="oldtitle",db={ie:function(){for(var a=4,c=b.createElement("div");(c.innerHTML="<!--[if gt IE "+a+"]><i></i><![endif]-->")&&c.getElementsByTagName("i")[0];a+=1);return a>4?a:0/0}(),iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||E};z=e.prototype,z._when=function(a){return d.when.apply(d,a)},z.render=function(a){if(this.rendered||this.destroyed)return this;var b,c=this,e=this.options,f=this.cache,g=this.elements,h=e.content.text,i=e.content.title,j=e.content.button,k=e.position,l=("."+this._id+" ",[]);return d.attr(this.target[0],"aria-describedby",this._id),f.posClass=this._createPosClass((this.position={my:k.my,at:k.at}).my),this.tooltip=g.tooltip=b=d("<div/>",{id:this._id,"class":[S,Z,e.style.classes,f.posClass].join(" "),width:e.style.width||"",height:e.style.height||"",tracking:"mouse"===k.target&&k.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":E,"aria-describedby":this._id+"-content","aria-hidden":D}).toggleClass(ab,this.disabled).attr(U,this.id).data(S,this).appendTo(k.container).append(g.content=d("<div />",{"class":S+"-content",id:this._id+"-content","aria-atomic":D})),this.rendered=-1,this.positioning=D,i&&(this._createTitle(),d.isFunction(i)||l.push(this._updateTitle(i,E))),j&&this._createButton(),d.isFunction(h)||l.push(this._updateContent(h,E)),this.rendered=D,this._setWidget(),d.each(R,function(a){var b;"render"===this.initialize&&(b=this(c))&&(c.plugins[a]=b)}),this._unassignEvents(),this._assignEvents(),this._when(l).then(function(){c._trigger("render"),c.positioning=E,c.hiddenDuringWait||!e.show.ready&&!a||c.toggle(D,f.event,E),c.hiddenDuringWait=E}),y.api[this.id]=this,this},z.destroy=function(a){function b(){if(!this.destroyed){this.destroyed=D;var a,b=this.target,c=b.attr(cb);this.rendered&&this.tooltip.stop(1,0).find("*").remove().end().remove(),d.each(this.plugins,function(){this.destroy&&this.destroy()});for(a in this.timers)clearTimeout(this.timers[a]);b.removeData(S).removeAttr(U).removeAttr(T).removeAttr("aria-describedby"),this.options.suppress&&c&&b.attr("title",c).removeAttr(cb),this._unassignEvents(),this.options=this.elements=this.cache=this.timers=this.plugins=this.mouse=F,delete y.api[this.id]}}return this.destroyed?this.target:(a===D&&"hide"!==this.triggering||!this.rendered?b.call(this):(this.tooltip.one("tooltiphidden",d.proxy(b,this)),!this.triggering&&this.hide()),this.target)},B=z.checks={builtin:{"^id$":function(a,b,c,e){var f=c===D?y.nextid:c,g=S+"-"+f;f!==E&&f.length>0&&!d("#"+g).length?(this._id=g,this.rendered&&(this.tooltip[0].id=this._id,this.elements.content[0].id=this._id+"-content",this.elements.title[0].id=this._id+"-title")):a[b]=e},"^prerender":function(a,b,c){c&&!this.rendered&&this.render(this.options.show.ready)},"^content.text$":function(a,b,c){this._updateContent(c)},"^content.attr$":function(a,b,c,d){this.options.content.text===this.target.attr(d)&&this._updateContent(this.target.attr(c))},"^content.title$":function(a,b,c){return c?(c&&!this.elements.title&&this._createTitle(),void this._updateTitle(c)):this._removeTitle()},"^content.button$":function(a,b,c){this._updateButton(c)},"^content.title.(text|button)$":function(a,b,c){this.set("content."+b,c)},"^position.(my|at)$":function(a,b,c){"string"==typeof c&&(this.position[b]=a[b]=new A(c,"at"===b))},"^position.container$":function(a,b,c){this.rendered&&this.tooltip.appendTo(c)},"^show.ready$":function(a,b,c){c&&(!this.rendered&&this.render(D)||this.toggle(D))},"^style.classes$":function(a,b,c,d){this.rendered&&this.tooltip.removeClass(d).addClass(c)},"^style.(width|height)":function(a,b,c){this.rendered&&this.tooltip.css(b,c)},"^style.widget|content.title":function(){this.rendered&&this._setWidget()},"^style.def":function(a,b,c){this.rendered&&this.tooltip.toggleClass(Z,!!c)},"^events.(render|show|move|hide|focus|blur)$":function(a,b,c){this.rendered&&this.tooltip[(d.isFunction(c)?"":"un")+"bind"]("tooltip"+b,c)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){if(this.rendered){var a=this.options.position;this.tooltip.attr("tracking","mouse"===a.target&&a.adjust.mouse),this._unassignEvents(),this._assignEvents()}}}},z.get=function(a){if(this.destroyed)return this;var b=i(this.options,a.toLowerCase()),c=b[0][b[1]];return c.precedance?c.string():c};var eb=/^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,fb=/^prerender|show\.ready/i;z.set=function(a,b){if(this.destroyed)return this;{var c,e=this.rendered,f=E,g=this.options;this.checks}return"string"==typeof a?(c=a,a={},a[c]=b):a=d.extend({},a),d.each(a,function(b,c){if(e&&fb.test(b))return void delete a[b];var h,j=i(g,b.toLowerCase());h=j[0][j[1]],j[0][j[1]]=c&&c.nodeType?d(c):c,f=eb.test(b)||f,a[b]=[j[0],j[1],c,h]}),h(g),this.positioning=D,d.each(a,d.proxy(j,this)),this.positioning=E,this.rendered&&this.tooltip[0].offsetWidth>0&&f&&this.reposition("mouse"===g.position.target?F:this.cache.event),this},z._update=function(a,b){var c=this,e=this.cache;return this.rendered&&a?(d.isFunction(a)&&(a=a.call(this.elements.target,e.event,this)||""),d.isFunction(a.then)?(e.waiting=D,a.then(function(a){return e.waiting=E,c._update(a,b)},F,function(a){return c._update(a,b)})):a===E||!a&&""!==a?E:(a.jquery&&a.length>0?b.empty().append(a.css({display:"block",visibility:"visible"})):b.html(a),this._waitForContent(b).then(function(a){c.rendered&&c.tooltip[0].offsetWidth>0&&c.reposition(e.event,!a.length)}))):E},z._waitForContent=function(a){var b=this.cache;return b.waiting=D,(d.fn.imagesLoaded?a.imagesLoaded():d.Deferred().resolve([])).done(function(){b.waiting=E}).promise()},z._updateContent=function(a,b){this._update(a,this.elements.content,b)},z._updateTitle=function(a,b){this._update(a,this.elements.title,b)===E&&this._removeTitle(E)},z._createTitle=function(){var a=this.elements,b=this._id+"-title";a.titlebar&&this._removeTitle(),a.titlebar=d("<div />",{"class":S+"-titlebar "+(this.options.style.widget?k("header"):"")}).append(a.title=d("<div />",{id:b,"class":S+"-title","aria-atomic":D})).insertBefore(a.content).delegate(".qtip-close","mousedown keydown mouseup keyup mouseout",function(a){d(this).toggleClass("ui-state-active ui-state-focus","down"===a.type.substr(-4))}).delegate(".qtip-close","mouseover mouseout",function(a){d(this).toggleClass("ui-state-hover","mouseover"===a.type)}),this.options.content.button&&this._createButton()},z._removeTitle=function(a){var b=this.elements;b.title&&(b.titlebar.remove(),b.titlebar=b.title=b.button=F,a!==E&&this.reposition())},z._createPosClass=function(a){return S+"-pos-"+(a||this.options.position.my).abbrev()},z.reposition=function(c,e){if(!this.rendered||this.positioning||this.destroyed)return this;this.positioning=D;var f,g,h,i,j=this.cache,k=this.tooltip,l=this.options.position,m=l.target,n=l.my,o=l.at,p=l.viewport,q=l.container,r=l.adjust,s=r.method.split(" "),t=k.outerWidth(E),u=k.outerHeight(E),v=0,w=0,x=k.css("position"),y={left:0,top:0},z=k[0].offsetWidth>0,A=c&&"scroll"===c.type,B=d(a),C=q[0].ownerDocument,F=this.mouse;if(d.isArray(m)&&2===m.length)o={x:L,y:K},y={left:m[0],top:m[1]};else if("mouse"===m)o={x:L,y:K},(!r.mouse||this.options.hide.distance)&&j.origin&&j.origin.pageX?c=j.origin:!c||c&&("resize"===c.type||"scroll"===c.type)?c=j.event:F&&F.pageX&&(c=F),"static"!==x&&(y=q.offset()),C.body.offsetWidth!==(a.innerWidth||C.documentElement.clientWidth)&&(g=d(b.body).offset()),y={left:c.pageX-y.left+(g&&g.left||0),top:c.pageY-y.top+(g&&g.top||0)},r.mouse&&A&&F&&(y.left-=(F.scrollX||0)-B.scrollLeft(),y.top-=(F.scrollY||0)-B.scrollTop());else{if("event"===m?c&&c.target&&"scroll"!==c.type&&"resize"!==c.type?j.target=d(c.target):c.target||(j.target=this.elements.target):"event"!==m&&(j.target=d(m.jquery?m:this.elements.target)),m=j.target,m=d(m).eq(0),0===m.length)return this;m[0]===b||m[0]===a?(v=db.iOS?a.innerWidth:m.width(),w=db.iOS?a.innerHeight:m.height(),m[0]===a&&(y={top:(p||m).scrollTop(),left:(p||m).scrollLeft()})):R.imagemap&&m.is("area")?f=R.imagemap(this,m,o,R.viewport?s:E):R.svg&&m&&m[0].ownerSVGElement?f=R.svg(this,m,o,R.viewport?s:E):(v=m.outerWidth(E),w=m.outerHeight(E),y=m.offset()),f&&(v=f.width,w=f.height,g=f.offset,y=f.position),y=this.reposition.offset(m,y,q),(db.iOS>3.1&&db.iOS<4.1||db.iOS>=4.3&&db.iOS<4.33||!db.iOS&&"fixed"===x)&&(y.left-=B.scrollLeft(),y.top-=B.scrollTop()),(!f||f&&f.adjustable!==E)&&(y.left+=o.x===N?v:o.x===O?v/2:0,y.top+=o.y===M?w:o.y===O?w/2:0)}return y.left+=r.x+(n.x===N?-t:n.x===O?-t/2:0),y.top+=r.y+(n.y===M?-u:n.y===O?-u/2:0),R.viewport?(h=y.adjusted=R.viewport(this,y,l,v,w,t,u),g&&h.left&&(y.left+=g.left),g&&h.top&&(y.top+=g.top),h.my&&(this.position.my=h.my)):y.adjusted={left:0,top:0},j.posClass!==(i=this._createPosClass(this.position.my))&&k.removeClass(j.posClass).addClass(j.posClass=i),this._trigger("move",[y,p.elem||p],c)?(delete y.adjusted,e===E||!z||isNaN(y.left)||isNaN(y.top)||"mouse"===m||!d.isFunction(l.effect)?k.css(y):d.isFunction(l.effect)&&(l.effect.call(k,this,d.extend({},y)),k.queue(function(a){d(this).css({opacity:"",height:""}),db.ie&&this.style.removeAttribute("filter"),a()})),this.positioning=E,this):this},z.reposition.offset=function(a,c,e){function f(a,b){c.left+=b*a.scrollLeft(),c.top+=b*a.scrollTop()}if(!e[0])return c;var g,h,i,j,k=d(a[0].ownerDocument),l=!!db.ie&&"CSS1Compat"!==b.compatMode,m=e[0];do"static"!==(h=d.css(m,"position"))&&("fixed"===h?(i=m.getBoundingClientRect(),f(k,-1)):(i=d(m).position(),i.left+=parseFloat(d.css(m,"borderLeftWidth"))||0,i.top+=parseFloat(d.css(m,"borderTopWidth"))||0),c.left-=i.left+(parseFloat(d.css(m,"marginLeft"))||0),c.top-=i.top+(parseFloat(d.css(m,"marginTop"))||0),g||"hidden"===(j=d.css(m,"overflow"))||"visible"===j||(g=d(m)));while(m=m.offsetParent);return g&&(g[0]!==k[0]||l)&&f(g,1),c};var gb=(A=z.reposition.Corner=function(a,b){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,O).toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.forceY=!!b;var c=a.charAt(0);this.precedance="t"===c||"b"===c?H:G}).prototype;gb.invert=function(a,b){this[a]=this[a]===L?N:this[a]===N?L:b||this[a]},gb.string=function(a){var b=this.x,c=this.y,d=b!==c?"center"===b||"center"!==c&&(this.precedance===H||this.forceY)?[c,b]:[b,c]:[b];return a!==!1?d.join(" "):d},gb.abbrev=function(){var a=this.string(!1);return a[0].charAt(0)+(a[1]&&a[1].charAt(0)||"")},gb.clone=function(){return new A(this.string(),this.forceY)},z.toggle=function(a,c){var e=this.cache,f=this.options,g=this.tooltip;if(c){if(/over|enter/.test(c.type)&&e.event&&/out|leave/.test(e.event.type)&&f.show.target.add(c.target).length===f.show.target.length&&g.has(c.relatedTarget).length)return this;e.event=d.event.fix(c)}if(this.waiting&&!a&&(this.hiddenDuringWait=D),!this.rendered)return a?this.render(1):this;if(this.destroyed||this.disabled)return this;var h,i,j,k=a?"show":"hide",l=this.options[k],m=(this.options[a?"hide":"show"],this.options.position),n=this.options.content,o=this.tooltip.css("width"),p=this.tooltip.is(":visible"),q=a||1===l.target.length,r=!c||l.target.length<2||e.target[0]===c.target;return(typeof a).search("boolean|number")&&(a=!p),h=!g.is(":animated")&&p===a&&r,i=h?F:!!this._trigger(k,[90]),this.destroyed?this:(i!==E&&a&&this.focus(c),!i||h?this:(d.attr(g[0],"aria-hidden",!a),a?(this.mouse&&(e.origin=d.event.fix(this.mouse)),d.isFunction(n.text)&&this._updateContent(n.text,E),d.isFunction(n.title)&&this._updateTitle(n.title,E),!C&&"mouse"===m.target&&m.adjust.mouse&&(d(b).bind("mousemove."+S,this._storeMouse),C=D),o||g.css("width",g.outerWidth(E)),this.reposition(c,arguments[2]),o||g.css("width",""),l.solo&&("string"==typeof l.solo?d(l.solo):d(W,l.solo)).not(g).not(l.target).qtip("hide",d.Event("tooltipsolo"))):(clearTimeout(this.timers.show),delete e.origin,C&&!d(W+'[tracking="true"]:visible',l.solo).not(g).length&&(d(b).unbind("mousemove."+S),C=E),this.blur(c)),j=d.proxy(function(){a?(db.ie&&g[0].style.removeAttribute("filter"),g.css("overflow",""),"string"==typeof l.autofocus&&d(this.options.show.autofocus,g).focus(),this.options.show.target.trigger("qtip-"+this.id+"-inactive")):g.css({display:"",visibility:"",opacity:"",left:"",top:""}),this._trigger(a?"visible":"hidden")},this),l.effect===E||q===E?(g[k](),j()):d.isFunction(l.effect)?(g.stop(1,1),l.effect.call(g,this),g.queue("fx",function(a){j(),a()})):g.fadeTo(90,a?1:0,j),a&&l.target.trigger("qtip-"+this.id+"-inactive"),this))},z.show=function(a){return this.toggle(D,a)},z.hide=function(a){return this.toggle(E,a)},z.focus=function(a){if(!this.rendered||this.destroyed)return this;var b=d(W),c=this.tooltip,e=parseInt(c[0].style.zIndex,10),f=y.zindex+b.length;return c.hasClass($)||this._trigger("focus",[f],a)&&(e!==f&&(b.each(function(){this.style.zIndex>e&&(this.style.zIndex=this.style.zIndex-1)}),b.filter("."+$).qtip("blur",a)),c.addClass($)[0].style.zIndex=f),this},z.blur=function(a){return!this.rendered||this.destroyed?this:(this.tooltip.removeClass($),this._trigger("blur",[this.tooltip.css("zIndex")],a),this)},z.disable=function(a){return this.destroyed?this:("toggle"===a?a=!(this.rendered?this.tooltip.hasClass(ab):this.disabled):"boolean"!=typeof a&&(a=D),this.rendered&&this.tooltip.toggleClass(ab,a).attr("aria-disabled",a),this.disabled=!!a,this)},z.enable=function(){return this.disable(E)},z._createButton=function(){var a=this,b=this.elements,c=b.tooltip,e=this.options.content.button,f="string"==typeof e,g=f?e:"Close tooltip";b.button&&b.button.remove(),b.button=e.jquery?e:d("<a />",{"class":"qtip-close "+(this.options.style.widget?"":S+"-icon"),title:g,"aria-label":g}).prepend(d("<span />",{"class":"ui-icon ui-icon-close",html:"&times;"})),b.button.appendTo(b.titlebar||c).attr("role","button").click(function(b){return c.hasClass(ab)||a.hide(b),E})},z._updateButton=function(a){if(!this.rendered)return E;var b=this.elements.button;a?this._createButton():b.remove()},z._setWidget=function(){var a=this.options.style.widget,b=this.elements,c=b.tooltip,d=c.hasClass(ab);c.removeClass(ab),ab=a?"ui-state-disabled":"qtip-disabled",c.toggleClass(ab,d),c.toggleClass("ui-helper-reset "+k(),a).toggleClass(Z,this.options.style.def&&!a),b.content&&b.content.toggleClass(k("content"),a),b.titlebar&&b.titlebar.toggleClass(k("header"),a),b.button&&b.button.toggleClass(S+"-icon",!a)},z._storeMouse=function(a){return(this.mouse=d.event.fix(a)).type="mousemove",this},z._bind=function(a,b,c,e,f){if(a&&c&&b.length){var g="."+this._id+(e?"-"+e:"");return d(a).bind((b.split?b:b.join(g+" "))+g,d.proxy(c,f||this)),this}},z._unbind=function(a,b){return a&&d(a).unbind("."+this._id+(b?"-"+b:"")),this},z._trigger=function(a,b,c){var e=d.Event("tooltip"+a);return e.originalEvent=c&&d.extend({},c)||this.cache.event||F,this.triggering=a,this.tooltip.trigger(e,[this].concat(b||[])),this.triggering=E,!e.isDefaultPrevented()},z._bindEvents=function(a,b,c,e,f,g){var h=c.filter(e).add(e.filter(c)),i=[];h.length&&(d.each(b,function(b,c){var e=d.inArray(c,a);e>-1&&i.push(a.splice(e,1)[0])}),i.length&&(this._bind(h,i,function(a){var b=this.rendered?this.tooltip[0].offsetWidth>0:!1;(b?g:f).call(this,a)}),c=c.not(h),e=e.not(h))),this._bind(c,a,f),this._bind(e,b,g)},z._assignInitialEvents=function(a){function b(a){return this.disabled||this.destroyed?E:(this.cache.event=a&&d.event.fix(a),this.cache.target=a&&d(a.target),clearTimeout(this.timers.show),void(this.timers.show=l.call(this,function(){this.render("object"==typeof a||c.show.ready)},c.prerender?0:c.show.delay)))}var c=this.options,e=c.show.target,f=c.hide.target,g=c.show.event?d.trim(""+c.show.event).split(" "):[],h=c.hide.event?d.trim(""+c.hide.event).split(" "):[];this._bind(this.elements.target,["remove","removeqtip"],function(){this.destroy(!0)},"destroy"),/mouse(over|enter)/i.test(c.show.event)&&!/mouse(out|leave)/i.test(c.hide.event)&&h.push("mouseleave"),this._bind(e,"mousemove",function(a){this._storeMouse(a),this.cache.onTarget=D}),this._bindEvents(g,h,e,f,b,function(){return this.timers?void clearTimeout(this.timers.show):E}),(c.show.ready||c.prerender)&&b.call(this,a)},z._assignEvents=function(){var c=this,e=this.options,f=e.position,g=this.tooltip,h=e.show.target,i=e.hide.target,j=f.container,k=f.viewport,l=d(b),q=(d(b.body),d(a)),r=e.show.event?d.trim(""+e.show.event).split(" "):[],s=e.hide.event?d.trim(""+e.hide.event).split(" "):[];d.each(e.events,function(a,b){c._bind(g,"toggle"===a?["tooltipshow","tooltiphide"]:["tooltip"+a],b,null,g)}),/mouse(out|leave)/i.test(e.hide.event)&&"window"===e.hide.leave&&this._bind(l,["mouseout","blur"],function(a){/select|option/.test(a.target.nodeName)||a.relatedTarget||this.hide(a)}),e.hide.fixed?i=i.add(g.addClass(Y)):/mouse(over|enter)/i.test(e.show.event)&&this._bind(i,"mouseleave",function(){clearTimeout(this.timers.show)}),(""+e.hide.event).indexOf("unfocus")>-1&&this._bind(j.closest("html"),["mousedown","touchstart"],function(a){var b=d(a.target),c=this.rendered&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0,e=b.parents(W).filter(this.tooltip[0]).length>0;b[0]===this.target[0]||b[0]===this.tooltip[0]||e||this.target.has(b[0]).length||!c||this.hide(a)}),"number"==typeof e.hide.inactive&&(this._bind(h,"qtip-"+this.id+"-inactive",o,"inactive"),this._bind(i.add(g),y.inactiveEvents,o)),this._bindEvents(r,s,h,i,m,n),this._bind(h.add(g),"mousemove",function(a){if("number"==typeof e.hide.distance){var b=this.cache.origin||{},c=this.options.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&this.hide(a)}this._storeMouse(a)}),"mouse"===f.target&&f.adjust.mouse&&(e.hide.event&&this._bind(h,["mouseenter","mouseleave"],function(a){return this.cache?void(this.cache.onTarget="mouseenter"===a.type):E}),this._bind(l,"mousemove",function(a){this.rendered&&this.cache.onTarget&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0&&this.reposition(a)})),(f.adjust.resize||k.length)&&this._bind(d.event.special.resize?k:q,"resize",p),f.adjust.scroll&&this._bind(q.add(f.container),"scroll",p)},z._unassignEvents=function(){var c=this.options,e=c.show.target,f=c.hide.target,g=d.grep([this.elements.target[0],this.rendered&&this.tooltip[0],c.position.container[0],c.position.viewport[0],c.position.container.closest("html")[0],a,b],function(a){return"object"==typeof a});e&&e.toArray&&(g=g.concat(e.toArray())),f&&f.toArray&&(g=g.concat(f.toArray())),this._unbind(g)._unbind(g,"destroy")._unbind(g,"inactive")},d(function(){q(W,["mouseenter","mouseleave"],function(a){var b="mouseenter"===a.type,c=d(a.currentTarget),e=d(a.relatedTarget||a.target),f=this.options;b?(this.focus(a),c.hasClass(Y)&&!c.hasClass(ab)&&clearTimeout(this.timers.hide)):"mouse"===f.position.target&&f.position.adjust.mouse&&f.hide.event&&f.show.target&&!e.closest(f.show.target[0]).length&&this.hide(a),c.toggleClass(_,b)}),q("["+U+"]",X,o)}),y=d.fn.qtip=function(a,b,e){var f=(""+a).toLowerCase(),g=F,i=d.makeArray(arguments).slice(1),j=i[i.length-1],k=this[0]?d.data(this[0],S):F;return!arguments.length&&k||"api"===f?k:"string"==typeof a?(this.each(function(){var a=d.data(this,S);if(!a)return D;if(j&&j.timeStamp&&(a.cache.event=j),!b||"option"!==f&&"options"!==f)a[f]&&a[f].apply(a,i);else{if(e===c&&!d.isPlainObject(b))return g=a.get(b),E;a.set(b,e)}}),g!==F?g:this):"object"!=typeof a&&arguments.length?void 0:(k=h(d.extend(D,{},a)),this.each(function(a){var b,c;return c=d.isArray(k.id)?k.id[a]:k.id,c=!c||c===E||c.length<1||y.api[c]?y.nextid++:c,b=r(d(this),c,k),b===E?D:(y.api[c]=b,d.each(R,function(){"initialize"===this.initialize&&this(b)}),void b._assignInitialEvents(j))}))},d.qtip=e,y.api={},d.each({attr:function(a,b){if(this.length){var c=this[0],e="title",f=d.data(c,"qtip");if(a===e&&f&&"object"==typeof f&&f.options.suppress)return arguments.length<2?d.attr(c,cb):(f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",b),this.attr(cb,b))}return d.fn["attr"+bb].apply(this,arguments)},clone:function(a){var b=(d([]),d.fn["clone"+bb].apply(this,arguments));return a||b.filter("["+cb+"]").attr("title",function(){return d.attr(this,cb)}).removeAttr(cb),b}},function(a,b){if(!b||d.fn[a+bb])return D;var c=d.fn[a+bb]=d.fn[a];d.fn[a]=function(){return b.apply(this,arguments)||c.apply(this,arguments)}}),d.ui||(d["cleanData"+bb]=d.cleanData,d.cleanData=function(a){for(var b,c=0;(b=d(a[c])).length;c++)if(b.attr(T))try{b.triggerHandler("removeqtip")}catch(e){}d["cleanData"+bb].apply(this,arguments)}),y.version="2.2.1",y.nextid=0,y.inactiveEvents=X,y.zindex=15e3,y.defaults={prerender:E,id:E,overwrite:D,suppress:D,content:{text:D,attr:"title",title:E,button:E},position:{my:"top left",at:"bottom right",target:E,container:E,viewport:E,adjust:{x:0,y:0,mouse:D,scroll:D,resize:D,method:"flipinvert flipinvert"},effect:function(a,b){d(this).animate(b,{duration:200,queue:E})}},show:{target:E,event:"mouseenter",effect:D,delay:90,solo:E,ready:E,autofocus:E},hide:{target:E,event:"mouseleave",effect:D,delay:0,fixed:E,inactive:E,leave:"window",distance:E},style:{classes:"",widget:E,width:E,height:E,def:D},events:{render:F,move:F,show:F,hide:F,toggle:F,visible:F,hidden:F,focus:F,blur:F}};var hb,ib="margin",jb="border",kb="color",lb="background-color",mb="transparent",nb=" !important",ob=!!b.createElement("canvas").getContext,pb=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,qb={},rb=["Webkit","O","Moz","ms"];if(ob)var sb=a.devicePixelRatio||1,tb=function(){var a=b.createElement("canvas").getContext("2d");return a.backingStorePixelRatio||a.webkitBackingStorePixelRatio||a.mozBackingStorePixelRatio||a.msBackingStorePixelRatio||a.oBackingStorePixelRatio||1}(),ub=sb/tb;else var vb=function(a,b,c){return"<qtipvml:"+a+' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" '+(b||"")+' style="behavior: url(#default#VML); '+(c||"")+'" />'};d.extend(v.prototype,{init:function(a){var b,c;c=this.element=a.elements.tip=d("<div />",{"class":S+"-tip"}).prependTo(a.tooltip),ob?(b=d("<canvas />").appendTo(this.element)[0].getContext("2d"),b.lineJoin="miter",b.miterLimit=1e5,b.save()):(b=vb("shape",'coordorigin="0,0"',"position:absolute;"),this.element.html(b+b),a._bind(d("*",c).add(c),["click","mousedown"],function(a){a.stopPropagation()},this._ns)),a._bind(a.tooltip,"tooltipmove",this.reposition,this._ns,this),this.create()},_swapDimensions:function(){this.size[0]=this.options.height,this.size[1]=this.options.width},_resetDimensions:function(){this.size[0]=this.options.width,this.size[1]=this.options.height},_useTitle:function(a){var b=this.qtip.elements.titlebar;return b&&(a.y===K||a.y===O&&this.element.position().top+this.size[1]/2+this.options.offset<b.outerHeight(D))},_parseCorner:function(a){var b=this.qtip.options.position.my;return a===E||b===E?a=E:a===D?a=new A(b.string()):a.string||(a=new A(a),a.fixed=D),a},_parseWidth:function(a,b,c){var d=this.qtip.elements,e=jb+s(b)+"Width";return(c?u(c,e):u(d.content,e)||u(this._useTitle(a)&&d.titlebar||d.content,e)||u(d.tooltip,e))||0},_parseRadius:function(a){var b=this.qtip.elements,c=jb+s(a.y)+s(a.x)+"Radius";return db.ie<9?0:u(this._useTitle(a)&&b.titlebar||b.content,c)||u(b.tooltip,c)||0},_invalidColour:function(a,b,c){var d=a.css(b);return!d||c&&d===a.css(c)||pb.test(d)?E:d},_parseColours:function(a){var b=this.qtip.elements,c=this.element.css("cssText",""),e=jb+s(a[a.precedance])+s(kb),f=this._useTitle(a)&&b.titlebar||b.content,g=this._invalidColour,h=[];return h[0]=g(c,lb)||g(f,lb)||g(b.content,lb)||g(b.tooltip,lb)||c.css(lb),h[1]=g(c,e,kb)||g(f,e,kb)||g(b.content,e,kb)||g(b.tooltip,e,kb)||b.tooltip.css(e),d("*",c).add(c).css("cssText",lb+":"+mb+nb+";"+jb+":0"+nb+";"),h},_calculateSize:function(a){var b,c,d,e=a.precedance===H,f=this.options.width,g=this.options.height,h="c"===a.abbrev(),i=(e?f:g)*(h?.5:1),j=Math.pow,k=Math.round,l=Math.sqrt(j(i,2)+j(g,2)),m=[this.border/i*l,this.border/g*l];return m[2]=Math.sqrt(j(m[0],2)-j(this.border,2)),m[3]=Math.sqrt(j(m[1],2)-j(this.border,2)),b=l+m[2]+m[3]+(h?0:m[0]),c=b/l,d=[k(c*f),k(c*g)],e?d:d.reverse()},_calculateTip:function(a,b,c){c=c||1,b=b||this.size;var d=b[0]*c,e=b[1]*c,f=Math.ceil(d/2),g=Math.ceil(e/2),h={br:[0,0,d,e,d,0],bl:[0,0,d,0,0,e],tr:[0,e,d,0,d,e],tl:[0,0,0,e,d,e],tc:[0,e,f,0,d,e],bc:[0,0,d,0,f,e],rc:[0,0,d,g,0,e],lc:[d,0,d,e,0,g]};return h.lt=h.br,h.rt=h.bl,h.lb=h.tr,h.rb=h.tl,h[a.abbrev()]},_drawCoords:function(a,b){a.beginPath(),a.moveTo(b[0],b[1]),a.lineTo(b[2],b[3]),a.lineTo(b[4],b[5]),a.closePath()},create:function(){var a=this.corner=(ob||db.ie)&&this._parseCorner(this.options.corner);return(this.enabled=!!this.corner&&"c"!==this.corner.abbrev())&&(this.qtip.cache.corner=a.clone(),this.update()),this.element.toggle(this.enabled),this.corner},update:function(b,c){if(!this.enabled)return this;var e,f,g,h,i,j,k,l,m=this.qtip.elements,n=this.element,o=n.children(),p=this.options,q=this.size,r=p.mimic,s=Math.round;b||(b=this.qtip.cache.corner||this.corner),r===E?r=b:(r=new A(r),r.precedance=b.precedance,"inherit"===r.x?r.x=b.x:"inherit"===r.y?r.y=b.y:r.x===r.y&&(r[b.precedance]=b[b.precedance])),f=r.precedance,b.precedance===G?this._swapDimensions():this._resetDimensions(),e=this.color=this._parseColours(b),e[1]!==mb?(l=this.border=this._parseWidth(b,b[b.precedance]),p.border&&1>l&&!pb.test(e[1])&&(e[0]=e[1]),this.border=l=p.border!==D?p.border:l):this.border=l=0,k=this.size=this._calculateSize(b),n.css({width:k[0],height:k[1],lineHeight:k[1]+"px"}),j=b.precedance===H?[s(r.x===L?l:r.x===N?k[0]-q[0]-l:(k[0]-q[0])/2),s(r.y===K?k[1]-q[1]:0)]:[s(r.x===L?k[0]-q[0]:0),s(r.y===K?l:r.y===M?k[1]-q[1]-l:(k[1]-q[1])/2)],ob?(g=o[0].getContext("2d"),g.restore(),g.save(),g.clearRect(0,0,6e3,6e3),h=this._calculateTip(r,q,ub),i=this._calculateTip(r,this.size,ub),o.attr(I,k[0]*ub).attr(J,k[1]*ub),o.css(I,k[0]).css(J,k[1]),this._drawCoords(g,i),g.fillStyle=e[1],g.fill(),g.translate(j[0]*ub,j[1]*ub),this._drawCoords(g,h),g.fillStyle=e[0],g.fill()):(h=this._calculateTip(r),h="m"+h[0]+","+h[1]+" l"+h[2]+","+h[3]+" "+h[4]+","+h[5]+" xe",j[2]=l&&/^(r|b)/i.test(b.string())?8===db.ie?2:1:0,o.css({coordsize:k[0]+l+" "+(k[1]+l),antialias:""+(r.string().indexOf(O)>-1),left:j[0]-j[2]*Number(f===G),top:j[1]-j[2]*Number(f===H),width:k[0]+l,height:k[1]+l}).each(function(a){var b=d(this);b[b.prop?"prop":"attr"]({coordsize:k[0]+l+" "+(k[1]+l),path:h,fillcolor:e[0],filled:!!a,stroked:!a}).toggle(!(!l&&!a)),!a&&b.html(vb("stroke",'weight="'+2*l+'px" color="'+e[1]+'" miterlimit="1000" joinstyle="miter"'))})),a.opera&&setTimeout(function(){m.tip.css({display:"inline-block",visibility:"visible"})},1),c!==E&&this.calculate(b,k)},calculate:function(a,b){if(!this.enabled)return E;var c,e,f=this,g=this.qtip.elements,h=this.element,i=this.options.offset,j=(g.tooltip.hasClass("ui-widget"),{});return a=a||this.corner,c=a.precedance,b=b||this._calculateSize(a),e=[a.x,a.y],c===G&&e.reverse(),d.each(e,function(d,e){var h,k,l;
188
  e===O?(h=c===H?L:K,j[h]="50%",j[ib+"-"+h]=-Math.round(b[c===H?0:1]/2)+i):(h=f._parseWidth(a,e,g.tooltip),k=f._parseWidth(a,e,g.content),l=f._parseRadius(a),j[e]=Math.max(-f.border,d?k:i+(l>h?l:-h)))}),j[a[c]]-=b[c===G?0:1],h.css({margin:"",top:"",bottom:"",left:"",right:""}).css(j),j},reposition:function(a,b,d){function e(a,b,c,d,e){a===Q&&j.precedance===b&&k[d]&&j[c]!==O?j.precedance=j.precedance===G?H:G:a!==Q&&k[d]&&(j[b]=j[b]===O?k[d]>0?d:e:j[b]===d?e:d)}function f(a,b,e){j[a]===O?p[ib+"-"+b]=o[a]=g[ib+"-"+b]-k[b]:(h=g[e]!==c?[k[b],-g[b]]:[-k[b],g[b]],(o[a]=Math.max(h[0],h[1]))>h[0]&&(d[b]-=k[b],o[b]=E),p[g[e]!==c?e:b]=o[a])}if(this.enabled){var g,h,i=b.cache,j=this.corner.clone(),k=d.adjusted,l=b.options.position.adjust.method.split(" "),m=l[0],n=l[1]||l[0],o={left:E,top:E,x:0,y:0},p={};this.corner.fixed!==D&&(e(m,G,H,L,N),e(n,H,G,K,M),(j.string()!==i.corner.string()||i.cornerTop!==k.top||i.cornerLeft!==k.left)&&this.update(j,E)),g=this.calculate(j),g.right!==c&&(g.left=-g.right),g.bottom!==c&&(g.top=-g.bottom),g.user=this.offset,(o.left=m===Q&&!!k.left)&&f(G,L,N),(o.top=n===Q&&!!k.top)&&f(H,K,M),this.element.css(p).toggle(!(o.x&&o.y||j.x===O&&o.y||j.y===O&&o.x)),d.left-=g.left.charAt?g.user:m!==Q||o.top||!o.left&&!o.top?g.left+this.border:0,d.top-=g.top.charAt?g.user:n!==Q||o.left||!o.left&&!o.top?g.top+this.border:0,i.cornerLeft=k.left,i.cornerTop=k.top,i.corner=j.clone()}},destroy:function(){this.qtip._unbind(this.qtip.tooltip,this._ns),this.qtip.elements.tip&&this.qtip.elements.tip.find("*").remove().end().remove()}}),hb=R.tip=function(a){return new v(a,a.options.style.tip)},hb.initialize="render",hb.sanitize=function(a){if(a.style&&"tip"in a.style){var b=a.style.tip;"object"!=typeof b&&(b=a.style.tip={corner:b}),/string|boolean/i.test(typeof b.corner)||(b.corner=D)}},B.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){this.create(),this.qtip.reposition()},"^style.tip.(height|width)$":function(a){this.size=[a.width,a.height],this.update(),this.qtip.reposition()},"^content.title|style.(classes|widget)$":function(){this.update()}},d.extend(D,y.defaults,{style:{tip:{corner:D,mimic:E,width:6,height:6,border:D,offset:0}}});var wb,xb,yb="qtip-modal",zb="."+yb;xb=function(){function a(a){if(d.expr[":"].focusable)return d.expr[":"].focusable;var b,c,e,f=!isNaN(d.attr(a,"tabindex")),g=a.nodeName&&a.nodeName.toLowerCase();return"area"===g?(b=a.parentNode,c=b.name,a.href&&c&&"map"===b.nodeName.toLowerCase()?(e=d("img[usemap=#"+c+"]")[0],!!e&&e.is(":visible")):!1):/input|select|textarea|button|object/.test(g)?!a.disabled:"a"===g?a.href||f:f}function c(a){k.length<1&&a.length?a.not("body").blur():k.first().focus()}function e(a){if(i.is(":visible")){var b,e=d(a.target),h=f.tooltip,j=e.closest(W);b=j.length<1?E:parseInt(j[0].style.zIndex,10)>parseInt(h[0].style.zIndex,10),b||e.closest(W)[0]===h[0]||c(e),g=a.target===k[k.length-1]}}var f,g,h,i,j=this,k={};d.extend(j,{init:function(){return i=j.elem=d("<div />",{id:"qtip-overlay",html:"<div></div>",mousedown:function(){return E}}).hide(),d(b.body).bind("focusin"+zb,e),d(b).bind("keydown"+zb,function(a){f&&f.options.show.modal.escape&&27===a.keyCode&&f.hide(a)}),i.bind("click"+zb,function(a){f&&f.options.show.modal.blur&&f.hide(a)}),j},update:function(b){f=b,k=b.options.show.modal.stealfocus!==E?b.tooltip.find("*").filter(function(){return a(this)}):[]},toggle:function(a,e,g){var k=(d(b.body),a.tooltip),l=a.options.show.modal,m=l.effect,n=e?"show":"hide",o=i.is(":visible"),p=d(zb).filter(":visible:not(:animated)").not(k);return j.update(a),e&&l.stealfocus!==E&&c(d(":focus")),i.toggleClass("blurs",l.blur),e&&i.appendTo(b.body),i.is(":animated")&&o===e&&h!==E||!e&&p.length?j:(i.stop(D,E),d.isFunction(m)?m.call(i,e):m===E?i[n]():i.fadeTo(parseInt(g,10)||90,e?1:0,function(){e||i.hide()}),e||i.queue(function(a){i.css({left:"",top:""}),d(zb).length||i.detach(),a()}),h=e,f.destroyed&&(f=F),j)}}),j.init()},xb=new xb,d.extend(w.prototype,{init:function(a){var b=a.tooltip;return this.options.on?(a.elements.overlay=xb.elem,b.addClass(yb).css("z-index",y.modal_zindex+d(zb).length),a._bind(b,["tooltipshow","tooltiphide"],function(a,c,e){var f=a.originalEvent;if(a.target===b[0])if(f&&"tooltiphide"===a.type&&/mouse(leave|enter)/.test(f.type)&&d(f.relatedTarget).closest(xb.elem[0]).length)try{a.preventDefault()}catch(g){}else(!f||f&&"tooltipsolo"!==f.type)&&this.toggle(a,"tooltipshow"===a.type,e)},this._ns,this),a._bind(b,"tooltipfocus",function(a,c){if(!a.isDefaultPrevented()&&a.target===b[0]){var e=d(zb),f=y.modal_zindex+e.length,g=parseInt(b[0].style.zIndex,10);xb.elem[0].style.zIndex=f-1,e.each(function(){this.style.zIndex>g&&(this.style.zIndex-=1)}),e.filter("."+$).qtip("blur",a.originalEvent),b.addClass($)[0].style.zIndex=f,xb.update(c);try{a.preventDefault()}catch(h){}}},this._ns,this),void a._bind(b,"tooltiphide",function(a){a.target===b[0]&&d(zb).filter(":visible").not(b).last().qtip("focus",a)},this._ns,this)):this},toggle:function(a,b,c){return a&&a.isDefaultPrevented()?this:void xb.toggle(this.qtip,!!b,c)},destroy:function(){this.qtip.tooltip.removeClass(yb),this.qtip._unbind(this.qtip.tooltip,this._ns),xb.toggle(this.qtip,E),delete this.qtip.elements.overlay}}),wb=R.modal=function(a){return new w(a,a.options.show.modal)},wb.sanitize=function(a){a.show&&("object"!=typeof a.show.modal?a.show.modal={on:!!a.show.modal}:"undefined"==typeof a.show.modal.on&&(a.show.modal.on=D))},y.modal_zindex=y.zindex-200,wb.initialize="render",B.modal={"^show.modal.(on|blur)$":function(){this.destroy(),this.init(),this.qtip.elems.overlay.toggle(this.qtip.tooltip[0].offsetWidth>0)}},d.extend(D,y.defaults,{show:{modal:{on:E,effect:D,blur:D,stealfocus:D,escape:D}}}),R.viewport=function(c,d,e,f,g,h,i){function j(a,b,c,e,f,g,h,i,j){var k=d[f],s=u[a],t=v[a],w=c===Q,x=s===f?j:s===g?-j:-j/2,y=t===f?i:t===g?-i:-i/2,z=q[f]+r[f]-(n?0:m[f]),A=z-k,B=k+j-(h===I?o:p)-z,C=x-(u.precedance===a||s===u[b]?y:0)-(t===O?i/2:0);return w?(C=(s===f?1:-1)*x,d[f]+=A>0?A:B>0?-B:0,d[f]=Math.max(-m[f]+r[f],k-C,Math.min(Math.max(-m[f]+r[f]+(h===I?o:p),k+C),d[f],"center"===s?k-x:1e9))):(e*=c===P?2:0,A>0&&(s!==f||B>0)?(d[f]-=C+e,l.invert(a,f)):B>0&&(s!==g||A>0)&&(d[f]-=(s===O?-C:C)+e,l.invert(a,g)),d[f]<q&&-d[f]>B&&(d[f]=k,l=u.clone())),d[f]-k}var k,l,m,n,o,p,q,r,s=e.target,t=c.elements.tooltip,u=e.my,v=e.at,w=e.adjust,x=w.method.split(" "),y=x[0],z=x[1]||x[0],A=e.viewport,B=e.container,C=(c.cache,{left:0,top:0});return A.jquery&&s[0]!==a&&s[0]!==b.body&&"none"!==w.method?(m=B.offset()||C,n="static"===B.css("position"),k="fixed"===t.css("position"),o=A[0]===a?A.width():A.outerWidth(E),p=A[0]===a?A.height():A.outerHeight(E),q={left:k?0:A.scrollLeft(),top:k?0:A.scrollTop()},r=A.offset()||C,("shift"!==y||"shift"!==z)&&(l=u.clone()),C={left:"none"!==y?j(G,H,y,w.x,L,N,I,f,h):0,top:"none"!==z?j(H,G,z,w.y,K,M,J,g,i):0,my:l}):C},R.polys={polygon:function(a,b){var c,d,e,f={width:0,height:0,position:{top:1e10,right:0,bottom:0,left:1e10},adjustable:E},g=0,h=[],i=1,j=1,k=0,l=0;for(g=a.length;g--;)c=[parseInt(a[--g],10),parseInt(a[g+1],10)],c[0]>f.position.right&&(f.position.right=c[0]),c[0]<f.position.left&&(f.position.left=c[0]),c[1]>f.position.bottom&&(f.position.bottom=c[1]),c[1]<f.position.top&&(f.position.top=c[1]),h.push(c);if(d=f.width=Math.abs(f.position.right-f.position.left),e=f.height=Math.abs(f.position.bottom-f.position.top),"c"===b.abbrev())f.position={left:f.position.left+f.width/2,top:f.position.top+f.height/2};else{for(;d>0&&e>0&&i>0&&j>0;)for(d=Math.floor(d/2),e=Math.floor(e/2),b.x===L?i=d:b.x===N?i=f.width-d:i+=Math.floor(d/2),b.y===K?j=e:b.y===M?j=f.height-e:j+=Math.floor(e/2),g=h.length;g--&&!(h.length<2);)k=h[g][0]-f.position.left,l=h[g][1]-f.position.top,(b.x===L&&k>=i||b.x===N&&i>=k||b.x===O&&(i>k||k>f.width-i)||b.y===K&&l>=j||b.y===M&&j>=l||b.y===O&&(j>l||l>f.height-j))&&h.splice(g,1);f.position={left:h[0][0],top:h[0][1]}}return f},rect:function(a,b,c,d){return{width:Math.abs(c-a),height:Math.abs(d-b),position:{left:Math.min(a,c),top:Math.min(b,d)}}},_angles:{tc:1.5,tr:7/4,tl:5/4,bc:.5,br:.25,bl:.75,rc:2,lc:1,c:0},ellipse:function(a,b,c,d,e){var f=R.polys._angles[e.abbrev()],g=0===f?0:c*Math.cos(f*Math.PI),h=d*Math.sin(f*Math.PI);return{width:2*c-Math.abs(g),height:2*d-Math.abs(h),position:{left:a+g,top:b+h},adjustable:E}},circle:function(a,b,c,d){return R.polys.ellipse(a,b,c,c,d)}},R.svg=function(a,c,e){for(var f,g,h,i,j,k,l,m,n,o=(d(b),c[0]),p=d(o.ownerSVGElement),q=o.ownerDocument,r=(parseInt(c.css("stroke-width"),10)||0)/2;!o.getBBox;)o=o.parentNode;if(!o.getBBox||!o.parentNode)return E;switch(o.nodeName){case"ellipse":case"circle":m=R.polys.ellipse(o.cx.baseVal.value,o.cy.baseVal.value,(o.rx||o.r).baseVal.value+r,(o.ry||o.r).baseVal.value+r,e);break;case"line":case"polygon":case"polyline":for(l=o.points||[{x:o.x1.baseVal.value,y:o.y1.baseVal.value},{x:o.x2.baseVal.value,y:o.y2.baseVal.value}],m=[],k=-1,i=l.numberOfItems||l.length;++k<i;)j=l.getItem?l.getItem(k):l[k],m.push.apply(m,[j.x,j.y]);m=R.polys.polygon(m,e);break;default:m=o.getBBox(),m={width:m.width,height:m.height,position:{left:m.x,top:m.y}}}return n=m.position,p=p[0],p.createSVGPoint&&(g=o.getScreenCTM(),l=p.createSVGPoint(),l.x=n.left,l.y=n.top,h=l.matrixTransform(g),n.left=h.x,n.top=h.y),q!==b&&"mouse"!==a.position.target&&(f=d((q.defaultView||q.parentWindow).frameElement).offset(),f&&(n.left+=f.left,n.top+=f.top)),q=d(q),n.left+=q.scrollLeft(),n.top+=q.scrollTop(),m},R.imagemap=function(a,b,c){b.jquery||(b=d(b));var e,f,g,h,i,j=(b.attr("shape")||"rect").toLowerCase().replace("poly","polygon"),k=d('img[usemap="#'+b.parent("map").attr("name")+'"]'),l=d.trim(b.attr("coords")),m=l.replace(/,$/,"").split(",");if(!k.length)return E;if("polygon"===j)h=R.polys.polygon(m,c);else{if(!R.polys[j])return E;for(g=-1,i=m.length,f=[];++g<i;)f.push(parseInt(m[g],10));h=R.polys[j].apply(this,f.concat(c))}return e=k.offset(),e.left+=Math.ceil((k.outerWidth(E)-k.width())/2),e.top+=Math.ceil((k.outerHeight(E)-k.height())/2),h.position.left+=e.left,h.position.top+=e.top,h};var Ab,Bb='<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>';d.extend(x.prototype,{_scroll:function(){var b=this.qtip.elements.overlay;b&&(b[0].style.top=d(a).scrollTop()+"px")},init:function(c){var e=c.tooltip;d("select, object").length<1&&(this.bgiframe=c.elements.bgiframe=d(Bb).appendTo(e),c._bind(e,"tooltipmove",this.adjustBGIFrame,this._ns,this)),this.redrawContainer=d("<div/>",{id:S+"-rcontainer"}).appendTo(b.body),c.elements.overlay&&c.elements.overlay.addClass("qtipmodal-ie6fix")&&(c._bind(a,["scroll","resize"],this._scroll,this._ns,this),c._bind(e,["tooltipshow"],this._scroll,this._ns,this)),this.redraw()},adjustBGIFrame:function(){var a,b,c=this.qtip.tooltip,d={height:c.outerHeight(E),width:c.outerWidth(E)},e=this.qtip.plugins.tip,f=this.qtip.elements.tip;b=parseInt(c.css("borderLeftWidth"),10)||0,b={left:-b,top:-b},e&&f&&(a="x"===e.corner.precedance?[I,L]:[J,K],b[a[1]]-=f[a[0]]()),this.bgiframe.css(b).css(d)},redraw:function(){if(this.qtip.rendered<1||this.drawing)return this;var a,b,c,d,e=this.qtip.tooltip,f=this.qtip.options.style,g=this.qtip.options.position.container;return this.qtip.drawing=1,f.height&&e.css(J,f.height),f.width?e.css(I,f.width):(e.css(I,"").appendTo(this.redrawContainer),b=e.width(),1>b%2&&(b+=1),c=e.css("maxWidth")||"",d=e.css("minWidth")||"",a=(c+d).indexOf("%")>-1?g.width()/100:0,c=(c.indexOf("%")>-1?a:1)*parseInt(c,10)||b,d=(d.indexOf("%")>-1?a:1)*parseInt(d,10)||0,b=c+d?Math.min(Math.max(b,d),c):b,e.css(I,Math.round(b)).appendTo(g)),this.drawing=0,this},destroy:function(){this.bgiframe&&this.bgiframe.remove(),this.qtip._unbind([a,this.qtip.tooltip],this._ns)}}),Ab=R.ie6=function(a){return 6===db.ie?new x(a):E},Ab.initialize="render",B.ie6={"^content|style$":function(){this.redraw()}}})}(window,document);
189
- //# sourceMappingURL=jquery.qtip.min.js.map
190
  </script>
166
  */
167
  function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t<e.length;t++)i[t]=e[t];return i}return Array.from(e)}var _slice=Array.prototype.slice;!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):e.parsley=t(e.jQuery)}(this,function(e){"use strict";function t(e,t){return e.parsleyAdaptedCallback||(e.parsleyAdaptedCallback=function(){var i=Array.prototype.slice.call(arguments,0);i.unshift(this),e.apply(t||A,i)}),e.parsleyAdaptedCallback}function i(e){return 0===e.lastIndexOf(D,0)?e.substr(D.length):e}var n=1,r={},s={attr:function(e,t,i){var n,r,s,a=new RegExp("^"+t,"i");if("undefined"==typeof i)i={};else for(n in i)i.hasOwnProperty(n)&&delete i[n];if("undefined"==typeof e||"undefined"==typeof e[0])return i;for(s=e[0].attributes,n=s.length;n--;)r=s[n],r&&r.specified&&a.test(r.name)&&(i[this.camelize(r.name.slice(t.length))]=this.deserializeValue(r.value));return i},checkAttr:function(e,t,i){return e.is("["+t+i+"]")},setAttr:function(e,t,i,n){e[0].setAttribute(this.dasherize(t+i),String(n))},generateID:function(){return""+n++},deserializeValue:function(t){var i;try{return t?"true"==t||("false"==t?!1:"null"==t?null:isNaN(i=Number(t))?/^[\[\{]/.test(t)?e.parseJSON(t):t:i):t}catch(n){return t}},camelize:function(e){return e.replace(/-+(.)?/g,function(e,t){return t?t.toUpperCase():""})},dasherize:function(e){return e.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()},warn:function(){var e;window.console&&"function"==typeof window.console.warn&&(e=window.console).warn.apply(e,arguments)},warnOnce:function(e){r[e]||(r[e]=!0,this.warn.apply(this,arguments))},_resetWarnings:function(){r={}},trimString:function(e){return e.replace(/^\s+|\s+$/g,"")},namespaceEvents:function(t,i){return t=this.trimString(t||"").split(/\s+/),t[0]?e.map(t,function(e){return e+"."+i}).join(" "):""},objectCreate:Object.create||function(){var e=function(){};return function(t){if(arguments.length>1)throw Error("Second argument not supported");if("object"!=typeof t)throw TypeError("Argument must be an object");e.prototype=t;var i=new e;return e.prototype=null,i}}()},a=s,o={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset], input[type=hidden]",priorityEnabled:!0,multiple:null,group:null,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,triggerAfterFailure:"input",errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(e){},errorsContainer:function(e){},errorsWrapper:'<ul class="parsley-errors-list"></ul>',errorTemplate:"<li></li>"},l=function(){};l.prototype={asyncSupport:!0,actualizeOptions:function(){return a.attr(this.$element,this.options.namespace,this.domOptions),this.parent&&this.parent.actualizeOptions&&this.parent.actualizeOptions(),this},_resetOptions:function(e){this.domOptions=a.objectCreate(this.parent.options),this.options=a.objectCreate(this.domOptions);for(var t in e)e.hasOwnProperty(t)&&(this.options[t]=e[t]);this.actualizeOptions()},_listeners:null,on:function(e,t){this._listeners=this._listeners||{};var i=this._listeners[e]=this._listeners[e]||[];return i.push(t),this},subscribe:function(t,i){e.listenTo(this,t.toLowerCase(),i)},off:function(e,t){var i=this._listeners&&this._listeners[e];if(i)if(t)for(var n=i.length;n--;)i[n]===t&&i.splice(n,1);else delete this._listeners[e];return this},unsubscribe:function(t,i){e.unsubscribeTo(this,t.toLowerCase())},trigger:function(e,t,i){t=t||this;var n,r=this._listeners&&this._listeners[e];if(r)for(var s=r.length;s--;)if(n=r[s].call(t,t,i),n===!1)return n;return this.parent?this.parent.trigger(e,t,i):!0},reset:function(){if("ParsleyForm"!==this.__class__)return this._resetUI(),this._trigger("reset");for(var e=0;e<this.fields.length;e++)this.fields[e].reset();this._trigger("reset")},destroy:function(){if(this._destroyUI(),"ParsleyForm"!==this.__class__)return this.$element.removeData("Parsley"),this.$element.removeData("ParsleyFieldMultiple"),void this._trigger("destroy");for(var e=0;e<this.fields.length;e++)this.fields[e].destroy();this.$element.removeData("Parsley"),this._trigger("destroy")},asyncIsValid:function(e,t){return a.warnOnce("asyncIsValid is deprecated; please use whenValid instead"),this.whenValid({group:e,force:t})},_findRelated:function(){return this.options.multiple?this.parent.$element.find("["+this.options.namespace+'multiple="'+this.options.multiple+'"]'):this.$element}};var u={string:function(e){return e},integer:function(e){if(isNaN(e))throw'Requirement is not an integer: "'+e+'"';return parseInt(e,10)},number:function(e){if(isNaN(e))throw'Requirement is not a number: "'+e+'"';return parseFloat(e)},reference:function(t){var i=e(t);if(0===i.length)throw'No such reference: "'+t+'"';return i},"boolean":function(e){return"false"!==e},object:function(e){return a.deserializeValue(e)},regexp:function(e){var t="";return/^\/.*\/(?:[gimy]*)$/.test(e)?(t=e.replace(/.*\/([gimy]*)$/,"$1"),e=e.replace(new RegExp("^/(.*?)/"+t+"$"),"$1")):e="^"+e+"$",new RegExp(e,t)}},d=function(e,t){var i=e.match(/^\s*\[(.*)\]\s*$/);if(!i)throw'Requirement is not an array: "'+e+'"';var n=i[1].split(",").map(a.trimString);if(n.length!==t)throw"Requirement has "+n.length+" values when "+t+" are needed";return n},h=function(e,t){var i=u[e||"string"];if(!i)throw'Unknown requirement specification: "'+e+'"';return i(t)},p=function(e,t,i){var n=null,r={};for(var s in e)if(s){var a=i(s);"string"==typeof a&&(a=h(e[s],a)),r[s]=a}else n=h(e[s],t);return[n,r]},f=function(t){e.extend(!0,this,t)};f.prototype={validate:function(t,i){if(this.fn)return arguments.length>3&&(i=[].slice.call(arguments,1,-1)),this.fn.call(this,t,i);if(e.isArray(t)){if(!this.validateMultiple)throw"Validator `"+this.name+"` does not handle multiple values";return this.validateMultiple.apply(this,arguments)}if(this.validateNumber)return isNaN(t)?!1:(arguments[0]=parseFloat(arguments[0]),this.validateNumber.apply(this,arguments));if(this.validateString)return this.validateString.apply(this,arguments);throw"Validator `"+this.name+"` only handles multiple values"},parseRequirements:function(t,i){if("string"!=typeof t)return e.isArray(t)?t:[t];var n=this.requirementType;if(e.isArray(n)){for(var r=d(t,n.length),s=0;s<r.length;s++)r[s]=h(n[s],r[s]);return r}return e.isPlainObject(n)?p(n,t,i):[h(n,t)]},requirementType:"string",priority:2};var c=function(e,t){this.__class__="ParsleyValidatorRegistry",this.locale="en",this.init(e||{},t||{})},m={email:/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,number:/^-?(\d*\.)?\d+(e[-+]?\d+)?$/i,integer:/^-?\d+$/,digits:/^\d+$/,alphanum:/^\w+$/i,url:new RegExp("^(?:(?:https?|ftp)://)?(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:/\\S*)?$","i")};m.range=m.number;var g=function(e){var t=(""+e).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);return t?Math.max(0,(t[1]?t[1].length:0)-(t[2]?+t[2]:0)):0};c.prototype={init:function(t,i){this.catalog=i,this.validators=e.extend({},this.validators);for(var n in t)this.addValidator(n,t[n].fn,t[n].priority);window.Parsley.trigger("parsley:validator:init")},setLocale:function(e){if("undefined"==typeof this.catalog[e])throw new Error(e+" is not available in the catalog");return this.locale=e,this},addCatalog:function(e,t,i){return"object"==typeof t&&(this.catalog[e]=t),!0===i?this.setLocale(e):this},addMessage:function(e,t,i){return"undefined"==typeof this.catalog[e]&&(this.catalog[e]={}),this.catalog[e][t]=i,this},addMessages:function(e,t){for(var i in t)this.addMessage(e,i,t[i]);return this},addValidator:function(e,t,i){if(this.validators[e])a.warn('Validator "'+e+'" is already defined.');else if(o.hasOwnProperty(e))return void a.warn('"'+e+'" is a restricted keyword and is not a valid validator name.');return this._setValidator.apply(this,arguments)},updateValidator:function(e,t,i){return this.validators[e]?this._setValidator(this,arguments):(a.warn('Validator "'+e+'" is not already defined.'),this.addValidator.apply(this,arguments))},removeValidator:function(e){return this.validators[e]||a.warn('Validator "'+e+'" is not defined.'),delete this.validators[e],this},_setValidator:function(e,t,i){"object"!=typeof t&&(t={fn:t,priority:i}),t.validate||(t=new f(t)),this.validators[e]=t;for(var n in t.messages||{})this.addMessage(n,e,t.messages[n]);return this},getErrorMessage:function(e){var t;if("type"===e.name){var i=this.catalog[this.locale][e.name]||{};t=i[e.requirements]}else t=this.formatMessage(this.catalog[this.locale][e.name],e.requirements);return t||this.catalog[this.locale].defaultMessage||this.catalog.en.defaultMessage},formatMessage:function(e,t){if("object"==typeof t){for(var i in t)e=this.formatMessage(e,t[i]);return e}return"string"==typeof e?e.replace(/%s/i,t):""},validators:{notblank:{validateString:function(e){return/\S/.test(e)},priority:2},required:{validateMultiple:function(e){return e.length>0},validateString:function(e){return/\S/.test(e)},priority:512},type:{validateString:function(e,t){var i=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],n=i.step,r=void 0===n?"1":n,s=i.base,a=void 0===s?0:s,o=m[t];if(!o)throw new Error("validator type `"+t+"` is not supported");if(!o.test(e))return!1;if("number"===t&&!/^any$/i.test(r||"")){var l=Number(e),u=Math.max(g(r),g(a));if(g(l)>u)return!1;var d=function(e){return Math.round(e*Math.pow(10,u))};if((d(l)-d(a))%d(r)!=0)return!1}return!0},requirementType:{"":"string",step:"string",base:"number"},priority:256},pattern:{validateString:function(e,t){return t.test(e)},requirementType:"regexp",priority:64},minlength:{validateString:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxlength:{validateString:function(e,t){return e.length<=t},requirementType:"integer",priority:30},length:{validateString:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},mincheck:{validateMultiple:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxcheck:{validateMultiple:function(e,t){return e.length<=t},requirementType:"integer",priority:30},check:{validateMultiple:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},min:{validateNumber:function(e,t){return e>=t},requirementType:"number",priority:30},max:{validateNumber:function(e,t){return t>=e},requirementType:"number",priority:30},range:{validateNumber:function(e,t,i){return e>=t&&i>=e},requirementType:["number","number"],priority:30},equalto:{validateString:function(t,i){var n=e(i);return n.length?t===n.val():t===i},priority:256}}};var y={},v=function T(e,t,i){for(var n=[],r=[],s=0;s<e.length;s++){for(var a=!1,o=0;o<t.length;o++)if(e[s].assert.name===t[o].assert.name){a=!0;break}a?r.push(e[s]):n.push(e[s])}return{kept:r,added:n,removed:i?[]:T(t,e,!0).added}};y.Form={_actualizeTriggers:function(){var e=this;this.$element.on("submit.Parsley",function(t){e.onSubmitValidate(t)}),this.$element.on("click.Parsley",'input[type="submit"], button[type="submit"]',function(t){e.onSubmitButton(t)}),!1!==this.options.uiEnabled&&this.$element.attr("novalidate","")},focus:function(){if(this._focusedField=null,!0===this.validationResult||"none"===this.options.focus)return null;for(var e=0;e<this.fields.length;e++){var t=this.fields[e];if(!0!==t.validationResult&&t.validationResult.length>0&&"undefined"==typeof t.options.noFocus&&(this._focusedField=t.$element,"first"===this.options.focus))break}return null===this._focusedField?null:this._focusedField.focus()},_destroyUI:function(){this.$element.off(".Parsley")}},y.Field={_reflowUI:function(){if(this._buildUI(),this._ui){var e=v(this.validationResult,this._ui.lastValidationResult);this._ui.lastValidationResult=this.validationResult,this._manageStatusClass(),this._manageErrorsMessages(e),this._actualizeTriggers(),!e.kept.length&&!e.added.length||this._failedOnce||(this._failedOnce=!0,this._actualizeTriggers())}},getErrorsMessages:function(){if(!0===this.validationResult)return[];for(var e=[],t=0;t<this.validationResult.length;t++)e.push(this.validationResult[t].errorMessage||this._getErrorMessage(this.validationResult[t].assert));return e},addError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.message,n=t.assert,r=t.updateClass,s=void 0===r?!0:r;this._buildUI(),this._addError(e,{message:i,assert:n}),s&&this._errorClass()},updateError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.message,n=t.assert,r=t.updateClass,s=void 0===r?!0:r;this._buildUI(),this._updateError(e,{message:i,assert:n}),s&&this._errorClass()},removeError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.updateClass,n=void 0===i?!0:i;this._buildUI(),this._removeError(e),n&&this._manageStatusClass()},_manageStatusClass:function(){this.hasConstraints()&&this.needsValidation()&&!0===this.validationResult?this._successClass():this.validationResult.length>0?this._errorClass():this._resetClass()},_manageErrorsMessages:function(t){if("undefined"==typeof this.options.errorsMessagesDisabled){if("undefined"!=typeof this.options.errorMessage)return t.added.length||t.kept.length?(this._insertErrorWrapper(),0===this._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&this._ui.$errorsWrapper.append(e(this.options.errorTemplate).addClass("parsley-custom-error-message")),this._ui.$errorsWrapper.addClass("filled").find(".parsley-custom-error-message").html(this.options.errorMessage)):this._ui.$errorsWrapper.removeClass("filled").find(".parsley-custom-error-message").remove();for(var i=0;i<t.removed.length;i++)this._removeError(t.removed[i].assert.name);for(i=0;i<t.added.length;i++)this._addError(t.added[i].assert.name,{message:t.added[i].errorMessage,assert:t.added[i].assert});for(i=0;i<t.kept.length;i++)this._updateError(t.kept[i].assert.name,{message:t.kept[i].errorMessage,assert:t.kept[i].assert})}},_addError:function(t,i){var n=i.message,r=i.assert;this._insertErrorWrapper(),this._ui.$errorsWrapper.addClass("filled").append(e(this.options.errorTemplate).addClass("parsley-"+t).html(n||this._getErrorMessage(r)))},_updateError:function(e,t){var i=t.message,n=t.assert;this._ui.$errorsWrapper.addClass("filled").find(".parsley-"+e).html(i||this._getErrorMessage(n))},_removeError:function(e){this._ui.$errorsWrapper.removeClass("filled").find(".parsley-"+e).remove()},_getErrorMessage:function(e){var t=e.name+"Message";return"undefined"!=typeof this.options[t]?window.Parsley.formatMessage(this.options[t],e.requirements):window.Parsley.getErrorMessage(e)},_buildUI:function(){if(!this._ui&&!1!==this.options.uiEnabled){var t={};this.$element.attr(this.options.namespace+"id",this.__id__),t.$errorClassHandler=this._manageClassHandler(),t.errorsWrapperId="parsley-id-"+(this.options.multiple?"multiple-"+this.options.multiple:this.__id__),t.$errorsWrapper=e(this.options.errorsWrapper).attr("id",t.errorsWrapperId),t.lastValidationResult=[],t.validationInformationVisible=!1,this._ui=t}},_manageClassHandler:function(){if("string"==typeof this.options.classHandler&&e(this.options.classHandler).length)return e(this.options.classHandler);var t=this.options.classHandler.call(this,this);return"undefined"!=typeof t&&t.length?t:!this.options.multiple||this.$element.is("select")?this.$element:this.$element.parent()},_insertErrorWrapper:function(){var t;if(0!==this._ui.$errorsWrapper.parent().length)return this._ui.$errorsWrapper.parent();if("string"==typeof this.options.errorsContainer){if(e(this.options.errorsContainer).length)return e(this.options.errorsContainer).append(this._ui.$errorsWrapper);a.warn("The errors container `"+this.options.errorsContainer+"` does not exist in DOM")}else"function"==typeof this.options.errorsContainer&&(t=this.options.errorsContainer.call(this,this));if("undefined"!=typeof t&&t.length)return t.append(this._ui.$errorsWrapper);var i=this.$element;return this.options.multiple&&(i=i.parent()),i.after(this._ui.$errorsWrapper)},_actualizeTriggers:function(){var e=this,t=this._findRelated();t.off(".Parsley"),this._failedOnce?t.on(a.namespaceEvents(this.options.triggerAfterFailure,"Parsley"),function(){e.validate()}):t.on(a.namespaceEvents(this.options.trigger,"Parsley"),function(t){e._eventValidate(t)})},_eventValidate:function(e){(!/key|input/.test(e.type)||this._ui&&this._ui.validationInformationVisible||!(this.getValue().length<=this.options.validationThreshold))&&this.validate()},_resetUI:function(){this._failedOnce=!1,this._actualizeTriggers(),"undefined"!=typeof this._ui&&(this._ui.$errorsWrapper.removeClass("filled").children().remove(),this._resetClass(),this._ui.lastValidationResult=[],this._ui.validationInformationVisible=!1)},_destroyUI:function(){this._resetUI(),"undefined"!=typeof this._ui&&this._ui.$errorsWrapper.remove(),delete this._ui},_successClass:function(){this._ui.validationInformationVisible=!0,this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass)},_errorClass:function(){this._ui.validationInformationVisible=!0,this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass)},_resetClass:function(){this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass)}};var _=function(t,i,n){this.__class__="ParsleyForm",this.__id__=a.generateID(),this.$element=e(t),this.domOptions=i,this.options=n,this.parent=window.Parsley,this.fields=[],this.validationResult=null},w={pending:null,resolved:!0,rejected:!1};_.prototype={onSubmitValidate:function(e){var t=this;if(!0!==e.parsley){var i=this._$submitSource||this.$element.find('input[type="submit"], button[type="submit"]').first();if(this._$submitSource=null,this.$element.find(".parsley-synthetic-submit-button").prop("disabled",!0),!i.is("[formnovalidate]")){var n=this.whenValidate({event:e});"resolved"===n.state()&&!1!==this._trigger("submit")||(e.stopImmediatePropagation(),e.preventDefault(),"pending"===n.state()&&n.done(function(){t._submit(i)}))}}},onSubmitButton:function(t){this._$submitSource=e(t.target)},_submit:function(t){if(!1!==this._trigger("submit")){if(t){var i=this.$element.find(".parsley-synthetic-submit-button").prop("disabled",!1);0===i.length&&(i=e('<input class="parsley-synthetic-submit-button" type="hidden">').appendTo(this.$element)),i.attr({name:t.attr("name"),value:t.attr("value")})}this.$element.trigger(e.extend(e.Event("submit"),{parsley:!0}))}},validate:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling validate on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1],s=i[2];t={group:n,force:r,event:s}}return w[this.whenValidate(t).state()]},whenValidate:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force,s=i.event;this.submitEvent=s,s&&(this.submitEvent=e.extend({},s,{preventDefault:function(){a.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"),t.validationResult=!1}})),this.validationResult=!0,this._trigger("validate"),this._refreshFields();var o=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValidate({force:r,group:n})})}),l=function(){var i=e.Deferred();return!1===t.validationResult&&i.reject(),i.resolve().promise()};return e.when.apply(e,_toConsumableArray(o)).done(function(){t._trigger("success")}).fail(function(){t.validationResult=!1,t.focus(),t._trigger("error")}).always(function(){t._trigger("validated")}).pipe(l,l)},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={group:n,force:r}}return w[this.whenValid(t).state()]},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force;this._refreshFields();var s=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValid({group:n,force:r})})});return e.when.apply(e,_toConsumableArray(s))},_refreshFields:function(){return this.actualizeOptions()._bindFields()},_bindFields:function(){var t=this,i=this.fields;return this.fields=[],this.fieldsMappedById={},this._withoutReactualizingFormOptions(function(){t.$element.find(t.options.inputs).not(t.options.excluded).each(function(e,i){var n=new window.Parsley.Factory(i,{},t);"ParsleyField"!==n.__class__&&"ParsleyFieldMultiple"!==n.__class__||!0===n.options.excluded||"undefined"==typeof t.fieldsMappedById[n.__class__+"-"+n.__id__]&&(t.fieldsMappedById[n.__class__+"-"+n.__id__]=n,t.fields.push(n))}),e(i).not(t.fields).each(function(e,t){t._trigger("reset")})}),this},_withoutReactualizingFormOptions:function(e){var t=this.actualizeOptions;this.actualizeOptions=function(){return this};var i=e();return this.actualizeOptions=t,i},_trigger:function(e){return this.trigger("form:"+e)}};var b=function(t,i,n,r,s){if(!/ParsleyField/.test(t.__class__))throw new Error("ParsleyField or ParsleyFieldMultiple instance expected");var a=window.Parsley._validatorRegistry.validators[i],o=new f(a);e.extend(this,{validator:o,name:i,requirements:n,priority:r||t.options[i+"Priority"]||o.priority,isDomConstraint:!0===s}),this._parseRequirements(t.options)},F=function(e){var t=e[0].toUpperCase();return t+e.slice(1)};b.prototype={validate:function(e,t){var i=this.requirementList.slice(0);return i.unshift(e),i.push(t),this.validator.validate.apply(this.validator,i)},_parseRequirements:function(e){var t=this;this.requirementList=this.validator.parseRequirements(this.requirements,function(i){return e[t.name+F(i)]})}};var C=function(t,i,n,r){this.__class__="ParsleyField",this.__id__=a.generateID(),this.$element=e(t),"undefined"!=typeof r&&(this.parent=r),this.options=n,this.domOptions=i,this.constraints=[],this.constraintsByName={},this.validationResult=[],this._bindConstraints()},$={pending:null,resolved:!0,rejected:!1};C.prototype={validate:function(t){arguments.length>=1&&!e.isPlainObject(t)&&(a.warnOnce("Calling validate on a parsley field without passing arguments as an object is deprecated."),t={options:t});var i=this.whenValidate(t);if(!i)return!0;switch(i.state()){case"pending":return null;case"resolved":return!0;case"rejected":return this.validationResult}},whenValidate:function(){var e=this,t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],i=t.force,n=t.group;return this.refreshConstraints(),!n||this._isInGroup(n)?(this.value=this.getValue(),this._trigger("validate"),this.whenValid({force:i,value:this.value,_refreshed:!0}).always(function(){e._reflowUI()}).done(function(){e._trigger("success")}).fail(function(){e._trigger("error")}).always(function(){e._trigger("validated")})):void 0},hasConstraints:function(){return 0!==this.constraints.length},needsValidation:function(e){return"undefined"==typeof e&&(e=this.getValue()),e.length||this._isRequired()||"undefined"!=typeof this.options.validateIfEmpty?!0:!1},_isInGroup:function(t){return e.isArray(this.options.group)?-1!==e.inArray(t,this.options.group):this.options.group===t},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley field without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={force:n,value:r}}var s=this.whenValid(t);return s?$[s.state()]:!0},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.force,r=void 0===n?!1:n,s=i.value,a=i.group,o=i._refreshed;if(o||this.refreshConstraints(),!a||this._isInGroup(a)){if(this.validationResult=!0,!this.hasConstraints())return e.when();if(("undefined"==typeof s||null===s)&&(s=this.getValue()),!this.needsValidation(s)&&!0!==r)return e.when();var l=this._getGroupedConstraints(),u=[];return e.each(l,function(i,n){var r=e.when.apply(e,_toConsumableArray(e.map(n,function(e){return t._validateConstraint(s,e)})));return u.push(r),"rejected"===r.state()?!1:void 0}),e.when.apply(e,u)}},_validateConstraint:function(t,i){var n=this,r=i.validate(t,this);return!1===r&&(r=e.Deferred().reject()),e.when(r).fail(function(e){!0===n.validationResult&&(n.validationResult=[]),n.validationResult.push({assert:i,errorMessage:"string"==typeof e&&e})})},getValue:function(){var e;return e="function"==typeof this.options.value?this.options.value(this):"undefined"!=typeof this.options.value?this.options.value:this.$element.val(),"undefined"==typeof e||null===e?"":this._handleWhitespace(e)},refreshConstraints:function(){return this.actualizeOptions()._bindConstraints()},addConstraint:function(e,t,i,n){if(window.Parsley._validatorRegistry.validators[e]){var r=new b(this,e,t,i,n);"undefined"!==this.constraintsByName[r.name]&&this.removeConstraint(r.name),this.constraints.push(r),this.constraintsByName[r.name]=r}return this},removeConstraint:function(e){for(var t=0;t<this.constraints.length;t++)if(e===this.constraints[t].name){this.constraints.splice(t,1);break}return delete this.constraintsByName[e],this},updateConstraint:function(e,t,i){return this.removeConstraint(e).addConstraint(e,t,i)},_bindConstraints:function(){for(var e=[],t={},i=0;i<this.constraints.length;i++)!1===this.constraints[i].isDomConstraint&&(e.push(this.constraints[i]),t[this.constraints[i].name]=this.constraints[i]);this.constraints=e,this.constraintsByName=t;for(var n in this.options)this.addConstraint(n,this.options[n],void 0,!0);return this._bindHtml5Constraints()},_bindHtml5Constraints:function(){(this.$element.hasClass("required")||this.$element.attr("required"))&&this.addConstraint("required",!0,void 0,!0),"string"==typeof this.$element.attr("pattern")&&this.addConstraint("pattern",this.$element.attr("pattern"),void 0,!0),"undefined"!=typeof this.$element.attr("min")&&"undefined"!=typeof this.$element.attr("max")?this.addConstraint("range",[this.$element.attr("min"),this.$element.attr("max")],void 0,!0):"undefined"!=typeof this.$element.attr("min")?this.addConstraint("min",this.$element.attr("min"),void 0,!0):"undefined"!=typeof this.$element.attr("max")&&this.addConstraint("max",this.$element.attr("max"),void 0,!0),"undefined"!=typeof this.$element.attr("minlength")&&"undefined"!=typeof this.$element.attr("maxlength")?this.addConstraint("length",[this.$element.attr("minlength"),this.$element.attr("maxlength")],void 0,!0):"undefined"!=typeof this.$element.attr("minlength")?this.addConstraint("minlength",this.$element.attr("minlength"),void 0,!0):"undefined"!=typeof this.$element.attr("maxlength")&&this.addConstraint("maxlength",this.$element.attr("maxlength"),void 0,!0);var e=this.$element.attr("type");return"undefined"==typeof e?this:"number"===e?this.addConstraint("type",["number",{step:this.$element.attr("step"),base:this.$element.attr("min")||this.$element.attr("value")}],void 0,!0):/^(email|url|range)$/i.test(e)?this.addConstraint("type",e,void 0,!0):this},_isRequired:function(){return"undefined"==typeof this.constraintsByName.required?!1:!1!==this.constraintsByName.required.requirements},_trigger:function(e){return this.trigger("field:"+e)},_handleWhitespace:function(e){return!0===this.options.trimValue&&a.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"'),"squish"===this.options.whitespace&&(e=e.replace(/\s{2,}/g," ")),("trim"===this.options.whitespace||"squish"===this.options.whitespace||!0===this.options.trimValue)&&(e=a.trimString(e)),e},_getGroupedConstraints:function(){if(!1===this.options.priorityEnabled)return[this.constraints];for(var e=[],t={},i=0;i<this.constraints.length;i++){var n=this.constraints[i].priority;t[n]||e.push(t[n]=[]),t[n].push(this.constraints[i])}return e.sort(function(e,t){return t[0].priority-e[0].priority}),e}};var x=C,P=function(){this.__class__="ParsleyFieldMultiple"};P.prototype={addElement:function(e){return this.$elements.push(e),this},refreshConstraints:function(){var t;if(this.constraints=[],this.$element.is("select"))return this.actualizeOptions()._bindConstraints(),this;for(var i=0;i<this.$elements.length;i++)if(e("html").has(this.$elements[i]).length){t=this.$elements[i].data("ParsleyFieldMultiple").refreshConstraints().constraints;for(var n=0;n<t.length;n++)this.addConstraint(t[n].name,t[n].requirements,t[n].priority,t[n].isDomConstraint)}else this.$elements.splice(i,1);return this},getValue:function(){if("function"==typeof this.options.value)value=this.options.value(this);else if("undefined"!=typeof this.options.value)return this.options.value;if(this.$element.is("input[type=radio]"))return this._findRelated().filter(":checked").val()||"";if(this.$element.is("input[type=checkbox]")){var t=[];return this._findRelated().filter(":checked").each(function(){t.push(e(this).val())}),t}return this.$element.is("select")&&null===this.$element.val()?[]:this.$element.val()},_init:function(){return this.$elements=[this.$element],this}};var E=function(t,i,n){this.$element=e(t);var r=this.$element.data("Parsley");if(r)return"undefined"!=typeof n&&r.parent===window.Parsley&&(r.parent=n,r._resetOptions(r.options)),r;if(!this.$element.length)throw new Error("You must bind Parsley on an existing element.");if("undefined"!=typeof n&&"ParsleyForm"!==n.__class__)throw new Error("Parent instance must be a ParsleyForm instance");return this.parent=n||window.Parsley,this.init(i)};E.prototype={init:function(e){return this.__class__="Parsley",this.__version__="2.3.5",this.__id__=a.generateID(),this._resetOptions(e),this.$element.is("form")||a.checkAttr(this.$element,this.options.namespace,"validate")&&!this.$element.is(this.options.inputs)?this.bind("parsleyForm"):this.isMultiple()?this.handleMultiple():this.bind("parsleyField")},isMultiple:function(){return this.$element.is("input[type=radio], input[type=checkbox]")||this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple")},handleMultiple:function(){var t,i,n=this;if(this.options.multiple||("undefined"!=typeof this.$element.attr("name")&&this.$element.attr("name").length?this.options.multiple=t=this.$element.attr("name"):"undefined"!=typeof this.$element.attr("id")&&this.$element.attr("id").length&&(this.options.multiple=this.$element.attr("id"))),this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple"))return this.options.multiple=this.options.multiple||this.__id__,this.bind("parsleyFieldMultiple");if(!this.options.multiple)return a.warn("To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.",this.$element),this;this.options.multiple=this.options.multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g,""),
168
  "undefined"!=typeof t&&e('input[name="'+t+'"]').each(function(t,i){e(i).is("input[type=radio], input[type=checkbox]")&&e(i).attr(n.options.namespace+"multiple",n.options.multiple)});for(var r=this._findRelated(),s=0;s<r.length;s++)if(i=e(r.get(s)).data("Parsley"),"undefined"!=typeof i){this.$element.data("ParsleyFieldMultiple")||i.addElement(this.$element);break}return this.bind("parsleyField",!0),i||this.bind("parsleyFieldMultiple")},bind:function(t,i){var n;switch(t){case"parsleyForm":n=e.extend(new _(this.$element,this.domOptions,this.options),window.ParsleyExtend)._bindFields();break;case"parsleyField":n=e.extend(new x(this.$element,this.domOptions,this.options,this.parent),window.ParsleyExtend);break;case"parsleyFieldMultiple":n=e.extend(new x(this.$element,this.domOptions,this.options,this.parent),new P,window.ParsleyExtend)._init();break;default:throw new Error(t+"is not a supported Parsley type")}return this.options.multiple&&a.setAttr(this.$element,this.options.namespace,"multiple",this.options.multiple),"undefined"!=typeof i?(this.$element.data("ParsleyFieldMultiple",n),n):(this.$element.data("Parsley",n),n._actualizeTriggers(),n._trigger("init"),n)}};var V=e.fn.jquery.split(".");if(parseInt(V[0])<=1&&parseInt(V[1])<8)throw"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.";V.forEach||a.warn("Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim");var M=e.extend(new l,{$element:e(document),actualizeOptions:null,_resetOptions:null,Factory:E,version:"2.3.5"});e.extend(x.prototype,y.Field,l.prototype),e.extend(_.prototype,y.Form,l.prototype),e.extend(E.prototype,l.prototype),e.fn.parsley=e.fn.psly=function(t){if(this.length>1){var i=[];return this.each(function(){i.push(e(this).parsley(t))}),i}return e(this).length?new E(this,t):void a.warn("You must bind Parsley on an existing element.")},"undefined"==typeof window.ParsleyExtend&&(window.ParsleyExtend={}),M.options=e.extend(a.objectCreate(o),window.ParsleyConfig),window.ParsleyConfig=M.options,window.Parsley=window.psly=M,window.ParsleyUtils=a;var O=window.Parsley._validatorRegistry=new c(window.ParsleyConfig.validators,window.ParsleyConfig.i18n);window.ParsleyValidator={},e.each("setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator".split(" "),function(t,i){window.Parsley[i]=e.proxy(O,i),window.ParsleyValidator[i]=function(){var e;return a.warnOnce("Accessing the method '"+i+"' through ParsleyValidator is deprecated. Simply call 'window.Parsley."+i+"(...)'"),(e=window.Parsley)[i].apply(e,arguments)}}),window.Parsley.UI=y,window.ParsleyUI={removeError:function(e,t,i){var n=!0!==i;return a.warnOnce("Accessing ParsleyUI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e.removeError(t,{updateClass:n})},getErrorsMessages:function(e){return a.warnOnce("Accessing ParsleyUI is deprecated. Call 'getErrorsMessages' on the instance directly."),e.getErrorsMessages()}},e.each("addError updateError".split(" "),function(e,t){window.ParsleyUI[t]=function(e,i,n,r,s){var o=!0!==s;return a.warnOnce("Accessing ParsleyUI is deprecated. Call '"+t+"' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e[t](i,{message:n,assert:r,updateClass:o})}}),/firefox/i.test(navigator.userAgent)&&e(document).on("change","select",function(t){e(t.target).trigger("input")}),!1!==window.ParsleyConfig.autoBind&&e(function(){e("[data-parsley-validate]").length&&e("[data-parsley-validate]").parsley()});var A=e({}),R=function(){a.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley")},D="parsley:";e.listen=function(e,n){var r;if(R(),"object"==typeof arguments[1]&&"function"==typeof arguments[2]&&(r=arguments[1],n=arguments[2]),"function"!=typeof n)throw new Error("Wrong parameters");window.Parsley.on(i(e),t(n,r))},e.listenTo=function(e,n,r){if(R(),!(e instanceof x||e instanceof _))throw new Error("Must give Parsley instance");if("string"!=typeof n||"function"!=typeof r)throw new Error("Wrong parameters");e.on(i(n),t(r))},e.unsubscribe=function(e,t){if(R(),"string"!=typeof e||"function"!=typeof t)throw new Error("Wrong arguments");window.Parsley.off(i(e),t.parsleyAdaptedCallback)},e.unsubscribeTo=function(e,t){if(R(),!(e instanceof x||e instanceof _))throw new Error("Must give Parsley instance");e.off(i(t))},e.unsubscribeAll=function(t){R(),window.Parsley.off(i(t)),e("form,input,textarea,select").each(function(){var n=e(this).data("Parsley");n&&n.off(i(t))})},e.emit=function(e,t){var n;R();var r=t instanceof x||t instanceof _,s=Array.prototype.slice.call(arguments,r?2:1);s.unshift(i(e)),r||(t=window.Parsley),(n=t).trigger.apply(n,_toConsumableArray(s))};e.extend(!0,M,{asyncValidators:{"default":{fn:function(e){return e.status>=200&&e.status<300},url:!1},reverse:{fn:function(e){return e.status<200||e.status>=300},url:!1}},addAsyncValidator:function(e,t,i,n){return M.asyncValidators[e]={fn:t,url:i||!1,options:n||{}},this}}),M.addValidator("remote",{requirementType:{"":"string",validator:"string",reverse:"boolean",options:"object"},validateString:function(t,i,n,r){var s,a,o={},l=n.validator||(!0===n.reverse?"reverse":"default");if("undefined"==typeof M.asyncValidators[l])throw new Error("Calling an undefined async validator: `"+l+"`");i=M.asyncValidators[l].url||i,i.indexOf("{value}")>-1?i=i.replace("{value}",encodeURIComponent(t)):o[r.$element.attr("name")||r.$element.attr("id")]=t;var u=e.extend(!0,n.options||{},M.asyncValidators[l].options);s=e.extend(!0,{},{url:i,data:o,type:"GET"},u),r.trigger("field:ajaxoptions",r,s),a=e.param(s),"undefined"==typeof M._remoteCache&&(M._remoteCache={});var d=M._remoteCache[a]=M._remoteCache[a]||e.ajax(s),h=function(){var t=M.asyncValidators[l].fn.call(r,d,i,n);return t||(t=e.Deferred().reject()),e.when(t)};return d.then(h,h)},priority:-1}),M.on("form:submit",function(){M._remoteCache={}}),window.ParsleyExtend.addAsyncValidator=function(){return ParsleyUtils.warnOnce("Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`"),M.addAsyncValidator.apply(M,arguments)},M.addMessages("en",{defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",number:"This value should be a valid number.",integer:"This value should be a valid integer.",digits:"This value should be digits.",alphanum:"This value should be alphanumeric."},notblank:"This value should not be blank.",required:"This value is required.",pattern:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or fewer.",length:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or fewer.",check:"You must select between %s and %s choices.",equalto:"This value should be the same."}),M.setLocale("en");var q=M;return q});
 
169
  </script>
170
 
171
 
185
 
186
  !function(a,b,c){!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):jQuery&&!jQuery.fn.qtip&&a(jQuery)}(function(d){"use strict";function e(a,b,c,e){this.id=c,this.target=a,this.tooltip=F,this.elements={target:a},this._id=S+"-"+c,this.timers={img:{}},this.options=b,this.plugins={},this.cache={event:{},target:d(),disabled:E,attr:e,onTooltip:E,lastClass:""},this.rendered=this.destroyed=this.disabled=this.waiting=this.hiddenDuringWait=this.positioning=this.triggering=E}function f(a){return a===F||"object"!==d.type(a)}function g(a){return!(d.isFunction(a)||a&&a.attr||a.length||"object"===d.type(a)&&(a.jquery||a.then))}function h(a){var b,c,e,h;return f(a)?E:(f(a.metadata)&&(a.metadata={type:a.metadata}),"content"in a&&(b=a.content,f(b)||b.jquery||b.done?b=a.content={text:c=g(b)?E:b}:c=b.text,"ajax"in b&&(e=b.ajax,h=e&&e.once!==E,delete b.ajax,b.text=function(a,b){var f=c||d(this).attr(b.options.content.attr)||"Loading...",g=d.ajax(d.extend({},e,{context:b})).then(e.success,F,e.error).then(function(a){return a&&h&&b.set("content.text",a),a},function(a,c,d){b.destroyed||0===a.status||b.set("content.text",c+": "+d)});return h?f:(b.set("content.text",f),g)}),"title"in b&&(d.isPlainObject(b.title)&&(b.button=b.title.button,b.title=b.title.text),g(b.title||E)&&(b.title=E))),"position"in a&&f(a.position)&&(a.position={my:a.position,at:a.position}),"show"in a&&f(a.show)&&(a.show=a.show.jquery?{target:a.show}:a.show===D?{ready:D}:{event:a.show}),"hide"in a&&f(a.hide)&&(a.hide=a.hide.jquery?{target:a.hide}:{event:a.hide}),"style"in a&&f(a.style)&&(a.style={classes:a.style}),d.each(R,function(){this.sanitize&&this.sanitize(a)}),a)}function i(a,b){for(var c,d=0,e=a,f=b.split(".");e=e[f[d++]];)d<f.length&&(c=e);return[c||a,f.pop()]}function j(a,b){var c,d,e;for(c in this.checks)for(d in this.checks[c])(e=new RegExp(d,"i").exec(a))&&(b.push(e),("builtin"===c||this.plugins[c])&&this.checks[c][d].apply(this.plugins[c]||this,b))}function k(a){return V.concat("").join(a?"-"+a+" ":" ")}function l(a,b){return b>0?setTimeout(d.proxy(a,this),b):void a.call(this)}function m(a){this.tooltip.hasClass(ab)||(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this.timers.show=l.call(this,function(){this.toggle(D,a)},this.options.show.delay))}function n(a){if(!this.tooltip.hasClass(ab)&&!this.destroyed){var b=d(a.relatedTarget),c=b.closest(W)[0]===this.tooltip[0],e=b[0]===this.options.show.target[0];if(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this!==b[0]&&"mouse"===this.options.position.target&&c||this.options.hide.fixed&&/mouse(out|leave|move)/.test(a.type)&&(c||e))try{a.preventDefault(),a.stopImmediatePropagation()}catch(f){}else this.timers.hide=l.call(this,function(){this.toggle(E,a)},this.options.hide.delay,this)}}function o(a){!this.tooltip.hasClass(ab)&&this.options.hide.inactive&&(clearTimeout(this.timers.inactive),this.timers.inactive=l.call(this,function(){this.hide(a)},this.options.hide.inactive))}function p(a){this.rendered&&this.tooltip[0].offsetWidth>0&&this.reposition(a)}function q(a,c,e){d(b.body).delegate(a,(c.split?c:c.join("."+S+" "))+"."+S,function(){var a=y.api[d.attr(this,U)];a&&!a.disabled&&e.apply(a,arguments)})}function r(a,c,f){var g,i,j,k,l,m=d(b.body),n=a[0]===b?m:a,o=a.metadata?a.metadata(f.metadata):F,p="html5"===f.metadata.type&&o?o[f.metadata.name]:F,q=a.data(f.metadata.name||"qtipopts");try{q="string"==typeof q?d.parseJSON(q):q}catch(r){}if(k=d.extend(D,{},y.defaults,f,"object"==typeof q?h(q):F,h(p||o)),i=k.position,k.id=c,"boolean"==typeof k.content.text){if(j=a.attr(k.content.attr),k.content.attr===E||!j)return E;k.content.text=j}if(i.container.length||(i.container=m),i.target===E&&(i.target=n),k.show.target===E&&(k.show.target=n),k.show.solo===D&&(k.show.solo=i.container.closest("body")),k.hide.target===E&&(k.hide.target=n),k.position.viewport===D&&(k.position.viewport=i.container),i.container=i.container.eq(0),i.at=new A(i.at,D),i.my=new A(i.my),a.data(S))if(k.overwrite)a.qtip("destroy",!0);else if(k.overwrite===E)return E;return a.attr(T,c),k.suppress&&(l=a.attr("title"))&&a.removeAttr("title").attr(cb,l).attr("title",""),g=new e(a,k,c,!!j),a.data(S,g),g}function s(a){return a.charAt(0).toUpperCase()+a.slice(1)}function t(a,b){var d,e,f=b.charAt(0).toUpperCase()+b.slice(1),g=(b+" "+rb.join(f+" ")+f).split(" "),h=0;if(qb[b])return a.css(qb[b]);for(;d=g[h++];)if((e=a.css(d))!==c)return qb[b]=d,e}function u(a,b){return Math.ceil(parseFloat(t(a,b)))}function v(a,b){this._ns="tip",this.options=b,this.offset=b.offset,this.size=[b.width,b.height],this.init(this.qtip=a)}function w(a,b){this.options=b,this._ns="-modal",this.init(this.qtip=a)}function x(a){this._ns="ie6",this.init(this.qtip=a)}var y,z,A,B,C,D=!0,E=!1,F=null,G="x",H="y",I="width",J="height",K="top",L="left",M="bottom",N="right",O="center",P="flipinvert",Q="shift",R={},S="qtip",T="data-hasqtip",U="data-qtip-id",V=["ui-widget","ui-tooltip"],W="."+S,X="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),Y=S+"-fixed",Z=S+"-default",$=S+"-focus",_=S+"-hover",ab=S+"-disabled",bb="_replacedByqTip",cb="oldtitle",db={ie:function(){for(var a=4,c=b.createElement("div");(c.innerHTML="<!--[if gt IE "+a+"]><i></i><![endif]-->")&&c.getElementsByTagName("i")[0];a+=1);return a>4?a:0/0}(),iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||E};z=e.prototype,z._when=function(a){return d.when.apply(d,a)},z.render=function(a){if(this.rendered||this.destroyed)return this;var b,c=this,e=this.options,f=this.cache,g=this.elements,h=e.content.text,i=e.content.title,j=e.content.button,k=e.position,l=("."+this._id+" ",[]);return d.attr(this.target[0],"aria-describedby",this._id),f.posClass=this._createPosClass((this.position={my:k.my,at:k.at}).my),this.tooltip=g.tooltip=b=d("<div/>",{id:this._id,"class":[S,Z,e.style.classes,f.posClass].join(" "),width:e.style.width||"",height:e.style.height||"",tracking:"mouse"===k.target&&k.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":E,"aria-describedby":this._id+"-content","aria-hidden":D}).toggleClass(ab,this.disabled).attr(U,this.id).data(S,this).appendTo(k.container).append(g.content=d("<div />",{"class":S+"-content",id:this._id+"-content","aria-atomic":D})),this.rendered=-1,this.positioning=D,i&&(this._createTitle(),d.isFunction(i)||l.push(this._updateTitle(i,E))),j&&this._createButton(),d.isFunction(h)||l.push(this._updateContent(h,E)),this.rendered=D,this._setWidget(),d.each(R,function(a){var b;"render"===this.initialize&&(b=this(c))&&(c.plugins[a]=b)}),this._unassignEvents(),this._assignEvents(),this._when(l).then(function(){c._trigger("render"),c.positioning=E,c.hiddenDuringWait||!e.show.ready&&!a||c.toggle(D,f.event,E),c.hiddenDuringWait=E}),y.api[this.id]=this,this},z.destroy=function(a){function b(){if(!this.destroyed){this.destroyed=D;var a,b=this.target,c=b.attr(cb);this.rendered&&this.tooltip.stop(1,0).find("*").remove().end().remove(),d.each(this.plugins,function(){this.destroy&&this.destroy()});for(a in this.timers)clearTimeout(this.timers[a]);b.removeData(S).removeAttr(U).removeAttr(T).removeAttr("aria-describedby"),this.options.suppress&&c&&b.attr("title",c).removeAttr(cb),this._unassignEvents(),this.options=this.elements=this.cache=this.timers=this.plugins=this.mouse=F,delete y.api[this.id]}}return this.destroyed?this.target:(a===D&&"hide"!==this.triggering||!this.rendered?b.call(this):(this.tooltip.one("tooltiphidden",d.proxy(b,this)),!this.triggering&&this.hide()),this.target)},B=z.checks={builtin:{"^id$":function(a,b,c,e){var f=c===D?y.nextid:c,g=S+"-"+f;f!==E&&f.length>0&&!d("#"+g).length?(this._id=g,this.rendered&&(this.tooltip[0].id=this._id,this.elements.content[0].id=this._id+"-content",this.elements.title[0].id=this._id+"-title")):a[b]=e},"^prerender":function(a,b,c){c&&!this.rendered&&this.render(this.options.show.ready)},"^content.text$":function(a,b,c){this._updateContent(c)},"^content.attr$":function(a,b,c,d){this.options.content.text===this.target.attr(d)&&this._updateContent(this.target.attr(c))},"^content.title$":function(a,b,c){return c?(c&&!this.elements.title&&this._createTitle(),void this._updateTitle(c)):this._removeTitle()},"^content.button$":function(a,b,c){this._updateButton(c)},"^content.title.(text|button)$":function(a,b,c){this.set("content."+b,c)},"^position.(my|at)$":function(a,b,c){"string"==typeof c&&(this.position[b]=a[b]=new A(c,"at"===b))},"^position.container$":function(a,b,c){this.rendered&&this.tooltip.appendTo(c)},"^show.ready$":function(a,b,c){c&&(!this.rendered&&this.render(D)||this.toggle(D))},"^style.classes$":function(a,b,c,d){this.rendered&&this.tooltip.removeClass(d).addClass(c)},"^style.(width|height)":function(a,b,c){this.rendered&&this.tooltip.css(b,c)},"^style.widget|content.title":function(){this.rendered&&this._setWidget()},"^style.def":function(a,b,c){this.rendered&&this.tooltip.toggleClass(Z,!!c)},"^events.(render|show|move|hide|focus|blur)$":function(a,b,c){this.rendered&&this.tooltip[(d.isFunction(c)?"":"un")+"bind"]("tooltip"+b,c)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){if(this.rendered){var a=this.options.position;this.tooltip.attr("tracking","mouse"===a.target&&a.adjust.mouse),this._unassignEvents(),this._assignEvents()}}}},z.get=function(a){if(this.destroyed)return this;var b=i(this.options,a.toLowerCase()),c=b[0][b[1]];return c.precedance?c.string():c};var eb=/^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,fb=/^prerender|show\.ready/i;z.set=function(a,b){if(this.destroyed)return this;{var c,e=this.rendered,f=E,g=this.options;this.checks}return"string"==typeof a?(c=a,a={},a[c]=b):a=d.extend({},a),d.each(a,function(b,c){if(e&&fb.test(b))return void delete a[b];var h,j=i(g,b.toLowerCase());h=j[0][j[1]],j[0][j[1]]=c&&c.nodeType?d(c):c,f=eb.test(b)||f,a[b]=[j[0],j[1],c,h]}),h(g),this.positioning=D,d.each(a,d.proxy(j,this)),this.positioning=E,this.rendered&&this.tooltip[0].offsetWidth>0&&f&&this.reposition("mouse"===g.position.target?F:this.cache.event),this},z._update=function(a,b){var c=this,e=this.cache;return this.rendered&&a?(d.isFunction(a)&&(a=a.call(this.elements.target,e.event,this)||""),d.isFunction(a.then)?(e.waiting=D,a.then(function(a){return e.waiting=E,c._update(a,b)},F,function(a){return c._update(a,b)})):a===E||!a&&""!==a?E:(a.jquery&&a.length>0?b.empty().append(a.css({display:"block",visibility:"visible"})):b.html(a),this._waitForContent(b).then(function(a){c.rendered&&c.tooltip[0].offsetWidth>0&&c.reposition(e.event,!a.length)}))):E},z._waitForContent=function(a){var b=this.cache;return b.waiting=D,(d.fn.imagesLoaded?a.imagesLoaded():d.Deferred().resolve([])).done(function(){b.waiting=E}).promise()},z._updateContent=function(a,b){this._update(a,this.elements.content,b)},z._updateTitle=function(a,b){this._update(a,this.elements.title,b)===E&&this._removeTitle(E)},z._createTitle=function(){var a=this.elements,b=this._id+"-title";a.titlebar&&this._removeTitle(),a.titlebar=d("<div />",{"class":S+"-titlebar "+(this.options.style.widget?k("header"):"")}).append(a.title=d("<div />",{id:b,"class":S+"-title","aria-atomic":D})).insertBefore(a.content).delegate(".qtip-close","mousedown keydown mouseup keyup mouseout",function(a){d(this).toggleClass("ui-state-active ui-state-focus","down"===a.type.substr(-4))}).delegate(".qtip-close","mouseover mouseout",function(a){d(this).toggleClass("ui-state-hover","mouseover"===a.type)}),this.options.content.button&&this._createButton()},z._removeTitle=function(a){var b=this.elements;b.title&&(b.titlebar.remove(),b.titlebar=b.title=b.button=F,a!==E&&this.reposition())},z._createPosClass=function(a){return S+"-pos-"+(a||this.options.position.my).abbrev()},z.reposition=function(c,e){if(!this.rendered||this.positioning||this.destroyed)return this;this.positioning=D;var f,g,h,i,j=this.cache,k=this.tooltip,l=this.options.position,m=l.target,n=l.my,o=l.at,p=l.viewport,q=l.container,r=l.adjust,s=r.method.split(" "),t=k.outerWidth(E),u=k.outerHeight(E),v=0,w=0,x=k.css("position"),y={left:0,top:0},z=k[0].offsetWidth>0,A=c&&"scroll"===c.type,B=d(a),C=q[0].ownerDocument,F=this.mouse;if(d.isArray(m)&&2===m.length)o={x:L,y:K},y={left:m[0],top:m[1]};else if("mouse"===m)o={x:L,y:K},(!r.mouse||this.options.hide.distance)&&j.origin&&j.origin.pageX?c=j.origin:!c||c&&("resize"===c.type||"scroll"===c.type)?c=j.event:F&&F.pageX&&(c=F),"static"!==x&&(y=q.offset()),C.body.offsetWidth!==(a.innerWidth||C.documentElement.clientWidth)&&(g=d(b.body).offset()),y={left:c.pageX-y.left+(g&&g.left||0),top:c.pageY-y.top+(g&&g.top||0)},r.mouse&&A&&F&&(y.left-=(F.scrollX||0)-B.scrollLeft(),y.top-=(F.scrollY||0)-B.scrollTop());else{if("event"===m?c&&c.target&&"scroll"!==c.type&&"resize"!==c.type?j.target=d(c.target):c.target||(j.target=this.elements.target):"event"!==m&&(j.target=d(m.jquery?m:this.elements.target)),m=j.target,m=d(m).eq(0),0===m.length)return this;m[0]===b||m[0]===a?(v=db.iOS?a.innerWidth:m.width(),w=db.iOS?a.innerHeight:m.height(),m[0]===a&&(y={top:(p||m).scrollTop(),left:(p||m).scrollLeft()})):R.imagemap&&m.is("area")?f=R.imagemap(this,m,o,R.viewport?s:E):R.svg&&m&&m[0].ownerSVGElement?f=R.svg(this,m,o,R.viewport?s:E):(v=m.outerWidth(E),w=m.outerHeight(E),y=m.offset()),f&&(v=f.width,w=f.height,g=f.offset,y=f.position),y=this.reposition.offset(m,y,q),(db.iOS>3.1&&db.iOS<4.1||db.iOS>=4.3&&db.iOS<4.33||!db.iOS&&"fixed"===x)&&(y.left-=B.scrollLeft(),y.top-=B.scrollTop()),(!f||f&&f.adjustable!==E)&&(y.left+=o.x===N?v:o.x===O?v/2:0,y.top+=o.y===M?w:o.y===O?w/2:0)}return y.left+=r.x+(n.x===N?-t:n.x===O?-t/2:0),y.top+=r.y+(n.y===M?-u:n.y===O?-u/2:0),R.viewport?(h=y.adjusted=R.viewport(this,y,l,v,w,t,u),g&&h.left&&(y.left+=g.left),g&&h.top&&(y.top+=g.top),h.my&&(this.position.my=h.my)):y.adjusted={left:0,top:0},j.posClass!==(i=this._createPosClass(this.position.my))&&k.removeClass(j.posClass).addClass(j.posClass=i),this._trigger("move",[y,p.elem||p],c)?(delete y.adjusted,e===E||!z||isNaN(y.left)||isNaN(y.top)||"mouse"===m||!d.isFunction(l.effect)?k.css(y):d.isFunction(l.effect)&&(l.effect.call(k,this,d.extend({},y)),k.queue(function(a){d(this).css({opacity:"",height:""}),db.ie&&this.style.removeAttribute("filter"),a()})),this.positioning=E,this):this},z.reposition.offset=function(a,c,e){function f(a,b){c.left+=b*a.scrollLeft(),c.top+=b*a.scrollTop()}if(!e[0])return c;var g,h,i,j,k=d(a[0].ownerDocument),l=!!db.ie&&"CSS1Compat"!==b.compatMode,m=e[0];do"static"!==(h=d.css(m,"position"))&&("fixed"===h?(i=m.getBoundingClientRect(),f(k,-1)):(i=d(m).position(),i.left+=parseFloat(d.css(m,"borderLeftWidth"))||0,i.top+=parseFloat(d.css(m,"borderTopWidth"))||0),c.left-=i.left+(parseFloat(d.css(m,"marginLeft"))||0),c.top-=i.top+(parseFloat(d.css(m,"marginTop"))||0),g||"hidden"===(j=d.css(m,"overflow"))||"visible"===j||(g=d(m)));while(m=m.offsetParent);return g&&(g[0]!==k[0]||l)&&f(g,1),c};var gb=(A=z.reposition.Corner=function(a,b){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,O).toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.forceY=!!b;var c=a.charAt(0);this.precedance="t"===c||"b"===c?H:G}).prototype;gb.invert=function(a,b){this[a]=this[a]===L?N:this[a]===N?L:b||this[a]},gb.string=function(a){var b=this.x,c=this.y,d=b!==c?"center"===b||"center"!==c&&(this.precedance===H||this.forceY)?[c,b]:[b,c]:[b];return a!==!1?d.join(" "):d},gb.abbrev=function(){var a=this.string(!1);return a[0].charAt(0)+(a[1]&&a[1].charAt(0)||"")},gb.clone=function(){return new A(this.string(),this.forceY)},z.toggle=function(a,c){var e=this.cache,f=this.options,g=this.tooltip;if(c){if(/over|enter/.test(c.type)&&e.event&&/out|leave/.test(e.event.type)&&f.show.target.add(c.target).length===f.show.target.length&&g.has(c.relatedTarget).length)return this;e.event=d.event.fix(c)}if(this.waiting&&!a&&(this.hiddenDuringWait=D),!this.rendered)return a?this.render(1):this;if(this.destroyed||this.disabled)return this;var h,i,j,k=a?"show":"hide",l=this.options[k],m=(this.options[a?"hide":"show"],this.options.position),n=this.options.content,o=this.tooltip.css("width"),p=this.tooltip.is(":visible"),q=a||1===l.target.length,r=!c||l.target.length<2||e.target[0]===c.target;return(typeof a).search("boolean|number")&&(a=!p),h=!g.is(":animated")&&p===a&&r,i=h?F:!!this._trigger(k,[90]),this.destroyed?this:(i!==E&&a&&this.focus(c),!i||h?this:(d.attr(g[0],"aria-hidden",!a),a?(this.mouse&&(e.origin=d.event.fix(this.mouse)),d.isFunction(n.text)&&this._updateContent(n.text,E),d.isFunction(n.title)&&this._updateTitle(n.title,E),!C&&"mouse"===m.target&&m.adjust.mouse&&(d(b).bind("mousemove."+S,this._storeMouse),C=D),o||g.css("width",g.outerWidth(E)),this.reposition(c,arguments[2]),o||g.css("width",""),l.solo&&("string"==typeof l.solo?d(l.solo):d(W,l.solo)).not(g).not(l.target).qtip("hide",d.Event("tooltipsolo"))):(clearTimeout(this.timers.show),delete e.origin,C&&!d(W+'[tracking="true"]:visible',l.solo).not(g).length&&(d(b).unbind("mousemove."+S),C=E),this.blur(c)),j=d.proxy(function(){a?(db.ie&&g[0].style.removeAttribute("filter"),g.css("overflow",""),"string"==typeof l.autofocus&&d(this.options.show.autofocus,g).focus(),this.options.show.target.trigger("qtip-"+this.id+"-inactive")):g.css({display:"",visibility:"",opacity:"",left:"",top:""}),this._trigger(a?"visible":"hidden")},this),l.effect===E||q===E?(g[k](),j()):d.isFunction(l.effect)?(g.stop(1,1),l.effect.call(g,this),g.queue("fx",function(a){j(),a()})):g.fadeTo(90,a?1:0,j),a&&l.target.trigger("qtip-"+this.id+"-inactive"),this))},z.show=function(a){return this.toggle(D,a)},z.hide=function(a){return this.toggle(E,a)},z.focus=function(a){if(!this.rendered||this.destroyed)return this;var b=d(W),c=this.tooltip,e=parseInt(c[0].style.zIndex,10),f=y.zindex+b.length;return c.hasClass($)||this._trigger("focus",[f],a)&&(e!==f&&(b.each(function(){this.style.zIndex>e&&(this.style.zIndex=this.style.zIndex-1)}),b.filter("."+$).qtip("blur",a)),c.addClass($)[0].style.zIndex=f),this},z.blur=function(a){return!this.rendered||this.destroyed?this:(this.tooltip.removeClass($),this._trigger("blur",[this.tooltip.css("zIndex")],a),this)},z.disable=function(a){return this.destroyed?this:("toggle"===a?a=!(this.rendered?this.tooltip.hasClass(ab):this.disabled):"boolean"!=typeof a&&(a=D),this.rendered&&this.tooltip.toggleClass(ab,a).attr("aria-disabled",a),this.disabled=!!a,this)},z.enable=function(){return this.disable(E)},z._createButton=function(){var a=this,b=this.elements,c=b.tooltip,e=this.options.content.button,f="string"==typeof e,g=f?e:"Close tooltip";b.button&&b.button.remove(),b.button=e.jquery?e:d("<a />",{"class":"qtip-close "+(this.options.style.widget?"":S+"-icon"),title:g,"aria-label":g}).prepend(d("<span />",{"class":"ui-icon ui-icon-close",html:"&times;"})),b.button.appendTo(b.titlebar||c).attr("role","button").click(function(b){return c.hasClass(ab)||a.hide(b),E})},z._updateButton=function(a){if(!this.rendered)return E;var b=this.elements.button;a?this._createButton():b.remove()},z._setWidget=function(){var a=this.options.style.widget,b=this.elements,c=b.tooltip,d=c.hasClass(ab);c.removeClass(ab),ab=a?"ui-state-disabled":"qtip-disabled",c.toggleClass(ab,d),c.toggleClass("ui-helper-reset "+k(),a).toggleClass(Z,this.options.style.def&&!a),b.content&&b.content.toggleClass(k("content"),a),b.titlebar&&b.titlebar.toggleClass(k("header"),a),b.button&&b.button.toggleClass(S+"-icon",!a)},z._storeMouse=function(a){return(this.mouse=d.event.fix(a)).type="mousemove",this},z._bind=function(a,b,c,e,f){if(a&&c&&b.length){var g="."+this._id+(e?"-"+e:"");return d(a).bind((b.split?b:b.join(g+" "))+g,d.proxy(c,f||this)),this}},z._unbind=function(a,b){return a&&d(a).unbind("."+this._id+(b?"-"+b:"")),this},z._trigger=function(a,b,c){var e=d.Event("tooltip"+a);return e.originalEvent=c&&d.extend({},c)||this.cache.event||F,this.triggering=a,this.tooltip.trigger(e,[this].concat(b||[])),this.triggering=E,!e.isDefaultPrevented()},z._bindEvents=function(a,b,c,e,f,g){var h=c.filter(e).add(e.filter(c)),i=[];h.length&&(d.each(b,function(b,c){var e=d.inArray(c,a);e>-1&&i.push(a.splice(e,1)[0])}),i.length&&(this._bind(h,i,function(a){var b=this.rendered?this.tooltip[0].offsetWidth>0:!1;(b?g:f).call(this,a)}),c=c.not(h),e=e.not(h))),this._bind(c,a,f),this._bind(e,b,g)},z._assignInitialEvents=function(a){function b(a){return this.disabled||this.destroyed?E:(this.cache.event=a&&d.event.fix(a),this.cache.target=a&&d(a.target),clearTimeout(this.timers.show),void(this.timers.show=l.call(this,function(){this.render("object"==typeof a||c.show.ready)},c.prerender?0:c.show.delay)))}var c=this.options,e=c.show.target,f=c.hide.target,g=c.show.event?d.trim(""+c.show.event).split(" "):[],h=c.hide.event?d.trim(""+c.hide.event).split(" "):[];this._bind(this.elements.target,["remove","removeqtip"],function(){this.destroy(!0)},"destroy"),/mouse(over|enter)/i.test(c.show.event)&&!/mouse(out|leave)/i.test(c.hide.event)&&h.push("mouseleave"),this._bind(e,"mousemove",function(a){this._storeMouse(a),this.cache.onTarget=D}),this._bindEvents(g,h,e,f,b,function(){return this.timers?void clearTimeout(this.timers.show):E}),(c.show.ready||c.prerender)&&b.call(this,a)},z._assignEvents=function(){var c=this,e=this.options,f=e.position,g=this.tooltip,h=e.show.target,i=e.hide.target,j=f.container,k=f.viewport,l=d(b),q=(d(b.body),d(a)),r=e.show.event?d.trim(""+e.show.event).split(" "):[],s=e.hide.event?d.trim(""+e.hide.event).split(" "):[];d.each(e.events,function(a,b){c._bind(g,"toggle"===a?["tooltipshow","tooltiphide"]:["tooltip"+a],b,null,g)}),/mouse(out|leave)/i.test(e.hide.event)&&"window"===e.hide.leave&&this._bind(l,["mouseout","blur"],function(a){/select|option/.test(a.target.nodeName)||a.relatedTarget||this.hide(a)}),e.hide.fixed?i=i.add(g.addClass(Y)):/mouse(over|enter)/i.test(e.show.event)&&this._bind(i,"mouseleave",function(){clearTimeout(this.timers.show)}),(""+e.hide.event).indexOf("unfocus")>-1&&this._bind(j.closest("html"),["mousedown","touchstart"],function(a){var b=d(a.target),c=this.rendered&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0,e=b.parents(W).filter(this.tooltip[0]).length>0;b[0]===this.target[0]||b[0]===this.tooltip[0]||e||this.target.has(b[0]).length||!c||this.hide(a)}),"number"==typeof e.hide.inactive&&(this._bind(h,"qtip-"+this.id+"-inactive",o,"inactive"),this._bind(i.add(g),y.inactiveEvents,o)),this._bindEvents(r,s,h,i,m,n),this._bind(h.add(g),"mousemove",function(a){if("number"==typeof e.hide.distance){var b=this.cache.origin||{},c=this.options.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&this.hide(a)}this._storeMouse(a)}),"mouse"===f.target&&f.adjust.mouse&&(e.hide.event&&this._bind(h,["mouseenter","mouseleave"],function(a){return this.cache?void(this.cache.onTarget="mouseenter"===a.type):E}),this._bind(l,"mousemove",function(a){this.rendered&&this.cache.onTarget&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0&&this.reposition(a)})),(f.adjust.resize||k.length)&&this._bind(d.event.special.resize?k:q,"resize",p),f.adjust.scroll&&this._bind(q.add(f.container),"scroll",p)},z._unassignEvents=function(){var c=this.options,e=c.show.target,f=c.hide.target,g=d.grep([this.elements.target[0],this.rendered&&this.tooltip[0],c.position.container[0],c.position.viewport[0],c.position.container.closest("html")[0],a,b],function(a){return"object"==typeof a});e&&e.toArray&&(g=g.concat(e.toArray())),f&&f.toArray&&(g=g.concat(f.toArray())),this._unbind(g)._unbind(g,"destroy")._unbind(g,"inactive")},d(function(){q(W,["mouseenter","mouseleave"],function(a){var b="mouseenter"===a.type,c=d(a.currentTarget),e=d(a.relatedTarget||a.target),f=this.options;b?(this.focus(a),c.hasClass(Y)&&!c.hasClass(ab)&&clearTimeout(this.timers.hide)):"mouse"===f.position.target&&f.position.adjust.mouse&&f.hide.event&&f.show.target&&!e.closest(f.show.target[0]).length&&this.hide(a),c.toggleClass(_,b)}),q("["+U+"]",X,o)}),y=d.fn.qtip=function(a,b,e){var f=(""+a).toLowerCase(),g=F,i=d.makeArray(arguments).slice(1),j=i[i.length-1],k=this[0]?d.data(this[0],S):F;return!arguments.length&&k||"api"===f?k:"string"==typeof a?(this.each(function(){var a=d.data(this,S);if(!a)return D;if(j&&j.timeStamp&&(a.cache.event=j),!b||"option"!==f&&"options"!==f)a[f]&&a[f].apply(a,i);else{if(e===c&&!d.isPlainObject(b))return g=a.get(b),E;a.set(b,e)}}),g!==F?g:this):"object"!=typeof a&&arguments.length?void 0:(k=h(d.extend(D,{},a)),this.each(function(a){var b,c;return c=d.isArray(k.id)?k.id[a]:k.id,c=!c||c===E||c.length<1||y.api[c]?y.nextid++:c,b=r(d(this),c,k),b===E?D:(y.api[c]=b,d.each(R,function(){"initialize"===this.initialize&&this(b)}),void b._assignInitialEvents(j))}))},d.qtip=e,y.api={},d.each({attr:function(a,b){if(this.length){var c=this[0],e="title",f=d.data(c,"qtip");if(a===e&&f&&"object"==typeof f&&f.options.suppress)return arguments.length<2?d.attr(c,cb):(f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",b),this.attr(cb,b))}return d.fn["attr"+bb].apply(this,arguments)},clone:function(a){var b=(d([]),d.fn["clone"+bb].apply(this,arguments));return a||b.filter("["+cb+"]").attr("title",function(){return d.attr(this,cb)}).removeAttr(cb),b}},function(a,b){if(!b||d.fn[a+bb])return D;var c=d.fn[a+bb]=d.fn[a];d.fn[a]=function(){return b.apply(this,arguments)||c.apply(this,arguments)}}),d.ui||(d["cleanData"+bb]=d.cleanData,d.cleanData=function(a){for(var b,c=0;(b=d(a[c])).length;c++)if(b.attr(T))try{b.triggerHandler("removeqtip")}catch(e){}d["cleanData"+bb].apply(this,arguments)}),y.version="2.2.1",y.nextid=0,y.inactiveEvents=X,y.zindex=15e3,y.defaults={prerender:E,id:E,overwrite:D,suppress:D,content:{text:D,attr:"title",title:E,button:E},position:{my:"top left",at:"bottom right",target:E,container:E,viewport:E,adjust:{x:0,y:0,mouse:D,scroll:D,resize:D,method:"flipinvert flipinvert"},effect:function(a,b){d(this).animate(b,{duration:200,queue:E})}},show:{target:E,event:"mouseenter",effect:D,delay:90,solo:E,ready:E,autofocus:E},hide:{target:E,event:"mouseleave",effect:D,delay:0,fixed:E,inactive:E,leave:"window",distance:E},style:{classes:"",widget:E,width:E,height:E,def:D},events:{render:F,move:F,show:F,hide:F,toggle:F,visible:F,hidden:F,focus:F,blur:F}};var hb,ib="margin",jb="border",kb="color",lb="background-color",mb="transparent",nb=" !important",ob=!!b.createElement("canvas").getContext,pb=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,qb={},rb=["Webkit","O","Moz","ms"];if(ob)var sb=a.devicePixelRatio||1,tb=function(){var a=b.createElement("canvas").getContext("2d");return a.backingStorePixelRatio||a.webkitBackingStorePixelRatio||a.mozBackingStorePixelRatio||a.msBackingStorePixelRatio||a.oBackingStorePixelRatio||1}(),ub=sb/tb;else var vb=function(a,b,c){return"<qtipvml:"+a+' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" '+(b||"")+' style="behavior: url(#default#VML); '+(c||"")+'" />'};d.extend(v.prototype,{init:function(a){var b,c;c=this.element=a.elements.tip=d("<div />",{"class":S+"-tip"}).prependTo(a.tooltip),ob?(b=d("<canvas />").appendTo(this.element)[0].getContext("2d"),b.lineJoin="miter",b.miterLimit=1e5,b.save()):(b=vb("shape",'coordorigin="0,0"',"position:absolute;"),this.element.html(b+b),a._bind(d("*",c).add(c),["click","mousedown"],function(a){a.stopPropagation()},this._ns)),a._bind(a.tooltip,"tooltipmove",this.reposition,this._ns,this),this.create()},_swapDimensions:function(){this.size[0]=this.options.height,this.size[1]=this.options.width},_resetDimensions:function(){this.size[0]=this.options.width,this.size[1]=this.options.height},_useTitle:function(a){var b=this.qtip.elements.titlebar;return b&&(a.y===K||a.y===O&&this.element.position().top+this.size[1]/2+this.options.offset<b.outerHeight(D))},_parseCorner:function(a){var b=this.qtip.options.position.my;return a===E||b===E?a=E:a===D?a=new A(b.string()):a.string||(a=new A(a),a.fixed=D),a},_parseWidth:function(a,b,c){var d=this.qtip.elements,e=jb+s(b)+"Width";return(c?u(c,e):u(d.content,e)||u(this._useTitle(a)&&d.titlebar||d.content,e)||u(d.tooltip,e))||0},_parseRadius:function(a){var b=this.qtip.elements,c=jb+s(a.y)+s(a.x)+"Radius";return db.ie<9?0:u(this._useTitle(a)&&b.titlebar||b.content,c)||u(b.tooltip,c)||0},_invalidColour:function(a,b,c){var d=a.css(b);return!d||c&&d===a.css(c)||pb.test(d)?E:d},_parseColours:function(a){var b=this.qtip.elements,c=this.element.css("cssText",""),e=jb+s(a[a.precedance])+s(kb),f=this._useTitle(a)&&b.titlebar||b.content,g=this._invalidColour,h=[];return h[0]=g(c,lb)||g(f,lb)||g(b.content,lb)||g(b.tooltip,lb)||c.css(lb),h[1]=g(c,e,kb)||g(f,e,kb)||g(b.content,e,kb)||g(b.tooltip,e,kb)||b.tooltip.css(e),d("*",c).add(c).css("cssText",lb+":"+mb+nb+";"+jb+":0"+nb+";"),h},_calculateSize:function(a){var b,c,d,e=a.precedance===H,f=this.options.width,g=this.options.height,h="c"===a.abbrev(),i=(e?f:g)*(h?.5:1),j=Math.pow,k=Math.round,l=Math.sqrt(j(i,2)+j(g,2)),m=[this.border/i*l,this.border/g*l];return m[2]=Math.sqrt(j(m[0],2)-j(this.border,2)),m[3]=Math.sqrt(j(m[1],2)-j(this.border,2)),b=l+m[2]+m[3]+(h?0:m[0]),c=b/l,d=[k(c*f),k(c*g)],e?d:d.reverse()},_calculateTip:function(a,b,c){c=c||1,b=b||this.size;var d=b[0]*c,e=b[1]*c,f=Math.ceil(d/2),g=Math.ceil(e/2),h={br:[0,0,d,e,d,0],bl:[0,0,d,0,0,e],tr:[0,e,d,0,d,e],tl:[0,0,0,e,d,e],tc:[0,e,f,0,d,e],bc:[0,0,d,0,f,e],rc:[0,0,d,g,0,e],lc:[d,0,d,e,0,g]};return h.lt=h.br,h.rt=h.bl,h.lb=h.tr,h.rb=h.tl,h[a.abbrev()]},_drawCoords:function(a,b){a.beginPath(),a.moveTo(b[0],b[1]),a.lineTo(b[2],b[3]),a.lineTo(b[4],b[5]),a.closePath()},create:function(){var a=this.corner=(ob||db.ie)&&this._parseCorner(this.options.corner);return(this.enabled=!!this.corner&&"c"!==this.corner.abbrev())&&(this.qtip.cache.corner=a.clone(),this.update()),this.element.toggle(this.enabled),this.corner},update:function(b,c){if(!this.enabled)return this;var e,f,g,h,i,j,k,l,m=this.qtip.elements,n=this.element,o=n.children(),p=this.options,q=this.size,r=p.mimic,s=Math.round;b||(b=this.qtip.cache.corner||this.corner),r===E?r=b:(r=new A(r),r.precedance=b.precedance,"inherit"===r.x?r.x=b.x:"inherit"===r.y?r.y=b.y:r.x===r.y&&(r[b.precedance]=b[b.precedance])),f=r.precedance,b.precedance===G?this._swapDimensions():this._resetDimensions(),e=this.color=this._parseColours(b),e[1]!==mb?(l=this.border=this._parseWidth(b,b[b.precedance]),p.border&&1>l&&!pb.test(e[1])&&(e[0]=e[1]),this.border=l=p.border!==D?p.border:l):this.border=l=0,k=this.size=this._calculateSize(b),n.css({width:k[0],height:k[1],lineHeight:k[1]+"px"}),j=b.precedance===H?[s(r.x===L?l:r.x===N?k[0]-q[0]-l:(k[0]-q[0])/2),s(r.y===K?k[1]-q[1]:0)]:[s(r.x===L?k[0]-q[0]:0),s(r.y===K?l:r.y===M?k[1]-q[1]-l:(k[1]-q[1])/2)],ob?(g=o[0].getContext("2d"),g.restore(),g.save(),g.clearRect(0,0,6e3,6e3),h=this._calculateTip(r,q,ub),i=this._calculateTip(r,this.size,ub),o.attr(I,k[0]*ub).attr(J,k[1]*ub),o.css(I,k[0]).css(J,k[1]),this._drawCoords(g,i),g.fillStyle=e[1],g.fill(),g.translate(j[0]*ub,j[1]*ub),this._drawCoords(g,h),g.fillStyle=e[0],g.fill()):(h=this._calculateTip(r),h="m"+h[0]+","+h[1]+" l"+h[2]+","+h[3]+" "+h[4]+","+h[5]+" xe",j[2]=l&&/^(r|b)/i.test(b.string())?8===db.ie?2:1:0,o.css({coordsize:k[0]+l+" "+(k[1]+l),antialias:""+(r.string().indexOf(O)>-1),left:j[0]-j[2]*Number(f===G),top:j[1]-j[2]*Number(f===H),width:k[0]+l,height:k[1]+l}).each(function(a){var b=d(this);b[b.prop?"prop":"attr"]({coordsize:k[0]+l+" "+(k[1]+l),path:h,fillcolor:e[0],filled:!!a,stroked:!a}).toggle(!(!l&&!a)),!a&&b.html(vb("stroke",'weight="'+2*l+'px" color="'+e[1]+'" miterlimit="1000" joinstyle="miter"'))})),a.opera&&setTimeout(function(){m.tip.css({display:"inline-block",visibility:"visible"})},1),c!==E&&this.calculate(b,k)},calculate:function(a,b){if(!this.enabled)return E;var c,e,f=this,g=this.qtip.elements,h=this.element,i=this.options.offset,j=(g.tooltip.hasClass("ui-widget"),{});return a=a||this.corner,c=a.precedance,b=b||this._calculateSize(a),e=[a.x,a.y],c===G&&e.reverse(),d.each(e,function(d,e){var h,k,l;
187
  e===O?(h=c===H?L:K,j[h]="50%",j[ib+"-"+h]=-Math.round(b[c===H?0:1]/2)+i):(h=f._parseWidth(a,e,g.tooltip),k=f._parseWidth(a,e,g.content),l=f._parseRadius(a),j[e]=Math.max(-f.border,d?k:i+(l>h?l:-h)))}),j[a[c]]-=b[c===G?0:1],h.css({margin:"",top:"",bottom:"",left:"",right:""}).css(j),j},reposition:function(a,b,d){function e(a,b,c,d,e){a===Q&&j.precedance===b&&k[d]&&j[c]!==O?j.precedance=j.precedance===G?H:G:a!==Q&&k[d]&&(j[b]=j[b]===O?k[d]>0?d:e:j[b]===d?e:d)}function f(a,b,e){j[a]===O?p[ib+"-"+b]=o[a]=g[ib+"-"+b]-k[b]:(h=g[e]!==c?[k[b],-g[b]]:[-k[b],g[b]],(o[a]=Math.max(h[0],h[1]))>h[0]&&(d[b]-=k[b],o[b]=E),p[g[e]!==c?e:b]=o[a])}if(this.enabled){var g,h,i=b.cache,j=this.corner.clone(),k=d.adjusted,l=b.options.position.adjust.method.split(" "),m=l[0],n=l[1]||l[0],o={left:E,top:E,x:0,y:0},p={};this.corner.fixed!==D&&(e(m,G,H,L,N),e(n,H,G,K,M),(j.string()!==i.corner.string()||i.cornerTop!==k.top||i.cornerLeft!==k.left)&&this.update(j,E)),g=this.calculate(j),g.right!==c&&(g.left=-g.right),g.bottom!==c&&(g.top=-g.bottom),g.user=this.offset,(o.left=m===Q&&!!k.left)&&f(G,L,N),(o.top=n===Q&&!!k.top)&&f(H,K,M),this.element.css(p).toggle(!(o.x&&o.y||j.x===O&&o.y||j.y===O&&o.x)),d.left-=g.left.charAt?g.user:m!==Q||o.top||!o.left&&!o.top?g.left+this.border:0,d.top-=g.top.charAt?g.user:n!==Q||o.left||!o.left&&!o.top?g.top+this.border:0,i.cornerLeft=k.left,i.cornerTop=k.top,i.corner=j.clone()}},destroy:function(){this.qtip._unbind(this.qtip.tooltip,this._ns),this.qtip.elements.tip&&this.qtip.elements.tip.find("*").remove().end().remove()}}),hb=R.tip=function(a){return new v(a,a.options.style.tip)},hb.initialize="render",hb.sanitize=function(a){if(a.style&&"tip"in a.style){var b=a.style.tip;"object"!=typeof b&&(b=a.style.tip={corner:b}),/string|boolean/i.test(typeof b.corner)||(b.corner=D)}},B.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){this.create(),this.qtip.reposition()},"^style.tip.(height|width)$":function(a){this.size=[a.width,a.height],this.update(),this.qtip.reposition()},"^content.title|style.(classes|widget)$":function(){this.update()}},d.extend(D,y.defaults,{style:{tip:{corner:D,mimic:E,width:6,height:6,border:D,offset:0}}});var wb,xb,yb="qtip-modal",zb="."+yb;xb=function(){function a(a){if(d.expr[":"].focusable)return d.expr[":"].focusable;var b,c,e,f=!isNaN(d.attr(a,"tabindex")),g=a.nodeName&&a.nodeName.toLowerCase();return"area"===g?(b=a.parentNode,c=b.name,a.href&&c&&"map"===b.nodeName.toLowerCase()?(e=d("img[usemap=#"+c+"]")[0],!!e&&e.is(":visible")):!1):/input|select|textarea|button|object/.test(g)?!a.disabled:"a"===g?a.href||f:f}function c(a){k.length<1&&a.length?a.not("body").blur():k.first().focus()}function e(a){if(i.is(":visible")){var b,e=d(a.target),h=f.tooltip,j=e.closest(W);b=j.length<1?E:parseInt(j[0].style.zIndex,10)>parseInt(h[0].style.zIndex,10),b||e.closest(W)[0]===h[0]||c(e),g=a.target===k[k.length-1]}}var f,g,h,i,j=this,k={};d.extend(j,{init:function(){return i=j.elem=d("<div />",{id:"qtip-overlay",html:"<div></div>",mousedown:function(){return E}}).hide(),d(b.body).bind("focusin"+zb,e),d(b).bind("keydown"+zb,function(a){f&&f.options.show.modal.escape&&27===a.keyCode&&f.hide(a)}),i.bind("click"+zb,function(a){f&&f.options.show.modal.blur&&f.hide(a)}),j},update:function(b){f=b,k=b.options.show.modal.stealfocus!==E?b.tooltip.find("*").filter(function(){return a(this)}):[]},toggle:function(a,e,g){var k=(d(b.body),a.tooltip),l=a.options.show.modal,m=l.effect,n=e?"show":"hide",o=i.is(":visible"),p=d(zb).filter(":visible:not(:animated)").not(k);return j.update(a),e&&l.stealfocus!==E&&c(d(":focus")),i.toggleClass("blurs",l.blur),e&&i.appendTo(b.body),i.is(":animated")&&o===e&&h!==E||!e&&p.length?j:(i.stop(D,E),d.isFunction(m)?m.call(i,e):m===E?i[n]():i.fadeTo(parseInt(g,10)||90,e?1:0,function(){e||i.hide()}),e||i.queue(function(a){i.css({left:"",top:""}),d(zb).length||i.detach(),a()}),h=e,f.destroyed&&(f=F),j)}}),j.init()},xb=new xb,d.extend(w.prototype,{init:function(a){var b=a.tooltip;return this.options.on?(a.elements.overlay=xb.elem,b.addClass(yb).css("z-index",y.modal_zindex+d(zb).length),a._bind(b,["tooltipshow","tooltiphide"],function(a,c,e){var f=a.originalEvent;if(a.target===b[0])if(f&&"tooltiphide"===a.type&&/mouse(leave|enter)/.test(f.type)&&d(f.relatedTarget).closest(xb.elem[0]).length)try{a.preventDefault()}catch(g){}else(!f||f&&"tooltipsolo"!==f.type)&&this.toggle(a,"tooltipshow"===a.type,e)},this._ns,this),a._bind(b,"tooltipfocus",function(a,c){if(!a.isDefaultPrevented()&&a.target===b[0]){var e=d(zb),f=y.modal_zindex+e.length,g=parseInt(b[0].style.zIndex,10);xb.elem[0].style.zIndex=f-1,e.each(function(){this.style.zIndex>g&&(this.style.zIndex-=1)}),e.filter("."+$).qtip("blur",a.originalEvent),b.addClass($)[0].style.zIndex=f,xb.update(c);try{a.preventDefault()}catch(h){}}},this._ns,this),void a._bind(b,"tooltiphide",function(a){a.target===b[0]&&d(zb).filter(":visible").not(b).last().qtip("focus",a)},this._ns,this)):this},toggle:function(a,b,c){return a&&a.isDefaultPrevented()?this:void xb.toggle(this.qtip,!!b,c)},destroy:function(){this.qtip.tooltip.removeClass(yb),this.qtip._unbind(this.qtip.tooltip,this._ns),xb.toggle(this.qtip,E),delete this.qtip.elements.overlay}}),wb=R.modal=function(a){return new w(a,a.options.show.modal)},wb.sanitize=function(a){a.show&&("object"!=typeof a.show.modal?a.show.modal={on:!!a.show.modal}:"undefined"==typeof a.show.modal.on&&(a.show.modal.on=D))},y.modal_zindex=y.zindex-200,wb.initialize="render",B.modal={"^show.modal.(on|blur)$":function(){this.destroy(),this.init(),this.qtip.elems.overlay.toggle(this.qtip.tooltip[0].offsetWidth>0)}},d.extend(D,y.defaults,{show:{modal:{on:E,effect:D,blur:D,stealfocus:D,escape:D}}}),R.viewport=function(c,d,e,f,g,h,i){function j(a,b,c,e,f,g,h,i,j){var k=d[f],s=u[a],t=v[a],w=c===Q,x=s===f?j:s===g?-j:-j/2,y=t===f?i:t===g?-i:-i/2,z=q[f]+r[f]-(n?0:m[f]),A=z-k,B=k+j-(h===I?o:p)-z,C=x-(u.precedance===a||s===u[b]?y:0)-(t===O?i/2:0);return w?(C=(s===f?1:-1)*x,d[f]+=A>0?A:B>0?-B:0,d[f]=Math.max(-m[f]+r[f],k-C,Math.min(Math.max(-m[f]+r[f]+(h===I?o:p),k+C),d[f],"center"===s?k-x:1e9))):(e*=c===P?2:0,A>0&&(s!==f||B>0)?(d[f]-=C+e,l.invert(a,f)):B>0&&(s!==g||A>0)&&(d[f]-=(s===O?-C:C)+e,l.invert(a,g)),d[f]<q&&-d[f]>B&&(d[f]=k,l=u.clone())),d[f]-k}var k,l,m,n,o,p,q,r,s=e.target,t=c.elements.tooltip,u=e.my,v=e.at,w=e.adjust,x=w.method.split(" "),y=x[0],z=x[1]||x[0],A=e.viewport,B=e.container,C=(c.cache,{left:0,top:0});return A.jquery&&s[0]!==a&&s[0]!==b.body&&"none"!==w.method?(m=B.offset()||C,n="static"===B.css("position"),k="fixed"===t.css("position"),o=A[0]===a?A.width():A.outerWidth(E),p=A[0]===a?A.height():A.outerHeight(E),q={left:k?0:A.scrollLeft(),top:k?0:A.scrollTop()},r=A.offset()||C,("shift"!==y||"shift"!==z)&&(l=u.clone()),C={left:"none"!==y?j(G,H,y,w.x,L,N,I,f,h):0,top:"none"!==z?j(H,G,z,w.y,K,M,J,g,i):0,my:l}):C},R.polys={polygon:function(a,b){var c,d,e,f={width:0,height:0,position:{top:1e10,right:0,bottom:0,left:1e10},adjustable:E},g=0,h=[],i=1,j=1,k=0,l=0;for(g=a.length;g--;)c=[parseInt(a[--g],10),parseInt(a[g+1],10)],c[0]>f.position.right&&(f.position.right=c[0]),c[0]<f.position.left&&(f.position.left=c[0]),c[1]>f.position.bottom&&(f.position.bottom=c[1]),c[1]<f.position.top&&(f.position.top=c[1]),h.push(c);if(d=f.width=Math.abs(f.position.right-f.position.left),e=f.height=Math.abs(f.position.bottom-f.position.top),"c"===b.abbrev())f.position={left:f.position.left+f.width/2,top:f.position.top+f.height/2};else{for(;d>0&&e>0&&i>0&&j>0;)for(d=Math.floor(d/2),e=Math.floor(e/2),b.x===L?i=d:b.x===N?i=f.width-d:i+=Math.floor(d/2),b.y===K?j=e:b.y===M?j=f.height-e:j+=Math.floor(e/2),g=h.length;g--&&!(h.length<2);)k=h[g][0]-f.position.left,l=h[g][1]-f.position.top,(b.x===L&&k>=i||b.x===N&&i>=k||b.x===O&&(i>k||k>f.width-i)||b.y===K&&l>=j||b.y===M&&j>=l||b.y===O&&(j>l||l>f.height-j))&&h.splice(g,1);f.position={left:h[0][0],top:h[0][1]}}return f},rect:function(a,b,c,d){return{width:Math.abs(c-a),height:Math.abs(d-b),position:{left:Math.min(a,c),top:Math.min(b,d)}}},_angles:{tc:1.5,tr:7/4,tl:5/4,bc:.5,br:.25,bl:.75,rc:2,lc:1,c:0},ellipse:function(a,b,c,d,e){var f=R.polys._angles[e.abbrev()],g=0===f?0:c*Math.cos(f*Math.PI),h=d*Math.sin(f*Math.PI);return{width:2*c-Math.abs(g),height:2*d-Math.abs(h),position:{left:a+g,top:b+h},adjustable:E}},circle:function(a,b,c,d){return R.polys.ellipse(a,b,c,c,d)}},R.svg=function(a,c,e){for(var f,g,h,i,j,k,l,m,n,o=(d(b),c[0]),p=d(o.ownerSVGElement),q=o.ownerDocument,r=(parseInt(c.css("stroke-width"),10)||0)/2;!o.getBBox;)o=o.parentNode;if(!o.getBBox||!o.parentNode)return E;switch(o.nodeName){case"ellipse":case"circle":m=R.polys.ellipse(o.cx.baseVal.value,o.cy.baseVal.value,(o.rx||o.r).baseVal.value+r,(o.ry||o.r).baseVal.value+r,e);break;case"line":case"polygon":case"polyline":for(l=o.points||[{x:o.x1.baseVal.value,y:o.y1.baseVal.value},{x:o.x2.baseVal.value,y:o.y2.baseVal.value}],m=[],k=-1,i=l.numberOfItems||l.length;++k<i;)j=l.getItem?l.getItem(k):l[k],m.push.apply(m,[j.x,j.y]);m=R.polys.polygon(m,e);break;default:m=o.getBBox(),m={width:m.width,height:m.height,position:{left:m.x,top:m.y}}}return n=m.position,p=p[0],p.createSVGPoint&&(g=o.getScreenCTM(),l=p.createSVGPoint(),l.x=n.left,l.y=n.top,h=l.matrixTransform(g),n.left=h.x,n.top=h.y),q!==b&&"mouse"!==a.position.target&&(f=d((q.defaultView||q.parentWindow).frameElement).offset(),f&&(n.left+=f.left,n.top+=f.top)),q=d(q),n.left+=q.scrollLeft(),n.top+=q.scrollTop(),m},R.imagemap=function(a,b,c){b.jquery||(b=d(b));var e,f,g,h,i,j=(b.attr("shape")||"rect").toLowerCase().replace("poly","polygon"),k=d('img[usemap="#'+b.parent("map").attr("name")+'"]'),l=d.trim(b.attr("coords")),m=l.replace(/,$/,"").split(",");if(!k.length)return E;if("polygon"===j)h=R.polys.polygon(m,c);else{if(!R.polys[j])return E;for(g=-1,i=m.length,f=[];++g<i;)f.push(parseInt(m[g],10));h=R.polys[j].apply(this,f.concat(c))}return e=k.offset(),e.left+=Math.ceil((k.outerWidth(E)-k.width())/2),e.top+=Math.ceil((k.outerHeight(E)-k.height())/2),h.position.left+=e.left,h.position.top+=e.top,h};var Ab,Bb='<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>';d.extend(x.prototype,{_scroll:function(){var b=this.qtip.elements.overlay;b&&(b[0].style.top=d(a).scrollTop()+"px")},init:function(c){var e=c.tooltip;d("select, object").length<1&&(this.bgiframe=c.elements.bgiframe=d(Bb).appendTo(e),c._bind(e,"tooltipmove",this.adjustBGIFrame,this._ns,this)),this.redrawContainer=d("<div/>",{id:S+"-rcontainer"}).appendTo(b.body),c.elements.overlay&&c.elements.overlay.addClass("qtipmodal-ie6fix")&&(c._bind(a,["scroll","resize"],this._scroll,this._ns,this),c._bind(e,["tooltipshow"],this._scroll,this._ns,this)),this.redraw()},adjustBGIFrame:function(){var a,b,c=this.qtip.tooltip,d={height:c.outerHeight(E),width:c.outerWidth(E)},e=this.qtip.plugins.tip,f=this.qtip.elements.tip;b=parseInt(c.css("borderLeftWidth"),10)||0,b={left:-b,top:-b},e&&f&&(a="x"===e.corner.precedance?[I,L]:[J,K],b[a[1]]-=f[a[0]]()),this.bgiframe.css(b).css(d)},redraw:function(){if(this.qtip.rendered<1||this.drawing)return this;var a,b,c,d,e=this.qtip.tooltip,f=this.qtip.options.style,g=this.qtip.options.position.container;return this.qtip.drawing=1,f.height&&e.css(J,f.height),f.width?e.css(I,f.width):(e.css(I,"").appendTo(this.redrawContainer),b=e.width(),1>b%2&&(b+=1),c=e.css("maxWidth")||"",d=e.css("minWidth")||"",a=(c+d).indexOf("%")>-1?g.width()/100:0,c=(c.indexOf("%")>-1?a:1)*parseInt(c,10)||b,d=(d.indexOf("%")>-1?a:1)*parseInt(d,10)||0,b=c+d?Math.min(Math.max(b,d),c):b,e.css(I,Math.round(b)).appendTo(g)),this.drawing=0,this},destroy:function(){this.bgiframe&&this.bgiframe.remove(),this.qtip._unbind([a,this.qtip.tooltip],this._ns)}}),Ab=R.ie6=function(a){return 6===db.ie?new x(a):E},Ab.initialize="render",B.ie6={"^content|style$":function(){this.redraw()}}})}(window,document);
 
188
  </script>
installer/dup-installer/classes/class.db.php CHANGED
@@ -26,7 +26,6 @@ class DUPX_DB
26
  public static function connect($host, $username, $password, $dbname = '')
27
  {
28
  $dbh = null;
29
-
30
  try {
31
  //sock connections
32
  if ('sock' === substr($host, -4)) {
@@ -92,7 +91,7 @@ class DUPX_DB
92
  *
93
  * @param obj $dbh A valid database link handle
94
  * @param string $name A valid table name to remove
95
- *
96
  * @return null
97
  */
98
  public static function dropTable($dbh, $name)
@@ -122,12 +121,12 @@ class DUPX_DB
122
  }
123
 
124
  if (DUPX_U::isTraversable($collations)) {
125
- foreach ($collations as $key => $val) {
126
- $status[$key]['name'] = $val;
127
- $status[$key]['found'] = (in_array($val, $localhost)) ? 1 : 0;
128
- }
129
  }
130
  }
 
131
  $result->free();
132
 
133
  return $status;
@@ -143,7 +142,7 @@ class DUPX_DB
143
  */
144
  public static function getDatabases($dbh, $dbuser = '')
145
  {
146
- $sql = strlen($dbuser) ? "SHOW DATABASES LIKE '%'".mysqli_real_escape_string($dbh, $dbuser)."%'" : 'SHOW DATABASES';
147
  $query = @mysqli_query($dbh, $sql);
148
  if ($query) {
149
  while ($db = @mysqli_fetch_array($query)) {
@@ -256,7 +255,7 @@ class DUPX_DB
256
  return version_compare($version, '4.1', '>=');
257
  case 'set_charset' :
258
  return version_compare($version, '5.0.7', '>=');
259
- };
260
  return false;
261
  }
262
 
@@ -291,7 +290,7 @@ class DUPX_DB
291
  {
292
  $result = array();
293
 
294
- DUPX_Log::info("calling mysqli query on $sql");
295
  $query_result = mysqli_query($dbh, $sql);
296
 
297
  if ($query_result !== false) {
@@ -363,11 +362,27 @@ class DUPX_DB
363
 
364
  if (self::hasAbility($dbh, 'collation') && !empty($charset)) {
365
  if (function_exists('mysqli_set_charset') && self::hasAbility($dbh, 'set_charset')) {
366
- return mysqli_set_charset($dbh, $charset);
 
 
 
 
 
 
367
  } else {
368
  $sql = " SET NAMES ".mysqli_real_escape_string($dbh, $charset);
369
- if (!empty($collate)) $sql .= " COLLATE ".mysqli_real_escape_string($dbh, $collate);
370
- return mysqli_query($dbh, $sql);
 
 
 
 
 
 
 
 
 
 
371
  }
372
  }
373
  }
@@ -388,4 +403,22 @@ class DUPX_DB
388
  }
389
  return in_array($table_name, $cached_table_names);
390
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  }
26
  public static function connect($host, $username, $password, $dbname = '')
27
  {
28
  $dbh = null;
 
29
  try {
30
  //sock connections
31
  if ('sock' === substr($host, -4)) {
91
  *
92
  * @param obj $dbh A valid database link handle
93
  * @param string $name A valid table name to remove
94
+ *
95
  * @return null
96
  */
97
  public static function dropTable($dbh, $name)
121
  }
122
 
123
  if (DUPX_U::isTraversable($collations)) {
124
+ foreach ($collations as $key => $val) {
125
+ $status[$key]['name'] = $val;
126
+ $status[$key]['found'] = (in_array($val, $localhost)) ? 1 : 0;
 
127
  }
128
  }
129
+ }
130
  $result->free();
131
 
132
  return $status;
142
  */
143
  public static function getDatabases($dbh, $dbuser = '')
144
  {
145
+ $sql = strlen($dbuser) ? "SHOW DATABASES LIKE '%".mysqli_real_escape_string($dbh, $dbuser)."%'" : 'SHOW DATABASES';
146
  $query = @mysqli_query($dbh, $sql);
147
  if ($query) {
148
  while ($db = @mysqli_fetch_array($query)) {
255
  return version_compare($version, '4.1', '>=');
256
  case 'set_charset' :
257
  return version_compare($version, '5.0.7', '>=');
258
+ }
259
  return false;
260
  }
261
 
290
  {
291
  $result = array();
292
 
293
+ DUPX_Log::info("calling mysqli query on $sql", DUPX_Log::LV_HARD_DEBUG);
294
  $query_result = mysqli_query($dbh, $sql);
295
 
296
  if ($query_result !== false) {
362
 
363
  if (self::hasAbility($dbh, 'collation') && !empty($charset)) {
364
  if (function_exists('mysqli_set_charset') && self::hasAbility($dbh, 'set_charset')) {
365
+ if (($result = mysqli_set_charset($dbh, mysqli_real_escape_string($dbh, $charset))) === false) {
366
+ $errMsg = mysqli_error($dbh);
367
+ DUPX_Log::info('DATABASE ERROR: mysqli_set_charset '.DUPX_Log::varToString($charset).' MSG: '.$errMsg);
368
+ } else {
369
+ DUPX_Log::info('DATABASE: mysqli_set_charset '.DUPX_Log::varToString($charset), DUPX_Log::LV_DETAILED);
370
+ }
371
+ return $result;
372
  } else {
373
  $sql = " SET NAMES ".mysqli_real_escape_string($dbh, $charset);
374
+ if (!empty($collate)) {
375
+ $sql .= " COLLATE ".mysqli_real_escape_string($dbh, $collate);
376
+ }
377
+
378
+ if (($result = mysqli_query($dbh, $sql)) === false) {
379
+ $errMsg = mysqli_error($dbh);
380
+ DUPX_Log::info('DATABASE SQL ERROR: '.DUPX_Log::varToString($sql).' MSG: '.$errMsg);
381
+ } else {
382
+ DUPX_Log::info('DATABASE SQL: '.DUPX_Log::varToString($sql), DUPX_Log::LV_DETAILED);
383
+ }
384
+
385
+ return $result;
386
  }
387
  }
388
  }
403
  }
404
  return in_array($table_name, $cached_table_names);
405
  }
406
+
407
+ /**
408
+ * mysqli_query wrapper with logging
409
+ *
410
+ * @param mysqli $link
411
+ * @param string $sql
412
+ * @return type
413
+ */
414
+ public static function mysqli_query($link, $sql, $file = '', $line = '')
415
+ {
416
+ if (($result = mysqli_query($link, $sql)) === false) {
417
+ DUPX_Log::info('DB QUERY [ERROR]['.$file.':'.$line.'] SQL: '.DUPX_Log::varToString($sql)."\n\t MSG: ".mysqli_error($link));
418
+ } else {
419
+ DUPX_Log::info('DB QUERY ['.$file.':'.$line.']: '.DUPX_Log::varToString($sql), DUPX_Log::LV_HARD_DEBUG);
420
+ }
421
+
422
+ return $result;
423
+ }
424
  }
installer/dup-installer/classes/class.engine.php CHANGED
@@ -1,6 +1,4 @@
1
  <?php
2
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
-
4
  /**
5
  * Walks every table in db that then walks every row and column replacing searches with replaces
6
  * large tables are split into 50k row blocks to save on memory.
@@ -11,39 +9,42 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
11
  * @package SC\DUPX\UpdateEngine
12
  *
13
  */
 
 
14
  class DUPX_UpdateEngine
15
  {
 
16
 
17
  /**
18
  * Used to report on all log errors into the installer-txt.log
19
  *
20
- * @param string $report The report error array of all error types
21
- *
22
  * @return string Writes the results of the update engine tables to the log
23
  */
24
- public static function logErrors($report)
25
  {
26
- if (!empty($report['errsql'])) {
 
 
27
  DUPX_Log::info("--------------------------------------");
28
  DUPX_Log::info("DATA-REPLACE ERRORS (MySQL)");
29
- foreach ($report['errsql'] as $error) {
30
  DUPX_Log::info($error);
31
  }
32
  DUPX_Log::info("");
33
  }
34
- if (!empty($report['errser'])) {
35
  DUPX_Log::info("--------------------------------------");
36
  DUPX_Log::info("DATA-REPLACE ERRORS (Serialization):");
37
- foreach ($report['errser'] as $error) {
38
  DUPX_Log::info($error);
39
  }
40
  DUPX_Log::info("");
41
  }
42
- if (!empty($report['errkey'])) {
43
  DUPX_Log::info("--------------------------------------");
44
  DUPX_Log::info("DATA-REPLACE ERRORS (Key):");
45
  DUPX_Log::info('Use SQL: SELECT @row := @row + 1 as row, t.* FROM some_table t, (SELECT @row := 0) r');
46
- foreach ($report['errkey'] as $error) {
47
  DUPX_Log::info($error);
48
  }
49
  }
@@ -52,22 +53,18 @@ class DUPX_UpdateEngine
52
  /**
53
  * Used to report on all log stats into the installer-txt.log
54
  *
55
- * @param string $report The report stats array of all error types
56
- *
57
  * @return string Writes the results of the update engine tables to the log
58
  */
59
- public static function logStats($report)
60
  {
61
- if (!empty($report) && is_array($report)) {
 
 
 
62
  $stats = "--------------------------------------\n";
63
- $srchnum = 0;
64
- foreach ($GLOBALS['REPLACE_LIST'] as $item) {
65
- $srchnum++;
66
- $stats .= sprintf("Search{$srchnum}:\t'%s' \nChange{$srchnum}:\t'%s' \n", $item['search'], $item['replace']);
67
- }
68
- $stats .= sprintf("SCANNED:\tTables:%d \t|\t Rows:%d \t|\t Cells:%d \n", $report['scan_tables'], $report['scan_rows'], $report['scan_cells']);
69
- $stats .= sprintf("UPDATED:\tTables:%d \t|\t Rows:%d \t|\t Cells:%d \n", $report['updt_tables'], $report['updt_rows'], $report['updt_cells']);
70
- $stats .= sprintf("ERRORS:\t\t%d \nRUNTIME:\t%f sec", $report['err_all'], $report['time']);
71
  DUPX_Log::info($stats);
72
  }
73
  }
@@ -75,30 +72,26 @@ class DUPX_UpdateEngine
75
  /**
76
  * Returns only the text type columns of a table ignoring all numeric types
77
  *
78
- * @param obj $dbh A valid database link handle
79
  * @param string $table A valid table name
80
  *
81
  * @return array All the column names of a table
82
  */
83
- public static function getTextColumns($conn, $table)
84
  {
85
- $type_where = "type NOT LIKE 'tinyint%' AND ";
86
- $type_where .= "type NOT LIKE 'smallint%' AND ";
87
- $type_where .= "type NOT LIKE 'mediumint%' AND ";
88
- $type_where .= "type NOT LIKE 'int%' AND ";
89
- $type_where .= "type NOT LIKE 'bigint%' AND ";
90
- $type_where .= "type NOT LIKE 'float%' AND ";
91
- $type_where .= "type NOT LIKE 'double%' AND ";
92
- $type_where .= "type NOT LIKE 'decimal%' AND ";
93
- $type_where .= "type NOT LIKE 'numeric%' AND ";
94
- $type_where .= "type NOT LIKE 'date%' AND ";
95
- $type_where .= "type NOT LIKE 'time%' AND ";
96
- $type_where .= "type NOT LIKE 'year%' ";
97
-
98
- $result = mysqli_query($conn, "SHOW COLUMNS FROM `".mysqli_real_escape_string($conn, $table)."` WHERE {$type_where}");
99
  if (!$result) {
100
  return null;
101
  }
 
102
  $fields = array();
103
  if (mysqli_num_rows($result) > 0) {
104
  while ($row = mysqli_fetch_assoc($result)) {
@@ -107,380 +100,617 @@ class DUPX_UpdateEngine
107
  }
108
 
109
  //Return Primary which is needed for index lookup. LIKE '%PRIMARY%' is less accurate with lookup
110
- //$result = mysqli_query($conn, "SHOW INDEX FROM `{$table}` WHERE KEY_NAME LIKE '%PRIMARY%'");
111
- $result = mysqli_query($conn, "SHOW INDEX FROM `".mysqli_real_escape_string($conn, $table)."`");
112
  if (mysqli_num_rows($result) > 0) {
113
  while ($row = mysqli_fetch_assoc($result)) {
114
  $fields[] = $row['Column_name'];
115
  }
116
  }
117
 
118
- return (count($fields) > 0) ? $fields : null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  }
120
 
121
  /**
122
  * Begins the processing for replace logic
123
  *
124
- * @param mysql $dbh The db connection object
125
- * @param array $list Key value pair of 'search' and 'replace' arrays
126
  * @param array $tables The tables we want to look at
127
- * @param array $fullsearch Search every column regardless of its data type
128
  *
129
  * @return array Collection of information gathered during the run.
130
  */
131
- public static function load($conn, $list = array(), $tables = array(), $fullsearch = false)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
- @mysqli_autocommit($conn, false);
135
-
136
- $report = array(
137
- 'scan_tables' => 0,
138
- 'scan_rows' => 0,
139
- 'scan_cells' => 0,
140
- 'updt_tables' => 0,
141
- 'updt_rows' => 0,
142
- 'updt_cells' => 0,
143
- 'errsql' => array(),
144
- 'errser' => array(),
145
- 'errkey' => array(),
146
- 'errsql_sum' => 0,
147
- 'errser_sum' => 0,
148
- 'errkey_sum' => 0,
149
- 'time' => '',
150
- 'err_all' => 0
151
  );
 
152
 
153
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
154
-
155
- function set_sql_column_safe(&$str) {
156
- $str = "`$str`";
157
- }
158
 
159
- $profile_start = DUPX_U::getMicrotime();
160
- if (is_array($tables) && !empty($tables)) {
161
 
162
- foreach ($tables as $table) {
163
- $report['scan_tables']++;
164
- $columns = array();
165
-
166
- // Get a list of columns in this table
167
- $fields = mysqli_query($conn, 'DESCRIBE ' . mysqli_real_escape_string($conn, $table));
168
- if (DUPX_U::isTraversable($fields)) {
169
- while ($column = mysqli_fetch_array($fields)) {
170
- $columns[$column['Field']] = $column['Key'] == 'PRI' ? true : false;
171
- }
172
- }
173
-
174
- // Count the number of rows we have in the table if large we'll split into blocks
175
- $row_count = mysqli_query($conn, "SELECT COUNT(*) FROM `".mysqli_real_escape_string($conn, $table)."`");
176
- $rows_result = mysqli_fetch_array($row_count);
177
- @mysqli_free_result($row_count);
178
- $row_count = $rows_result[0];
179
- if ($row_count == 0) {
180
- DUPX_Log::info("{$table}^ ({$row_count})");
181
- continue;
182
- }
183
 
184
- $page_size = 25000;
185
- $offset = ($page_size + 1);
186
- $pages = ceil($row_count / $page_size);
187
-
188
- // Grab the columns of the table. Only grab text based columns because
189
- // they are the only data types that should allow any type of search/replace logic
190
- $colList = '*';
191
- $colMsg = '*';
192
- if (!$fullsearch) {
193
- $colList = self::getTextColumns($conn, $table);
194
- if ($colList != null && is_array($colList)) {
195
- array_walk($colList, 'set_sql_column_safe');
196
- $colList = implode(',', $colList);
197
- }
198
- $colMsg = (empty($colList)) ? '*' : '~';
199
- }
200
 
201
- if (empty($colList)) {
202
- DUPX_Log::info("{$table}^ ({$row_count})");
203
- continue;
204
- } else {
205
- DUPX_Log::info("{$table}{$colMsg} ({$row_count})");
206
- }
207
 
208
- //Paged Records
209
- for ($page = 0; $page < $pages; $page++) {
210
- $current_row = 0;
211
- $start = $page * $page_size;
212
- $end = $start + $page_size;
213
- $sql = sprintf("SELECT {$colList} FROM `%s` LIMIT %d, %d", mysqli_real_escape_string($conn, $table), $start, $offset);
214
- $data = mysqli_query($conn, $sql);
 
 
 
215
 
216
- if (!$data) {
217
- $report['errsql'][] = mysqli_error($conn);
218
- }
219
 
220
- $scan_count = ($row_count < $end) ? $row_count : $end;
221
- DUPX_Log::info("\tScan => {$start} of {$scan_count}", 2);
222
-
223
- //Loops every row
224
- while ($row = mysqli_fetch_array($data)) {
225
- $report['scan_rows']++;
226
- $current_row++;
227
- $upd_col = array();
228
- $upd_sql = array();
229
- $where_sql = array();
230
- $upd = false;
231
- $serial_err = 0;
232
- $is_unkeyed = !in_array(true, $columns);
233
- $rowErrors = array();
234
-
235
- //Loops every cell
236
- foreach ($columns as $column => $primary_key) {
237
- $report['scan_cells']++;
238
- if (!isset($row[$column])) continue;
239
-
240
- $safe_column = '`'.mysqli_real_escape_string($conn, $column).'`';
241
- $edited_data = $data_to_fix = $row[$column];
242
- $base64converted = false;
243
- $txt_found = false;
244
-
245
- //Unkeyed table code
246
- //Added this here to add all columns to $where_sql
247
- //The if statement with $txt_found would skip additional columns -TG
248
- if($is_unkeyed && ! empty($data_to_fix)) {
249
- $where_sql[] = $safe_column . ' = "' . mysqli_real_escape_string($conn, $data_to_fix) . '"';
250
- }
251
 
252
- //Only replacing string values
253
- if (!empty($row[$column]) && !is_numeric($row[$column]) && $primary_key != 1) {
254
- // Search strings in data
255
- foreach ($list as $item) {
256
- if (strpos($edited_data, $item['search']) !== false) {
257
- $txt_found = true;
258
- break;
259
- }
260
- }
261
-
262
- if (!$txt_found) {
263
- //if not found decetc Base 64
264
- if (($decoded = DUPX_U::is_base64($row[$column])) !== false) {
265
- $edited_data = $decoded;
266
- $base64converted = true;
267
-
268
- // Search strings in data decoded
269
- foreach ($list as $item) {
270
- if (strpos($edited_data, $item['search']) !== false) {
271
- $txt_found = true;
272
- break;
273
- }
274
- }
275
- }
276
-
277
- //Skip table cell if match not found
278
- if (!$txt_found) {
279
- continue;
280
- }
281
- }
282
-
283
- if (self::isSerialized($edited_data) && strlen($edited_data) > MAX_STRLEN_SERIALIZED_CHECK) {
284
- // skip search and replace for too big serialized string
285
- $serial_err++;
286
- $trimLen = DUPX_Log::isLevel(DUPX_Log::LV_HARD_DEBUG) ? 10000 : 150;
287
- $rowErrors[$column] = 'ENGINE: serialize data too big to convert; data len:'.strlen($edited_data).' Max size:'.MAX_STRLEN_SERIALIZED_CHECK;
288
- $rowErrors[$column] .= "\n\tDATA: ".mb_strimwidth($edited_data, 0, $trimLen, ' [...]');
289
- } else {
290
- //Replace logic - level 1: simple check on any string or serlized strings
291
- foreach ($list as $item) {
292
- $objArr = array();
293
- $edited_data = self::recursiveUnserializeReplace($item['search'], $item['replace'], $edited_data, false, $objArr);
294
- }
295
-
296
- //Replace logic - level 2: repair serialized strings that have become broken
297
- $serial_check = self::fixSerialString($edited_data);
298
- if ($serial_check['fixed']) {
299
- $edited_data = $serial_check['data'];
300
- } elseif ($serial_check['tried'] && !$serial_check['fixed']) {
301
- $serial_err++;
302
- $trimLen = DUPX_Log::isLevel(DUPX_Log::LV_HARD_DEBUG) ? 10000 : 150;
303
- $rowErrors[$column] = 'ENGINE: serialize data serial check error';
304
- $rowErrors[$column] .= "\n\tDATA: ".mb_strimwidth($edited_data, 0, $trimLen, ' [...]');
305
- }
306
- }
307
- }
308
 
309
- //Change was made
310
- if ($serial_err > 0 || $edited_data != $data_to_fix) {
311
- $report['updt_cells']++;
312
- //Base 64 encode
313
- if ($base64converted) {
314
- $edited_data = base64_encode($edited_data);
315
- }
316
- $upd_col[] = $safe_column;
317
- $upd_sql[] = $safe_column . ' = "' . mysqli_real_escape_string($conn, $edited_data) . '"';
318
- $upd = true;
319
- }
 
 
320
 
321
- if ($primary_key) {
322
- $where_sql[] = $safe_column . ' = "' . mysqli_real_escape_string($conn, $data_to_fix) . '"';
323
- }
324
- }
325
 
326
- //PERFORM ROW UPDATE
327
- if ($upd && !empty($where_sql)) {
328
- $sql = "UPDATE `".mysqli_real_escape_string($conn, $table)."` SET " . implode(', ', $upd_sql) . ' WHERE ' . implode(' AND ', array_filter($where_sql));
329
- $result = mysqli_query($conn, $sql);
330
- if ($result) {
331
- foreach ($rowErrors as $errCol => $msgCol) {
332
- $longMsg = $msgCol."\n\tTABLE:".$table.' COLUMN: '.$errCol. ' WHERE: '.implode(' AND ', array_filter($where_sql));
333
- $report['errser'][] = $longMsg;
334
-
335
- $nManager->addFinalReportNotice(array(
336
- 'shortMsg' => 'DATA-REPLACE ERROR: Serialization',
337
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
338
- 'longMsg' => $longMsg,
339
- 'sections' => 'search_replace'
340
- ));
341
- }
342
- $report['updt_rows']++;
343
- } else {
344
- $errMsg = mysqli_error($conn);
345
- $report['errsql'][] = (DUPX_Log::isLevel(DUPX_Log::LV_DEBUG))
346
- ? 'DB ERROR: ' . $errMsg . "\nSQL: ".mb_strimwidth($sql, 0, 100000, ' [...]')."\n"
347
- : 'DB ERROR: ' . $errMsg;
348
-
349
- $nManager->addFinalReportNotice(array(
350
- 'shortMsg' => 'DATA-REPLACE ERRORS: MySQL',
351
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
352
- 'longMsg' => $errMsg,
353
- 'longMsgMode'=> DUPX_NOTICE_ITEM::MSG_MODE_PRE,
354
- 'sections' => 'search_replace'
355
- ));
356
- }
357
- //DEBUG ONLY:
358
- DUPX_Log::info("\t".mb_strimwidth($sql, 0, 100000, ' [...]')."\n", DUPX_Log::LV_HARD_DEBUG);
359
- } elseif ($upd) {
360
- $errMsg = sprintf("Row [%s] on Table [%s] requires a manual update.", $current_row, $table);
361
- $report['errkey'][] = $errMsg;
362
-
363
- $nManager->addFinalReportNotice(array(
364
- 'shortMsg' => 'DATA-REPLACE ERROR: Key',
365
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
366
- 'longMsg' => $errMsg,
367
- 'sections' => 'search_replace'
368
- ));
369
- }
370
- }
371
- //DUPX_U::fcgiFlush();
372
- @mysqli_free_result($data);
373
- }
374
 
375
- if ($upd) {
376
- $report['updt_tables']++;
377
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  }
379
  }
380
 
381
- @mysqli_commit($conn);
382
- @mysqli_autocommit($conn, true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
 
384
- $nManager->saveNotices();
 
 
 
385
 
386
- $profile_end = DUPX_U::getMicrotime();
387
- $report['time'] = DUPX_U::elapsedTime($profile_end, $profile_start);
388
- $report['errsql_sum'] = empty($report['errsql']) ? 0 : count($report['errsql']);
389
- $report['errser_sum'] = empty($report['errser']) ? 0 : count($report['errser']);
390
- $report['errkey_sum'] = empty($report['errkey']) ? 0 : count($report['errkey']);
391
- $report['err_all'] = $report['errsql_sum'] + $report['errser_sum'] + $report['errkey_sum'];
392
 
393
- return $report;
394
  }
395
 
396
  /**
397
- * Take a serialized array and unserialized it replacing elements and
398
- * serializing any subordinate arrays and performing the replace.
399
  *
400
- * @param string $from String we're looking to replace.
401
- * @param string $to What we want it to be replaced with
402
- * @param array $data Used to pass any subordinate arrays back to in.
403
- * @param bool $serialised Does the array passed via $data need serializing.
404
  *
405
- * @return array The original array with all elements replaced as needed.
406
  */
407
- public static function recursiveUnserializeReplace($from = '', $to = '', $data = '', $serialised = false, &$objArr = array(), $fixpartials = false)
408
  {
409
- // some unseriliased data cannot be re-serialised eg. SimpleXMLElements
410
- try {
411
- DUPX_Handler::setMode(DUPX_Handler::MODE_OFF);
412
- if (is_string($data) && ($unserialized = @unserialize($data)) !== false) {
413
- $data = self::recursiveUnserializeReplace($from, $to, $unserialized, true, $objArr, $fixpartials);
414
- } elseif (is_array($data)) {
415
- $_tmp = array();
416
- foreach ($data as $key => $value) {
417
- $_tmp[$key] = self::recursiveUnserializeReplace($from, $to, $value, false, $objArr, $fixpartials);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
  }
419
- $data = $_tmp;
420
- unset($_tmp);
421
- } elseif (is_object($data)) {
422
- foreach ($objArr as $obj){
423
- if($obj === spl_object_hash($data)){
424
- DUPX_Log::info("Recursion detected.");
425
- return $data;
426
  }
427
  }
428
 
429
- $objArr[] = spl_object_hash($data);
430
- // RSR NEW LOGIC
431
- $_tmp = $data;
432
- if($fixpartials){
433
- if(method_exists($data,"getObjectVars")) {
434
- $props = $data->getObjectVars();
435
- }else{
436
- $props = get_object_vars($data);
437
- }
438
- foreach ($props as $key => $value) {
439
- $obj_replace_result = self::recursiveUnserializeReplace($from, $to, $value, false, $objArr, $fixpartials);
440
- if(method_exists($_tmp,"setVar")){
441
- $property_name = self::cleanPropertyName($_tmp,$key);
442
- $_tmp->setVar($property_name,$obj_replace_result);
443
- }else{
444
- $_tmp->$key = $obj_replace_result;
445
  }
446
  }
447
- }else{
448
- $props = get_object_vars($data);
449
- foreach ($props as $key => $value) {
450
- if (isset($_tmp->$key)) {
451
- $_tmp->$key = self::recursiveUnserializeReplace($from, $to, $value, false, $objArr);
452
- } else {
453
-
454
- // $key is like \0
455
- $int_key = intval($key);
456
- if ($key == $int_key && isset($_tmp->$int_key)) {
457
- $_tmp->$int_key = self::recursiveUnserializeReplace($from, $to, $value, false, $objArr);
458
- } else {
459
- throw new Exception('Object key->'.$key.' is not exist');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
460
  }
461
  }
462
  }
463
  }
464
- $data = $_tmp;
465
- unset($_tmp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  } else {
467
- if (is_string($data)) {
468
- $data = str_replace($from, $to, $data);
 
 
 
 
 
 
 
 
469
  }
470
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
 
472
- DUPX_Handler::setMode();
473
- if ($serialised) {
474
- return serialize($data);
 
 
 
 
 
 
 
 
475
  }
476
- } catch (Exception $error) {
477
- DUPX_Log::info("\nRECURSIVE UNSERIALIZE ERROR: With string\n" . $error, 2);
478
- } catch (Error $error) {
479
- DUPX_Log::info("\nRECURSIVE UNSERIALIZE ERROR: With string\n" . print_r($error, true), 2);
 
 
480
  }
 
481
  return $data;
482
  }
483
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
  /**
485
  * Test if a string in properly serialized
486
  *
@@ -488,7 +718,7 @@ class DUPX_UpdateEngine
488
  *
489
  * @return bool Is the string a serialized string
490
  */
491
- public static function isSerialized($data)
492
  {
493
  if (!is_string($data)) {
494
  return false;
@@ -497,9 +727,9 @@ class DUPX_UpdateEngine
497
  } else {
498
  try {
499
  DUPX_Handler::setMode(DUPX_Handler::MODE_OFF);
500
- $unserialize_ret = @unserialize($data) !== false;
501
  DUPX_Handler::setMode();
502
- return $unserialize_ret;
503
  } catch (Exception $e) {
504
  DUPX_Log::info("Unserialize exception: ".$e->getMessage());
505
  //DEBUG ONLY:
@@ -508,6 +738,84 @@ class DUPX_UpdateEngine
508
  }
509
  }
510
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
 
512
  /**
513
  * Fixes the string length of a string object that has been serialized but the length is broken
@@ -519,34 +827,133 @@ class DUPX_UpdateEngine
519
  public static function fixSerialString($data)
520
  {
521
  $result = array('data' => $data, 'fixed' => false, 'tried' => false);
522
- if (preg_match("/s:[0-9]+:/", $data)) {
523
- if (!self::isSerialized($data)) {
524
- $regex = '!(?<=^|;)s:(\d+)(?=:"(.*?)";(?:}|a:|s:|b:|d:|i:|o:|N;))!s';
525
- $serial_string = preg_match('/^s:[0-9]+:"(.*$)/s', trim($data), $matches);
526
- //Nested serial string
527
- if ($serial_string) {
528
- $inner = preg_replace_callback($regex, 'DUPX_UpdateEngine::fixStringCallback',
529
- rtrim($matches[1], '";'));
530
- $serialized_fixed = 's:' . strlen($inner) . ':"' . $inner . '";';
531
- } else {
532
- $serialized_fixed = preg_replace_callback($regex, 'DUPX_UpdateEngine::fixStringCallback', $data);
533
- }
534
 
535
- if (self::isSerialized($serialized_fixed)) {
536
- $result['data'] = $serialized_fixed;
537
- $result['fixed'] = true;
538
- }
539
- $result['tried'] = true;
 
 
 
 
 
540
  }
 
 
541
  }
 
542
  return $result;
543
  }
544
 
545
  /**
546
- * The call back method call from via fixSerialString
 
 
 
 
 
547
  */
548
- private static function fixStringCallback($matches)
549
  {
550
- return 's:' . strlen(($matches[2]));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  }
552
  }
1
  <?php
 
 
2
  /**
3
  * Walks every table in db that then walks every row and column replacing searches with replaces
4
  * large tables are split into 50k row blocks to save on memory.
9
  * @package SC\DUPX\UpdateEngine
10
  *
11
  */
12
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
13
+
14
  class DUPX_UpdateEngine
15
  {
16
+ private static $report = null;
17
 
18
  /**
19
  * Used to report on all log errors into the installer-txt.log
20
  *
 
 
21
  * @return string Writes the results of the update engine tables to the log
22
  */
23
+ public static function logErrors()
24
  {
25
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
26
+
27
+ if (!empty($s3Funcs->report['errsql'])) {
28
  DUPX_Log::info("--------------------------------------");
29
  DUPX_Log::info("DATA-REPLACE ERRORS (MySQL)");
30
+ foreach ($s3Funcs->report['errsql'] as $error) {
31
  DUPX_Log::info($error);
32
  }
33
  DUPX_Log::info("");
34
  }
35
+ if (!empty($s3Funcs->report['errser'])) {
36
  DUPX_Log::info("--------------------------------------");
37
  DUPX_Log::info("DATA-REPLACE ERRORS (Serialization):");
38
+ foreach ($s3Funcs->report['errser'] as $error) {
39
  DUPX_Log::info($error);
40
  }
41
  DUPX_Log::info("");
42
  }
43
+ if (!empty($s3Funcs->report['errkey'])) {
44
  DUPX_Log::info("--------------------------------------");
45
  DUPX_Log::info("DATA-REPLACE ERRORS (Key):");
46
  DUPX_Log::info('Use SQL: SELECT @row := @row + 1 as row, t.* FROM some_table t, (SELECT @row := 0) r');
47
+ foreach ($s3Funcs->report['errkey'] as $error) {
48
  DUPX_Log::info($error);
49
  }
50
  }
53
  /**
54
  * Used to report on all log stats into the installer-txt.log
55
  *
 
 
56
  * @return string Writes the results of the update engine tables to the log
57
  */
58
+ public static function logStats()
59
  {
60
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
61
+ DUPX_Log::resetIndent();
62
+
63
+ if (!empty($s3Funcs->report) && is_array($s3Funcs->report)) {
64
  $stats = "--------------------------------------\n";
65
+ $stats .= sprintf("SCANNED:\tTables:%d \t|\t Rows:%d \t|\t Cells:%d \n", $s3Funcs->report['scan_tables'], $s3Funcs->report['scan_rows'], $s3Funcs->report['scan_cells']);
66
+ $stats .= sprintf("UPDATED:\tTables:%d \t|\t Rows:%d \t|\t Cells:%d \n", $s3Funcs->report['updt_tables'], $s3Funcs->report['updt_rows'], $s3Funcs->report['updt_cells']);
67
+ $stats .= sprintf("ERRORS:\t\t%d \nRUNTIME:\t%f sec", $s3Funcs->report['err_all'], $s3Funcs->report['time']);
 
 
 
 
 
68
  DUPX_Log::info($stats);
69
  }
70
  }
72
  /**
73
  * Returns only the text type columns of a table ignoring all numeric types
74
  *
75
+ * @param obj $conn A valid database link handle
76
  * @param string $table A valid table name
77
  *
78
  * @return array All the column names of a table
79
  */
80
+ private static function getTextColumns($table)
81
  {
82
+ $dbh = DUPX_S3_Funcs::getInstance()->getDbConnection();
83
+
84
+ $type_where = '';
85
+ $type_where .= "type LIKE '%char%' OR ";
86
+ $type_where .= "type LIKE '%text' OR ";
87
+ $type_where .= "type LIKE '%blob' ";
88
+ $sql = "SHOW COLUMNS FROM `".mysqli_real_escape_string($dbh, $table)."` WHERE {$type_where}";
89
+
90
+ $result = DUPX_DB::mysqli_query($dbh, $sql, __FILE__, __LINE__);
 
 
 
 
 
91
  if (!$result) {
92
  return null;
93
  }
94
+
95
  $fields = array();
96
  if (mysqli_num_rows($result) > 0) {
97
  while ($row = mysqli_fetch_assoc($result)) {
100
  }
101
 
102
  //Return Primary which is needed for index lookup. LIKE '%PRIMARY%' is less accurate with lookup
103
+ //$result = mysqli_query($dbh, "SHOW INDEX FROM `{$table}` WHERE KEY_NAME LIKE '%PRIMARY%'");
104
+ $result = mysqli_query($dbh, "SHOW INDEX FROM `".mysqli_real_escape_string($dbh, $table)."`");
105
  if (mysqli_num_rows($result) > 0) {
106
  while ($row = mysqli_fetch_assoc($result)) {
107
  $fields[] = $row['Column_name'];
108
  }
109
  }
110
 
111
+ return (count($fields) > 0) ? array_unique($fields) : null;
112
+ }
113
+
114
+ public static function set_sql_column_safe(&$str)
115
+ {
116
+ $str = "`$str`";
117
+ }
118
+
119
+ public static function loadInit()
120
+ {
121
+ DUPX_Log::info('ENGINE LOAD INIT', DUPX_Log::LV_DEBUG);
122
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
123
+ $s3Funcs->report['profile_start'] = DUPX_U::getMicrotime();
124
+
125
+ $dbh = $s3Funcs->getDbConnection();
126
+ @mysqli_autocommit($dbh, false);
127
  }
128
 
129
  /**
130
  * Begins the processing for replace logic
131
  *
 
 
132
  * @param array $tables The tables we want to look at
 
133
  *
134
  * @return array Collection of information gathered during the run.
135
  */
136
+ public static function load($tables = array())
137
+ {
138
+ self::loadInit();
139
+
140
+ if (is_array($tables)) {
141
+ foreach ($tables as $table) {
142
+ self::evaluateTalbe($table);
143
+ }
144
+ }
145
+
146
+ self::commitAndSave();
147
+ return self::loadEnd();
148
+ }
149
+
150
+ public static function commitAndSave()
151
  {
152
+ DUPX_Log::info('ENGINE COMMIT AND SAVE', DUPX_Log::LV_DEBUG);
153
+
154
+ $dbh = DUPX_S3_Funcs::getInstance()->getDbConnection();
155
+
156
+ @mysqli_commit($dbh);
157
+ @mysqli_autocommit($dbh, true);
158
+
159
+ DUPX_NOTICE_MANAGER::getInstance()->saveNotices();
160
+ }
161
+
162
+ public static function loadEnd()
163
+ {
164
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
165
+ DUPX_Log::info('ENGINE LOAD END', DUPX_Log::LV_DEBUG);
166
+
167
+ $s3Funcs->report['profile_end'] = DUPX_U::getMicrotime();
168
+ $s3Funcs->report['time'] = DUPX_U::elapsedTime($s3Funcs->report['profile_end'], $s3Funcs->report['profile_start']);
169
+ $s3Funcs->report['errsql_sum'] = empty($s3Funcs->report['errsql']) ? 0 : count($s3Funcs->report['errsql']);
170
+ $s3Funcs->report['errser_sum'] = empty($s3Funcs->report['errser']) ? 0 : count($s3Funcs->report['errser']);
171
+ $s3Funcs->report['errkey_sum'] = empty($s3Funcs->report['errkey']) ? 0 : count($s3Funcs->report['errkey']);
172
+ $s3Funcs->report['err_all'] = $s3Funcs->report['errsql_sum'] + $s3Funcs->report['errser_sum'] + $s3Funcs->report['errkey_sum'];
173
+
174
+ return $s3Funcs->report;
175
+ }
176
 
177
+ public static function getTableRowParamsDefault($table = '')
178
+ {
179
+ return array(
180
+ 'table' => $table,
181
+ 'updated' => false,
182
+ 'row_count' => 0,
183
+ 'columns' => array(),
184
+ 'colList' => '*',
185
+ 'colMsg' => 'every column',
186
+ 'columnsSRList' => array(),
187
+ 'pages' => 0,
188
+ 'page_size' => 0,
189
+ 'page' => 0,
190
+ 'current_row' => 0
 
 
 
191
  );
192
+ }
193
 
194
+ private static function getTableRowsParams($table)
195
+ {
196
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
197
+ $dbh = $s3Funcs->getDbConnection();
 
198
 
199
+ $rowsParams = self::getTableRowParamsDefault($table);
 
200
 
201
+ // Count the number of rows we have in the table if large we'll split into blocks
202
+ $rowsParams['row_count'] = mysqli_query($dbh, "SELECT COUNT(*) FROM `".mysqli_real_escape_string($dbh, $rowsParams['table'])."`");
203
+ if (!$rowsParams['row_count']) {
204
+ return null;
205
+ }
206
+ $rows_result = mysqli_fetch_array($rowsParams['row_count']);
207
+ @mysqli_free_result($rowsParams['row_count']);
208
+ $rowsParams['row_count'] = $rows_result[0];
209
+ if ($rowsParams['row_count'] == 0) {
210
+ $rowsParams['colMsg'] = 'no columns ';
211
+ self::logEvaluateTable($rowsParams);
212
+ return null;
213
+ }
 
 
 
 
 
 
 
 
214
 
215
+ // Get a list of columns in this table
216
+ $sql = 'DESCRIBE '.mysqli_real_escape_string($dbh, $rowsParams['table']);
217
+ $fields = mysqli_query($dbh, $sql);
218
+ if (!$fields) {
219
+ return null;
220
+ }
221
+ while ($column = mysqli_fetch_array($fields)) {
222
+ $rowsParams['columns'][$column['Field']] = $column['Key'] == 'PRI' ? true : false;
223
+ }
 
 
 
 
 
 
 
224
 
225
+ $rowsParams['page_size'] = $GLOBALS['DATABASE_PAGE_SIZE'];
226
+ $rowsParams['pages'] = ceil($rowsParams['row_count'] / $rowsParams['page_size']);
 
 
 
 
227
 
228
+ // Grab the columns of the table. Only grab text based columns because
229
+ // they are the only data types that should allow any type of search/replace logic
230
+ if (!$s3Funcs->getPost('fullsearch')) {
231
+ $rowsParams['colList'] = self::getTextColumns($rowsParams['table']);
232
+ if ($rowsParams['colList'] != null && is_array($rowsParams['colList'])) {
233
+ array_walk($rowsParams['colList'], array(__CLASS__, 'set_sql_column_safe'));
234
+ $rowsParams['colList'] = implode(',', $rowsParams['colList']);
235
+ }
236
+ $rowsParams['colMsg'] = (empty($rowsParams['colList'])) ? 'every column' : 'text columns';
237
+ }
238
 
239
+ if (empty($rowsParams['colList'])) {
240
+ $rowsParams['colMsg'] = 'no columns ';
241
+ }
242
 
243
+ self::logEvaluateTable($rowsParams);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
 
245
+ if (empty($rowsParams['colList'])) {
246
+ return null;
247
+ } else {
248
+ // PREPARE SEARCH AN REPLACE LISF FOR TABLES
249
+ $rowsParams['columnsSRList'] = self::getColumnsSearchReplaceList($rowsParams['table'], $rowsParams['columns']);
250
+ return $rowsParams;
251
+ }
252
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
+ public static function logEvaluateTable($rowsParams)
255
+ {
256
+ DUPX_Log::resetIndent();
257
+ $log = "\n".'EVALUATE TABLE: '.str_pad(DUPX_Log::varToString($rowsParams['table']), 50, '_', STR_PAD_RIGHT);
258
+ $log .= '[ROWS:'.str_pad($rowsParams['row_count'], 6, " ", STR_PAD_LEFT).']';
259
+ $log .= '[PG:'.str_pad($rowsParams['pages'], 4, " ", STR_PAD_LEFT).']';
260
+ $log .= '[SCAN:'.$rowsParams['colMsg'].']';
261
+ if (DUPX_Log::isLevel(DUPX_Log::LV_DETAILED)) {
262
+ $log .= '[COLS: '.$rowsParams['colList'].']';
263
+ }
264
+ DUPX_Log::info($log);
265
+ DUPX_Log::incIndent();
266
+ }
267
 
268
+ public static function evaluateTalbe($table)
269
+ {
270
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
 
271
 
272
+ // init table params if isn't inizialized
273
+ if (!self::initTableParams($table)) {
274
+ return false;
275
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
 
277
+ //Paged Records
278
+ $pages = $s3Funcs->cTableParams['pages'];
279
+ for ($page = 0; $page < $pages; $page ++) {
280
+ self::evaluateTableRows($table, $page);
281
+ }
282
+
283
+ if ($s3Funcs->cTableParams['updated']) {
284
+ $s3Funcs->report['updt_tables'] ++;
285
+ }
286
+ }
287
+
288
+ public static function evaluateTableRows($table, $page)
289
+ {
290
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
291
+
292
+ // init table params if isn't inizialized
293
+ if (!self::initTableParams($table)) {
294
+ return false;
295
+ }
296
+
297
+ $s3Funcs->cTableParams['page'] = $page;
298
+ if ($s3Funcs->cTableParams['page'] >= $s3Funcs->cTableParams['pages']) {
299
+ DUPX_Log::info('ENGINE EXIT PAGE:'.DUPX_Log::varToString($table).' PAGES:'.$s3Funcs->cTableParams['pages'], DUPX_Log::LV_DEBUG);
300
+ return false;
301
+ }
302
+
303
+ self::evaluatePagedRows($s3Funcs->cTableParams);
304
+ }
305
+
306
+ public static function initTableParams($table)
307
+ {
308
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
309
+ if (is_null($s3Funcs->cTableParams) || $s3Funcs->cTableParams['table'] !== $table) {
310
+ DUPX_Log::info('ENGINE INIT TABLE PARAMS '.DUPX_Log::varToString($table), DUPX_Log::LV_DETAILED);
311
+ $s3Funcs->report['scan_tables'] ++;
312
+
313
+ if (($s3Funcs->cTableParams = self::getTableRowsParams($table)) === null) {
314
+ DUPX_Log::info('ENGINE TABLE PARAMS EMPTY', DUPX_Log::LV_DEBUG);
315
+ return false;
316
  }
317
  }
318
 
319
+ return true;
320
+ }
321
+
322
+ /**
323
+ * evaluate rows with pagination
324
+ *
325
+ * @param array $rowsParams
326
+ *
327
+ * @return boolean // if true table is modified and updated
328
+ */
329
+ private static function evaluatePagedRows(&$rowsParams)
330
+ {
331
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
332
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
333
+ $dbh = $s3Funcs->getDbConnection();
334
+ $start = $rowsParams['page'] * $rowsParams['page_size'];
335
+ $end = $start + $rowsParams['page_size'] - 1;
336
+
337
+ $sql = sprintf("SELECT {$rowsParams['colList']} FROM `%s` LIMIT %d, %d", $rowsParams['table'], $start, $rowsParams['page_size']);
338
+ $data = DUPX_DB::mysqli_query($dbh, $sql, __FILE__, __LINE__);
339
+
340
+ $scan_count = min($rowsParams['row_count'], $end);
341
+ if (DUPX_Log::isLevel(DUPX_Log::LV_DETAILED)) {
342
+ DUPX_Log::info('ENGINE EV TABLE '.str_pad(DUPX_Log::varToString($rowsParams['table']), 50, '_', STR_PAD_RIGHT).
343
+ '[PAGE:'.str_pad($rowsParams['page'], 4, " ", STR_PAD_LEFT).']'.
344
+ '[START:'.str_pad($start, 6, " ", STR_PAD_LEFT).']'.
345
+ '[OF:'.str_pad($scan_count, 6, " ", STR_PAD_LEFT).']', DUPX_Log::LV_DETAILED);
346
+ }
347
+
348
+ if (!$data) {
349
+ $errMsg = mysqli_error($dbh);
350
+ $s3Funcs->report['errsql'][] = $errMsg;
351
+ $nManager->addFinalReportNotice(array(
352
+ 'shortMsg' => 'DATA-REPLACE ERRORS: MySQL',
353
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
354
+ 'longMsg' => $errMsg,
355
+ 'sections' => 'search_replace'
356
+ ));
357
+ }
358
 
359
+ //Loops every row
360
+ while ($row = mysqli_fetch_assoc($data)) {
361
+ self::evaluateRow($rowsParams, $row);
362
+ }
363
 
364
+ //DUPX_U::fcgiFlush();
365
+ @mysqli_free_result($data);
 
 
 
 
366
 
367
+ return $rowsParams['updated'];
368
  }
369
 
370
  /**
371
+ * evaluate single row columns
 
372
  *
373
+ * @param array $rowsParams
374
+ * @param array $row
 
 
375
  *
376
+ * @return boolean true if row is modified and updated
377
  */
378
+ private static function evaluateRow(&$rowsParams, $row)
379
  {
380
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
381
+ $s3Funcs = DUPX_S3_Funcs::getInstance();
382
+ $dbh = $s3Funcs->getDbConnection();
383
+ $maxSerializeLenCheck = $s3Funcs->getPost('maxSerializeStrlen');
384
+
385
+ $s3Funcs->report['scan_rows'] ++;
386
+ $rowsParams['current_row'] ++;
387
+
388
+ $upd_col = array();
389
+ $upd_sql = array();
390
+ $where_sql = array();
391
+ $upd = false;
392
+ $serial_err = 0;
393
+ $is_unkeyed = !in_array(true, $rowsParams['columns']);
394
+
395
+ $rowErrors = array();
396
+
397
+
398
+ //Loops every cell
399
+ foreach ($rowsParams['columns'] as $column => $primary_key) {
400
+ $s3Funcs->report['scan_cells'] ++;
401
+ if (!isset($row[$column])) {
402
+ continue;
403
+ }
404
+
405
+ $safe_column = '`'.mysqli_real_escape_string($dbh, $column).'`';
406
+ $edited_data = $data_to_fix = $row[$column];
407
+ $base64converted = false;
408
+ $txt_found = false;
409
+
410
+ //Unkeyed table code
411
+ //Added this here to add all columns to $where_sql
412
+ //The if statement with $txt_found would skip additional columns -TG
413
+ if ($is_unkeyed && !empty($data_to_fix)) {
414
+ $where_sql[] = $safe_column.' = "'.mysqli_real_escape_string($dbh, $data_to_fix).'"';
415
+ }
416
+
417
+ //Only replacing string values
418
+ if (!empty($row[$column]) && !is_numeric($row[$column]) && $primary_key != 1) {
419
+ // get search and reaplace list for column
420
+ $tColList = &$rowsParams['columnsSRList'][$column]['list'];
421
+ $tColSearchList = &$rowsParams['columnsSRList'][$column]['sList'];
422
+ $tColreplaceList = &$rowsParams['columnsSRList'][$column]['rList'];
423
+ $tColExactMatch = $rowsParams['columnsSRList'][$column]['exactMatch'];
424
+
425
+ // skip empty search col
426
+ if (empty($tColSearchList)) {
427
+ continue;
428
  }
429
+
430
+ // Search strings in data
431
+ foreach ($tColList as $item) {
432
+ if (strpos($edited_data, $item['search']) !== false) {
433
+ $txt_found = true;
434
+ break;
 
435
  }
436
  }
437
 
438
+ if (!$txt_found) {
439
+ //if not found decetc Base 64
440
+ if (($decoded = DUPX_U::is_base64($row[$column])) !== false) {
441
+ $edited_data = $decoded;
442
+ $base64converted = true;
443
+
444
+ // Search strings in data decoded
445
+ foreach ($tColList as $item) {
446
+ if (strpos($edited_data, $item['search']) !== false) {
447
+ $txt_found = true;
448
+ break;
449
+ }
 
 
 
 
450
  }
451
  }
452
+
453
+ //Skip table cell if match not found
454
+ if (!$txt_found) {
455
+ continue;
456
+ }
457
+ }
458
+
459
+ // 0 no limit
460
+ if ($maxSerializeLenCheck > 0 && self::is_serialized_string($edited_data) && strlen($edited_data) > $maxSerializeLenCheck) {
461
+ $serial_err ++;
462
+ $trimLen = DUPX_Log::isLevel(DUPX_Log::LV_HARD_DEBUG) ? 10000 : 200;
463
+ $rowErrors[$column] = 'ENGINE: serialize data too big to convert; data len:'.strlen($edited_data).' Max size:'.$maxSerializeLenCheck;
464
+ $rowErrors[$column] .= "\n\tDATA: ".mb_strimwidth($edited_data, 0, $trimLen, ' [...]');
465
+ } else {
466
+ //Replace logic - level 1: simple check on any string or serlized strings
467
+ if ($tColExactMatch) {
468
+ // if is exact match search and replace the itentical string
469
+ if (($rIndex = array_search($edited_data, $tColSearchList)) !== false) {
470
+ DUPX_Log::info("ColExactMatch ".$column.' search:'.$edited_data.' replace:'.$tColreplaceList[$rIndex].' index:'.$rIndex, DUPX_Log::LV_DEBUG);
471
+ $edited_data = $tColreplaceList[$rIndex];
472
+ }
473
+ } else {
474
+ // search if column contain search list
475
+ $edited_data = self::searchAndReplaceItems($tColSearchList, $tColreplaceList, $edited_data);
476
+
477
+ //Replace logic - level 2: repair serialized strings that have become broken
478
+ // check value without unserialize it
479
+ if (self::is_serialized_string($edited_data)) {
480
+ $serial_check = self::fixSerialString($edited_data);
481
+ if ($serial_check['fixed']) {
482
+ $edited_data = $serial_check['data'];
483
+ } elseif ($serial_check['tried'] && !$serial_check['fixed']) {
484
+ $serial_err ++;
485
+ $trimLen = DUPX_Log::isLevel(DUPX_Log::LV_HARD_DEBUG) ? 10000 : 200;
486
+ $rowErrors[$column] = 'ENGINE: serialize data serial check error';
487
+ $rowErrors[$column] .= "\n\tDATA: ".mb_strimwidth($edited_data, 0, $trimLen, ' [...]');
488
  }
489
  }
490
  }
491
  }
492
+ }
493
+
494
+ //Change was made
495
+ if ($serial_err > 0 || $edited_data != $data_to_fix) {
496
+ $s3Funcs->report['updt_cells'] ++;
497
+ //Base 64 encode
498
+ if ($base64converted) {
499
+ $edited_data = base64_encode($edited_data);
500
+ }
501
+ $upd_col[] = $safe_column;
502
+ $upd_sql[] = $safe_column.' = "'.mysqli_real_escape_string($dbh, $edited_data).'"';
503
+ $upd = true;
504
+ }
505
+
506
+ if ($primary_key) {
507
+ $where_sql[] = $safe_column.' = "'.mysqli_real_escape_string($dbh, $data_to_fix).'"';
508
+ }
509
+ }
510
+
511
+ //PERFORM ROW UPDATE
512
+ if ($upd && !empty($where_sql)) {
513
+ $sql = "UPDATE `{$rowsParams['table']}` SET ".implode(', ', $upd_sql).' WHERE '.implode(' AND ', array_filter($where_sql));
514
+ $result = DUPX_DB::mysqli_query($dbh, $sql, __FILE__, __LINE__);
515
+
516
+ if ($result) {
517
+ foreach ($rowErrors as $errCol => $msgCol) {
518
+ $longMsg = $msgCol."\n\tTABLE:".$rowsParams['table'].' COLUMN: '.$errCol.' WHERE: '.implode(' AND ', array_filter($where_sql));
519
+ $s3Funcs->report['errser'][] = $longMsg;
520
+
521
+ $nManager->addFinalReportNotice(array(
522
+ 'shortMsg' => 'DATA-REPLACE ERROR: Serialization',
523
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
524
+ 'longMsg' => $longMsg,
525
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE,
526
+ 'sections' => 'search_replace'
527
+ ));
528
+ }
529
+ $s3Funcs->report['updt_rows'] ++;
530
+ $rowsParams['updated'] = true;
531
+ } else {
532
+ $errMsg = mysqli_error($dbh)."\n\tTABLE:".$rowsParams['table'].' COLUMN: '.$errCol.' WHERE: '.implode(' AND ', array_filter($where_sql));
533
+ $s3Funcs->report['errsql'][] = ($GLOBALS['LOGGING'] == 1) ? 'DB ERROR: '.$errMsg : 'DB ERROR: '.$errMsg."\nSQL: [{$sql}]\n";
534
+ $nManager->addFinalReportNotice(array(
535
+ 'shortMsg' => 'DATA-REPLACE ERRORS: MySQL',
536
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
537
+ 'longMsg' => $errMsg,
538
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE,
539
+ 'sections' => 'search_replace'
540
+ ));
541
+ }
542
+ } elseif ($upd) {
543
+ $errMsg = sprintf("Row [%s] on Table [%s] requires a manual update.", $rowsParams['current_row'], $rowsParams['table']);
544
+ $s3Funcs->report['errkey'][] = $errMsg;
545
+
546
+ $nManager->addFinalReportNotice(array(
547
+ 'shortMsg' => 'DATA-REPLACE ERROR: Key',
548
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
549
+ 'longMsg' => $errMsg,
550
+ 'sections' => 'search_replace'
551
+ ));
552
+ }
553
+
554
+ return $rowsParams['updated'];
555
+ }
556
+
557
+ private static function getColumnsSearchReplaceList($table, $columns)
558
+ {
559
+ // PREPARE SEARCH AN REPLACE LISF FOR TABLES
560
+ $srManager = DUPX_S_R_MANAGER::getInstance();
561
+ $searchList = array();
562
+ $replaceList = array();
563
+ $list = $srManager->getSearchReplaceList($table);
564
+ foreach ($list as $item) {
565
+ $searchList[] = $item['search'];
566
+ $replaceList[] = $item['replace'];
567
+ }
568
+
569
+ $columnsSRList = array();
570
+ foreach ($columns as $column => $primary_key) {
571
+ if (($cScope = self::getSearchReplaceCustomScope($table, $column)) === false) {
572
+ // if don't have custom scope get normal search and reaplce table list
573
+ $columnsSRList[$column] = array(
574
+ 'list' => &$list,
575
+ 'sList' => &$searchList,
576
+ 'rList' => &$replaceList,
577
+ 'exactMatch' => false
578
+ );
579
  } else {
580
+ // if column have custom scope overvrite default table search/replace list
581
+ $columnsSRList[$column] = array(
582
+ 'list' => $srManager->getSearchReplaceList($cScope, true, false),
583
+ 'sList' => array(),
584
+ 'rList' => array(),
585
+ 'exactMatch' => self::isExactMatch($table, $column)
586
+ );
587
+ foreach ($columnsSRList[$column]['list'] as $item) {
588
+ $columnsSRList[$column]['sList'][] = $item['search'];
589
+ $columnsSRList[$column]['rList'][] = $item['replace'];
590
  }
591
  }
592
+ }
593
+
594
+ return $columnsSRList;
595
+ }
596
+
597
+ /**
598
+ * searches and replaces strings without deserializing
599
+ * recursion for arrays
600
+ *
601
+ * @param array $search
602
+ * @param array $replace
603
+ * @param mixed $data
604
+ *
605
+ * @return mixed
606
+ */
607
+ public static function searchAndReplaceItems($search, $replace, $data)
608
+ {
609
+
610
+ if (empty($data) || is_numeric($data) || is_bool($data) || is_callable($data)) {
611
+
612
+ /* do nothing */
613
+ } else if (is_string($data)) {
614
+
615
+ // Multiple replace string. If the string is serialized will fixed with fixSerialString
616
+ $data = str_replace($search, $replace, $data);
617
+ } else if (is_array($data)) {
618
 
619
+ $_tmp = array();
620
+ foreach ($data as $key => $value) {
621
+
622
+ // prevent recursion overhead
623
+ if (empty($value) || is_numeric($value) || is_bool($value) || is_callable($value) || is_object($data)) {
624
+
625
+ $_tmp[$key] = $value;
626
+ } else {
627
+
628
+ $_tmp[$key] = self::searchAndReplaceItems($search, $replace, $value, false);
629
+ }
630
  }
631
+
632
+ $data = $_tmp;
633
+ unset($_tmp);
634
+ } elseif (is_object($data)) {
635
+ // it can never be an object type
636
+ DUPX_Log::info("OBJECT DATA IMPOSSIBLE\n");
637
  }
638
+
639
  return $data;
640
  }
641
 
642
+ /**
643
+ * FROM WORDPRESS
644
+ * Check value to find if it was serialized.
645
+ *
646
+ * If $data is not an string, then returned value will always be false.
647
+ * Serialized data is always a string.
648
+ *
649
+ * @since 2.0.5
650
+ *
651
+ * @param string $data Value to check to see if was serialized.
652
+ * @param bool $strict Optional. Whether to be strict about the end of the string. Default true.
653
+ * @return bool False if not serialized and true if it was.
654
+ */
655
+ public static function is_serialized_string($data, $strict = true)
656
+ {
657
+ // if it isn't a string, it isn't serialized.
658
+ if (!is_string($data)) {
659
+ return false;
660
+ }
661
+ $data = trim($data);
662
+ if ('N;' == $data) {
663
+ return true;
664
+ }
665
+ if (strlen($data) < 4) {
666
+ return false;
667
+ }
668
+ if (':' !== $data[1]) {
669
+ return false;
670
+ }
671
+ if ($strict) {
672
+ $lastc = substr($data, -1);
673
+ if (';' !== $lastc && '}' !== $lastc) {
674
+ return false;
675
+ }
676
+ } else {
677
+ $semicolon = strpos($data, ';');
678
+ $brace = strpos($data, '}');
679
+ // Either ; or } must exist.
680
+ if (false === $semicolon && false === $brace) {
681
+ return false;
682
+ }
683
+ // But neither must be in the first X characters.
684
+ if (false !== $semicolon && $semicolon < 3) {
685
+ return false;
686
+ }
687
+ if (false !== $brace && $brace < 4) {
688
+ return false;
689
+ }
690
+ }
691
+ $token = $data[0];
692
+ switch ($token) {
693
+ case 's' :
694
+ if ($strict) {
695
+ if ('"' !== substr($data, -2, 1)) {
696
+ return false;
697
+ }
698
+ } elseif (false === strpos($data, '"')) {
699
+ return false;
700
+ }
701
+ // or else fall through
702
+ case 'a' :
703
+ case 'O' :
704
+ return (bool) preg_match("/^{$token}:[0-9]+:/s", $data);
705
+ case 'b' :
706
+ case 'i' :
707
+ case 'd' :
708
+ $end = $strict ? '$' : '';
709
+ return (bool) preg_match("/^{$token}:[0-9.E-]+;$end/", $data);
710
+ }
711
+ return false;
712
+ }
713
+
714
  /**
715
  * Test if a string in properly serialized
716
  *
718
  *
719
  * @return bool Is the string a serialized string
720
  */
721
+ public static function unserializeTest($data)
722
  {
723
  if (!is_string($data)) {
724
  return false;
727
  } else {
728
  try {
729
  DUPX_Handler::setMode(DUPX_Handler::MODE_OFF);
730
+ $unserialize_ret = @unserialize($data);
731
  DUPX_Handler::setMode();
732
+ return ($unserialize_ret !== false);
733
  } catch (Exception $e) {
734
  DUPX_Log::info("Unserialize exception: ".$e->getMessage());
735
  //DEBUG ONLY:
738
  }
739
  }
740
  }
741
+ /**
742
+ * custom columns list
743
+ * if the table / column pair exists in this array then the search scope will be overwritten with that contained in the array
744
+ *
745
+ * @var array
746
+ */
747
+ private static $customScopes = array(
748
+ 'signups' => array(
749
+ 'domain' => array(
750
+ 'scope' => 'domain_host',
751
+ 'exact' => true
752
+ ),
753
+ 'path' => array(
754
+ 'scope' => 'domain_path',
755
+ 'exact' => true
756
+ )
757
+ ),
758
+ 'site' => array(
759
+ 'domain' => array(
760
+ 'scope' => 'domain_host',
761
+ 'exact' => true
762
+ ),
763
+ 'path' => array(
764
+ 'scope' => 'domain_path',
765
+ 'exact' => true
766
+ )
767
+ )
768
+ );
769
+
770
+ /**
771
+ *
772
+ * @param string $table
773
+ * @param string $column
774
+ * @return boolean|string false if custom scope not found or return custom scoper for table/column
775
+ */
776
+ private static function getSearchReplaceCustomScope($table, $column)
777
+ {
778
+ if (strpos($table, $GLOBALS['DUPX_AC']->wp_tableprefix) !== 0) {
779
+ return false;
780
+ }
781
+
782
+ $table_key = substr($table, strlen($GLOBALS['DUPX_AC']->wp_tableprefix));
783
+
784
+ if (!array_key_exists($table_key, self::$customScopes)) {
785
+ return false;
786
+ }
787
+
788
+ if (!array_key_exists($column, self::$customScopes[$table_key])) {
789
+ return false;
790
+ }
791
+
792
+ return self::$customScopes[$table_key][$column]['scope'];
793
+ }
794
+
795
+ /**
796
+ *
797
+ * @param string $table
798
+ * @param string $column
799
+ * @return boolean if true search a exact match in column if false search as LIKE
800
+ */
801
+ private static function isExactMatch($table, $column)
802
+ {
803
+ if (strpos($table, $GLOBALS['DUPX_AC']->wp_tableprefix) !== 0) {
804
+ return false;
805
+ }
806
+
807
+ $table_key = substr($table, strlen($GLOBALS['DUPX_AC']->wp_tableprefix));
808
+
809
+ if (!array_key_exists($table_key, self::$customScopes)) {
810
+ return false;
811
+ }
812
+
813
+ if (!array_key_exists($column, self::$customScopes[$table_key])) {
814
+ return false;
815
+ }
816
+
817
+ return self::$customScopes[$table_key][$column]['exact'];
818
+ }
819
 
820
  /**
821
  * Fixes the string length of a string object that has been serialized but the length is broken
827
  public static function fixSerialString($data)
828
  {
829
  $result = array('data' => $data, 'fixed' => false, 'tried' => false);
 
 
 
 
 
 
 
 
 
 
 
 
830
 
831
+ // check if serialized string must be fixed
832
+ if (!self::unserializeTest($data)) {
833
+
834
+ $serialized_fixed = self::recursiveFixSerialString($data);
835
+
836
+ if (self::unserializeTest($serialized_fixed)) {
837
+
838
+ $result['data'] = $serialized_fixed;
839
+
840
+ $result['fixed'] = true;
841
  }
842
+
843
+ $result['tried'] = true;
844
  }
845
+
846
  return $result;
847
  }
848
 
849
  /**
850
+ * Fixes the string length of a string object that has been serialized but the length is broken
851
+ * Work on nested serialized string recursively.
852
+ *
853
+ * @param string $data The string ojbect to recalculate the size on.
854
+ *
855
+ * @return string A serialized string that fixes and string length types
856
  */
857
+ public static function recursiveFixSerialString($data)
858
  {
859
+
860
+ if (!self::is_serialized_string($data)) {
861
+ return $data;
862
+ }
863
+
864
+ $result = '';
865
+
866
+ $matches = null;
867
+
868
+ $openLevel = 0;
869
+ $openContent = '';
870
+ $openContentL2 = '';
871
+
872
+ // parse every char
873
+ for ($i = 0; $i < strlen($data); $i++) {
874
+
875
+ $cChar = $data[$i];
876
+
877
+ $addChar = true;
878
+
879
+ if ($cChar == 's') {
880
+
881
+ // test if is a open string
882
+ if (preg_match('/^(s:\d+:")/', substr($data, $i), $matches)) {
883
+
884
+ $addChar = false;
885
+
886
+ $openLevel ++;
887
+
888
+ $i += strlen($matches[0]) - 1;
889
+ }
890
+ } else if ($openLevel > 0 && $cChar == '"') {
891
+
892
+ // test if is a close string
893
+ if (preg_match('/^";(?:}|a:|s:|S:|b:|d:|i:|o:|O:|C:|r:|R:|N;)/', substr($data, $i))) {
894
+
895
+ $addChar = false;
896
+
897
+ switch ($openLevel) {
898
+ case 1:
899
+ // level 1
900
+ // flush string content
901
+ $result .= 's:'.strlen($openContent).':"'.$openContent.'";';
902
+
903
+ $openContent = '';
904
+
905
+ break;
906
+ case 2;
907
+ // level 2
908
+ // fix serial string level2
909
+ $sublevelstr = self::recursiveFixSerialString($openContentL2);
910
+
911
+ // flush content on level 1
912
+ $openContent .= 's:'.strlen($sublevelstr).':"'.$sublevelstr.'";';
913
+
914
+ $openContentL2 = '';
915
+
916
+ break;
917
+ default:
918
+ // level > 2
919
+ // keep writing at level 2; it will be corrected with recursion
920
+ break;
921
+ }
922
+
923
+ $openLevel --;
924
+
925
+ $closeString = '";';
926
+
927
+ $i += strlen($closeString) - 1;
928
+ }
929
+ }
930
+
931
+
932
+ if ($addChar) {
933
+
934
+ switch ($openLevel) {
935
+ case 0:
936
+ // level 0
937
+ // add char on result
938
+ $result .= $cChar;
939
+
940
+ break;
941
+ case 1:
942
+ // level 1
943
+ // add char on content level1
944
+ $openContent .= $cChar;
945
+
946
+ break;
947
+ default:
948
+ // level > 1
949
+ // add char on content level2
950
+ $openContentL2 .= $cChar;
951
+
952
+ break;
953
+ }
954
+ }
955
+ }
956
+
957
+ return $result;
958
  }
959
  }
installer/dup-installer/classes/class.http.php CHANGED
@@ -43,7 +43,13 @@ class DUPX_HTTP
43
  $isSecure = true;
44
  }
45
  $protocol = $isSecure ? 'https' : 'http';
46
- $url = "{$protocol}://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
 
 
 
 
 
 
47
  $url = ($show_query) ? $url : preg_replace('/\?.*/', '', $url);
48
  return $url;
49
  }
43
  $isSecure = true;
44
  }
45
  $protocol = $isSecure ? 'https' : 'http';
46
+ // for ngrok url and Local by Flywheel Live URL
47
+ if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) {
48
+ $host = $_SERVER['HTTP_X_ORIGINAL_HOST'];
49
+ } else {
50
+ $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];//WAS SERVER_NAME and caused problems on some boxes
51
+ }
52
+ $url = "{$protocol}://{$host}{$_SERVER['REQUEST_URI']}";
53
  $url = ($show_query) ? $url : preg_replace('/\?.*/', '', $url);
54
  return $url;
55
  }
installer/dup-installer/classes/class.s3.func.php ADDED
@@ -0,0 +1,1319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class used to update and edit web server configuration files
4
+ * for .htaccess, web.config and user.ini
5
+ *
6
+ * Standard: PSR-2
7
+ * @link http://www.php-fig.org/psr/psr-2 Full Documentation
8
+ *
9
+ * @package SC\DUPX\Crypt
10
+ *
11
+ */
12
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
13
+
14
+ /**
15
+ * Step 3 functions
16
+ * Singlethon
17
+ */
18
+ final class DUPX_S3_Funcs
19
+ {
20
+ const MODE_NORMAL = 1;
21
+ // const MODE_CHUNK = 2; reserved for PRO version
22
+ const MODE_SKIP = 3; // not implemented yet
23
+
24
+ /**
25
+ *
26
+ * @var DUPX_S3_Funcs
27
+ */
28
+ protected static $instance = null;
29
+
30
+ /**
31
+ *
32
+ * @var array
33
+ */
34
+ public $post = null;
35
+
36
+ /**
37
+ *
38
+ * @var array
39
+ */
40
+ public $cTableParams = null;
41
+
42
+ /**
43
+ *
44
+ * @var array
45
+ */
46
+ public $report = array();
47
+
48
+ /**
49
+ *
50
+ * @var int
51
+ */
52
+ private $timeStart = null;
53
+
54
+ /**
55
+ *
56
+ * @var database connection
57
+ */
58
+ private $dbh = null;
59
+
60
+ /**
61
+ *
62
+ * @var bool
63
+ */
64
+ private $fullReport = false;
65
+
66
+ private function __construct()
67
+ {
68
+ $this->timeStart = DUPX_U::getMicrotime();
69
+ }
70
+
71
+ /**
72
+ *
73
+ * @return self
74
+ */
75
+ public static function getInstance()
76
+ {
77
+ if (is_null(self::$instance)) {
78
+ self::$instance = new self;
79
+ }
80
+ return self::$instance;
81
+ }
82
+
83
+ /**
84
+ * inizialize 3sFunc data
85
+ */
86
+ public function initData()
87
+ {
88
+ DUPX_Log::info('INIT S3 DATA', 2);
89
+ // else init data from $_POST
90
+ $this->setPostData();
91
+ $this->setReplaceList();
92
+ $this->initReport();
93
+ $this->copyOriginalConfigFiles();
94
+ }
95
+
96
+ private function initReport()
97
+ {
98
+ $this->report = self::getInitReport();
99
+ }
100
+
101
+ public static function getInitReport()
102
+ {
103
+ return array(
104
+ 'pass' => 0,
105
+ 'chunk' => 0,
106
+ 'chunkPos' => array(),
107
+ 'progress_perc' => 0,
108
+ 'scan_tables' => 0,
109
+ 'scan_rows' => 0,
110
+ 'scan_cells' => 0,
111
+ 'updt_tables' => 0,
112
+ 'updt_rows' => 0,
113
+ 'updt_cells' => 0,
114
+ 'errsql' => array(),
115
+ 'errser' => array(),
116
+ 'errkey' => array(),
117
+ 'errsql_sum' => 0,
118
+ 'errser_sum' => 0,
119
+ 'errkey_sum' => 0,
120
+ 'profile_start' => '',
121
+ 'profile_end' => '',
122
+ 'time' => '',
123
+ 'err_all' => 0,
124
+ 'warn_all' => 0,
125
+ 'warnlist' => array()
126
+ );
127
+ }
128
+
129
+ public function getJsonReport()
130
+ {
131
+ $this->report['warn_all'] = empty($this->report['warnlist']) ? 0 : count($this->report['warnlist']);
132
+
133
+ if ($this->fullReport) {
134
+ return array(
135
+ 'step1' => json_decode(urldecode($this->post['json'])),
136
+ 'step3' => $this->report
137
+ );
138
+ } else {
139
+ return array(
140
+ 'step3' => $this->report
141
+ );
142
+ }
143
+ }
144
+
145
+ private static function logSectionHeader($title, $func, $line)
146
+ {
147
+ $log = "\n".'===================================='."\n".
148
+ $title;
149
+ if ($GLOBALS["LOGGING"] > 1) {
150
+ $log .= ' [FUNC: '.$func.' L:'.$line.']';
151
+ }
152
+ $log .= "\n".
153
+ '====================================';
154
+ DUPX_Log::info($log);
155
+ }
156
+
157
+ private function setPostData()
158
+ {
159
+ // POST PARAMS
160
+ // SEARCH AND SEPLACE SETTINGS
161
+ $this->post = array();
162
+
163
+ $this->post['blogname'] = isset($_POST['blogname']) ? htmlspecialchars($_POST['blogname'], ENT_QUOTES) : 'No Blog Title Set';
164
+ $this->post['postguid'] = filter_input(INPUT_POST, 'postguid', FILTER_VALIDATE_BOOLEAN, array('options' => array('default' => false)));
165
+ $this->post['fullsearch'] = filter_input(INPUT_POST, 'fullsearch', FILTER_VALIDATE_BOOLEAN, array('options' => array('default' => false)));
166
+
167
+ $this->post['path_old'] = DUPX_U::isset_sanitize($_POST, 'path_old', array('default' => null, 'trim' => true));
168
+ $this->post['path_new'] = DUPX_U::isset_sanitize($_POST, 'path_new', array('default' => null, 'trim' => true));
169
+
170
+ $this->post['siteurl'] = DUPX_U::isset_sanitize($_POST, 'siteurl', array('default' => null, 'trim' => true));
171
+ if (!is_null($this->post['siteurl'])) {
172
+ $this->post['siteurl'] = rtrim($this->post['siteurl'], '/');
173
+ }
174
+
175
+ $this->post['url_old'] = DUPX_U::isset_sanitize($_POST, 'url_old', array('default' => null, 'trim' => true));
176
+ if (!is_null($this->post['url_old'])) {
177
+ $this->post['siteurl'] = rtrim($this->post['url_old'], '/');
178
+ }
179
+
180
+ $this->post['url_new'] = DUPX_U::isset_sanitize($_POST, 'url_new', array('default' => null, 'trim' => true));
181
+ if (!is_null($this->post['url_new'])) {
182
+ $this->post['siteurl'] = rtrim($this->post['url_new'], '/');
183
+ }
184
+
185
+ $this->post['tables'] = isset($_POST['tables']) && is_array($_POST['tables']) ? array_map('DUPX_U::sanitize_text_field', $_POST['tables']) : array();
186
+ $this->post['maxSerializeStrlen'] = filter_input(INPUT_POST, DUPX_CTRL::NAME_MAX_SERIALIZE_STRLEN_IN_M, FILTER_VALIDATE_INT,
187
+ array("options" => array('default' => DUPX_Constants::DEFAULT_MAX_STRLEN_SERIALIZED_CHECK_IN_M, 'min_range' => 0))) * 1000000;
188
+ $this->post['replaceMail'] = filter_input(INPUT_POST, 'search_replace_email_domain', FILTER_VALIDATE_BOOLEAN, array('options' => array('default' => false)));
189
+
190
+ // DATABASE CONNECTION
191
+ $this->post['dbhost'] = trim(filter_input(INPUT_POST, 'dbhost', FILTER_DEFAULT, array('options' => array('default' => ''))));
192
+ $this->post['dbuser'] = trim(filter_input(INPUT_POST, 'dbuser', FILTER_DEFAULT, array('options' => array('default' => ''))));
193
+ $this->post['dbname'] = trim(filter_input(INPUT_POST, 'dbname', FILTER_DEFAULT, array('options' => array('default' => ''))));
194
+ $this->post['dbpass'] = trim(filter_input(INPUT_POST, 'dbpass', FILTER_DEFAULT, array('options' => array('default' => ''))));
195
+ $this->post['dbcharset'] = DUPX_U::isset_sanitize($_POST, 'dbcharset', array('default' => ''));
196
+ $this->post['dbcollate'] = DUPX_U::isset_sanitize($_POST, 'dbcollate', array('default' => ''));
197
+
198
+ // NEW ADMIN USER
199
+ $this->post['wp_username'] = DUPX_U::isset_sanitize($_POST, 'wp_username', array('default' => '', 'trim' => true));
200
+ $this->post['wp_password'] = DUPX_U::isset_sanitize($_POST, 'wp_password', array('default' => '', 'trim' => true));
201
+ $this->post['wp_mail'] = DUPX_U::isset_sanitize($_POST, 'wp_mail', array('default' => '', 'trim' => true));
202
+ $this->post['wp_nickname'] = DUPX_U::isset_sanitize($_POST, 'wp_nickname', array('default' => '', 'trim' => true));
203
+ $this->post['wp_first_name'] = DUPX_U::isset_sanitize($_POST, 'wp_first_name', array('default' => '', 'trim' => true));
204
+ $this->post['wp_last_name'] = DUPX_U::isset_sanitize($_POST, 'wp_last_name', array('default' => '', 'trim' => true));
205
+
206
+ // WP CONFIG SETTINGS
207
+ $this->post['ssl_admin'] = filter_input(INPUT_POST, 'ssl_admin', FILTER_VALIDATE_BOOLEAN, array('options' => array('default' => false)));
208
+ $this->post['cache_wp'] = filter_input(INPUT_POST, 'cache_wp', FILTER_VALIDATE_BOOLEAN, array('options' => array('default' => false)));
209
+ $this->post['cache_path'] = filter_input(INPUT_POST, 'cache_path', FILTER_VALIDATE_BOOLEAN, array('options' => array('default' => false)));
210
+
211
+ // OTHER
212
+ $this->post['exe_safe_mode'] = filter_input(INPUT_POST, 'exe_safe_mode', FILTER_VALIDATE_BOOLEAN, array('options' => array('default' => false)));
213
+ $this->post['config_mode'] = DUPX_U::isset_sanitize($_POST, 'config_mode', array('default' => 'NEW'));
214
+ $this->post['plugins'] = filter_input(INPUT_POST, 'plugins', FILTER_SANITIZE_STRING,
215
+ array(
216
+ 'options' => array(
217
+ 'default' => array()
218
+ ),
219
+ 'flags' => FILTER_REQUIRE_ARRAY,
220
+ ));
221
+
222
+ $this->post['json'] = filter_input(INPUT_POST, 'json', FILTER_DEFAULT, array('options' => array('default' => '{}')));
223
+ }
224
+
225
+ /**
226
+ * get vaule post if thepost isn't inizialized inizialize it
227
+ *
228
+ * @param string $key
229
+ * @return mixed
230
+ */
231
+ public function getPost($key = null)
232
+ {
233
+ if (is_null($this->post)) {
234
+ $this->initData();
235
+ }
236
+
237
+ if (is_null($key)) {
238
+ return $this->post;
239
+ } else if (isset($this->post[$key])) {
240
+ return $this->post[$key];
241
+ } else {
242
+ return null;
243
+ }
244
+ }
245
+
246
+ /**
247
+ * add table in tables list to scan in search and replace engine if isn't already in array
248
+ *
249
+ * @param string $table
250
+ */
251
+ public function addTable($table)
252
+ {
253
+ if (empty($table)) {
254
+ return;
255
+ }
256
+
257
+ // make sure post data is inizialized
258
+ $this->getPost();
259
+ if (!in_array($table, $this->post['tables'])) {
260
+ $this->post['tables'][] = $table;
261
+ }
262
+ }
263
+
264
+ /**
265
+ * open db connection if is closed
266
+ */
267
+ private function dbConnection()
268
+ {
269
+ if (is_null($this->dbh)) {
270
+ // make sure post data is inizialized
271
+ $this->getPost();
272
+
273
+ //MYSQL CONNECTION
274
+ $this->dbh = DUPX_DB::connect($this->post['dbhost'], $this->post['dbuser'], $this->post['dbpass'], $this->post['dbname']);
275
+ $dbConnError = (mysqli_connect_error()) ? 'Error: '.mysqli_connect_error() : 'Unable to Connect';
276
+
277
+ if (!$this->dbh) {
278
+ $msg = "Unable to connect with the following parameters: <br/> <b>HOST:</b> {$post_db_host}<br/> <b>DATABASE:</b> {$post_db_name}<br/>";
279
+ $msg .= "<b>Connection Error:</b> {$dbConnError}";
280
+ DUPX_Log::error($msg);
281
+ }
282
+
283
+ $db_max_time = mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_TIME']);
284
+ @mysqli_query($this->dbh, "SET wait_timeout = ".mysqli_real_escape_string($this->dbh, $db_max_time));
285
+
286
+ $post_db_charset = $this->post['dbcharset'];
287
+ $post_db_collate = $this->post['dbcollate'];
288
+ DUPX_DB::setCharset($this->dbh, $post_db_charset, $post_db_collate);
289
+ }
290
+ }
291
+
292
+ public function getDbConnection()
293
+ {
294
+ // make sure dbConnection is inizialized
295
+ $this->dbConnection();
296
+ return $this->dbh;
297
+ }
298
+
299
+ /**
300
+ * close db connection if is open
301
+ */
302
+ public function closeDbConnection()
303
+ {
304
+ if (!is_null($this->dbh)) {
305
+ mysqli_close($this->dbh);
306
+ $this->dbh = null;
307
+ }
308
+ }
309
+
310
+ public function initLog()
311
+ {
312
+ // make sure dbConnection is inizialized
313
+ $this->dbConnection();
314
+
315
+ $charsetServer = @mysqli_character_set_name($this->dbh);
316
+ $charsetClient = @mysqli_character_set_name($this->dbh);
317
+
318
+ //LOGGING
319
+ $date = @date('h:i:s');
320
+ $log = "\n\n".
321
+ "********************************************************************************\n".
322
+ "DUPLICATOR PRO INSTALL-LOG\n".
323
+ "STEP-3 START @ ".$date."\n".
324
+ "NOTICE: Do NOT post to public sites or forums\n".
325
+ "********************************************************************************\n".
326
+ "CHARSET SERVER:\t".DUPX_Log::varToString($charsetServer)."\n".
327
+ "CHARSET CLIENT:\t".DUPX_Log::varToString($charsetClient)."\n".
328
+ "********************************************************************************\n".
329
+ "OPTIONS:\n";
330
+
331
+ $skipOpts = array('tables', 'plugins', 'dbpass', 'json', 'search', 'replace', 'mu_search', 'mu_replace', 'wp_password');
332
+ foreach ($this->post as $key => $val) {
333
+ if (in_array($key, $skipOpts)) {
334
+ continue;
335
+ }
336
+ $log .= str_pad($key, 22, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($val)."\n";
337
+ }
338
+ $log .= "********************************************************************************\n";
339
+
340
+ DUPX_Log::info($log);
341
+
342
+ $POST_LOG = $this->post;
343
+ unset($POST_LOG['tables']);
344
+ unset($POST_LOG['plugins']);
345
+ unset($POST_LOG['dbpass']);
346
+ ksort($POST_LOG);
347
+
348
+ //Detailed logging
349
+ $log = "--------------------------------------\n";
350
+ $log .= "POST DATA\n";
351
+ $log .= "--------------------------------------\n";
352
+ $log .= print_r($POST_LOG, true);
353
+ DUPX_Log::info($log, DUPX_Log::LV_DEBUG);
354
+
355
+ $log = "--------------------------------------\n";
356
+ $log .= "TABLES TO SCAN\n";
357
+ $log .= "--------------------------------------\n";
358
+ $log .= (isset($this->post['tables']) && count($this->post['tables']) > 0) ? DUPX_Log::varToString($this->post['tables']) : 'No tables selected to update';
359
+ $log .= "--------------------------------------\n";
360
+ $log .= "KEEP PLUGINS ACTIVE\n";
361
+ $log .= "--------------------------------------\n";
362
+ $log .= (isset($this->post['plugins']) && count($this->post['plugins']) > 0) ? DUPX_Log::varToString($this->post['plugins']) : 'No plugins selected for activation';
363
+ DUPX_Log::info($log, 2);
364
+ DUPX_Log::flush();
365
+ }
366
+
367
+ /**
368
+ *
369
+ * @staticvar type $configTransformer
370
+ *
371
+ * @return WPConfigTransformer
372
+ */
373
+ public function getWpConfigTransformer()
374
+ {
375
+ static $configTransformer = null;
376
+
377
+ if (is_null($configTransformer)) {
378
+ //@todo: integrate all logic into DUPX_WPConfig::updateVars
379
+ if (is_writable($this->getWpconfigArkPath())) {
380
+ $configTransformer = new WPConfigTransformer($this->getWpconfigArkPath());
381
+ } else {
382
+ $err_log = "\nWARNING: Unable to update file permissions and write to dup-wp-config-arc__[HASH].txt. ";
383
+ $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. ";
384
+ $err_log .= "If performing a 'Manual Extraction' please be sure to select the 'Manual Archive Extraction' option on step 1 under options.";
385
+ chmod($this->getWpconfigArkPath(), 0644) ? DUPX_Log::info("File Permission Update: dup-wp-config-arc__[HASH].txt set to 0644") : DUPX_Log::error("{$err_log}");
386
+ }
387
+ }
388
+
389
+ return $configTransformer;
390
+ }
391
+
392
+ /**
393
+ *
394
+ * @staticvar string $path
395
+ * @return string
396
+ */
397
+ public function getWpconfigArkPath()
398
+ {
399
+ static $path = null;
400
+ if (is_null($path)) {
401
+ $path = $GLOBALS['DUPX_AC']->installSiteOverwriteOn ? $GLOBALS['DUPX_ROOT'].'/dup-wp-config-arc__'.$GLOBALS['DUPX_AC']->package_hash.'.txt' : $GLOBALS['DUPX_ROOT'].'/wp-config.php';
402
+ }
403
+ return $path;
404
+ }
405
+
406
+ /**
407
+ *
408
+ * @staticvar string $path
409
+ * @return string
410
+ */
411
+ public function getHtaccessArkPath()
412
+ {
413
+ static $path = null;
414
+ if (is_null($path)) {
415
+ $path = $GLOBALS['DUPX_ROOT'].'/htaccess.orig';
416
+ }
417
+ return $path;
418
+ }
419
+
420
+ /**
421
+ *
422
+ * @staticvar string $path
423
+ * @return string
424
+ */
425
+ public function getOrigWpConfigPath()
426
+ {
427
+ static $path = null;
428
+ if (is_null($path)) {
429
+ $path = $GLOBALS['DUPX_INIT'].'/dup-orig-wp-config__'.$GLOBALS['DUPX_AC']->package_hash.'.txt';
430
+ }
431
+ return $path;
432
+ }
433
+
434
+ /**
435
+ *
436
+ * @staticvar string $path
437
+ * @return string
438
+ */
439
+ public function getOrigHtaccessPath()
440
+ {
441
+ static $path = null;
442
+ if (is_null($path)) {
443
+ $path = $GLOBALS['DUPX_INIT'].'/dup-orig-wp-config__'.$GLOBALS['DUPX_AC']->package_hash.'.txt';
444
+ }
445
+ return $GLOBALS['DUPX_INIT'].'/dup-orig-htaccess__'.$GLOBALS['DUPX_AC']->package_hash.'.txt';
446
+ }
447
+
448
+ /**
449
+ *
450
+ * @return string
451
+ */
452
+ public function copyOriginalConfigFiles()
453
+ {
454
+ $wpOrigPath = $this->getOrigWpConfigPath();
455
+ $wpArkPath = $this->getWpconfigArkPath();
456
+
457
+ if (file_exists($wpOrigPath)) {
458
+ if (!@unlink($wpOrigPath)) {
459
+ DUPX_Log::info('Can\'t delete copy of WP Config orig file');
460
+ }
461
+ }
462
+
463
+ if (!file_exists($wpArkPath)) {
464
+ DUPX_Log::info('WP Config ark file don\' exists');
465
+ }
466
+
467
+ if (!@copy($wpArkPath, $wpOrigPath)) {
468
+ $errors = error_get_last();
469
+ DUPX_Log::info("COPY ERROR: ".$errors['type']."\n".$errors['message']);
470
+ } else {
471
+ echo DUPX_Log::info("Original WP Config file copied", 2);
472
+ }
473
+
474
+ $htOrigPath = $this->getOrigHtaccessPath();
475
+ $htArkPath = $this->getHtaccessArkPath();
476
+
477
+ if (file_exists($htOrigPath)) {
478
+ if (!@unlink($htOrigPath)) {
479
+ DUPX_Log::info('Can\'t delete copy of htaccess orig file');
480
+ }
481
+ }
482
+
483
+ if (!file_exists($htArkPath)) {
484
+ DUPX_Log::info('htaccess ark file don\' exists');
485
+ }
486
+
487
+ if (!@copy($htArkPath, $htOrigPath)) {
488
+ $errors = error_get_last();
489
+ DUPX_Log::info("COPY ERROR: ".$errors['type']."\n".$errors['message']);
490
+ } else {
491
+ echo DUPX_Log::info("htaccess file copied", 2);
492
+ }
493
+ }
494
+
495
+ /**
496
+ * set replace list
497
+ *
498
+ * Auto inizialize function
499
+ */
500
+ public function setReplaceList()
501
+ {
502
+ self::logSectionHeader('SET SEARCH AND REPLACE LIST', __FUNCTION__, __LINE__);
503
+ $this->setGlobalSearchAndReplaceList();
504
+ }
505
+
506
+ /**
507
+ *
508
+ * @return int MODE_NORAML
509
+ */
510
+ public function getEngineMode()
511
+ {
512
+ return self::MODE_NORMAL;
513
+ }
514
+
515
+ private function setGlobalSearchAndReplaceList()
516
+ {
517
+ $s_r_manager = DUPX_S_R_MANAGER::getInstance();
518
+
519
+ // make sure dbConnection is inizialized
520
+ $this->dbConnection();
521
+
522
+ // DIRS PATHS
523
+ $post_path_old = $this->post['path_old'];
524
+ $post_path_new = $this->post['path_new'];
525
+ $s_r_manager->addItem($post_path_old, $post_path_new, DUPX_S_R_ITEM::TYPE_PATH, 10);
526
+
527
+ // URLS
528
+ // url from _POST
529
+ $old_urls_list = array($this->post['url_old']);
530
+ $post_url_new = $this->post['url_new'];
531
+ $at_new_domain = '@'.DUPX_U::getDomain($post_url_new);
532
+
533
+ try {
534
+ $confTransformer = $this->getWpConfigTransformer();
535
+
536
+ // urls from wp-config
537
+ if (!is_null($confTransformer)) {
538
+ if ($confTransformer->exists('constant', 'WP_HOME')) {
539
+ $old_urls_list[] = $confTransformer->get_value('constant', 'WP_HOME');
540
+ }
541
+
542
+ if ($confTransformer->exists('constant', 'WP_SITEURL')) {
543
+ $old_urls_list[] = $confTransformer->get_value('constant', 'WP_SITEURL');
544
+ }
545
+ }
546
+
547
+ // urls from db
548
+ $dbUrls = mysqli_query($this->dbh, 'SELECT * FROM `'.mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix).'options` where option_name IN (\'siteurl\',\'home\')');
549
+ if ($dbUrls instanceof mysqli_result) {
550
+ while ($row = $dbUrls->fetch_object()) {
551
+ $old_urls_list[] = $row->option_value;
552
+ }
553
+ } else {
554
+ DUPX_Log::info('DB ERROR: '.mysqli_error($this->dbh));
555
+ }
556
+ } catch (Exception $e) {
557
+ DUPX_Log::info('CONTINUE EXCEPTION: '.$e->getMessage());
558
+ DUPX_Log::info('TRACE:');
559
+ DUPX_Log::info($e->getTraceAsString());
560
+ }
561
+
562
+ foreach (array_unique($old_urls_list) as $old_url) {
563
+ $s_r_manager->addItem($old_url, $post_url_new, DUPX_S_R_ITEM::TYPE_URL_NORMALIZE_DOMAIN, 10);
564
+
565
+ // Replace email address (xyz@oldomain.com to xyz@newdomain.com).
566
+ if ($this->post['replaceMail']) {
567
+ $at_old_domain = '@'.DUPX_U::getDomain($old_url);
568
+ $s_r_manager->addItem($at_old_domain, $at_new_domain, DUPX_S_R_ITEM::TYPE_STRING, 20);
569
+ }
570
+ }
571
+ }
572
+
573
+ public function runSearchAndReplace()
574
+ {
575
+ self::logSectionHeader('RUN SEARCH AND REPLACE', __FUNCTION__, __LINE__);
576
+
577
+ // make sure post data is inizialized
578
+ $this->getPost();
579
+
580
+ DUPX_UpdateEngine::load($this->post['tables']);
581
+ DUPX_UpdateEngine::logStats();
582
+ DUPX_UpdateEngine::logErrors();
583
+ }
584
+
585
+ public function removeMaincenanceMode()
586
+ {
587
+ self::logSectionHeader('REMOVE MAINTENANCE MODE', __FUNCTION__, __LINE__);
588
+ // make sure post data is inizialized
589
+ $this->getPost();
590
+
591
+
592
+ if (isset($this->post['remove_redundant']) && $this->post['remove_redundant']) {
593
+ if ($GLOBALS['DUPX_STATE']->mode == DUPX_InstallerMode::OverwriteInstall) {
594
+ DUPX_U::maintenanceMode(false, $GLOBALS['DUPX_ROOT']);
595
+ }
596
+ }
597
+ }
598
+
599
+ public function removeLicenseKey()
600
+ {
601
+ self::logSectionHeader('REMOVE LICENSE KEY', __FUNCTION__, __LINE__);
602
+ // make sure dbConnection is inizialized
603
+ $this->dbConnection();
604
+
605
+ if (isset($GLOBALS['DUPX_AC']->brand) && isset($GLOBALS['DUPX_AC']->brand->enabled) && $GLOBALS['DUPX_AC']->brand->enabled) {
606
+ $license_check = mysqli_query($this->dbh,
607
+ "SELECT COUNT(1) AS count FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE `option_name` LIKE 'duplicator_pro_license_key' ");
608
+ $license_row = mysqli_fetch_row($license_check);
609
+ $license_count = is_null($license_row) ? 0 : $license_row[0];
610
+ if ($license_count > 0) {
611
+ mysqli_query($this->dbh,
612
+ "UPDATE `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET `option_value` = '' WHERE `option_name` LIKE 'duplicator_pro_license_key'");
613
+ }
614
+ }
615
+ }
616
+
617
+ public function createNewAdminUser()
618
+ {
619
+ self::logSectionHeader('CREATE NEW ADMIN USER', __FUNCTION__, __LINE__);
620
+ // make sure dbConnection is inizialized
621
+ $this->dbConnection();
622
+
623
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
624
+
625
+ if (strlen($this->post['wp_username']) >= 4 && strlen($this->post['wp_password']) >= 6) {
626
+ $wp_username = mysqli_real_escape_string($this->dbh, $this->post['wp_username']);
627
+ $newuser_check = mysqli_query($this->dbh,
628
+ "SELECT COUNT(*) AS count FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."users` WHERE user_login = '{$wp_username}' ");
629
+ $newuser_row = mysqli_fetch_row($newuser_check);
630
+ $newuser_count = is_null($newuser_row) ? 0 : $newuser_row[0];
631
+
632
+ if ($newuser_count == 0) {
633
+
634
+ $newuser_datetime = @date("Y-m-d H:i:s");
635
+ $newuser_datetime = mysqli_real_escape_string($this->dbh, $newuser_datetime);
636
+ $newuser_security = mysqli_real_escape_string($this->dbh, 'a:1:{s:13:"administrator";b:1;}');
637
+
638
+ $post_wp_username = $this->post['wp_username'];
639
+ $post_wp_password = $this->post['wp_password'];
640
+
641
+ $post_wp_mail = $this->post['wp_mail'];
642
+ $post_wp_nickname = $this->post['wp_nickname'];
643
+ if (empty($post_wp_nickname)) {
644
+ $post_wp_nickname = $post_wp_username;
645
+ }
646
+ $post_wp_first_name = $this->post['wp_first_name'];
647
+ $post_wp_last_name = $this->post['wp_last_name'];
648
+
649
+ $wp_username = mysqli_real_escape_string($this->dbh, $post_wp_username);
650
+ $wp_password = mysqli_real_escape_string($this->dbh, $post_wp_password);
651
+ $wp_mail = mysqli_real_escape_string($this->dbh, $post_wp_mail);
652
+ $wp_nickname = mysqli_real_escape_string($this->dbh, $post_wp_nickname);
653
+ $wp_first_name = mysqli_real_escape_string($this->dbh, $post_wp_first_name);
654
+ $wp_last_name = mysqli_real_escape_string($this->dbh, $post_wp_last_name);
655
+
656
+ $newuser1 = @mysqli_query($this->dbh,
657
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."users`
658
+ (`user_login`, `user_pass`, `user_nicename`, `user_email`, `user_registered`, `user_activation_key`, `user_status`, `display_name`)
659
+ VALUES ('{$wp_username}', MD5('{$wp_password}'), '{$wp_username}', '{$wp_mail}', '{$newuser_datetime}', '', '0', '{$wp_username}')");
660
+
661
+ $newuser1_insert_id = intval(mysqli_insert_id($this->dbh));
662
+
663
+ $newuser2 = @mysqli_query($this->dbh,
664
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta`
665
+ (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', '".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."capabilities', '{$newuser_security}')");
666
+
667
+ $newuser3 = @mysqli_query($this->dbh,
668
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta`
669
+ (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', '".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."user_level', '10')");
670
+
671
+ //Misc Meta-Data Settings:
672
+ @mysqli_query($this->dbh,
673
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'rich_editing', 'true')");
674
+ @mysqli_query($this->dbh,
675
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'admin_color', 'fresh')");
676
+ @mysqli_query($this->dbh,
677
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'nickname', '{$wp_nickname}')");
678
+ @mysqli_query($this->dbh,
679
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'first_name', '{$wp_first_name}')");
680
+ @mysqli_query($this->dbh,
681
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'last_name', '{$wp_last_name}')");
682
+
683
+ DUPX_Log::info("\nNEW WP-ADMIN USER:");
684
+ if ($newuser1 && $newuser2 && $newuser3) {
685
+ DUPX_Log::info("- New username '{$this->post['wp_username']}' was created successfully allong with MU usermeta.");
686
+ } elseif ($newuser1) {
687
+ DUPX_Log::info("- New username '{$this->post['wp_username']}' was created successfully.");
688
+ } else {
689
+ $newuser_warnmsg = "- Failed to create the user '{$this->post['wp_username']}' \n ";
690
+ $this->report['warnlist'][] = $newuser_warnmsg;
691
+
692
+ $nManager->addFinalReportNotice(array(
693
+ 'shortMsg' => 'New admin user create error',
694
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
695
+ 'longMsg' => $newuser_warnmsg,
696
+ 'sections' => 'general'
697
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE, 'new-user-create-error');
698
+
699
+ DUPX_Log::info($newuser_warnmsg);
700
+ }
701
+ } else {
702
+ $newuser_warnmsg = "\nNEW WP-ADMIN USER:\n - Username '{$this->post['wp_username']}' already exists in the database. Unable to create new account.\n";
703
+ $this->report['warnlist'][] = $newuser_warnmsg;
704
+
705
+ $nManager->addFinalReportNotice(array(
706
+ 'shortMsg' => 'New admin user create error',
707
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
708
+ 'longMsg' => $newuser_warnmsg,
709
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE,
710
+ 'sections' => 'general'
711
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE, 'new-user-create-error');
712
+
713
+ DUPX_Log::info($newuser_warnmsg);
714
+ }
715
+ }
716
+ }
717
+
718
+ public function configurationFileUpdate()
719
+ {
720
+ self::logSectionHeader('CONFIGURATION FILE UPDATES', __FUNCTION__, __LINE__);
721
+ DUPX_Log::incIndent();
722
+ // make sure post data is inizialized
723
+ $this->getPost();
724
+ $strReplaced = 0;
725
+
726
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
727
+ try {
728
+ if (file_exists($this->getWpconfigArkPath())) {
729
+ $confTransformer = $this->getWpConfigTransformer();
730
+
731
+ $mu_newDomain = parse_url($this->getPost('url_new'));
732
+ $mu_oldDomain = parse_url($this->getPost('url_old'));
733
+ $mu_newDomainHost = $mu_newDomain['host'];
734
+ $mu_oldDomainHost = $mu_oldDomain['host'];
735
+ $mu_newUrlPath = parse_url($this->getPost('url_new'), PHP_URL_PATH);
736
+ $mu_oldUrlPath = parse_url($this->getPost('url_old'), PHP_URL_PATH);
737
+
738
+ if (empty($mu_newUrlPath) || ($mu_newUrlPath == '/')) {
739
+ $mu_newUrlPath = '/';
740
+ } else {
741
+ $mu_newUrlPath = rtrim($mu_newUrlPath, '/').'/';
742
+ }
743
+
744
+ if (empty($mu_oldUrlPath) || ($mu_oldUrlPath == '/')) {
745
+ $mu_oldUrlPath = '/';
746
+ } else {
747
+ $mu_oldUrlPath = rtrim($mu_oldUrlPath, '/').'/';
748
+ }
749
+
750
+ if ($confTransformer->exists('constant', 'WP_HOME')) {
751
+ $confTransformer->update('constant', 'WP_HOME', $this->post['url_new'], array('normalize' => true, 'add' => false));
752
+ DUPX_Log::info('UPDATE WP_HOME '.DUPX_Log::varToString($this->post['url_new']));
753
+ }
754
+ if ($confTransformer->exists('constant', 'WP_SITEURL')) {
755
+ $confTransformer->update('constant', 'WP_SITEURL', $this->post['url_new'], array('normalize' => true, 'add' => false));
756
+ DUPX_Log::info('UPDATE WP_SITEURL '.DUPX_Log::varToString($this->post['url_new']));
757
+ }
758
+ if ($confTransformer->exists('constant', 'DOMAIN_CURRENT_SITE')) {
759
+ $confTransformer->update('constant', 'DOMAIN_CURRENT_SITE', $mu_newDomainHost, array('normalize' => true, 'add' => false));
760
+ DUPX_Log::info('UPDATE DOMAIN_CURRENT_SITE '.DUPX_Log::varToString($mu_newDomainHost));
761
+ }
762
+ if ($confTransformer->exists('constant', 'PATH_CURRENT_SITE')) {
763
+ $confTransformer->update('constant', 'PATH_CURRENT_SITE', $mu_newUrlPath, array('normalize' => true, 'add' => false));
764
+ DUPX_Log::info('UPDATE PATH_CURRENT_SITE '.DUPX_Log::varToString($mu_newUrlPath));
765
+ }
766
+
767
+ /**
768
+ * clean multisite settings for security reasons.
769
+ */
770
+ if ($confTransformer->exists('constant', 'WP_ALLOW_MULTISITE')) {
771
+ $confTransformer->remove('constant', 'WP_ALLOW_MULTISITE');
772
+ DUPX_Log::info('REMOVED WP_ALLOW_MULTISITE');
773
+ }
774
+ if ($confTransformer->exists('constant', 'ALLOW_MULTISITE')) {
775
+ $confTransformer->update('constant', 'ALLOW_MULTISITE', 'false', array('add' => false, 'raw' => true, 'normalize' => true));
776
+ DUPX_Log::info('TRANSFORMER: ALLOW_MULTISITE constant value set to false in WP config file');
777
+ }
778
+ if ($confTransformer->exists('constant', 'MULTISITE')) {
779
+ $confTransformer->update('constant', 'MULTISITE', 'false', array('add' => false, 'raw' => true, 'normalize' => true));
780
+ DUPX_Log::info('TRANSFORMER: MULTISITE constant value set to false in WP config file');
781
+ }
782
+ if ($confTransformer->exists('constant', 'NOBLOGREDIRECT')) {
783
+ $confTransformer->update('constant', 'NOBLOGREDIRECT', 'false', array('add' => false, 'raw' => true, 'normalize' => true));
784
+ DUPX_Log::info('TRANSFORMER: NOBLOGREDIRECT constant value set to false in WP config file');
785
+ }
786
+ if ($confTransformer->exists('constant', 'SUBDOMAIN_INSTALL')) {
787
+ $confTransformer->remove('constant', 'SUBDOMAIN_INSTALL');
788
+ DUPX_Log::info('TRANSFORMER: SUBDOMAIN_INSTALL constant removed from WP config file');
789
+ }
790
+ if ($confTransformer->exists('constant', 'VHOST')) {
791
+ $confTransformer->remove('constant', 'VHOST');
792
+ DUPX_Log::info('TRANSFORMER: VHOST constant removed from WP config file');
793
+ }
794
+ if ($confTransformer->exists('constant', 'SUNRISE')) {
795
+ $confTransformer->remove('constant', 'SUNRISE');
796
+ DUPX_Log::info('TRANSFORMER: SUNRISE constant removed from WP config file');
797
+ }
798
+
799
+
800
+ $dbname = DUPX_U::getEscapedGenericString($this->post['dbname']);
801
+ $dbuser = DUPX_U::getEscapedGenericString($this->post['dbuser']);
802
+ $dbpass = DUPX_U::getEscapedGenericString($this->post['dbpass']);
803
+ $dbhost = DUPX_U::getEscapedGenericString($this->post['dbhost']);
804
+
805
+ $confTransformer->update('constant', 'DB_NAME', $dbname, array('raw' => true));
806
+ DUPX_Log::info('UPDATE DB_NAME '.DUPX_Log::varToString($dbname));
807
+
808
+ $confTransformer->update('constant', 'DB_USER', $dbuser, array('raw' => true));
809
+ DUPX_Log::info('UPDATE DB_USER '.DUPX_Log::varToString($dbuser));
810
+
811
+ $confTransformer->update('constant', 'DB_PASSWORD', $dbpass, array('raw' => true));
812
+ DUPX_Log::info('UPDATE DB_PASSWORD '.DUPX_Log::varToString('** OBSCURED **'));
813
+
814
+ $confTransformer->update('constant', 'DB_HOST', $dbhost, array('raw' => true));
815
+ DUPX_Log::info('UPDATE DB_HOST '.DUPX_Log::varToString($dbhost));
816
+
817
+ //SSL CHECKS
818
+ if ($this->post['ssl_admin']) {
819
+ $confTransformer->update('constant', 'FORCE_SSL_ADMIN', 'true', array('raw' => true, 'normalize' => true));
820
+ DUPX_Log::info('UPDATE FORCE_SSL_ADMIN '.DUPX_Log::varToString(true));
821
+ } else {
822
+ if ($confTransformer->exists('constant', 'FORCE_SSL_ADMIN')) {
823
+ $confTransformer->update('constant', 'FORCE_SSL_ADMIN', 'false', array('raw' => true, 'add' => false, 'normalize' => true));
824
+ DUPX_Log::info('UPDATE FORCE_SSL_ADMIN '.DUPX_Log::varToString(false));
825
+ }
826
+ }
827
+
828
+ // COOKIE_DOMAIN
829
+ if ($confTransformer->exists('constant', 'COOKIE_DOMAIN')) {
830
+ $const_val = $confTransformer->get_value('constant', 'COOKIE_DOMAIN');
831
+ $const_new_val = str_replace($mu_oldDomainHost, $mu_newDomainHost, $const_val, $strReplaced);
832
+ if ($strReplaced > 0) {
833
+ $confTransformer->update('constant', 'COOKIE_DOMAIN', $const_new_val, array('normalize' => true));
834
+ }
835
+ }
836
+
837
+ if ($this->post['cache_wp']) {
838
+ $confTransformer->update('constant', 'WP_CACHE', 'true', array('raw' => true, 'normalize' => true));
839
+ DUPX_Log::info('UPDATE WP_CACHE '.DUPX_Log::varToString(true));
840
+ } else {
841
+ if ($confTransformer->exists('constant', 'WP_CACHE')) {
842
+ $confTransformer->update('constant', 'WP_CACHE', 'false', array('raw' => true, 'add' => false, 'normalize' => true));
843
+ DUPX_Log::info('UPDATE WP_CACHE '.DUPX_Log::varToString(false));
844
+ }
845
+ }
846
+
847
+ // Cache: [ ] Keep Home Path
848
+ if ($this->post['cache_path']) {
849
+ if ($confTransformer->exists('constant', 'WPCACHEHOME')) {
850
+ $wpcachehome_const_val = $confTransformer->get_value('constant', 'WPCACHEHOME');
851
+ $wpcachehome_const_val = DUPX_U::wp_normalize_path($wpcachehome_const_val);
852
+ $wpcachehome_new_const_val = str_replace($this->post['path_old'], $this->post['path_new'], $wpcachehome_const_val, $strReplaced);
853
+ if ($strReplaced > 0) {
854
+ $confTransformer->update('constant', 'WPCACHEHOME', $wpcachehome_new_const_val, array('normalize' => true));
855
+ DUPX_Log::info('UPDATE WPCACHEHOME '.DUPX_Log::varToString($wpcachehome_new_const_val));
856
+ }
857
+ }
858
+ } else {
859
+ $confTransformer->remove('constant', 'WPCACHEHOME');
860
+ DUPX_Log::info('REMOVE WPCACHEHOME');
861
+ }
862
+
863
+ if ($GLOBALS['DUPX_AC']->is_outer_root_wp_content_dir) {
864
+ if (empty($GLOBALS['DUPX_AC']->wp_content_dir_base_name)) {
865
+ $ret = $confTransformer->remove('constant', 'WP_CONTENT_DIR');
866
+ DUPX_Log::info('REMOVE WP_CONTENT_DIR');
867
+ // sometimes WP_CONTENT_DIR const removal failed, so we need to update them
868
+ if (false === $ret) {
869
+ $wpContentDir = "dirname(__FILE__).'/wp-content'";
870
+ $confTransformer->update('constant', 'WP_CONTENT_DIR', $wpContentDir, array('raw' => true, 'normalize' => true));
871
+ DUPX_Log::info('UPDATE WP_CONTENT_DIR '.DUPX_Log::varToString($wpContentDir));
872
+ }
873
+ } else {
874
+ $wpContentDir = "dirname(__FILE__).'/".$GLOBALS['DUPX_AC']->wp_content_dir_base_name."'";
875
+ $confTransformer->update('constant', 'WP_CONTENT_DIR', $wpContentDir, array('raw' => true, 'normalize' => true));
876
+ DUPX_Log::info('UPDATE WP_CONTENT_DIR '.DUPX_Log::varToString($wpContentDir));
877
+ }
878
+ } elseif ($confTransformer->exists('constant', 'WP_CONTENT_DIR')) {
879
+ $wp_content_dir_const_val = $confTransformer->get_value('constant', 'WP_CONTENT_DIR');
880
+ $wp_content_dir_const_val = DUPX_U::wp_normalize_path($wp_content_dir_const_val);
881
+ $new_path = str_replace($this->post['path_old'], $this->post['path_new'], $wp_content_dir_const_val, $strReplaced);
882
+ if ($strReplaced > 0) {
883
+ $confTransformer->update('constant', 'WP_CONTENT_DIR', $new_path, array('normalize' => true));
884
+ DUPX_Log::info('UPDATE WP_CONTENT_DIR '.DUPX_Log::varToString($new_path));
885
+ }
886
+ }
887
+
888
+ //WP_CONTENT_URL
889
+ // '/' added to prevent word boundary with domains that have the same root path
890
+ if ($GLOBALS['DUPX_AC']->is_outer_root_wp_content_dir) {
891
+ if (empty($GLOBALS['DUPX_AC']->wp_content_dir_base_name)) {
892
+ $ret = $confTransformer->remove('constant', 'WP_CONTENT_URL');
893
+ DUPX_Log::info('REMOVE WP_CONTENT_URL');
894
+ // sometimes WP_CONTENT_DIR const removal failed, so we need to update them
895
+ if (false === $ret) {
896
+ $new_url = $this->post['url_new'].'/wp-content';
897
+ $confTransformer->update('constant', 'WP_CONTENT_URL', $new_url, array('raw' => true, 'normalize' => true));
898
+ DUPX_Log::info('UPDATE WP_CONTENT_URL '.DUPX_Log::varToString($new_url));
899
+ }
900
+ } else {
901
+ $new_url = $this->post['url_new'].'/'.$GLOBALS['DUPX_AC']->wp_content_dir_base_name;
902
+ $confTransformer->update('constant', 'WP_CONTENT_URL', $new_url, array('normalize' => true));
903
+ DUPX_Log::info('UPDATE WP_CONTENT_URL '.DUPX_Log::varToString($new_url));
904
+ }
905
+ } elseif ($confTransformer->exists('constant', 'WP_CONTENT_URL')) {
906
+ $wp_content_url_const_val = $confTransformer->get_value('constant', 'WP_CONTENT_URL');
907
+ $new_path = str_replace($this->post['url_old'].'/', $this->post['url_new'].'/', $wp_content_url_const_val, $strReplaced);
908
+ if ($strReplaced > 0) {
909
+ $confTransformer->update('constant', 'WP_CONTENT_URL', $new_path, array('normalize' => true));
910
+ DUPX_Log::info('UPDATE WP_CONTENT_URL '.DUPX_Log::varToString($new_path));
911
+ }
912
+ }
913
+
914
+ //WP_TEMP_DIR
915
+ if ($confTransformer->exists('constant', 'WP_TEMP_DIR')) {
916
+ $wp_temp_dir_const_val = $confTransformer->get_value('constant', 'WP_TEMP_DIR');
917
+ $wp_temp_dir_const_val = DUPX_U::wp_normalize_path($wp_temp_dir_const_val);
918
+ $new_path = str_replace($this->post['path_old'], $this->post['path_new'], $wp_temp_dir_const_val, $strReplaced);
919
+ if ($strReplaced > 0) {
920
+ $confTransformer->update('constant', 'WP_TEMP_DIR', $new_path, array('normalize' => true));
921
+ DUPX_Log::info('UPDATE WP_TEMP_DIR '.DUPX_Log::varToString($new_path));
922
+ }
923
+ }
924
+
925
+ // WP_PLUGIN_DIR
926
+ if ($confTransformer->exists('constant', 'WP_PLUGIN_DIR')) {
927
+ $wp_plugin_dir_const_val = $confTransformer->get_value('constant', 'WP_PLUGIN_DIR');
928
+ $wp_plugin_dir_const_val = DUPX_U::wp_normalize_path($wp_plugin_dir_const_val);
929
+ $new_path = str_replace($this->post['path_old'], $this->post['path_new'], $wp_plugin_dir_const_val, $strReplaced);
930
+ if ($strReplaced > 0) {
931
+ $confTransformer->update('constant', 'WP_PLUGIN_DIR', $new_path, array('normalize' => true));
932
+ DUPX_Log::info('UPDATE WP_PLUGIN_DIR '.DUPX_Log::varToString($new_path));
933
+ }
934
+ }
935
+
936
+ // WP_PLUGIN_URL
937
+ if ($confTransformer->exists('constant', 'WP_PLUGIN_URL')) {
938
+ $wp_plugin_url_const_val = $confTransformer->get_value('constant', 'WP_PLUGIN_URL');
939
+ $new_path = str_replace($this->post['url_old'].'/', $this->post['url_new'].'/', $wp_plugin_url_const_val, $strReplaced);
940
+ if ($strReplaced > 0) {
941
+ $confTransformer->update('constant', 'WP_PLUGIN_URL', $new_path, array('normalize' => true));
942
+ DUPX_Log::info('UPDATE WP_PLUGIN_URL '.DUPX_Log::varToString($new_path));
943
+ }
944
+ }
945
+
946
+ // WPMU_PLUGIN_DIR
947
+ if ($confTransformer->exists('constant', 'WPMU_PLUGIN_DIR')) {
948
+ $wpmu_plugin_dir_const_val = $confTransformer->get_value('constant', 'WPMU_PLUGIN_DIR');
949
+ $wpmu_plugin_dir_const_val = DUPX_U::wp_normalize_path($wpmu_plugin_dir_const_val);
950
+ $new_path = str_replace($this->post['path_old'], $this->post['path_new'], $wpmu_plugin_dir_const_val, $strReplaced);
951
+ if ($strReplaced > 0) {
952
+ $confTransformer->update('constant', 'WPMU_PLUGIN_DIR', $new_path, array('normalize' => true));
953
+ DUPX_Log::info('UPDATE WPMU_PLUGIN_DIR '.DUPX_Log::varToString($new_path));
954
+ }
955
+ }
956
+
957
+ // WPMU_PLUGIN_URL
958
+ if ($confTransformer->exists('constant', 'WPMU_PLUGIN_URL')) {
959
+ $wpmu_plugin_url_const_val = $confTransformer->get_value('constant', 'WPMU_PLUGIN_URL');
960
+ $new_path = str_replace($this->post['url_old'].'/', $this->post['url_new'].'/', $wpmu_plugin_url_const_val, $strReplaced);
961
+ if ($strReplaced > 0) {
962
+ $confTransformer->update('constant', 'WPMU_PLUGIN_URL', $new_path, array('normalize' => true));
963
+ DUPX_Log::info('UPDATE WPMU_PLUGIN_URL '.DUPX_Log::varToString($new_path));
964
+ }
965
+ }
966
+ DUPX_Log::info("\n*** UPDATED WP CONFIG FILE ***");
967
+ } else {
968
+ DUPX_Log::info("WP-CONFIG ARK FILE NOT FOUND");
969
+ DUPX_Log::info("WP-CONFIG ARK FILE:\n - 'dup-wp-config-arc__[HASH].txt'");
970
+ DUPX_Log::info("SKIP FILE UPDATES\n");
971
+
972
+ $shortMsg = 'wp-config.php not found';
973
+ $longMsg = <<<LONGMSG
974
+ Error updating wp-config file.<br>
975
+ The installation is finished but check the wp-config.php file and manually update the incorrect values.
976
+ LONGMSG;
977
+ /* $nManager->addNextStepNotice(array(
978
+ 'shortMsg' => $shortMsg,
979
+ 'level' => DUPX_NOTICE_ITEM::CRITICAL,
980
+
981
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'wp-config-transformer-exception'); */
982
+ $nManager->addFinalReportNotice(array(
983
+ 'shortMsg' => $shortMsg,
984
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
985
+ 'longMsg' => $longMsg,
986
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
987
+ 'sections' => 'general'
988
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'wp-config-transformer-exception');
989
+ }
990
+ } catch (Exception $e) {
991
+ $shortMsg = 'wp-config.php transformer:'.$e->getMessage();
992
+ $longMsg = <<<LONGMSG
993
+ Error updating wp-config file.<br>
994
+ The installation is finished but check the wp-config.php file and manually update the incorrect values.
995
+ LONGMSG;
996
+ /* $nManager->addNextStepNotice(array(
997
+ 'shortMsg' => $shortMsg,
998
+ 'level' => DUPX_NOTICE_ITEM::CRITICAL,
999
+
1000
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'wp-config-transformer-exception'); */
1001
+ $nManager->addFinalReportNotice(array(
1002
+ 'shortMsg' => $shortMsg,
1003
+ 'level' => DUPX_NOTICE_ITEM::CRITICAL,
1004
+ 'longMsg' => $longMsg,
1005
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
1006
+ 'sections' => 'general'
1007
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'wp-config-transformer-exception');
1008
+
1009
+ DUPX_Log::info("WP-CONFIG TRANSFORMER EXCEPTION\n".$e->getTraceAsString());
1010
+ }
1011
+ DUPX_Log::resetIndent();
1012
+ }
1013
+
1014
+ public function htaccessUpdate()
1015
+ {
1016
+ $this->getPost();
1017
+ self::logSectionHeader('HTACCESS UPDATE MODE: '.DUPX_LOG::varToString($this->post['config_mode']), __FUNCTION__, __LINE__);
1018
+
1019
+
1020
+ switch ($this->post['config_mode']) {
1021
+ case 'NEW':
1022
+ DUPX_ServerConfig::createNewConfigs();
1023
+ break;
1024
+ case 'RESTORE':
1025
+ DUPX_ServerConfig::renameOrigConfigs();
1026
+ DUPX_Log::info("\nWARNING: Retaining the original .htaccess or web.config files may cause");
1027
+ DUPX_Log::info("issues with the initial setup of your site. If you run into issues with the install");
1028
+ DUPX_Log::info("process choose 'Create New' for the 'Config Files' options");
1029
+ break;
1030
+ case 'IGNORE':
1031
+ DUPX_Log::info("\nWARNING: Choosing the option to ignore the .htaccess, web.config and .user.ini files");
1032
+ DUPX_Log::info("can lead to install issues. The 'Ignore All' option is designed for advanced users.");
1033
+ break;
1034
+ }
1035
+ }
1036
+
1037
+ public function generalUpdateAndCleanup()
1038
+ {
1039
+ self::logSectionHeader('GENERAL UPDATES & CLEANUP', __FUNCTION__, __LINE__);
1040
+ // make sure dbConnection is inizialized
1041
+ $this->dbConnection();
1042
+
1043
+ $blog_name = mysqli_real_escape_string($this->dbh, $this->post['blogname']);
1044
+ $plugin_list = $this->post['plugins'];
1045
+
1046
+ if (!in_array('duplicator-pro/duplicator.php', $plugin_list)) {
1047
+ $plugin_list[] = 'duplicator-pro/duplicator.php';
1048
+ }
1049
+ $serial_plugin_list = @serialize($plugin_list);
1050
+
1051
+ /** FINAL UPDATES: Must happen after the global replace to prevent double pathing
1052
+ http://xyz.com/abc01 will become http://xyz.com/abc0101 with trailing data */
1053
+ mysqli_query($this->dbh,
1054
+ "UPDATE `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET option_value = '".mysqli_real_escape_string($this->dbh, $blog_name)."' WHERE option_name = 'blogname' ");
1055
+ mysqli_query($this->dbh,
1056
+ "UPDATE `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET option_value = '".mysqli_real_escape_string($this->dbh, $serial_plugin_list)."' WHERE option_name = 'active_plugins' ");
1057
+ mysqli_query($this->dbh,
1058
+ "UPDATE `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET option_value = '".mysqli_real_escape_string($this->dbh, $this->post['url_new'])."' WHERE option_name = 'home' ");
1059
+ mysqli_query($this->dbh,
1060
+ "UPDATE `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET option_value = '".mysqli_real_escape_string($this->dbh, $this->post['siteurl'])."' WHERE option_name = 'siteurl' ");
1061
+ mysqli_query($this->dbh,
1062
+ "INSERT INTO `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` (option_value, option_name) VALUES('".mysqli_real_escape_string($this->dbh,
1063
+ $this->post['exe_safe_mode'])."','duplicator_pro_exe_safe_mode')");
1064
+ //Reset the postguid data
1065
+ if ($this->post['postguid']) {
1066
+ mysqli_query($this->dbh,
1067
+ "UPDATE `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."posts` SET guid = REPLACE(guid, '".mysqli_real_escape_string($this->dbh, $this->post['url_new'])."', '".mysqli_real_escape_string($this->dbh,
1068
+ $this->post['url_old'])."')");
1069
+ $update_guid = @mysqli_affected_rows($this->dbh) or 0;
1070
+ DUPX_Log::info("Reverted '{$update_guid}' post guid columns back to '{$this->post['url_old']}'");
1071
+ }
1072
+ }
1073
+
1074
+ public function noticeTest()
1075
+ {
1076
+ self::logSectionHeader('NOTICES TEST', __FUNCTION__, __LINE__);
1077
+ // make sure dbConnection is inizialized
1078
+ $this->dbConnection();
1079
+
1080
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
1081
+ if (file_exists($this->getWpconfigArkPath())) {
1082
+ $wpconfig_ark_contents = file_get_contents($this->getWpconfigArkPath());
1083
+ $config_vars = array('WPCACHEHOME', 'COOKIE_DOMAIN', 'WP_SITEURL', 'WP_HOME', 'WP_TEMP_DIR');
1084
+ $config_found = DUPX_U::getListValues($config_vars, $wpconfig_ark_contents);
1085
+
1086
+ //Files
1087
+ if (!empty($config_found)) {
1088
+ $msg = "WP-CONFIG NOTICE: The wp-config.php has following values set [".implode(", ", $config_found)."]. \n";
1089
+ $msg .= "Please validate these values are correct by opening the file and checking the values.\n";
1090
+ $msg .= "See the codex link for more details: https://codex.wordpress.org/Editing_wp-config.php";
1091
+ // old system
1092
+ $this->report['warnlist'][] = $msg;
1093
+ DUPX_Log::info($msg);
1094
+
1095
+ $nManager->addFinalReportNotice(array(
1096
+ 'shortMsg' => 'wp-config notice',
1097
+ 'level' => DUPX_NOTICE_ITEM::NOTICE,
1098
+ 'longMsg' => $msg,
1099
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE,
1100
+ 'sections' => 'general'
1101
+ ));
1102
+ }
1103
+
1104
+ //-- Finally, back up the old wp-config and rename the new one
1105
+ $wpconfig_path = "{$GLOBALS['DUPX_ROOT']}/wp-config.php";
1106
+ if ($this->getWpconfigArkPath() !== $wpconfig_path) {
1107
+ if (copy($this->getWpconfigArkPath(), $wpconfig_path) === false) {
1108
+ DUPX_LOG::info(
1109
+ 'COPY SOURCE: '.DUPX_LOG::varToString($this->getWpconfigArkPath())."\n".
1110
+ "COPY DEST:".DUPX_LOG::varToString($wpconfig_path), DUPX_Log::LV_DEBUG);
1111
+ DUPX_Log::error("ERROR: Unable to copy 'dup-wp-config-arc__[HASH].txt' to 'wp-config.php'.\n".
1112
+ "Check server permissions for more details see FAQ: https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-055-q");
1113
+ }
1114
+ }
1115
+ } else {
1116
+ $msg = "WP-CONFIG NOTICE: <b>wp-config.php not found.</b><br><br>";
1117
+ $msg .= "No action on the wp-config was possible.<br>";
1118
+ $msg .= "Be sure to insert a properly modified wp-config for correct wordpress operation.";
1119
+ $this->report['warnlist'][] = $msg;
1120
+
1121
+ $nManager->addFinalReportNotice(array(
1122
+ 'shortMsg' => 'wp-config not found',
1123
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
1124
+ 'longMsg' => $msg,
1125
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
1126
+ 'sections' => 'general'
1127
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE, 'wp-config-not-found');
1128
+
1129
+ DUPX_Log::info($msg);
1130
+ }
1131
+
1132
+ //Database
1133
+ $result = @mysqli_query($this->dbh,
1134
+ "SELECT option_value FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE option_name IN ('upload_url_path','upload_path')");
1135
+ if ($result) {
1136
+ while ($row = mysqli_fetch_row($result)) {
1137
+ if (strlen($row[0])) {
1138
+ $msg = "MEDIA SETTINGS NOTICE: The table '".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options' has at least one the following values ['upload_url_path','upload_path'] \n";
1139
+ $msg .= "set please validate settings. These settings can be changed in the wp-admin by going to /wp-admin/options.php'";
1140
+
1141
+ $this->report['warnlist'][] = $msg;
1142
+ DUPX_Log::info($msg);
1143
+
1144
+ $nManager->addFinalReportNotice(array(
1145
+ 'shortMsg' => 'Media settings notice',
1146
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
1147
+ 'longMsg' => $msg,
1148
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE,
1149
+ 'sections' => 'general'
1150
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE, 'media-settings-notice');
1151
+
1152
+ break;
1153
+ }
1154
+ }
1155
+ }
1156
+
1157
+ $sql = "INSERT into ".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options (option_name, option_value) VALUES ('duplicator_pro_migration', '1');";
1158
+ @mysqli_query($this->dbh, $sql);
1159
+
1160
+ if (empty($this->report['warnlist'])) {
1161
+ DUPX_Log::info("No General Notices Found\n");
1162
+ }
1163
+ }
1164
+
1165
+ public function cleanupTmpFiles()
1166
+ {
1167
+ self::logSectionHeader('CLEANUP TMP FILES', __FUNCTION__, __LINE__);
1168
+ // make sure post data is inizialized
1169
+ $this->getPost();
1170
+
1171
+ //Cleanup any tmp files a developer may have forgotten about
1172
+ //Lets be proactive for the developer just in case
1173
+ $wpconfig_path_bak = "{$GLOBALS['DUPX_ROOT']}/wp-config.bak";
1174
+ $wpconfig_path_old = "{$GLOBALS['DUPX_ROOT']}/wp-config.old";
1175
+ $wpconfig_path_org = "{$GLOBALS['DUPX_ROOT']}/wp-config.org";
1176
+ $wpconfig_path_orig = "{$GLOBALS['DUPX_ROOT']}/wp-config.orig";
1177
+ $wpconfig_safe_check = array($wpconfig_path_bak, $wpconfig_path_old, $wpconfig_path_org, $wpconfig_path_orig);
1178
+ foreach ($wpconfig_safe_check as $file) {
1179
+ if (file_exists($file)) {
1180
+ $tmp_newfile = $file.uniqid('_');
1181
+ if (rename($file, $tmp_newfile) === false) {
1182
+ DUPX_Log::info("WARNING: Unable to rename '{$file}' to '{$tmp_newfile}'");
1183
+ }
1184
+ }
1185
+ }
1186
+ }
1187
+
1188
+ public function finalReportNotices()
1189
+ {
1190
+ self::logSectionHeader('FINAL REPORT NOTICES', __FUNCTION__, __LINE__);
1191
+
1192
+ $this->wpConfigFinalReport();
1193
+ $this->htaccessFinalReport();
1194
+ }
1195
+
1196
+ private function htaccessFinalReport()
1197
+ {
1198
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
1199
+
1200
+ $orig = file_get_contents($this->getOrigHtaccessPath());
1201
+ $new = file_get_contents($GLOBALS['DUPX_ROOT'].'/.htaccess');
1202
+
1203
+ $lightBoxContent = '<div class="row-cols-2">'.
1204
+ '<div class="col col-1"><b>Original .htaccess</b><pre>'.htmlspecialchars($orig).'</pre></div>'.
1205
+ '<div class="col col-2"><b>New .htaccess</b><pre>'.htmlspecialchars($new).'</pre></div>'.
1206
+ '</div>';
1207
+ $longMsg = DUPX_U_Html::getLigthBox('.htaccess changes', 'HTACCESS COMPARE', $lightBoxContent, false);
1208
+
1209
+ $nManager->addFinalReportNotice(array(
1210
+ 'shortMsg' => 'htaccess changes',
1211
+ 'level' => DUPX_NOTICE_ITEM::INFO,
1212
+ 'longMsg' => $longMsg,
1213
+ 'sections' => 'changes',
1214
+ 'open' => true,
1215
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML
1216
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'htaccess-changes');
1217
+ }
1218
+
1219
+ private function wpConfigFinalReport()
1220
+ {
1221
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
1222
+
1223
+ if (($orig = file_get_contents($this->getOrigWpConfigPath())) === false) {
1224
+ $orig = 'Can read origin wp-config.php file';
1225
+ } else {
1226
+ $orig = $this->obscureWpConfig($orig);
1227
+ }
1228
+
1229
+ if (($new = file_get_contents($GLOBALS['DUPX_ROOT'].'/wp-config.php')) === false) {
1230
+ $new = 'Can read wp-config.php file';
1231
+ } else {
1232
+ $new = $this->obscureWpConfig($new);
1233
+ }
1234
+
1235
+ $lightBoxContent = '<div class="row-cols-2">'.
1236
+ '<div class="col col-1"><b>Original wp-config.php</b><pre>'.htmlspecialchars($orig).'</pre></div>'.
1237
+ '<div class="col col-2"><b>New wp-config.php</b><pre>'.htmlspecialchars($new).'</pre></div>'.
1238
+ '</div>';
1239
+ $longMsg = DUPX_U_Html::getLigthBox('wp-config.php changes', 'WP-CONFIG.PHP COMPARE', $lightBoxContent, false);
1240
+
1241
+ $nManager->addFinalReportNotice(array(
1242
+ 'shortMsg' => 'wp-config.php changes',
1243
+ 'level' => DUPX_NOTICE_ITEM::INFO,
1244
+ 'longMsg' => $longMsg,
1245
+ 'sections' => 'changes',
1246
+ 'open' => true,
1247
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML
1248
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'wp-config-changes');
1249
+ }
1250
+
1251
+ private function obscureWpConfig($src)
1252
+ {
1253
+ $transformer = new WPConfigTransformerSrc($src);
1254
+ $obsKeys = array(
1255
+ 'DB_NAME',
1256
+ 'DB_USER',
1257
+ 'DB_HOST',
1258
+ 'DB_PASSWORD',
1259
+ 'AUTH_KEY',
1260
+ 'SECURE_AUTH_KEY',
1261
+ 'LOGGED_IN_KEY',
1262
+ 'NONCE_KEY',
1263
+ 'AUTH_SALT',
1264
+ 'SECURE_AUTH_SALT',
1265
+ 'LOGGED_IN_SALT',
1266
+ 'NONCE_SALT');
1267
+
1268
+ foreach ($obsKeys as $key) {
1269
+ if ($transformer->exists('constant', $key)) {
1270
+ $transformer->update('constant', $key, '**OBSCURED**');
1271
+ }
1272
+ }
1273
+
1274
+ return $transformer->getSrc();
1275
+ }
1276
+
1277
+ public function complete()
1278
+ {
1279
+ // make sure post data is inizialized
1280
+ $this->getPost();
1281
+ $this->closeDbConnection();
1282
+
1283
+ $ajax3_sum = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $this->timeStart);
1284
+ DUPX_Log::info("\nSTEP-3 COMPLETE @ ".@date('h:i:s')." - RUNTIME: {$ajax3_sum} \n\n");
1285
+
1286
+ $this->fullReport = true;
1287
+ $this->report['pass'] = 1;
1288
+ $this->report['chunk'] = 0;
1289
+ $this->report['chunkPos'] = null;
1290
+ $this->report['progress_perc'] = 100;
1291
+ // error_reporting($ajax3_error_level);
1292
+ }
1293
+
1294
+ public function error($message)
1295
+ {
1296
+ // make sure post data is inizialized
1297
+ $this->getPost();
1298
+
1299
+ $this->closeDbConnection();
1300
+
1301
+ $ajax3_sum = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $this->timeStart);
1302
+ DUPX_Log::info("\nSTEP-3 ERROR @ ".@date('h:i:s')." - RUNTIME: {$ajax3_sum} \n\n");
1303
+
1304
+ $this->report['pass'] = -1;
1305
+ $this->report['chunk'] = 0;
1306
+ $this->report['chunkPos'] = null;
1307
+ $this->report['error_message'] = $message;
1308
+ }
1309
+
1310
+ protected function __clone()
1311
+ {
1312
+
1313
+ }
1314
+
1315
+ public function __wakeup()
1316
+ {
1317
+ throw new Exception("Cannot unserialize singleton");
1318
+ }
1319
+ }
installer/dup-installer/classes/class.view.php CHANGED
@@ -1,73 +1,73 @@
1
- <?php
2
- /**
3
- *
4
- * Standard: PSR-2
5
- * @link http://www.php-fig.org/psr/psr-2 Full Documentation
6
- *
7
- * @package SC\DUPX
8
- *
9
- */
10
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
11
-
12
- /**
13
- * View functions
14
- */
15
- class DUPX_View_Funcs
16
- {
17
-
18
- public static function installerLogLink()
19
- {
20
- $log_url = $GLOBALS['DUPX_ROOT_URL'].'/'.$GLOBALS["LOG_FILE_NAME"].'?now='.DUPX_U::esc_attr($GLOBALS['NOW_TIME']);
21
- DUPX_U_Html::getLightBoxIframe('installer-log.txt', 'installer-log.txt', $log_url, true, true);
22
- }
23
-
24
- public static function getHelpLink($section = '')
25
- {
26
- switch ($section) {
27
- case "secure" :
28
- $helpOpenSection = 'section-security';
29
- break;
30
- case "step1" :
31
- $helpOpenSection = 'section-step-1';
32
- break;
33
- case "step2" :
34
- $helpOpenSection = 'section-step-2';
35
- break;
36
- case "step3" :
37
- $helpOpenSection = 'section-step-3';
38
- break;
39
- case "step4" :
40
- $helpOpenSection = 'section-step-4';
41
- break;
42
- case "help" :
43
- default :
44
- $helpOpenSection = '';
45
- }
46
-
47
- return "?view=help".
48
- "&archive={$GLOBALS['FW_ENCODED_PACKAGE_PATH']}".
49
- "&bootloader={$GLOBALS['BOOTLOADER_NAME']}&".
50
- "basic".
51
- '&open_section='.$helpOpenSection;
52
- }
53
-
54
- public static function helpLink($section, $linkLabel = 'Help')
55
- {
56
- $help_url = self::getHelpLink($section);
57
- DUPX_U_Html::getLightBoxIframe($linkLabel, 'HELP', $help_url);
58
- }
59
-
60
- public static function helpLockLink()
61
- {
62
- if ($GLOBALS['DUPX_AC']->secure_on) {
63
- self::helpLink('secure', '<i class="fa fa-lock fa-xs"></i>');
64
- } else {
65
- self::helpLink('secure', '<i class="fa fa-unlock-alt fa-xs"></i>');
66
- }
67
- }
68
-
69
- public static function helpIconLink($section)
70
- {
71
- self::helpLink($section, '<i class="fas fa-question-circle fa-sm"></i>');
72
- }
73
  }
1
+ <?php
2
+ /**
3
+ *
4
+ * Standard: PSR-2
5
+ * @link http://www.php-fig.org/psr/psr-2 Full Documentation
6
+ *
7
+ * @package SC\DUPX
8
+ *
9
+ */
10
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
11
+
12
+ /**
13
+ * View functions
14
+ */
15
+ class DUPX_View_Funcs
16
+ {
17
+
18
+ public static function installerLogLink()
19
+ {
20
+ $log_url = $GLOBALS['DUPX_ROOT_URL'].'/'.$GLOBALS["LOG_FILE_NAME"].'?now='.DUPX_U::esc_attr($GLOBALS['NOW_TIME']);
21
+ DUPX_U_Html::getLightBoxIframe('dup-installer-log.txt', 'installer-log.txt', $log_url, true, true);
22
+ }
23
+
24
+ public static function getHelpLink($section = '')
25
+ {
26
+ switch ($section) {
27
+ case "secure" :
28
+ $helpOpenSection = 'section-security';
29
+ break;
30
+ case "step1" :
31
+ $helpOpenSection = 'section-step-1';
32
+ break;
33
+ case "step2" :
34
+ $helpOpenSection = 'section-step-2';
35
+ break;
36
+ case "step3" :
37
+ $helpOpenSection = 'section-step-3';
38
+ break;
39
+ case "step4" :
40
+ $helpOpenSection = 'section-step-4';
41
+ break;
42
+ case "help" :
43
+ default :
44
+ $helpOpenSection = '';
45
+ }
46
+
47
+ return "?view=help".
48
+ "&archive={$GLOBALS['FW_ENCODED_PACKAGE_PATH']}".
49
+ "&bootloader={$GLOBALS['BOOTLOADER_NAME']}&".
50
+ "basic".
51
+ '&open_section='.$helpOpenSection;
52
+ }
53
+
54
+ public static function helpLink($section, $linkLabel = 'Help')
55
+ {
56
+ $help_url = self::getHelpLink($section);
57
+ DUPX_U_Html::getLightBoxIframe($linkLabel, 'HELP', $help_url);
58
+ }
59
+
60
+ public static function helpLockLink()
61
+ {
62
+ if ($GLOBALS['DUPX_AC']->secure_on) {
63
+ self::helpLink('secure', '<i class="fa fa-lock fa-xs"></i>');
64
+ } else {
65
+ self::helpLink('secure', '<i class="fa fa-unlock-alt fa-xs"></i>');
66
+ }
67
+ }
68
+
69
+ public static function helpIconLink($section)
70
+ {
71
+ self::helpLink($section, '<i class="fas fa-question-circle fa-sm"></i>');
72
+ }
73
  }
installer/dup-installer/classes/config/class.boot.php CHANGED
@@ -88,6 +88,7 @@ class DUPX_Boot
88
  require_once($GLOBALS['DUPX_INIT'].'/classes/utilities/class.u.notices.manager.php');
89
  require_once($GLOBALS['DUPX_INIT'].'/classes/utilities/class.u.html.php');
90
  require_once($GLOBALS['DUPX_INIT'].'/classes/config/class.constants.php');
 
91
  }
92
 
93
  public static function initArchiveAndLog()
88
  require_once($GLOBALS['DUPX_INIT'].'/classes/utilities/class.u.notices.manager.php');
89
  require_once($GLOBALS['DUPX_INIT'].'/classes/utilities/class.u.html.php');
90
  require_once($GLOBALS['DUPX_INIT'].'/classes/config/class.constants.php');
91
+ require_once($GLOBALS['DUPX_INIT'].'/ctrls/ctrl.base.php');
92
  }
93
 
94
  public static function initArchiveAndLog()
installer/dup-installer/classes/config/class.conf.srv.php CHANGED
@@ -276,20 +276,24 @@ HTACCESS;
276
  break;
277
  }
278
 
279
- if (is_dir(self::$rootPath)){
280
- $dir = new DirectoryIterator(self::$rootPath);
281
- foreach ($dir as $file) {
282
- if ($file->isFile()) {
283
- $name = $file->getFilename();
284
- if (strpos($name, '-duplicator.bak')) {
285
- if (preg_match($pattern, $name))
286
- return true;
287
- }
288
- }
289
- }
290
- }
 
 
 
 
291
 
292
- return false;
293
  }
294
 
295
  /**
@@ -317,198 +321,109 @@ HTACCESS;
317
  break;
318
  }
319
  }
320
-
321
- /**
322
- *
323
- * @staticvar string $path
324
- * @return string
325
- */
326
- public static function getWpconfigArkPath()
327
- {
328
- static $path = null;
329
- if (is_null($path)) {
330
- $path = $GLOBALS['DUPX_AC']->installSiteOverwriteOn ? $GLOBALS['DUPX_ROOT'].'/dup-wp-config-arc__'.$GLOBALS['DUPX_AC']->package_hash.'.txt' : $GLOBALS['DUPX_ROOT'].'/wp-config.php';
331
- }
332
- return $path;
333
- }
334
 
335
  /**
 
336
  *
337
- * @staticvar string $path
338
  * @return string
339
  */
340
- public static function getHtaccessArkPath()
341
  {
342
- static $path = null;
343
- if (is_null($path)) {
344
- $path = $GLOBALS['DUPX_ROOT'].'/htaccess.orig';
 
 
 
 
 
 
 
 
345
  }
346
- return $path;
347
  }
348
 
349
  /**
 
350
  *
351
- * @staticvar string $path
352
- * @return string
353
- */
354
- public static function getOrigWpConfigPath()
355
- {
356
- static $path = null;
357
- if (is_null($path)) {
358
- $path = $GLOBALS['DUPX_INIT'].'/dup-orig-wp-config__'.$GLOBALS['DUPX_AC']->package_hash.'.txt';
359
- }
360
- return $path;
361
- }
362
-
363
- /**
364
  *
365
- * @staticvar string $path
366
- * @return string
367
  */
368
- public static function getOrigHtaccessPath()
369
  {
370
- static $path = null;
371
- if (is_null($path)) {
372
- $path = $GLOBALS['DUPX_INIT'].'/dup-orig-wp-config__'.$GLOBALS['DUPX_AC']->package_hash.'.txt';
 
373
  }
374
- return $GLOBALS['DUPX_INIT'].'/dup-orig-htaccess__'.$GLOBALS['DUPX_AC']->package_hash.'.txt';
 
375
  }
376
 
377
  /**
378
- *
379
- * @return string
380
- */
381
- public static function copyOriginalConfigFiles()
 
 
 
 
 
382
  {
383
- $wpOrigPath = self::getOrigWpConfigPath();
384
- $wpArkPath = self::getWpconfigArkPath();
385
-
386
- if (file_exists($wpOrigPath)) {
387
- if (!@unlink($wpOrigPath)) {
388
- DUPX_Log::info('Can\'t delete copy of WP Config orig file');
389
- }
390
- }
391
-
392
- if (!file_exists($wpArkPath)) {
393
- DUPX_Log::info('WP Config ark file don\' exists');
394
- }
395
-
396
- if (!@copy($wpArkPath, $wpOrigPath)) {
397
- $errors = error_get_last();
398
- DUPX_Log::info("COPY ERROR: ".$errors['type']."\n".$errors['message']);
399
- } else {
400
- echo DUPX_Log::info("Original WP Config file copied", 2);
401
- }
402
-
403
- $htOrigPath = self::getOrigHtaccessPath();
404
- $htArkPath = self::getHtaccessArkPath();
405
-
406
- if (file_exists($htOrigPath)) {
407
- if (!@unlink($htOrigPath)) {
408
- DUPX_Log::info('Can\'t delete copy of htaccess orig file');
409
  }
410
  }
411
 
412
- if (!file_exists($htArkPath)) {
413
- DUPX_Log::info('htaccess ark file don\' exists');
414
- }
415
 
416
- if (!@copy($htArkPath, $htOrigPath)) {
417
- $errors = error_get_last();
418
- DUPX_Log::info("COPY ERROR: ".$errors['type']."\n".$errors['message']);
419
  } else {
420
- echo DUPX_Log::info("htaccess file copied", 2);
421
- }
422
- }
423
-
424
- public static function finalReportNotices()
425
- {
426
- DUPX_Log::info('FINAL REPORT NOTICES');
427
-
428
- self::wpConfigFinalReport();
429
- self::htaccessFinalReport();
430
- }
431
-
432
- private static function htaccessFinalReport()
433
- {
434
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
435
-
436
- $orig = file_get_contents(self::getOrigHtaccessPath());
437
- $new = file_get_contents($GLOBALS['DUPX_ROOT'].'/.htaccess');
438
-
439
- $lightBoxContent = '<div class="row-cols-2">'.
440
- '<div class="col col-1" style="background-color:#fff7f7"><b style="color:maroon"><i class="fas fa-sticky-note"></i> Original .htaccess</b><pre>'.htmlspecialchars($orig).'</pre></div>'.
441
- '<div class="col col-2" style="background-color:#f7fdf1"><b style="color:green"><i class="far fa-sticky-note"></i> New .htaccess</b><pre>'.htmlspecialchars($new).'</pre></div>'.
442
- '</div>';
443
- $longMsg = DUPX_U_Html::getLigthBox('.htaccess changes', 'HTACCESS COMPARE', $lightBoxContent, false);
444
-
445
- $nManager->addFinalReportNotice(array(
446
- 'shortMsg' => 'htaccess changes',
447
- 'level' => DUPX_NOTICE_ITEM::INFO,
448
- 'longMsg' => $longMsg,
449
- 'sections' => 'changes',
450
- 'open' => true,
451
- 'longMsgMode'=> DUPX_NOTICE_ITEM::MSG_MODE_HTML
452
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'htaccess-changes');
453
- }
454
-
455
- private static function wpConfigFinalReport()
456
- {
457
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
458
-
459
- if (($orig = file_get_contents(self::getOrigWpConfigPath())) === false) {
460
- $orig = 'Can read origin wp-config.php file';
461
- } else {
462
- $orig = self::obscureWpConfig($orig);
463
  }
464
 
465
- if (($new = file_get_contents($GLOBALS['DUPX_ROOT'].'/wp-config.php')) === false) {
466
- $new = 'Can read wp-config.php file';
467
  } else {
468
- $new = self::obscureWpConfig($new);
469
  }
470
-
471
- $lightBoxContent = '<div class="row-cols-2">'.
472
- '<div class="col col-1" style="background-color:#fff7f7"><b style="color:maroon"><i class="fas fa-sticky-note"></i> Original wp-config.php</b><pre class="s4-diff-viewer">'.htmlspecialchars($orig).'</pre></div>'.
473
- '<div class="col col-2" style="background-color:#f7fdf1"><b style="color:green"><i class="far fa-sticky-note"></i> New wp-config.php</b><pre class="s4-diff-viewer">'.htmlspecialchars($new).'</pre></div>'.
474
- '</div>';
475
- $longMsg = DUPX_U_Html::getLigthBox('wp-config.php changes', 'WP-CONFIG.PHP COMPARE', $lightBoxContent, false);
476
-
477
- $nManager->addFinalReportNotice(array(
478
- 'shortMsg' => 'wp-config.php changes',
479
- 'level' => DUPX_NOTICE_ITEM::INFO,
480
- 'longMsg' => $longMsg,
481
- 'sections' => 'changes',
482
- 'open' => true,
483
- 'longMsgMode'=> DUPX_NOTICE_ITEM::MSG_MODE_HTML
484
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'wp-config-changes');
485
- }
486
-
487
- private static function obscureWpConfig($src)
488
- {
489
- $transformer = new WPConfigTransformerSrc($src);
490
- $obsKeys = array(
491
- 'DB_NAME',
492
- 'DB_USER',
493
- 'DB_HOST',
494
- 'DB_PASSWORD',
495
- 'AUTH_KEY',
496
- 'SECURE_AUTH_KEY',
497
- 'LOGGED_IN_KEY',
498
- 'NONCE_KEY',
499
- 'AUTH_SALT',
500
- 'SECURE_AUTH_SALT',
501
- 'LOGGED_IN_SALT',
502
- 'NONCE_SALT');
503
-
504
- foreach ($obsKeys as $key) {
505
- if ($transformer->exists('constant', $key)) {
506
- $transformer->update('constant', $key, '**OBSCURED**');
507
- }
508
- }
509
-
510
- return $transformer->getSrc();
511
  }
512
  }
513
-
514
  DUPX_ServerConfig::init();
276
  break;
277
  }
278
 
279
+ if (is_dir(self::$rootPath)) {
280
+ $dir = new DirectoryIterator(self::$rootPath);
281
+ foreach ($dir as $file) {
282
+ if ($file->isDot()) {
283
+ continue;
284
+ }
285
+ if ($file->isFile()) {
286
+ $name = $file->getFilename();
287
+ if (strpos($name, '-duplicator.bak')) {
288
+ if (preg_match($pattern, $name)) {
289
+ return true;
290
+ }
291
+ }
292
+ }
293
+ }
294
+ }
295
 
296
+ return false;
297
  }
298
 
299
  /**
321
  break;
322
  }
323
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
  /**
326
+ * Get AddHadler line from existing WP .htaccess file
327
  *
328
+ * @param $path string root path
329
  * @return string
330
  */
331
+ private static function getOldHtaccessAddhandlerLine($path)
332
  {
333
+ $backupHtaccessPath = $path.'/.htaccess-'.$GLOBALS['DUPX_AC']->package_hash.'.orig';
334
+ if (file_exists($backupHtaccessPath)) {
335
+ $htaccessContent = file_get_contents($backupHtaccessPath);
336
+ if (!empty($htaccessContent)) {
337
+ // match and trim non commented line "AddHandler application/x-httpd-XXXX .php" case insenstive
338
+ $re = '/^[\s\t]*[^#]?[\s\t]*(AddHandler[\s\t]+.+\.php[ \t]?.*?)[\s\t]*$/mi';
339
+ $matches = array();
340
+ if (preg_match($re, $htaccessContent, $matches)) {
341
+ return "\n".$matches[1];
342
+ }
343
+ }
344
  }
345
+ return '';
346
  }
347
 
348
  /**
349
+ * Copies the code in htaccess.orig to .htaccess
350
  *
351
+ * @param $path The root path to the location of the server config files
352
+ * @param $new_htaccess_name New name of htaccess (either .htaccess or a backup name)
 
 
 
 
 
 
 
 
 
 
 
353
  *
354
+ * @return bool Returns true if the .htaccess file was retained successfully
 
355
  */
356
+ public static function renameHtaccess($path, $new_htaccess_name)
357
  {
358
+ $status = false;
359
+
360
+ if (!@rename($path.'/htaccess.orig', $path.'/'.$new_htaccess_name)) {
361
+ $status = true;
362
  }
363
+
364
+ return $status;
365
  }
366
 
367
  /**
368
+ * Sets up the web config file based on the inputs from the installer forms.
369
+ *
370
+ * @param int $mu_mode Is this site a specific multi-site mode
371
+ * @param object $dbh The database connection handle for this request
372
+ * @param string $path The path to the config file
373
+ *
374
+ * @return null
375
+ */
376
+ public static function setup($mu_mode, $mu_generation, $dbh, $path)
377
  {
378
+ DUPX_Log::info("\nWEB SERVER CONFIGURATION FILE UPDATED:");
379
+
380
+ $timestamp = date("Y-m-d H:i:s");
381
+ $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
382
+ $newdata = parse_url($post_url_new);
383
+ $newpath = DUPX_U::addSlash(isset($newdata['path']) ? $newdata['path'] : "");
384
+ $update_msg = "# This file was updated by Duplicator Pro on {$timestamp}.\n";
385
+ $update_msg .= (file_exists("{$path}/.htaccess")) ? "# See htaccess.orig for the .htaccess original file." : "";
386
+ $update_msg .= self::getOldHtaccessAddhandlerLine($path);
387
+
388
+
389
+ // no multisite
390
+ $empty_htaccess = false;
391
+ $query_result = @mysqli_query($dbh, "SELECT option_value FROM `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE option_name = 'permalink_structure' ");
392
+
393
+ if ($query_result) {
394
+ $row = @mysqli_fetch_array($query_result);
395
+ if ($row != null) {
396
+ $permalink_structure = trim($row[0]);
397
+ $empty_htaccess = empty($permalink_structure);
 
 
 
 
 
 
398
  }
399
  }
400
 
 
 
 
401
 
402
+ if ($empty_htaccess) {
403
+ $tmp_htaccess = '';
 
404
  } else {
405
+ $tmp_htaccess = <<<HTACCESS
406
+ {$update_msg}
407
+ # BEGIN WordPress
408
+ <IfModule mod_rewrite.c>
409
+ RewriteEngine On
410
+ RewriteBase {$newpath}
411
+ RewriteRule ^index\.php$ - [L]
412
+ RewriteCond %{REQUEST_FILENAME} !-f
413
+ RewriteCond %{REQUEST_FILENAME} !-d
414
+ RewriteRule . {$newpath}index.php [L]
415
+ </IfModule>
416
+ # END WordPress
417
+ HTACCESS;
418
+ DUPX_Log::info("- Preparing .htaccess file with basic setup.");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  }
420
 
421
+ if (@file_put_contents("{$path}/.htaccess", $tmp_htaccess) === FALSE) {
422
+ DUPX_Log::info("WARNING: Unable to update the .htaccess file! Please check the permission on the root directory and make sure the .htaccess exists.");
423
  } else {
424
+ DUPX_Log::info("- Successfully updated the .htaccess file setting.");
425
  }
426
+ @chmod("{$path}/.htaccess", 0644);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  }
428
  }
 
429
  DUPX_ServerConfig::init();
installer/dup-installer/classes/config/class.constants.php CHANGED
@@ -12,6 +12,14 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
  */
13
  class DUPX_Constants
14
  {
 
 
 
 
 
 
 
 
15
  /**
16
  * Init method used to auto initialize the global params
17
  *
@@ -36,6 +44,7 @@ class DUPX_Constants
36
  //DATABASE SETUP: all time in seconds
37
  //max_allowed_packet: max value 1073741824 (1268MB) see my.ini
38
  $GLOBALS['DB_MAX_TIME'] = 5000;
 
39
  $GLOBALS['DB_MAX_PACKETS'] = 268435456;
40
  $GLOBALS['DBCHARSET_DEFAULT'] = 'utf8';
41
  $GLOBALS['DBCOLLATE_DEFAULT'] = 'utf8_general_ci';
@@ -78,9 +87,9 @@ class DUPX_Constants
78
  $GLOBALS['LOG_FILE_PATH'] = $GLOBALS['DUPX_INIT'] . '/' . $GLOBALS["LOG_FILE_NAME"];
79
  $GLOBALS["NOTICES_FILE_NAME"] = "dup-installer-notices__{$GLOBALS['PACKAGE_HASH']}.json";
80
  $GLOBALS["NOTICES_FILE_PATH"] = $GLOBALS['DUPX_INIT'] . '/' . $GLOBALS["NOTICES_FILE_NAME"];
81
- $GLOBALS['CHOWN_ROOT_PATH'] = @chmod("{$GLOBALS['CURRENT_ROOT_PATH']}", 0755);
82
- $GLOBALS['CHOWN_LOG_PATH'] = @chmod("{$GLOBALS['LOG_FILE_PATH']}", 0644);
83
- $GLOBALS['CHOWN_NOTICES_PATH'] = @chmod("{$GLOBALS['NOTICES_FILE_PATH']}", 0644);
84
  $GLOBALS['URL_SSL'] = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? true : false;
85
  $GLOBALS['URL_PATH'] = ($GLOBALS['URL_SSL']) ? "https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}" : "http://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}";
86
  $GLOBALS['PHP_MEMORY_LIMIT'] = ini_get('memory_limit') === false ? 'n/a' : ini_get('memory_limit');
@@ -99,7 +108,13 @@ class DUPX_Constants
99
  $GLOBALS['LOG_FILE_HANDLE'] = @fopen($GLOBALS['LOG_FILE_PATH'], "a+");
100
  }
101
 
102
- $GLOBALS['HOST_NAME'] = strlen($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
 
 
 
 
 
 
103
 
104
  if (!defined('MAX_STRLEN_SERIALIZED_CHECK')) { define('MAX_STRLEN_SERIALIZED_CHECK', 2000000); }
105
  }
12
  */
13
  class DUPX_Constants
14
  {
15
+ const DEFAULT_MAX_STRLEN_SERIALIZED_CHECK_IN_M = 4; // 0 no limit
16
+
17
+ /**
18
+ *
19
+ * @var int
20
+ */
21
+ public static $maxStrlenSerializeCheck = self::DEFAULT_MAX_STRLEN_SERIALIZED_CHECK;
22
+
23
  /**
24
  * Init method used to auto initialize the global params
25
  *
44
  //DATABASE SETUP: all time in seconds
45
  //max_allowed_packet: max value 1073741824 (1268MB) see my.ini
46
  $GLOBALS['DB_MAX_TIME'] = 5000;
47
+ $GLOBALS['DATABASE_PAGE_SIZE'] = 3500;
48
  $GLOBALS['DB_MAX_PACKETS'] = 268435456;
49
  $GLOBALS['DBCHARSET_DEFAULT'] = 'utf8';
50
  $GLOBALS['DBCOLLATE_DEFAULT'] = 'utf8_general_ci';
87
  $GLOBALS['LOG_FILE_PATH'] = $GLOBALS['DUPX_INIT'] . '/' . $GLOBALS["LOG_FILE_NAME"];
88
  $GLOBALS["NOTICES_FILE_NAME"] = "dup-installer-notices__{$GLOBALS['PACKAGE_HASH']}.json";
89
  $GLOBALS["NOTICES_FILE_PATH"] = $GLOBALS['DUPX_INIT'] . '/' . $GLOBALS["NOTICES_FILE_NAME"];
90
+ $GLOBALS['CHOWN_ROOT_PATH'] = DupLiteSnapLibIOU::chmod("{$GLOBALS['CURRENT_ROOT_PATH']}", 'u+rwx');
91
+ $GLOBALS['CHOWN_LOG_PATH'] = DupLiteSnapLibIOU::chmod("{$GLOBALS['LOG_FILE_PATH']}", 'u+rw');
92
+ $GLOBALS['CHOWN_NOTICES_PATH'] = DupLiteSnapLibIOU::chmod("{$GLOBALS['NOTICES_FILE_PATH']}", 'u+rw');
93
  $GLOBALS['URL_SSL'] = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? true : false;
94
  $GLOBALS['URL_PATH'] = ($GLOBALS['URL_SSL']) ? "https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}" : "http://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}";
95
  $GLOBALS['PHP_MEMORY_LIMIT'] = ini_get('memory_limit') === false ? 'n/a' : ini_get('memory_limit');
108
  $GLOBALS['LOG_FILE_HANDLE'] = @fopen($GLOBALS['LOG_FILE_PATH'], "a+");
109
  }
110
 
111
+ // for ngrok url and Local by Flywheel Live URL
112
+ if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) {
113
+ $host = $_SERVER['HTTP_X_ORIGINAL_HOST'];
114
+ } else {
115
+ $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];//WAS SERVER_NAME and caused problems on some boxes
116
+ }
117
+ $GLOBALS['HOST_NAME'] = $host;
118
 
119
  if (!defined('MAX_STRLEN_SERIALIZED_CHECK')) { define('MAX_STRLEN_SERIALIZED_CHECK', 2000000); }
120
  }
installer/dup-installer/classes/utilities/class.u.php CHANGED
@@ -122,13 +122,11 @@ class DUPX_U
122
  }
123
 
124
  // If the destination directory does not exist create it
125
- if (!is_dir($dest)) {
126
- if (!mkdir($dest)) {
127
- // If the destination directory could not be created stop processing
128
- return false;
129
- }
130
- }
131
-
132
  // Open the source directory to read in files
133
  $iterator = new DirectoryIterator($src);
134
 
@@ -1781,5 +1779,38 @@ class DUPX_U
1781
  }
1782
  return $result;
1783
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1784
  }
1785
  DUPX_U::init();
122
  }
123
 
124
  // If the destination directory does not exist create it
125
+ if (!DupLiteSnapLibIOU::dirWriteCheckOrMkdir($dest, 'u+rwx')) {
126
+ // If the destination directory could not be created stop processing
127
+ return false;
128
+ }
129
+
 
 
130
  // Open the source directory to read in files
131
  $iterator = new DirectoryIterator($src);
132
 
1779
  }
1780
  return $result;
1781
  }
1782
+
1783
+ /**
1784
+ *
1785
+ * @param array $input // es $_POST $_GET $_REQUEST
1786
+ * @param string $key // key of array to check
1787
+ * @param array $options // array('default' => null, default value to return if key don't exist
1788
+ * 'trim' => false // if true trim sanitize value
1789
+ * )
1790
+ * @return type
1791
+ */
1792
+ public static function isset_sanitize($input, $key, $options = array())
1793
+ {
1794
+ $opt = array_merge(array('default' => null, 'trim' => false), $options);
1795
+ if (isset($input[$key])) {
1796
+ $result = DUPX_U::sanitize_text_field($input[$key]);
1797
+ if ($opt['trim']) {
1798
+ $result = trim($result);
1799
+ }
1800
+ return $result;
1801
+ } else {
1802
+ return $opt['default'];
1803
+ }
1804
+ }
1805
+
1806
+ public static function boolToStr($input)
1807
+ {
1808
+ return $input ? 'true' : 'false';
1809
+ }
1810
+
1811
+ public static function boolToEnable($input)
1812
+ {
1813
+ return $input ? 'enable' : 'disable';
1814
+ }
1815
  }
1816
  DUPX_U::init();
installer/dup-installer/classes/utilities/class.u.search.reaplce.manager.php ADDED
@@ -0,0 +1,611 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Search and reaplace manager
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2 Full Documentation
7
+ *
8
+ * @package SC\DUPX\U
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ /**
14
+ * Search and replace manager
15
+ * singleton class
16
+ */
17
+ final class DUPX_S_R_MANAGER
18
+ {
19
+ const GLOBAL_SCOPE_KEY = '___!GLOBAL!___!SCOPE!___';
20
+
21
+ /**
22
+ *
23
+ * @var DUPX_S_R_MANAGER
24
+ */
25
+ private static $instance = null;
26
+
27
+ /**
28
+ * full list items not sorted
29
+ * @var DUPX_S_R_ITEM[]
30
+ */
31
+ private $items = array();
32
+
33
+ /**
34
+ * items sorted by priority and scope
35
+ * [
36
+ * 10 => [
37
+ * '___!GLOBAL!___!SCOPE!___' => [
38
+ * DUPX_S_R_ITEM
39
+ * DUPX_S_R_ITEM
40
+ * DUPX_S_R_ITEM
41
+ * ],
42
+ * 'scope_one' => [
43
+ * DUPX_S_R_ITEM
44
+ * DUPX_S_R_ITEM
45
+ * ]
46
+ * ],
47
+ * 20 => [
48
+ * .
49
+ * .
50
+ * .
51
+ * ]
52
+ * ]
53
+ *
54
+ * @var array
55
+ */
56
+ private $prorityScopeItems = array();
57
+
58
+ /**
59
+ *
60
+ * @return DUPX_S_R_MANAGER
61
+ */
62
+ public static function getInstance()
63
+ {
64
+ if (is_null(self::$instance)) {
65
+ self::$instance = new self();
66
+ }
67
+
68
+ return self::$instance;
69
+ }
70
+
71
+ private function __construct()
72
+ {
73
+
74
+ }
75
+
76
+ /**
77
+ *
78
+ * @return array
79
+ */
80
+ public function getArrayData()
81
+ {
82
+ $data = array();
83
+
84
+ foreach ($this->items as $item) {
85
+ $data[] = $item->toArray();
86
+ }
87
+
88
+ return $data;
89
+ }
90
+
91
+ /**
92
+ *
93
+ * @param array $json
94
+ */
95
+ public function setFromArrayData($data)
96
+ {
97
+
98
+ foreach ($data as $itemArray) {
99
+ $new_item = DUPX_S_R_ITEM::getItemFromArray($itemArray);
100
+ $this->setNewItem($new_item);
101
+ }
102
+ }
103
+
104
+ /**
105
+ *
106
+ * @param string $search
107
+ * @param string $replace
108
+ * @param string $type // item type DUPX_S_R_ITEM::[TYPE_STRING|TYPE_URL|TYPE_URL_NORMALIZE_DOMAIN|TYPE_PATH]
109
+ * @param int $prority // lower first
110
+ * @param bool|string|string[] $scope // true = global scope | false = never | string signle scope | string[] scope list
111
+ *
112
+ * @return boolean|DUPX_S_R_ITEM // false if fail or new DUPX_S_R_ITEM
113
+ */
114
+ public function addItem($search, $replace, $type = DUPX_S_R_ITEM::TYPE_STRING, $prority = 10, $scope = true)
115
+ {
116
+ if (strlen((string) $search) == 0) {
117
+ return false;
118
+ }
119
+
120
+ if (is_bool($scope)) {
121
+ $scope = $scope ? self::GLOBAL_SCOPE_KEY : '';
122
+ }
123
+ DUPX_Log::info(
124
+ 'ADD SEARCH AND REPLACE ITEM'."\n".
125
+ 'Search:"'.$search.'" Replace:"'.$replace.'" Type:"'.$type.'" Prority:"'.$prority.'" Scope:"'.$scope, 2);
126
+ $new_item = new DUPX_S_R_ITEM($search, $replace, $type, $prority, $scope);
127
+
128
+ return $this->setNewItem($new_item);
129
+ }
130
+
131
+ /**
132
+ *
133
+ * @param DUPX_S_R_ITEM $new_item
134
+ *
135
+ * @return boolean|DUPX_S_R_ITEM // false if fail or new DUPX_S_R_ITEM
136
+ */
137
+ private function setNewItem($new_item)
138
+ {
139
+ $this->items[$new_item->getId()] = $new_item;
140
+
141
+ // create priority array
142
+ if (!isset($this->prorityScopeItems[$new_item->prority])) {
143
+ $this->prorityScopeItems[$new_item->prority] = array();
144
+
145
+ // sort by priority
146
+ ksort($this->prorityScopeItems);
147
+ }
148
+
149
+ // create scope list
150
+ foreach ($new_item->scope as $scope) {
151
+ if (!isset($this->prorityScopeItems[$new_item->prority][$scope])) {
152
+ $this->prorityScopeItems[$new_item->prority][$scope] = array();
153
+ }
154
+ $this->prorityScopeItems[$new_item->prority][$scope][] = $new_item;
155
+ }
156
+
157
+ return $new_item;
158
+ }
159
+
160
+ /**
161
+ * get all search and reaple items by scpoe
162
+ *
163
+ * @param null|string $scope if scope is empty get only global scope
164
+ * @return DUPX_S_R_ITEM[]
165
+ */
166
+ private function getSearchReplaceItems($scope = null, $globalScope = true)
167
+ {
168
+ $items_list = array();
169
+ foreach ($this->prorityScopeItems as $priority => $priority_list) {
170
+ // get scope list
171
+ if (!empty($scope) && isset($priority_list[$scope])) {
172
+ foreach ($priority_list[$scope] as $item) {
173
+ $items_list[] = $item;
174
+ }
175
+ }
176
+
177
+ // get global scope
178
+ if ($globalScope && isset($priority_list[self::GLOBAL_SCOPE_KEY])) {
179
+ foreach ($priority_list[self::GLOBAL_SCOPE_KEY] as $item) {
180
+ $items_list[] = $item;
181
+ }
182
+ }
183
+ }
184
+
185
+ return $items_list;
186
+ }
187
+
188
+ /**
189
+ * get replace list by scope
190
+ * result
191
+ * [
192
+ * ['search' => ...,'replace' => ...]
193
+ * ['search' => ...,'replace' => ...]
194
+ * ]
195
+ *
196
+ * @param null|string $scope if scope is empty get only global scope
197
+ * @param bool $unique_search If true it eliminates the double searches leaving the one with lower priority.
198
+ *
199
+ * @return array
200
+ */
201
+ public function getSearchReplaceList($scope = null, $unique_search = true, $globalScope = true)
202
+ {
203
+ DUPX_Log::info('-- SEARCH LIST -- SCOPE: '.DUPX_Log::varToString($scope), DUPX_Log::LV_DEBUG);
204
+
205
+ $items_list = $this->getSearchReplaceItems($scope, $globalScope);
206
+ DUPX_Log::info('-- SEARCH LIST ITEMS --'."\n".print_r($items_list, true), DUPX_Log::LV_HARD_DEBUG);
207
+
208
+ if ($unique_search) {
209
+ $items_list = self::uniqueSearchListItem($items_list);
210
+ DUPX_Log::info('-- UNIQUE LIST ITEMS --'."\n".print_r($items_list, true), DUPX_Log::LV_HARD_DEBUG);
211
+ }
212
+ $result = array();
213
+
214
+ foreach ($items_list as $item) {
215
+ $result = array_merge($result, $item->getPairsSearchReplace());
216
+ }
217
+
218
+ foreach ($result as $index => $c_sr) {
219
+ DUPX_Log::info(
220
+ 'SEARCH'.str_pad($index + 1, 3, ' ', STR_PAD_LEFT).":".
221
+ str_pad(DUPX_Log::varToString($c_sr['search'])." ", 50, '=', STR_PAD_RIGHT).
222
+ "=> ".
223
+ DUPX_Log::varToString($c_sr['replace']));
224
+ }
225
+
226
+ return $result;
227
+ }
228
+
229
+ /**
230
+ * remove duplicated search strings.
231
+ * Leave the object at lower priority
232
+ *
233
+ * @param DUPX_S_R_ITEM[] $list
234
+ * @return boolean|DUPX_S_R_ITEM[]
235
+ */
236
+ private static function uniqueSearchListItem($list)
237
+ {
238
+ $search_strings = array();
239
+ $result = array();
240
+
241
+ if (!is_array($list)) {
242
+ return false;
243
+ }
244
+
245
+ foreach ($list as $item) {
246
+ if (!in_array($item->search, $search_strings)) {
247
+ $result[] = $item;
248
+ $search_strings[] = $item->search;
249
+ }
250
+ }
251
+
252
+ return $result;
253
+ }
254
+
255
+ private function __clone()
256
+ {
257
+
258
+ }
259
+
260
+ private function __wakeup()
261
+ {
262
+
263
+ }
264
+ }
265
+
266
+ /**
267
+ * search and replace item use in manager to creat the search and replace list.
268
+ */
269
+ class DUPX_S_R_ITEM
270
+ {
271
+ private static $uniqueIdCount = 0;
272
+
273
+ const TYPE_STRING = 'str';
274
+ const TYPE_URL = 'url';
275
+ const TYPE_URL_NORMALIZE_DOMAIN = 'urlnd';
276
+ const TYPE_PATH = 'path';
277
+
278
+ /**
279
+ *
280
+ * @var int
281
+ */
282
+ private $id = 0;
283
+
284
+ /**
285
+ *
286
+ * @var int prority lower first
287
+ */
288
+ public $prority = 10;
289
+
290
+ /**
291
+ *
292
+ * @var string[] scope list
293
+ */
294
+ public $scope = array();
295
+
296
+ /**
297
+ *
298
+ * @var string type of string
299
+ */
300
+ public $type = self::TYPE_STRING;
301
+
302
+ /**
303
+ *
304
+ * @var string search string
305
+ */
306
+ public $search = '';
307
+
308
+ /**
309
+ *
310
+ * @var string replace string
311
+ */
312
+ public $replace = '';
313
+
314
+ /**
315
+ *
316
+ * @param string $search
317
+ * @param string $replace
318
+ * @param string $type
319
+ * @param int $prority
320
+ * @param string|string[] $scope if empty never used
321
+ */
322
+ public function __construct($search, $replace, $type = DUPX_S_R_ITEM::TYPE_STRING, $prority = 10, $scope = array())
323
+ {
324
+ if (!is_array($scope)) {
325
+ $this->scope = empty($scope) ? array() : array((string) $scope);
326
+ } else {
327
+ $this->scope = $scope;
328
+ }
329
+ $this->prority = (int) $prority;
330
+ switch ($type) {
331
+ case DUPX_S_R_ITEM::TYPE_URL:
332
+ case DUPX_S_R_ITEM::TYPE_URL_NORMALIZE_DOMAIN:
333
+ $this->search = rtrim($search, '/');
334
+ $this->replace = rtrim($replace, '/');
335
+ break;
336
+ case DUPX_S_R_ITEM::TYPE_PATH:
337
+ case DUPX_S_R_ITEM::TYPE_STRING:
338
+ default:
339
+ $this->search = (string) $search;
340
+ $this->replace = (string) $replace;
341
+ break;
342
+ }
343
+ $this->type = $type;
344
+ $this->id = self::$uniqueIdCount;
345
+ self::$uniqueIdCount ++;
346
+ }
347
+
348
+ public function toArray()
349
+ {
350
+ return array(
351
+ 'id' => $this->id,
352
+ 'prority' => $this->prority,
353
+ 'scope' => $this->scope,
354
+ 'type' => $this->type,
355
+ 'search' => $this->search,
356
+ 'replace' => $this->replace
357
+ );
358
+ }
359
+
360
+ public static function getItemFromArray($array)
361
+ {
362
+ $result = new self($array['search'], $array['replace'], $array['type'], $array['prority'], $array['scope']);
363
+ return $result;
364
+ }
365
+
366
+ /**
367
+ * return search an replace string
368
+ *
369
+ * result
370
+ * [
371
+ * ['search' => ...,'replace' => ...]
372
+ * ['search' => ...,'replace' => ...]
373
+ * ]
374
+ *
375
+ * @return array
376
+ */
377
+ public function getPairsSearchReplace()
378
+ {
379
+ switch ($this->type) {
380
+ case self::TYPE_URL:
381
+ return self::searchReplaceUrl($this->search, $this->replace);
382
+ case self::TYPE_URL_NORMALIZE_DOMAIN:
383
+ return self::searchReplaceUrl($this->search, $this->replace, true, true);
384
+ case self::TYPE_PATH:
385
+ return self::searchReplacePath($this->search, $this->replace);
386
+ case self::TYPE_STRING:
387
+ default:
388
+ return self::searchReplaceWithEncodings($this->search, $this->replace);
389
+ }
390
+ }
391
+
392
+ /**
393
+ * Get search and replace strings with encodings
394
+ * prevents unnecessary substitution like when search and reaplace are the same.
395
+ *
396
+ * result
397
+ * [
398
+ * ['search' => ...,'replace' => ...]
399
+ * ['search' => ...,'replace' => ...]
400
+ * ]
401
+ *
402
+ * @param string $search
403
+ * @param string $replace
404
+ * @param bool $json add json encode string
405
+ * @param bool $urlencode add urlencode string
406
+ *
407
+ * @return array pairs search and replace
408
+ */
409
+ public static function searchReplaceWithEncodings($search, $replace, $json = true, $urlencode = true)
410
+ {
411
+ $result = array();
412
+ if ($search != $replace) {
413
+ $result[] = array('search' => $search, 'replace' => $replace);
414
+ } else {
415
+ return array();
416
+ }
417
+
418
+ // JSON ENCODE
419
+ if ($json) {
420
+ $search_json = str_replace('"', "", json_encode($search));
421
+ $replace_json = str_replace('"', "", json_encode($replace));
422
+
423
+ if ($search != $search_json && $search_json != $replace_json) {
424
+ $result[] = array('search' => $search_json, 'replace' => $replace_json);
425
+ }
426
+ }
427
+
428
+ // URL ENCODE
429
+ if ($urlencode) {
430
+ $search_urlencode = urlencode($search);
431
+ $replace_urlencode = urlencode($replace);
432
+
433
+ if ($search != $search_urlencode && $search_urlencode != $replace_urlencode) {
434
+ $result[] = array('search' => $search_urlencode, 'replace' => $replace_urlencode);
435
+ }
436
+ }
437
+
438
+ return $result;
439
+ }
440
+
441
+ /**
442
+ * Add replace strings to substitute old url to new url
443
+ * 1) no protocol old url to no protocol new url (es. //www.hold.url => //www.new.url)
444
+ * 2) wrong protocol new url to right protocol new url (es. http://www.new.url => https://www.new.url)
445
+ *
446
+ * result
447
+ * [
448
+ * ['search' => ...,'replace' => ...]
449
+ * ['search' => ...,'replace' => ...]
450
+ * ]
451
+ *
452
+ * @param string $search_url
453
+ * @param string $replace_url
454
+ * @param bool $force_new_protocol if true force http or https protocol (work only if replace url have http or https scheme)
455
+ *
456
+ * @return array
457
+ */
458
+ public static function searchReplaceUrl($search_url, $replace_url, $force_new_protocol = true, $normalizeWww = false)
459
+ {
460
+ if (($parse_search_url = parse_url($search_url)) !== false && isset($parse_search_url['scheme'])) {
461
+ $search_url_raw = substr($search_url, strlen($parse_search_url['scheme']) + 1);
462
+ } else {
463
+ $search_url_raw = $search_url;
464
+ }
465
+
466
+ if (($parse_replace_url = parse_url($replace_url)) !== false && isset($parse_replace_url['scheme'])) {
467
+ $replace_url_raw = substr($replace_url, strlen($parse_replace_url['scheme']) + 1);
468
+ } else {
469
+ $replace_url_raw = $replace_url;
470
+ }
471
+ //SEARCH WITH NO PROTOCOL: RAW "//"
472
+ $result = self::searchReplaceWithEncodings($search_url_raw, $replace_url_raw);
473
+
474
+ // NORMALIZE source www
475
+ if ($normalizeWww && self::domainCanNormalized($search_url_raw)) {
476
+ if (self::isWww($search_url_raw)) {
477
+ $fromDomain = '//'.substr($search_url_raw , strlen('//www.'));
478
+ } else {
479
+ $fromDomain = '//www.'.substr($search_url_raw , strlen('//'));
480
+ }
481
+
482
+ // prevent double subsition for subdiv problems.
483
+ if (strpos($replace_url_raw, $fromDomain) !== 0) {
484
+ $result = array_merge($result, self::searchReplaceWithEncodings($fromDomain, $replace_url_raw));
485
+ }
486
+ }
487
+
488
+ // NORMALIZE source protocol
489
+ if ($force_new_protocol && $parse_replace_url !== false && isset($parse_replace_url['scheme'])) {
490
+ //FORCE NEW PROTOCOL [HTTP / HTTPS]
491
+ switch ($parse_replace_url['scheme']) {
492
+ case 'http':
493
+ $replace_url_wrong_protocol = 'https:'.$replace_url_raw;
494
+ break;
495
+ case 'https':
496
+ $replace_url_wrong_protocol = 'http:'.$replace_url_raw;
497
+ break;
498
+ default:
499
+ $replace_url_wrong_protocol = '';
500
+ break;
501
+ }
502
+
503
+ if (!empty($replace_url_wrong_protocol)) {
504
+ $result = array_merge($result, self::searchReplaceWithEncodings($replace_url_wrong_protocol, $replace_url));
505
+ }
506
+ }
507
+
508
+ return $result;
509
+ }
510
+
511
+ /**
512
+ * result
513
+ * [
514
+ * ['search' => ...,'replace' => ...]
515
+ * ['search' => ...,'replace' => ...]
516
+ * ]
517
+ *
518
+ * @param string $search_path
519
+ * @param string $replace_path
520
+ *
521
+ * @return array
522
+ */
523
+ public static function searchReplacePath($search_path, $replace_path)
524
+ {
525
+ $result = self::searchReplaceWithEncodings($search_path, $replace_path);
526
+
527
+ $search_path_unsetSafe = rtrim(DUPX_U::unsetSafePath($search_path), '\\');
528
+ $replace_path_unsetSafe = rtrim($replace_path, '/');
529
+ $result = array_merge($result, self::searchReplaceWithEncodings($search_path_unsetSafe, $replace_path_unsetSafe));
530
+
531
+ return $result;
532
+ }
533
+
534
+ /**
535
+ * get unique item id
536
+ *
537
+ * @return int
538
+ */
539
+ public function getId()
540
+ {
541
+ return $this->id;
542
+ }
543
+
544
+ /**
545
+ * @param $url string The URL whichs domain you want to get
546
+ * @return string The domain part of the given URL
547
+ * www.myurl.co.uk => myurl.co.uk
548
+ * www.google.com => google.com
549
+ * my.test.myurl.co.uk => myurl.co.uk
550
+ * www.myurl.localweb => myurl.localweb
551
+ *
552
+ */
553
+ public static function getDomain($url)
554
+ {
555
+ $pieces = parse_url($url);
556
+ $domain = isset($pieces['host']) ? $pieces['host'] : '';
557
+ $regs = null;
558
+ if (strpos($domain, ".") !== false) {
559
+ if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) {
560
+ return $regs['domain'];
561
+ } else {
562
+ $exDomain = explode('.', $domain);
563
+ return implode('.', array_slice($exDomain, -2, 2));
564
+ }
565
+ } else {
566
+ return $domain;
567
+ }
568
+ }
569
+
570
+ public static function domainCanNormalized($url)
571
+ {
572
+ $pieces = parse_url($url);
573
+
574
+ if (!isset($pieces['host'])) {
575
+ return false;
576
+ }
577
+
578
+ if (strpos($pieces['host'], ".") === false) {
579
+ return false;
580
+ }
581
+
582
+ $dLevels = explode('.', $pieces['host']);
583
+ if ($dLevels[0] == 'www') {
584
+ return true;
585
+ }
586
+
587
+ switch (count($dLevels)) {
588
+ case 1:
589
+ return false;
590
+ case 2:
591
+ return true;
592
+ case 3:
593
+ if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $pieces['host'], $regs)) {
594
+ return $regs['domain'] == $pieces['host'];
595
+ }
596
+ return false;
597
+ default:
598
+ return false;
599
+ }
600
+ }
601
+
602
+ public static function isWww($url)
603
+ {
604
+ $pieces = parse_url($url);
605
+ if (!isset($pieces['host'])) {
606
+ return false;
607
+ } else {
608
+ return strpos($pieces['host'], 'www.') === 0;
609
+ }
610
+ }
611
+ }
installer/dup-installer/ctrls/ctrl.base.php CHANGED
@@ -13,9 +13,8 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
13
  //Enum used to define the various test statues
14
  final class DUPX_CTRL_Status
15
  {
16
- const FAILED = 0;
17
- const SUCCESS = 1;
18
-
19
  }
20
 
21
  /**
@@ -23,10 +22,10 @@ final class DUPX_CTRL_Status
23
  */
24
  class DUPX_CTRL_Report
25
  {
26
- //Properties
27
- public $runTime;
28
- public $outputType = 'JSON';
29
- public $status;
30
 
31
  }
32
 
@@ -35,39 +34,41 @@ class DUPX_CTRL_Report
35
  */
36
  class DUPX_CTRL_Out
37
  {
38
- public $report = null;
39
- public $payload = null;
40
-
41
- private $timeStart;
42
- private $timeEnd;
43
-
44
- /**
45
- * Init this instance of the object
46
- */
47
- public function __construct()
48
- {
49
- $this->report = new DUPX_CTRL_Report();
50
- $this->payload = null;
51
- $this->startProcessTime();
52
- }
53
 
54
- public function startProcessTime()
55
- {
56
- $this->timeStart = $this->microtimeFloat();
57
- }
 
 
 
 
 
58
 
59
- public function getProcessTime()
60
- {
61
- $this->timeEnd = $this->microtimeFloat();
62
- $this->report->runTime = $this->timeEnd - $this->timeStart;
63
- return $this->report->runTime;
64
- }
65
 
66
- private function microtimeFloat()
67
- {
68
- list($usec, $sec) = explode(" ", microtime());
69
- return ((float)$usec + (float)$sec);
70
- }
 
71
 
 
 
 
 
 
 
72
 
 
 
 
73
  }
13
  //Enum used to define the various test statues
14
  final class DUPX_CTRL_Status
15
  {
16
+ const FAILED = 0;
17
+ const SUCCESS = 1;
 
18
  }
19
 
20
  /**
22
  */
23
  class DUPX_CTRL_Report
24
  {
25
+ //Properties
26
+ public $runTime;
27
+ public $outputType = 'JSON';
28
+ public $status;
29
 
30
  }
31
 
34
  */
35
  class DUPX_CTRL_Out
36
  {
37
+ public $report = null;
38
+ public $payload = null;
39
+ private $timeStart;
40
+ private $timeEnd;
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ /**
43
+ * Init this instance of the object
44
+ */
45
+ public function __construct()
46
+ {
47
+ $this->report = new DUPX_CTRL_Report();
48
+ $this->payload = null;
49
+ $this->startProcessTime();
50
+ }
51
 
52
+ public function startProcessTime()
53
+ {
54
+ $this->timeStart = $this->microtimeFloat();
55
+ }
 
 
56
 
57
+ public function getProcessTime()
58
+ {
59
+ $this->timeEnd = $this->microtimeFloat();
60
+ $this->report->runTime = $this->timeEnd - $this->timeStart;
61
+ return $this->report->runTime;
62
+ }
63
 
64
+ private function microtimeFloat()
65
+ {
66
+ list($usec, $sec) = explode(" ", microtime());
67
+ return ((float) $usec + (float) $sec);
68
+ }
69
+ }
70
 
71
+ class DUPX_CTRL
72
+ {
73
+ const NAME_MAX_SERIALIZE_STRLEN_IN_M = 'mstrlim';
74
  }
installer/dup-installer/ctrls/ctrl.s1.php CHANGED
@@ -5,12 +5,10 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
5
  /* @var $GLOBALS['DUPX_AC'] DUPX_ArchiveConfig */
6
 
7
  //OPTIONS
8
- $base_file_perms_value = (isset($_POST['file_perms_value'])) ? $_POST['file_perms_value'] : 'not set';
9
- $base_dir_perms_value = (isset($_POST['dir_perms_value'])) ? $_POST['dir_perms_value'] : 'not set';
10
  $_POST['set_file_perms'] = (isset($_POST['set_file_perms'])) ? 1 : 0;
11
  $_POST['set_dir_perms'] = (isset($_POST['set_dir_perms'])) ? 1 : 0;
12
- $_POST['file_perms_value'] = (isset($_POST['file_perms_value'])) ? intval(('0' . $_POST['file_perms_value']), 8) : 0755;
13
- $_POST['dir_perms_value'] = (isset($_POST['dir_perms_value'])) ? intval(('0' . $_POST['dir_perms_value']), 8) : 0644;
14
  $_POST['zip_filetime'] = (isset($_POST['zip_filetime'])) ? $_POST['zip_filetime'] : 'current';
15
  $_POST['config_mode'] = (isset($_POST['config_mode'])) ? $_POST['config_mode'] : 'NEW';
16
  $_POST['archive_engine'] = (isset($_POST['archive_engine'])) ? $_POST['archive_engine'] : 'manual';
@@ -81,52 +79,58 @@ DUPX_Log::info("* VERSION: {$GLOBALS['DUPX_AC']->version_dup}");
81
  DUPX_Log::info('* NOTICE: Do NOT post to public sites or forums!!');
82
  DUPX_Log::info("********************************************************************************");
83
 
84
- $colSize = 60;
85
- $os = defined('PHP_OS') ? PHP_OS : 'unknown';
86
- $log = str_pad(str_pad('PACKAGE INFO', 13, '_', STR_PAD_RIGHT).' '.'CURRENT SERVER', $colSize, ' ', STR_PAD_RIGHT).'| '.'ORIGINAL SERVER'."\n".
87
- str_pad(str_pad('PHP VERSION', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->version_php, $colSize, ' ', STR_PAD_RIGHT).'| '.phpversion()."\n".
88
- str_pad(str_pad('OS', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->version_os, $colSize, ' ', STR_PAD_RIGHT).'| '.$os."\n".
89
- str_pad('CREATED', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->created."\n".
90
- str_pad('WP VERSION', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->version_wp."\n".
91
- str_pad('DUP VERSION', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->version_dup."\n".
92
- str_pad('DB', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->version_db."\n".
93
- str_pad('DB TABLES', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->dbInfo->tablesFinalCount."\n".
94
- str_pad('DB ROWS', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->dbInfo->tablesRowCount."\n".
95
- str_pad('DB FILE SIZE', 13, '_', STR_PAD_RIGHT).':'.$GLOBALS['DUPX_AC']->dbInfo->tablesSizeOnDisk."\n".
 
96
  "********************************************************************************";
97
  DUPX_Log::info($log);
 
 
 
 
 
 
 
 
98
 
99
- DUPX_Log::info("PHP:\t\t".phpversion().' | SAPI: '.php_sapi_name());
100
- DUPX_Log::info("PHP MEMORY:\t".DUPX_Log::varToString($GLOBALS['PHP_MEMORY_LIMIT']).' | SUHOSIN: '.DUPX_Log::varToString($GLOBALS['PHP_SUHOSIN_ON']));
101
- DUPX_Log::info("SERVER:\t\t".DUPX_Log::varToString($_SERVER['SERVER_SOFTWARE']));
102
- DUPX_Log::info("DOC ROOT:\t".DUPX_Log::varToString($root_path));
103
- DUPX_Log::info("DOC ROOT 755:\t".DUPX_Log::varToString($GLOBALS['CHOWN_ROOT_PATH']));
104
- DUPX_Log::info("LOG FILE 644:\t".DUPX_Log::varToString($GLOBALS['CHOWN_LOG_PATH']));
105
- DUPX_Log::info("REQUEST URL:\t".DUPX_Log::varToString($GLOBALS['URL_PATH']));
106
- DUPX_Log::info("SAFE MODE :\t".DUPX_Log::varToString($_POST['exe_safe_mode']));
107
- DUPX_Log::info("CONFIG MODE :\t".DUPX_Log::varToString($_POST['config_mode']));
 
 
 
108
 
109
  $log = "--------------------------------------\n";
110
  $log .= "POST DATA\n";
111
  $log .= "--------------------------------------\n";
112
  $log .= print_r($POST_LOG, true);
113
- DUPX_Log::info($log, 2);
114
-
115
-
116
- $log = "--------------------------------------\n";
117
- $log .= "PRE-EXTRACT-CHECKS\n";
118
- $log .= "--------------------------------------";
119
- DUPX_Log::info($log);
120
- DUPX_ServerConfig::beforeExtractionSetup();
121
-
122
 
123
- $log = "--------------------------------------\n";
124
  $log .= "ARCHIVE SETUP\n";
125
  $log .= "--------------------------------------\n";
126
- $log .= "NAME:\t{$GLOBALS['FW_PACKAGE_NAME']}\n";
127
- $log .= "SIZE:\t".DUPX_U::readableByteSize(@filesize($GLOBALS['FW_PACKAGE_PATH']));
128
- DUPX_Log::info($log."\n", DUPX_Log::LV_DEFAULT, true);
129
 
 
 
130
 
131
  $target = $root_path;
132
 
@@ -142,9 +146,9 @@ switch ($post_archive_engine) {
142
  //-----------------------
143
  //SHELL EXEC
144
  case 'shellexec_unzip':
145
-
146
  $shell_exec_path = DUPX_Server::get_unzip_filepath();
147
- DUPX_Log::info("ZIP:\tShell Exec Unzip");
148
 
149
  $command = escapeshellcmd($shell_exec_path)." -o -qq ".escapeshellarg($archive_path)." -d ".escapeshellarg($target)." 2>&1";
150
  if ($_POST['zip_filetime'] == 'original') {
@@ -165,7 +169,7 @@ switch ($post_archive_engine) {
165
  //-----------------------
166
  //ZIP-ARCHIVE
167
  case 'ziparchive':
168
- DUPX_Log::info(">>> Starting ZipArchive Unzip");
169
 
170
  if (!class_exists('ZipArchive')) {
171
  DUPX_Log::info("ERROR: Stopping install process. Trying to extract without ZipArchive module installed. Please use the 'Manual Archive Extraction' mode to extract zip file.");
@@ -193,15 +197,13 @@ switch ($post_archive_engine) {
193
 
194
  for($i = 0; $i < $zip->numFiles; $i++) {
195
  $extract_filename = $zip->getNameIndex($i);
196
-
197
- // skip dup-installer folder. Alrady extracted in bootstrap
198
- if (strpos($extract_filename , $dupInstallerZipPath) === 0) {
199
- continue;
200
- }
201
 
202
- // skip no dupInstallerFolder files
203
- if (!empty($dupInstallerFolder) && strpos($extract_filename , $dupInstallerFolder) !== 0) {
204
- DUPX_Log::info("SKIP NOT DUB FOLDER: \"".$extract_filename."\"", 2);
 
 
 
205
  continue;
206
  }
207
 
@@ -236,7 +238,7 @@ switch ($post_archive_engine) {
236
  'sections' => array('files'),
237
  ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
238
  } else {
239
- DUPX_Log::info("DONE: ".$extract_filename,2);
240
  }
241
  } catch (Exception $ex) {
242
  if (DupLiteSnapLibUtilWp::isWpCore($extract_filename, DupLiteSnapLibUtilWp::PATH_RELATIVE)) {
@@ -365,40 +367,41 @@ if ($_POST['set_file_perms'] || $_POST['set_dir_perms']) {
365
  function getChildren()
366
  {
367
  try {
368
- return new IgnorantRecursiveDirectoryIterator($this->getPathname());
369
  } catch (UnexpectedValueException $e) {
370
  return new RecursiveArrayIterator(array());
371
  }
372
  }
373
  }
374
 
375
- DUPX_Log::info("PERMISSION UPDATES:");
376
- DUPX_Log::info(" -DIRS: '{$base_dir_perms_value}'");
377
- DUPX_Log::info(" -FILES: '{$base_file_perms_value}'");
378
- $set_file_perms = $_POST['set_file_perms'];
379
  $set_dir_perms = $_POST['set_dir_perms'];
380
  $set_file_mtime = ($_POST['zip_filetime'] == 'current');
381
  $file_perms_value = $_POST['file_perms_value'] ? $_POST['file_perms_value'] : 0755;
382
  $dir_perms_value = $_POST['dir_perms_value'] ? $_POST['dir_perms_value'] : 0644;
383
 
384
- $objects = new RecursiveIteratorIterator(new IgnorantRecursiveDirectoryIterator($root_path), RecursiveIteratorIterator::SELF_FIRST);
385
-
386
- foreach ($objects as $name => $object) {
387
- if ($set_file_perms && is_file($name)) {
388
 
389
- if (! @chmod($name, $file_perms_value)) {
390
- DUPX_Log::info("Permissions setting on file '{$name}' failed");
391
- }
392
- } else if ($set_dir_perms && is_dir($name)) {
393
 
394
- if (! @chmod($name, $dir_perms_value)) {
395
- DUPX_Log::info("Permissions setting on directory '{$name}' failed");
396
- }
397
- }
398
- if ($set_file_mtime) {
399
- @touch($name);
400
- }
401
- }
 
 
 
 
 
 
 
 
402
  } else {
403
  DUPX_Log::info("\nPERMISSION UPDATES: None Applied");
404
  }
5
  /* @var $GLOBALS['DUPX_AC'] DUPX_ArchiveConfig */
6
 
7
  //OPTIONS
 
 
8
  $_POST['set_file_perms'] = (isset($_POST['set_file_perms'])) ? 1 : 0;
9
  $_POST['set_dir_perms'] = (isset($_POST['set_dir_perms'])) ? 1 : 0;
10
+ $_POST['file_perms_value'] = (isset($_POST['file_perms_value'])) ? DUPX_U::sanitize_text_field($_POST['file_perms_value']) : 0755;
11
+ $_POST['dir_perms_value'] = (isset($_POST['dir_perms_value'])) ? DUPX_U::sanitize_text_field($_POST['dir_perms_value']) : 0644;
12
  $_POST['zip_filetime'] = (isset($_POST['zip_filetime'])) ? $_POST['zip_filetime'] : 'current';
13
  $_POST['config_mode'] = (isset($_POST['config_mode'])) ? $_POST['config_mode'] : 'NEW';
14
  $_POST['archive_engine'] = (isset($_POST['archive_engine'])) ? $_POST['archive_engine'] : 'manual';
79
  DUPX_Log::info('* NOTICE: Do NOT post to public sites or forums!!');
80
  DUPX_Log::info("********************************************************************************");
81
 
82
+ $colSize = 60;
83
+ $labelPadSize = 20;
84
+ $os = defined('PHP_OS') ? PHP_OS : 'unknown';
85
+ $log = str_pad(str_pad('PACKAGE INFO', $labelPadSize, '_', STR_PAD_RIGHT).' '.'CURRENT SERVER', $colSize, ' ', STR_PAD_RIGHT).'|'.'ORIGINAL SERVER'."\n".
86
+ str_pad(str_pad('PHP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_php, $colSize, ' ', STR_PAD_RIGHT).'|'.phpversion()."\n".
87
+ str_pad(str_pad('OS', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_os, $colSize, ' ', STR_PAD_RIGHT).'|'.$os."\n".
88
+ str_pad('CREATED', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->created."\n".
89
+ str_pad('WP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_wp."\n".
90
+ str_pad('DUP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_dup."\n".
91
+ str_pad('DB', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_db."\n".
92
+ str_pad('DB TABLES', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesFinalCount."\n".
93
+ str_pad('DB ROWS', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesRowCount."\n".
94
+ str_pad('DB FILE SIZE', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesSizeOnDisk."\n".
95
  "********************************************************************************";
96
  DUPX_Log::info($log);
97
+ DUPX_Log::info("SERVER INFO");
98
+ DUPX_Log::info(str_pad('PHP', $labelPadSize, '_', STR_PAD_RIGHT).': '.phpversion().' | SAPI: '.php_sapi_name());
99
+ DUPX_Log::info(str_pad('PHP MEMORY', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['PHP_MEMORY_LIMIT'].' | SUHOSIN: '.$GLOBALS['PHP_SUHOSIN_ON']);
100
+ DUPX_Log::info(str_pad('SERVER', $labelPadSize, '_', STR_PAD_RIGHT).': '.$_SERVER['SERVER_SOFTWARE']);
101
+ DUPX_Log::info(str_pad('DOC ROOT', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($root_path));
102
+ DUPX_Log::info(str_pad('DOC ROOT 755', $labelPadSize, '_', STR_PAD_RIGHT).': '.var_export($GLOBALS['CHOWN_ROOT_PATH'], true));
103
+ DUPX_Log::info(str_pad('LOG FILE 644', $labelPadSize, '_', STR_PAD_RIGHT).': '.var_export($GLOBALS['CHOWN_LOG_PATH'], true));
104
+ DUPX_Log::info(str_pad('REQUEST URL', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($GLOBALS['URL_PATH']));
105
 
106
+ DUPX_Log::info("********************************************************************************");
107
+ DUPX_Log::info("USER INPUTS");
108
+ DUPX_Log::info(str_pad('ARCHIVE ENGINE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['archive_engine']));
109
+ DUPX_Log::info(str_pad('SET DIR PERMS', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['set_dir_perms']));
110
+ DUPX_Log::info(str_pad('DIR PERMS VALUE', $labelPadSize, '_', STR_PAD_RIGHT).': '.decoct($_POST['dir_perms_value']));
111
+ DUPX_Log::info(str_pad('SET FILE PERMS', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['set_file_perms'] ));
112
+ DUPX_Log::info(str_pad('FILE PERMS VALUE', $labelPadSize, '_', STR_PAD_RIGHT).': '.decoct($_POST['file_perms_value']));
113
+ DUPX_Log::info(str_pad('SAFE MODE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['exe_safe_mode']));
114
+ DUPX_Log::info(str_pad('LOGGING', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['logging']));
115
+ DUPX_Log::info(str_pad('CONFIG MODE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['config_mode']));
116
+ DUPX_Log::info(str_pad('FILE TIME', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['zip_filetime']));
117
+ DUPX_Log::info("********************************************************************************\n");
118
 
119
  $log = "--------------------------------------\n";
120
  $log .= "POST DATA\n";
121
  $log .= "--------------------------------------\n";
122
  $log .= print_r($POST_LOG, true);
123
+ DUPX_Log::info($log, DUPX_Log::LV_DEBUG);
 
 
 
 
 
 
 
 
124
 
125
+ $log = "\n--------------------------------------\n";
126
  $log .= "ARCHIVE SETUP\n";
127
  $log .= "--------------------------------------\n";
128
+ $log .= str_pad('NAME', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($GLOBALS['FW_PACKAGE_NAME'])."\n";
129
+ $log .= str_pad('SIZE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_U::readableByteSize(@filesize($GLOBALS['FW_PACKAGE_PATH']));
130
+ DUPX_Log::info($log."\n", DUPX_Log::LV_DEFAULT, true);
131
 
132
+ DUPX_Log::info('PRE-EXTRACT-CHECKS');
133
+ DUPX_ServerConfig::beforeExtractionSetup();
134
 
135
  $target = $root_path;
136
 
146
  //-----------------------
147
  //SHELL EXEC
148
  case 'shellexec_unzip':
149
+ DUPX_Log::info("\n\nSTART ZIP FILE EXTRACTION SHELLEXEC >>> ");
150
  $shell_exec_path = DUPX_Server::get_unzip_filepath();
151
+
152
 
153
  $command = escapeshellcmd($shell_exec_path)." -o -qq ".escapeshellarg($archive_path)." -d ".escapeshellarg($target)." 2>&1";
154
  if ($_POST['zip_filetime'] == 'original') {
169
  //-----------------------
170
  //ZIP-ARCHIVE
171
  case 'ziparchive':
172
+ DUPX_Log::info("\n\nSTART ZIP FILE EXTRACTION STANDARD >>> ");
173
 
174
  if (!class_exists('ZipArchive')) {
175
  DUPX_Log::info("ERROR: Stopping install process. Trying to extract without ZipArchive module installed. Please use the 'Manual Archive Extraction' mode to extract zip file.");
197
 
198
  for($i = 0; $i < $zip->numFiles; $i++) {
199
  $extract_filename = $zip->getNameIndex($i);
 
 
 
 
 
200
 
201
+ // skip dup-installer folder. Alrady extracted in bootstrap
202
+ if (
203
+ (strpos($extract_filename, $dupInstallerZipPath) === 0) ||
204
+ (!empty($dupInstallerFolder) && strpos($extract_filename , $dupInstallerFolder) !== 0)
205
+ ) {
206
+ DUPX_Log::info("SKIPPING NOT IN ZIPATH:\"".DUPX_Log::varToString($extract_filename)."\"" , DUPX_Log::LV_DETAILED);
207
  continue;
208
  }
209
 
238
  'sections' => array('files'),
239
  ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
240
  } else {
241
+ DUPX_Log::info("FILE EXTRACTION DONE: ".DUPX_Log::varToString($extract_filename), DUPX_Log::LV_HARD_DEBUG);
242
  }
243
  } catch (Exception $ex) {
244
  if (DupLiteSnapLibUtilWp::isWpCore($extract_filename, DupLiteSnapLibUtilWp::PATH_RELATIVE)) {
367
  function getChildren()
368
  {
369
  try {
370
+ return new IgnorantRecursiveDirectoryIterator($this->getPathname(), RecursiveDirectoryIterator::SKIP_DOTS);
371
  } catch (UnexpectedValueException $e) {
372
  return new RecursiveArrayIterator(array());
373
  }
374
  }
375
  }
376
 
377
+ $set_file_perms = $_POST['set_file_perms'];
 
 
 
378
  $set_dir_perms = $_POST['set_dir_perms'];
379
  $set_file_mtime = ($_POST['zip_filetime'] == 'current');
380
  $file_perms_value = $_POST['file_perms_value'] ? $_POST['file_perms_value'] : 0755;
381
  $dir_perms_value = $_POST['dir_perms_value'] ? $_POST['dir_perms_value'] : 0644;
382
 
383
+ DUPX_Log::info("PERMISSION UPDATES:");
384
+ DUPX_Log::info(" -DIRS: '{$dir_perms_value}'");
385
+ DUPX_Log::info(" -FILES: '{$file_perms_value}'");
 
386
 
387
+ $objects = new RecursiveIteratorIterator(new IgnorantRecursiveDirectoryIterator($root_path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
 
 
 
388
 
389
+ foreach ($objects as $name => $object) {
390
+ if ($set_file_perms && is_file($name)) {
391
+ DUPX_Log::info("SET PERMISSION: ".DUPX_Log::varToString($name).'[MODE:'.$file_perms_value.']', DUPX_Log::LV_HARD_DEBUG);
392
+ if (!DupLiteSnapLibIOU::chmod($name, $file_perms_value)) {
393
+ DUPX_Log::info("Permissions setting on file '{$name}' failed");
394
+ }
395
+ } else if ($set_dir_perms && is_dir($name)) {
396
+ DUPX_Log::info("SET PERMISSION: ".DUPX_Log::varToString($name).'[MODE:'.$dir_perms_value.']', DUPX_Log::LV_HARD_DEBUG);
397
+ if (!DupLiteSnapLibIOU::chmod($name, $dir_perms_value)) {
398
+ DUPX_Log::info("Permissions setting on directory '{$name}' failed");
399
+ }
400
+ }
401
+ if ($set_file_mtime) {
402
+ @touch($name);
403
+ }
404
+ }
405
  } else {
406
  DUPX_Log::info("\nPERMISSION UPDATES: None Applied");
407
  }
installer/dup-installer/ctrls/ctrl.s2.base.php CHANGED
@@ -102,6 +102,25 @@ if($not_yet_logged){
102
  DUPX_Log::info('* STEP-2 START @ '.@date('h:i:s'));
103
  DUPX_Log::info('* NOTICE: Do NOT post to public sites or forums!!');
104
  DUPX_Log::info("********************************************************************************");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  $POST_LOG = $_POST;
106
  unset($POST_LOG['dbpass']);
107
  ksort($POST_LOG);
@@ -109,7 +128,8 @@ if($not_yet_logged){
109
  $log .= "POST DATA\n";
110
  $log .= "--------------------------------------\n";
111
  $log .= print_r($POST_LOG, true);
112
- DUPX_Log::info($log, 2);
 
113
  }
114
 
115
 
102
  DUPX_Log::info('* STEP-2 START @ '.@date('h:i:s'));
103
  DUPX_Log::info('* NOTICE: Do NOT post to public sites or forums!!');
104
  DUPX_Log::info("********************************************************************************");
105
+
106
+ $labelPadSize = 20;
107
+ DUPX_Log::info("USER INPUTS");
108
+ DUPX_Log::info(str_pad('VIEW MODE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['view_mode']));
109
+ DUPX_Log::info(str_pad('DB ACTION', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbaction']));
110
+ DUPX_Log::info(str_pad('DB HOST', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString('**OBSCURED**'));
111
+ DUPX_Log::info(str_pad('DB NAME', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString('**OBSCURED**'));
112
+ DUPX_Log::info(str_pad('DB PASS', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString('**OBSCURED**'));
113
+ DUPX_Log::info(str_pad('DB PORT', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString('**OBSCURED**'));
114
+ DUPX_Log::info(str_pad('NON-BREAKING SPACES', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbnbsp']));
115
+ DUPX_Log::info(str_pad('MYSQL MODE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbmysqlmode']));
116
+ DUPX_Log::info(str_pad('MYSQL MODE OPTS', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbmysqlmode_opts']));
117
+ DUPX_Log::info(str_pad('CHARSET', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbcharset']));
118
+ DUPX_Log::info(str_pad('COLLATE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbcollate']));
119
+ DUPX_Log::info(str_pad('COLLATE FB', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbcollatefb']));
120
+ DUPX_Log::info(str_pad('VIEW CREATION', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbobj_views']));
121
+ DUPX_Log::info(str_pad('STORED PROCEDURE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['dbobj_procs']));
122
+ DUPX_Log::info("********************************************************************************\n");
123
+
124
  $POST_LOG = $_POST;
125
  unset($POST_LOG['dbpass']);
126
  ksort($POST_LOG);
128
  $log .= "POST DATA\n";
129
  $log .= "--------------------------------------\n";
130
  $log .= print_r($POST_LOG, true);
131
+ DUPX_Log::info($log, DUPX_Log::LV_DEBUG, true);
132
+
133
  }
134
 
135
 
installer/dup-installer/ctrls/ctrl.s3.php CHANGED
@@ -1,671 +1,50 @@
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
- /** IDE HELPERS */
4
- /* @var $GLOBALS['DUPX_AC'] DUPX_ArchiveConfig */
5
 
6
  //-- START OF ACTION STEP 3: Update the database
7
  require_once($GLOBALS['DUPX_INIT'].'/classes/config/class.archive.config.php');
8
  require_once($GLOBALS['DUPX_INIT'].'/lib/config/class.wp.config.tranformer.php');
9
  require_once($GLOBALS['DUPX_INIT'].'/lib/config/class.wp.config.tranformer.src.php');
 
 
10
 
11
  /** JSON RESPONSE: Most sites have warnings turned off by default, but if they're turned on the warnings
12
  cause errors in the JSON data Here we hide the status so warning level is reset at it at the end */
13
- $ajax3_start = DUPX_U::getMicrotime();
14
- $ajax3_error_level = error_reporting();
15
- error_reporting(E_ERROR);
16
-
17
- //POST PARAMS
18
- $_POST['blogname'] = isset($_POST['blogname']) ? htmlspecialchars($_POST['blogname'], ENT_QUOTES) : 'No Blog Title Set';
19
- $_POST['postguid'] = isset($_POST['postguid']) && $_POST['postguid'] == 1 ? 1 : 0;
20
- $_POST['fullsearch'] = isset($_POST['fullsearch']) && $_POST['fullsearch'] == 1 ? 1 : 0;
21
- $_POST['path_old'] = isset($_POST['path_old']) ? trim($_POST['path_old']) : null;
22
- $_POST['path_new'] = isset($_POST['path_new']) ? trim($_POST['path_new']) : null;
23
- $_POST['siteurl'] = isset($_POST['siteurl']) ? rtrim(trim($_POST['siteurl']), '/') : null;
24
- $_POST['tables'] = isset($_POST['tables']) && is_array($_POST['tables']) ? array_map('stripcslashes', $_POST['tables']) : array();
25
-
26
- if (isset($_POST['url_old'])) {
27
- $post_url_old = DUPX_U::sanitize_text_field($_POST['url_old']);
28
- $_POST['url_old'] = trim($post_url_old);
29
- } else {
30
- $_POST['url_old'] = null;
31
- }
32
-
33
- if (isset($_POST['url_new'])) {
34
- $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
35
- $_POST['url_new'] = isset($_POST['url_new']) ? rtrim(trim($post_url_new), '/') : null;
36
- } else {
37
- $_POST['url_new'] = null;
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
- $replace_mail = filter_input(INPUT_POST, 'search_replace_email_domain', FILTER_VALIDATE_BOOLEAN);
44
-
45
-
46
- //MYSQL CONNECTION
47
- $dbh = DUPX_DB::connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass'], $_POST['dbname']);
48
- $dbConnError = (mysqli_connect_error()) ? 'Error: '.mysqli_connect_error() : 'Unable to Connect';
49
-
50
- if (!$dbh) {
51
- $msg = "Unable to connect with the following parameters: <br/> <b>HOST:</b> {$_POST['dbhost']}<br/> <b>DATABASE:</b> {$_POST['dbname']}<br/>";
52
- $msg .= "<b>Connection Error:</b> ".htmlentities($dbConnError);
53
- DUPX_Log::error($msg);
54
- }
55
-
56
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
57
-
58
- $charset_server = @mysqli_character_set_name($dbh);
59
- @mysqli_query($dbh, "SET wait_timeout = ".mysqli_real_escape_string($dbh, $GLOBALS['DB_MAX_TIME']));
60
- DUPX_DB::setCharset($dbh, $_POST['dbcharset'], $_POST['dbcollate']);
61
- $charset_client = @mysqli_character_set_name($dbh);
62
-
63
- //LOGGING
64
- $date = @date('h:i:s');
65
- $log = <<<LOG
66
- \n\n
67
- ********************************************************************************
68
- DUPLICATOR-LITE INSTALL-LOG
69
- STEP-3 START @ {$date}
70
- NOTICE: Do NOT post to public sites or forums
71
- ********************************************************************************
72
- CHARSET SERVER:\t{$charset_server}
73
- CHARSET CLIENT:\t{$charset_client}\n
74
- LOG;
75
- DUPX_Log::info($log);
76
-
77
- $POST_LOG = $_POST;
78
- unset($POST_LOG['tables']);
79
- unset($POST_LOG['plugins']);
80
- unset($POST_LOG['dbpass']);
81
- ksort($POST_LOG);
82
-
83
- //Detailed logging
84
- $log = "--------------------------------------\n";
85
- $log .= "POST DATA\n";
86
- $log .= "--------------------------------------\n";
87
- $log .= print_r($POST_LOG, true);
88
- $log .= "--------------------------------------\n";
89
- $log .= "TABLES TO SCAN\n";
90
- $log .= "--------------------------------------\n";
91
- $log .= (isset($_POST['tables']) && count($_POST['tables']) > 0) ? print_r($_POST['tables'], true) : 'No tables selected to update';
92
- $log .= "--------------------------------------\n";
93
- $log .= "KEEP PLUGINS ACTIVE\n";
94
- $log .= "--------------------------------------\n";
95
- $log .= (isset($_POST['plugins']) && count($_POST['plugins']) > 0) ? print_r($_POST['plugins'], true) : 'No plugins selected for activation';
96
- DUPX_Log::info($log, 2);
97
-
98
-
99
- //===============================================
100
- //UPDATE ENGINE
101
- //===============================================
102
- $log = "--------------------------------------\n";
103
- $log .= "SERIALIZER ENGINE\n";
104
- $log .= "[*] scan every column\n";
105
- $log .= "[~] scan only text columns\n";
106
- $log .= "[^] no searchable columns\n";
107
- $log .= "--------------------------------------";
108
- DUPX_Log::info($log);
109
-
110
- //===============================================
111
- // INIZIALIZE WP_CONFIG TRANSFORMER
112
- //===============================================
113
- $root_path = $GLOBALS['DUPX_ROOT'];
114
- $wpconfig_ark_path = DUPX_ServerConfig::getWpconfigArkPath();
115
- DUPX_ServerConfig::copyOriginalConfigFiles();
116
-
117
- $config_transformer = null;
118
- if (is_readable($wpconfig_ark_path)) {
119
- $config_transformer = new WPConfigTransformer($wpconfig_ark_path);
120
- }
121
-
122
- //===============================================
123
- // SEARCH AND REPLACE STRINGS
124
- //===============================================
125
-
126
- //CUSTOM REPLACE -> REPLACE LIST
127
- if (isset($_POST['search'])) {
128
- $search_count = count($_POST['search']);
129
- if ($search_count > 0) {
130
- for ($search_index = 0; $search_index < $search_count; $search_index++) {
131
- $search_for = $_POST['search'][$search_index];
132
- $replace_with = $_POST['replace'][$search_index];
133
-
134
- if (trim($search_for) != '') {
135
- DUPX_U::queueReplacementWithEncodings($search_for, $replace_with);
136
- }
137
- }
138
- }
139
- }
140
-
141
- // DIRS PATHS
142
- DUPX_U::queueReplacementWithEncodings($_POST['path_old'] , $_POST['path_new'] );
143
- $path_old_unsetSafe = rtrim(DUPX_U::unsetSafePath($_POST['path_old']), '\\');
144
- $path_new_unsetSafe = rtrim($_POST['path_new'], '/');
145
- DUPX_U::queueReplacementWithEncodings($path_old_unsetSafe , $path_new_unsetSafe );
146
-
147
- // URLS
148
- // url from _POST
149
- $old_urls_list = array(
150
- $_POST['url_old']
151
- );
152
-
153
  try {
154
- // urls from wp-config
155
- if (!is_null($config_transformer)) {
156
- if ($config_transformer->exists('constant', 'WP_HOME')) {
157
- $old_urls_list[] = $config_transformer->get_value('constant', 'WP_HOME');
158
- }
159
-
160
- if ($config_transformer->exists('constant', 'WP_SITEURL')) {
161
- $old_urls_list[] = $config_transformer->get_value('constant', 'WP_SITEURL');
162
- }
163
- }
164
-
165
-
166
- // urls from db
167
- $dbUrls = mysqli_query($dbh, 'SELECT * FROM `'.mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix).'options` where option_name IN (\'siteurl\',\'home\')');
168
- if ($dbUrls instanceof mysqli_result) {
169
- while ($row = $dbUrls->fetch_object()) {
170
- $old_urls_list[] = $row->option_value;
171
- }
172
- } else {
173
- DUPX_Log::info('DB ERROR: '. mysqli_error($dbh));
 
174
  }
175
- } catch(Exception $e) {
176
- DUPX_Log::info('CONTINUE EXCEPTION: '.$exceptionError->getMessage());
177
- DUPX_Log::info('TRACE:');
178
- DUPX_Log::info($exceptionError->getTraceAsString());
179
- }
180
-
181
- $at_new_domain = '@'.DUPX_U::getDomain($_POST['url_new']);
182
-
183
- $old_urls_list = array_unique ($old_urls_list);
184
- foreach ($old_urls_list as $old_url) {
185
- DUPX_U::replacmentUrlOldToNew($old_url, $_POST['url_new']);
186
-
187
- if ($replace_mail) {
188
- $at_old_domain = '@'.DUPX_U::getDomain($old_url);
189
-
190
- if ($at_new_domain !== $at_old_domain) {
191
- DUPX_U::queueReplacementWithEncodings($at_old_domain, $at_new_domain);
192
- }
193
- }
194
- }
195
-
196
- /*=============================================================
197
- * REMOVE TRAILING SLASH LOGIC:
198
- * In many cases the trailing slash of a url or path causes issues in some
199
- * enviroments; so by default all trailing slashes have been removed.
200
- * This has worked well for several years. However, there are some edge
201
- * cases where removing the trailing slash will cause issues such that
202
- * the following will happen:
203
- http://www.mysite.com >>>> http://C:/xampp/apache/htdocs/.mysite.com
204
- * So the edge case array is a place older for these types of issues.
205
- */
206
- $GLOBALS['REPLACE_LIST_EDGE_CASES'] = array('/www/');
207
- $_dupx_tmp_replace_list = $GLOBALS['REPLACE_LIST'];
208
- foreach ($_dupx_tmp_replace_list as $key => $val) {
209
- foreach ($GLOBALS['REPLACE_LIST_EDGE_CASES'] as $skip_val) {
210
- $search = $GLOBALS['REPLACE_LIST'][$key]['search'];
211
- $replace = $GLOBALS['REPLACE_LIST'][$key]['replace'];
212
- if (strcmp($skip_val, $search) !== 0) {
213
- $GLOBALS['REPLACE_LIST'][$key]['search'] = rtrim($search, '\/');
214
- $GLOBALS['REPLACE_LIST'][$key]['replace'] = rtrim($replace, '\/');
215
- } else {
216
- DUPX_Log::info("NOTICE: Edge case for path trimming detected on {$skip_val}");
217
- }
218
- }
219
- }
220
-
221
- DUPX_Log::info("Final replace list: \n". print_r($GLOBALS['REPLACE_LIST'], true), 2);
222
- $report = DUPX_UpdateEngine::load($dbh, $GLOBALS['REPLACE_LIST'], $_POST['tables'], $_POST['fullsearch']);
223
-
224
- //BUILD JSON RESPONSE
225
- $JSON = array();
226
- $JSON['step1'] = json_decode(urldecode($_POST['json']));
227
- $JSON['step3'] = $report;
228
- $JSON['step3']['warn_all'] = 0;
229
- $JSON['step3']['warnlist'] = array();
230
-
231
- DUPX_UpdateEngine::logStats($report);
232
- DUPX_UpdateEngine::logErrors($report);
233
-
234
- //===============================================
235
- //CREATE NEW ADMIN USER
236
- //===============================================
237
- if (strlen($_POST['wp_username']) >= 4 && strlen($_POST['wp_password']) >= 6) {
238
-
239
- $post_wp_username = $_POST['wp_username'];
240
- $post_wp_password = $_POST['wp_password'];
241
- $post_wp_mail = $_POST['wp_mail'];
242
- $post_wp_nickname = $_POST['wp_nickname'];
243
- if (empty($post_wp_nickname)) {
244
- $post_wp_nickname = $post_wp_username;
245
- }
246
- $post_wp_first_name = $_POST['wp_first_name'];
247
- $post_wp_last_name = $_POST['wp_last_name'];
248
-
249
- $post_wp_username = mysqli_real_escape_string($dbh, $post_wp_username);
250
- $post_wp_password = mysqli_real_escape_string($dbh, $post_wp_password);
251
-
252
- $post_wp_mail = mysqli_real_escape_string($dbh, $post_wp_mail);
253
- $post_wp_nickname = mysqli_real_escape_string($dbh, $post_wp_nickname);
254
- $post_wp_first_name = mysqli_real_escape_string($dbh, $post_wp_first_name);
255
- $post_wp_last_name = mysqli_real_escape_string($dbh, $post_wp_last_name);
256
-
257
- $newuser_check = mysqli_query($dbh, "SELECT COUNT(*) AS count FROM `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."users` WHERE user_login = '{$post_wp_username}' ");
258
- $newuser_row = mysqli_fetch_row($newuser_check);
259
- $newuser_count = is_null($newuser_row) ? 0 : $newuser_row[0];
260
-
261
- if ($newuser_count == 0) {
262
-
263
- $newuser_datetime = @date("Y-m-d H:i:s");
264
- $newuser_security = mysqli_real_escape_string($dbh, 'a:1:{s:13:"administrator";s:1:"1";}');
265
-
266
- $newuser1 = @mysqli_query($dbh,
267
- "INSERT INTO `{$GLOBALS['DUPX_AC']->wp_tableprefix}users`
268
- (`user_login`, `user_pass`, `user_nicename`, `user_email`, `user_registered`, `user_activation_key`, `user_status`, `display_name`)
269
- VALUES ('{$post_wp_username}', MD5('{$post_wp_password}'), '{$post_wp_username}', '{$post_wp_mail}', '{$newuser_datetime}', '', '0', '{$post_wp_username}')");
270
-
271
- $newuser1_insert_id = mysqli_insert_id($dbh);
272
-
273
- $newuser2 = @mysqli_query($dbh,
274
- "INSERT INTO `{$GLOBALS['DUPX_AC']->wp_tableprefix}usermeta`
275
- (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', '".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."capabilities', '{$newuser_security}')");
276
-
277
- $newuser3 = @mysqli_query($dbh,
278
- "INSERT INTO `{$GLOBALS['DUPX_AC']->wp_tableprefix}usermeta`
279
- (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', '{$GLOBALS['DUPX_AC']->wp_tableprefix}user_level', '10')");
280
-
281
- //Misc Meta-Data Settings:
282
- @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}', 'rich_editing', 'true')");
283
- @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}', 'admin_color', 'fresh')");
284
- @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}')");
285
- @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}')");
286
- @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}')");
287
-
288
- DUPX_Log::info("\nNEW WP-ADMIN USER:");
289
- if ($newuser1 && $newuser_test2 && $newuser3) {
290
- DUPX_Log::info("- New username '{$post_wp_username}' was created successfully allong with MU usermeta.");
291
- } elseif ($newuser1) {
292
- DUPX_Log::info("- New username '{$post_wp_username}' was created successfully.");
293
- } else {
294
- $newuser_warnmsg = "- Failed to create the user '{$post_wp_username}' \n ";
295
- $JSON['step3']['warnlist'][] = $newuser_warnmsg;
296
-
297
- $nManager->addFinalReportNotice(array(
298
- 'shortMsg' => 'New admin user create error',
299
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
300
- 'longMsg' => $newuser_warnmsg,
301
- 'sections' => 'general'
302
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE , 'new-user-create-error');
303
-
304
- DUPX_Log::info($newuser_warnmsg);
305
- }
306
- } else {
307
- $newuser_warnmsg = "\nNEW WP-ADMIN USER:\n - Username '{$post_wp_username}' already exists in the database. Unable to create new account.\n";
308
- $JSON['step3']['warnlist'][] = $newuser_warnmsg;
309
-
310
- $nManager->addFinalReportNotice(array(
311
- 'shortMsg' => 'New admin user create error',
312
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
313
- 'longMsg' => $newuser_warnmsg,
314
- 'sections' => 'general'
315
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE , 'new-user-create-error');
316
-
317
- DUPX_Log::info($newuser_warnmsg);
318
- }
319
- }
320
 
321
- //===============================================
322
- //CONFIGURATION FILE UPDATES
323
- //===============================================
324
- DUPX_Log::info("\n====================================");
325
- DUPX_Log::info('CONFIGURATION FILE UPDATES:');
326
- DUPX_Log::info("====================================\n");
327
-
328
- try {
329
- if (file_exists($wpconfig_ark_path)) {
330
-
331
- if (!is_writable($wpconfig_ark_path)) {
332
- $err_log = "\nWARNING: Unable to update file permissions and write to dup-wp-config-arc__[HASH].txt. ";
333
- $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. ";
334
- $err_log .= "If performing a 'Manual Extraction' please be sure to select the 'Manual Archive Extraction' option on step 1 under options.";
335
- 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}");
336
- }
337
-
338
- $config_transformer->update('constant', 'WP_HOME', $_POST['url_new'], array('normalize' => true, 'add' => false));
339
- $config_transformer->update('constant', 'WP_SITEURL', $_POST['url_new'], array('normalize' => true, 'add' => false));
340
-
341
- //SSL CHECKS
342
- if (isset($_POST['ssl_admin']) && $_POST['ssl_admin']) {
343
- $config_transformer->update('constant', 'FORCE_SSL_ADMIN', 'true', array('raw' => true, 'normalize' => true));
344
- } else {
345
- $config_transformer->update('constant', 'FORCE_SSL_ADMIN', 'false', array('raw' => true, 'add' => false, 'normalize' => true));
346
- }
347
-
348
- if (isset($_POST['cache_wp']) && $_POST['cache_wp']) {
349
- $config_transformer->update('constant', 'WP_CACHE', 'true', array('raw' => true, 'normalize' => true));
350
- } else {
351
- $config_transformer->update('constant', 'WP_CACHE', 'false', array('raw' => true, 'add' => false, 'normalize' => true));
352
- }
353
-
354
- // Cache: [ ] Keep Home Path
355
- if (isset($_POST['cache_path']) && $_POST['cache_path']) {
356
- if ($config_transformer->exists('constant', 'WPCACHEHOME')) {
357
- $wpcachehome_const_val = $config_transformer->get_value('constant', 'WPCACHEHOME');
358
- $wpcachehome_const_val = DUPX_U::wp_normalize_path($wpcachehome_const_val);
359
- $wpcachehome_new_const_val = str_replace($_POST['path_old'], $_POST['path_new'], $wpcachehome_const_val, $count);
360
- if ($count > 0) {
361
- $config_transformer->update('constant', 'WPCACHEHOME', $wpcachehome_new_const_val, array('normalize' => true));
362
- }
363
- }
364
- } else {
365
- $config_transformer->remove('constant', 'WPCACHEHOME');
366
- }
367
-
368
- if ($GLOBALS['DUPX_AC']->is_outer_root_wp_content_dir) {
369
- $config_transformer->remove('constant', 'WP_CONTENT_DIR');
370
- } elseif ($config_transformer->exists('constant', 'WP_CONTENT_DIR')) {
371
- $wp_content_dir_const_val = $config_transformer->get_value('constant', 'WP_CONTENT_DIR');
372
- $wp_content_dir_const_val = DUPX_U::wp_normalize_path($wp_content_dir_const_val);
373
- $new_path = str_replace($_POST['path_old'], $_POST['path_new'], $wp_content_dir_const_val, $count);
374
- if ($count > 0) {
375
- $config_transformer->update('constant', 'WP_CONTENT_DIR', $new_path, array('normalize' => true));
376
- }
377
- }
378
-
379
- //WP_CONTENT_URL
380
- // '/' added to prevent word boundary with domains that have the same root path
381
- if ($GLOBALS['DUPX_AC']->is_outer_root_wp_content_dir) {
382
- $config_transformer->remove('constant', 'WP_CONTENT_URL');
383
- } elseif ($config_transformer->exists('constant', 'WP_CONTENT_URL')) {
384
- $wp_content_url_const_val = $config_transformer->get_value('constant', 'WP_CONTENT_URL');
385
- $new_path = str_replace($_POST['url_old'] . '/', $_POST['url_new'] . '/', $wp_content_url_const_val, $count);
386
- if ($count > 0) {
387
- $config_transformer->update('constant', 'WP_CONTENT_URL', $new_path, array('normalize' => true));
388
- }
389
- }
390
-
391
- //WP_TEMP_DIR
392
- if ($config_transformer->exists('constant', 'WP_TEMP_DIR')) {
393
- $wp_temp_dir_const_val = $config_transformer->get_value('constant', 'WP_TEMP_DIR');
394
- $wp_temp_dir_const_val = DUPX_U::wp_normalize_path($wp_temp_dir_const_val);
395
- $new_path = str_replace($_POST['path_old'], $_POST['path_new'], $wp_temp_dir_const_val, $count);
396
- if ($count > 0) {
397
- $config_transformer->update('constant', 'WP_TEMP_DIR', $new_path, array('normalize' => true));
398
- }
399
- }
400
-
401
- // WP_PLUGIN_DIR
402
- if ($config_transformer->exists('constant', 'WP_PLUGIN_DIR')) {
403
- $wp_plugin_dir_const_val = $config_transformer->get_value('constant', 'WP_PLUGIN_DIR');
404
- $wp_plugin_dir_const_val = DUPX_U::wp_normalize_path($wp_plugin_dir_const_val);
405
- $new_path = str_replace($_POST['path_old'], $_POST['path_new'], $wp_plugin_dir_const_val, $count);
406
- if ($count > 0) {
407
- $config_transformer->update('constant', 'WP_PLUGIN_DIR', $new_path, array('normalize' => true));
408
- }
409
- }
410
-
411
- // WP_PLUGIN_URL
412
- if ($config_transformer->exists('constant', 'WP_PLUGIN_URL')) {
413
- $wp_plugin_url_const_val = $config_transformer->get_value('constant', 'WP_PLUGIN_URL');
414
- $new_path = str_replace($_POST['url_old'] . '/', $_POST['url_new'] . '/', $wp_plugin_url_const_val, $count);
415
- if ($count > 0) {
416
- $config_transformer->update('constant', 'WP_PLUGIN_URL', $new_path, array('normalize' => true));
417
- }
418
- }
419
-
420
- // WPMU_PLUGIN_DIR
421
- if ($config_transformer->exists('constant', 'WPMU_PLUGIN_DIR')) {
422
- $wpmu_plugin_dir_const_val = $config_transformer->get_value('constant', 'WPMU_PLUGIN_DIR');
423
- $wpmu_plugin_dir_const_val = DUPX_U::wp_normalize_path($wpmu_plugin_dir_const_val);
424
- $new_path = str_replace($_POST['path_old'], $_POST['path_new'], $wpmu_plugin_dir_const_val, $count);
425
- if ($count > 0) {
426
- $config_transformer->update('constant', 'WPMU_PLUGIN_DIR', $new_path, array('normalize' => true));
427
- }
428
- }
429
-
430
- // WPMU_PLUGIN_URL
431
- if ($config_transformer->exists('constant', 'WPMU_PLUGIN_URL')) {
432
- $wpmu_plugin_url_const_val = $config_transformer->get_value('constant', 'WPMU_PLUGIN_URL');
433
- $new_path = str_replace($_POST['url_old'] . '/', $_POST['url_new'] . '/', $wpmu_plugin_url_const_val, $count);
434
- if ($count > 0) {
435
- $config_transformer->update('constant', 'WPMU_PLUGIN_URL', $new_path, array('normalize' => true));
436
- }
437
- }
438
-
439
- // COOKIE_DOMAIN
440
- if ($config_transformer->exists('constant', 'COOKIE_DOMAIN')) {
441
-
442
- $post_url_old = DUPX_U::sanitize_text_field($_POST['url_old']);
443
- $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
444
-
445
- $parsed_post_url_old = parse_url($post_url_old);
446
- $parsed_post_url_new = parse_url($post_url_new);
447
-
448
- $old_cookie_domain = $parsed_post_url_old['host'];
449
- $new_cookie_domain = $parsed_post_url_new['host'];
450
-
451
- $const_val = $config_transformer->get_value('constant', 'COOKIE_DOMAIN'); $old_cookie_domain = $parsed_post_url_old['host'];
452
- $const_new_val= str_replace($old_cookie_domain, $new_cookie_domain, $const_val, $count);
453
-
454
- if ($count > 0) {
455
- $config_transformer->update('constant', 'COOKIE_DOMAIN', $const_new_val, array('normalize' => true));
456
- }
457
- }
458
-
459
- $db_host = isset($_POST['dbhost']) ? DUPX_U::sanitize_text_field($_POST['dbhost']) : '';
460
- $db_name = isset($_POST['dbname']) ? DUPX_U::sanitize_text_field($_POST['dbname']) : '';
461
- $db_user = isset($_POST['dbuser']) ? DUPX_U::sanitize_text_field($_POST['dbuser']) : '';
462
- $db_pass = isset($_POST['dbpass']) ? trim($_POST['dbpass']) : '';
463
- $db_pass = DUPX_U::getEscapedGenericString($db_pass);
464
-
465
- $config_transformer->update('constant', 'DB_NAME', $db_name);
466
- $config_transformer->update('constant', 'DB_USER', $db_user);
467
- $config_transformer->update('constant', 'DB_PASSWORD', $db_pass, array('raw' => true));
468
- $config_transformer->update('constant', 'DB_HOST', $db_host);
469
-
470
- DUPX_Log::info("UPDATED WP-CONFIG ARK FILE:\n - '{$wpconfig_ark_path}'");
471
-
472
- } else {
473
- DUPX_Log::info("AKR FILE NOT FOUND");
474
- DUPX_Log::info("WP-CONFIG ARK FILE:\n - '{$wpconfig_ark_path}'");
475
- DUPX_Log::info("SKIP FILE UPDATES\n");
476
-
477
- $shortMsg = 'wp-config.php not found';
478
- $longMsg = <<<LONGMSG
479
- Error updating wp-config file.<br>
480
- The installation is finished but check the wp-config.php file and manually update the incorrect values.
481
- LONGMSG;
482
- /* $nManager->addNextStepNotice(array(
483
- 'shortMsg' => $shortMsg,
484
- 'level' => DUPX_NOTICE_ITEM::CRITICAL,
485
-
486
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'wp-config-transformer-exception');*/
487
- $nManager->addFinalReportNotice(array(
488
- 'shortMsg' => $shortMsg,
489
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
490
- 'longMsg' => $longMsg,
491
- 'longMsgMode'=> DUPX_NOTICE_ITEM::MSG_MODE_HTML,
492
- 'sections' => 'general'
493
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'wp-config-transformer-exception');
494
-
495
- }
496
  } catch (Exception $e) {
497
- $shortMsg = 'wp-config.php transformer:'.$e->getMessage();
498
- $longMsg = <<<LONGMSG
499
- Error updating wp-config file.<br>
500
- The installation is finished but check the wp-config.php file and manually update the incorrect values.
501
- LONGMSG;
502
- /* $nManager->addNextStepNotice(array(
503
- 'shortMsg' => $shortMsg,
504
- 'level' => DUPX_NOTICE_ITEM::CRITICAL,
505
-
506
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'wp-config-transformer-exception');*/
507
- $nManager->addFinalReportNotice(array(
508
- 'shortMsg' => $shortMsg,
509
- 'level' => DUPX_NOTICE_ITEM::CRITICAL,
510
- 'longMsg' => $longMsg,
511
- 'longMsgMode'=> DUPX_NOTICE_ITEM::MSG_MODE_HTML,
512
- 'sections' => 'general'
513
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'wp-config-transformer-exception');
514
- }
515
-
516
- switch ($_POST['config_mode']) {
517
- case 'NEW':
518
- DUPX_ServerConfig::createNewConfigs();
519
- break;
520
- case 'RESTORE':
521
- DUPX_ServerConfig::renameOrigConfigs();
522
- DUPX_Log::info("\nWARNING: Retaining the original .htaccess or web.config files may cause");
523
- DUPX_Log::info("issues with the initial setup of your site. If you run into issues with the install");
524
- DUPX_Log::info("process choose 'Create New' for the 'Config Files' options");
525
- break;
526
- case 'IGNORE':
527
- DUPX_Log::info("\nWARNING: Choosing the option to ignore the .htaccess, web.config and .user.ini files");
528
- DUPX_Log::info("can lead to install issues. The 'Ignore All' option is designed for advanced users.");
529
- break;
530
  }
531
 
532
-
533
- //===============================================
534
- //GENERAL UPDATES & CLEANUP
535
- //===============================================
536
- //DUPX_Log::info("\n====================================");
537
- //DUPX_Log::info('GENERAL UPDATES & CLEANUP:');
538
- //DUPX_Log::info("====================================\n");
539
-
540
- $blog_name = mysqli_real_escape_string($dbh, $_POST['blogname']);
541
- $plugin_list = (isset($_POST['plugins'])) ? $_POST['plugins'] : array();
542
-
543
- if (!in_array('duplicator/duplicator.php', $plugin_list)) {
544
- $plugin_list[] = 'duplicator/duplicator.php';
545
- }
546
- $serial_plugin_list = @serialize($plugin_list);
547
- $serial_plugin_list = mysqli_real_escape_string($dbh, $serial_plugin_list);
548
-
549
- /** FINAL UPDATES: Must happen after the global replace to prevent double pathing
550
- http://xyz.com/abc01 will become http://xyz.com/abc0101 with trailing data */
551
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET option_value = '{$blog_name}' WHERE option_name = 'blogname' ");
552
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET option_value = '{$serial_plugin_list}' WHERE option_name = 'active_plugins' ");
553
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET option_value = '".mysqli_real_escape_string($dbh, $_POST['url_new'])."' WHERE option_name = 'home' ");
554
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` SET option_value = '".mysqli_real_escape_string($dbh, $_POST['siteurl'])."' WHERE option_name = 'siteurl' ");
555
- mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` (option_value, option_name) VALUES('".mysqli_real_escape_string($dbh, $_POST['exe_safe_mode'])."','duplicator_exe_safe_mode')");
556
- //Reset the postguid data
557
- if ($_POST['postguid']) {
558
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."posts` SET guid = REPLACE(guid, '".mysqli_real_escape_string($dbh, $_POST['url_new'])."', '".mysqli_real_escape_string($dbh, $_POST['url_old'])."')");
559
- $update_guid = @mysqli_affected_rows($dbh) or 0;
560
- DUPX_Log::info("Reverted '{$update_guid}' post guid columns back to '{$_POST['url_old']}'");
561
- }
562
-
563
- //===============================================
564
- //NOTICES TESTS
565
- //===============================================
566
- DUPX_Log::info("\n====================================");
567
- DUPX_Log::info("NOTICES");
568
- DUPX_Log::info("====================================\n");
569
-
570
- if (file_exists($wpconfig_ark_path)) {
571
- $config_vars = array('WPCACHEHOME', 'COOKIE_DOMAIN', 'WP_SITEURL', 'WP_HOME', 'WP_TEMP_DIR');
572
- $wpconfig_ark_contents = file_get_contents($wpconfig_ark_path);
573
- $config_found = DUPX_U::getListValues($config_vars, $wpconfig_ark_contents);
574
-
575
- //Files
576
- if (! empty($config_found)) {
577
- $msg = "WP-CONFIG NOTICE: The wp-config.php has following values set [".implode(", ", $config_found)."]. \n";
578
- $msg .= "Please validate these values are correct by opening the file and checking the values.\n";
579
- $msg .= "See the codex link for more details: https://codex.wordpress.org/Editing_wp-config.php";
580
- $JSON['step3']['warnlist'][] = $msg;
581
- DUPX_Log::info($msg);
582
-
583
- $nManager->addFinalReportNotice(array(
584
- 'shortMsg' => 'wp-config notice',
585
- 'level' => DUPX_NOTICE_ITEM::NOTICE,
586
- 'longMsg' => $msg,
587
- 'sections' => 'general'
588
- ));
589
- }
590
- } else {
591
- $msg = "WP-CONFIG NOTICE: <b>wp-config.php not found.</b><br><br>" ;
592
- $msg .= "No action on the wp-config was possible.<br>";
593
- $msg .= "Be sure to insert a properly modified wp-config for correct wordpress operation.";
594
- $JSON['step3']['warnlist'][] = $msg;
595
-
596
- $nManager->addFinalReportNotice(array(
597
- 'shortMsg' => 'wp-config not found',
598
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
599
- 'longMsg' => $msg,
600
- 'longMsgMode'=> DUPX_NOTICE_ITEM::MSG_MODE_HTML,
601
- 'sections' => 'general'
602
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE , 'wp-config-not-found');
603
-
604
- DUPX_Log::info($msg);
605
- }
606
-
607
- //Database
608
- $result = @mysqli_query($dbh, "SELECT option_value FROM `{$GLOBALS['DUPX_AC']->wp_tableprefix}options` WHERE option_name IN ('upload_url_path','upload_path')");
609
- if ($result) {
610
- while ($row = mysqli_fetch_row($result)) {
611
- if (strlen($row[0])) {
612
- $msg = "MEDIA SETTINGS NOTICE: The table '{$GLOBALS['DUPX_AC']->wp_tableprefix}options' has at least one the following values ['upload_url_path','upload_path'] \n";
613
- $msg .= "set please validate settings. These settings can be changed in the wp-admin by going to /wp-admin/options.php'";
614
- $JSON['step3']['warnlist'][] = $msg;
615
- DUPX_Log::info($msg);
616
-
617
- $nManager->addFinalReportNotice(array(
618
- 'shortMsg' => 'Media settings notice',
619
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
620
- 'longMsg' => $msg,
621
- 'sections' => 'general'
622
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE , 'media-settings-notice');
623
-
624
- break;
625
- }
626
- }
627
- }
628
-
629
- if (empty($JSON['step3']['warnlist'])) {
630
- DUPX_Log::info("No General Notices Found\n");
631
- }
632
-
633
- $JSON['step3']['warn_all'] = empty($JSON['step3']['warnlist']) ? 0 : count($JSON['step3']['warnlist']);
634
-
635
- mysqli_close($dbh);
636
-
637
-
638
- //-- Finally, back up the old wp-config and rename the new one
639
- if ($GLOBALS['DUPX_AC']->installSiteOverwriteOn) {
640
- $wpconfig_path = "{$GLOBALS['DUPX_ROOT']}/wp-config.php";
641
- if (copy($wpconfig_ark_path, $wpconfig_path) === false) {
642
- DUPX_Log::error("ERROR: Unable to copy '{$root_path}/dup-wp-config-arc__[HASH].txt' to '{$wpconfig_path}'. "
643
- . "Check server permissions for more details see FAQ: https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-055-q");
644
- }
645
- }
646
-
647
- //Cleanup any tmp files a developer may have forgotten about
648
- //Lets be proactive for the developer just in case
649
- $wpconfig_path_bak = "{$GLOBALS['DUPX_ROOT']}/wp-config.bak";
650
- $wpconfig_path_old = "{$GLOBALS['DUPX_ROOT']}/wp-config.old";
651
- $wpconfig_path_org = "{$GLOBALS['DUPX_ROOT']}/wp-config.org";
652
- $wpconfig_path_orig = "{$GLOBALS['DUPX_ROOT']}/wp-config.orig";
653
- $wpconfig_safe_check = array($wpconfig_path_bak, $wpconfig_path_old, $wpconfig_path_org, $wpconfig_path_orig);
654
-
655
- foreach ($wpconfig_safe_check as $file) {
656
- if(file_exists($file)) {
657
- $tmp_newfile = $file . uniqid('_');
658
- if(rename($file, $tmp_newfile) === false) {
659
- DUPX_Log::info("WARNING: Unable to rename '{$file}' to '{$tmp_newfile}'");
660
- }
661
- }
662
- }
663
- DUPX_ServerConfig::finalReportNotices();
664
- $nManager->saveNotices();
665
-
666
- $ajax3_sum = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $ajax3_start);
667
- DUPX_Log::info("\nSTEP-3 COMPLETE @ ".@date('h:i:s')." - RUNTIME: {$ajax3_sum} \n\n");
668
-
669
- $JSON['step3']['pass'] = 1;
670
- error_reporting($ajax3_error_level);
671
- die(DupLiteSnapLibUtil::wp_json_encode($JSON));
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
 
 
3
 
4
  //-- START OF ACTION STEP 3: Update the database
5
  require_once($GLOBALS['DUPX_INIT'].'/classes/config/class.archive.config.php');
6
  require_once($GLOBALS['DUPX_INIT'].'/lib/config/class.wp.config.tranformer.php');
7
  require_once($GLOBALS['DUPX_INIT'].'/lib/config/class.wp.config.tranformer.src.php');
8
+ require_once($GLOBALS['DUPX_INIT'].'/classes/utilities/class.u.search.reaplce.manager.php');
9
+ require_once($GLOBALS['DUPX_INIT'].'/classes/class.s3.func.php');
10
 
11
  /** JSON RESPONSE: Most sites have warnings turned off by default, but if they're turned on the warnings
12
  cause errors in the JSON data Here we hide the status so warning level is reset at it at the end */
13
+ // We have already removing warning from json resp
14
+ // It cause 500 internal server error so commenting out
15
+ /*
16
+ $ajax3_error_level = error_reporting();
17
+ error_reporting(E_ERROR);
18
+ */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  try {
20
+ DUPX_Log::setThrowExceptionOnError(true);
21
+
22
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
23
+ $s3Func = DUPX_S3_Funcs::getInstance();
24
+
25
+ switch ($s3Func->getEngineMode()) {
26
+ case DUPX_S3_Funcs::MODE_NORMAL:
27
+ default:
28
+ $s3Func->initLog();
29
+ $s3Func->runSearchAndReplace();
30
+
31
+ $s3Func->removeLicenseKey();
32
+ $s3Func->createNewAdminUser();
33
+ $s3Func->configurationFileUpdate();
34
+ $s3Func->htaccessUpdate();
35
+ $s3Func->generalUpdateAndCleanup();
36
+
37
+ $s3Func->noticeTest();
38
+ $s3Func->cleanupTmpFiles();
39
+ $s3Func->finalReportNotices();
40
+ $s3Func->complete();
41
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
+ $nManager->saveNotices();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  } catch (Exception $e) {
45
+ $s3Func->error($e->getMessage());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
 
48
+ $json = $s3Func->getJsonReport();
49
+ DUPX_Log::close();
50
+ die(DupLiteSnapLibUtil::wp_json_encode($json));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/dup-installer/index.php CHANGED
@@ -1,6 +1,12 @@
1
  <?php
2
  $API['BaseRootPath'] = str_ireplace('dup-installer', '', dirname(__FILE__));
3
- $API['BaseRootURL'] = '//' . $_SERVER['HTTP_HOST'] . str_ireplace('dup-installer', '', dirname($_SERVER['PHP_SELF']));
 
 
 
 
 
 
4
 
5
  if (file_exists("{$API['BaseRootPath']}\installer.php"))
6
  {
1
  <?php
2
  $API['BaseRootPath'] = str_ireplace('dup-installer', '', dirname(__FILE__));
3
+ // for ngrok url and Local by Flywheel Live URL
4
+ if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) {
5
+ $host = $_SERVER['HTTP_X_ORIGINAL_HOST'];
6
+ } else {
7
+ $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];//WAS SERVER_NAME and caused problems on some boxes
8
+ }
9
+ $API['BaseRootURL'] = '//' . $host . str_ireplace('dup-installer', '', dirname($_SERVER['PHP_SELF']));
10
 
11
  if (file_exists("{$API['BaseRootPath']}\installer.php"))
12
  {
installer/dup-installer/main.installer.php CHANGED
@@ -183,7 +183,13 @@ try {
183
  }
184
  }
185
 
186
- $GLOBALS['_CURRENT_URL_PATH'] = $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']);
 
 
 
 
 
 
187
  $GLOBALS['NOW_TIME'] = @date("His");
188
 
189
  if (!chdir($GLOBALS['DUPX_INIT'])) {
@@ -198,8 +204,6 @@ try {
198
  DUPX_Log::error("An invalid request was made to '{$post_ctrl_action}'. In order to protect this request from unauthorized access please "
199
  . "<a href='../{$GLOBALS['BOOTLOADER_NAME']}'>restart this install process</a>.");
200
  }
201
- require_once($GLOBALS['DUPX_INIT'].'/ctrls/ctrl.base.php');
202
-
203
  //PASSWORD CHECK
204
  if ($GLOBALS['DUPX_AC']->secure_on) {
205
  $pass_hasher = new DUPX_PasswordHash(8, FALSE);
@@ -254,17 +258,16 @@ if (!empty($unespectOutput)) {
254
  <title>Duplicator</title>
255
  <link rel='stylesheet' href='assets/font-awesome/css/all.min.css' type='text/css' media='all' />
256
 
257
- <link rel="apple-touch-icon" sizes="180x180" href="/dup-installer/favicon/lite01_apple-touch-icon.png">
258
- <link rel="icon" type="image/png" sizes="32x32" href="/dup-installer/favicon/lite01_favicon-32x32.png">
259
- <link rel="icon" type="image/png" sizes="16x16" href="/dup-installer/favicon/lite01_favicon-16x16.png">
260
- <link rel="manifest" href="/dup-installer/favicon/site.webmanifest">
261
- <link rel="mask-icon" href="/dup-installer/favicon/lite01_safari-pinned-tab.svg" color="#5bbad5">
262
- <link rel="shortcut icon" href="/dup-installer/favicon/lite01_favicon.ico">
263
  <meta name="msapplication-TileColor" content="#da532c">
264
- <meta name="msapplication-config" content="/favicon/dup-installer/browserconfig.xml">
265
  <meta name="theme-color" content="#ffffff">
266
 
267
- <link rel='stylesheet' href='assets/font-awesome/css/font-awesome.min.css' type='text/css' media='all' />
268
  <?php
269
  require_once($GLOBALS['DUPX_INIT'] . '/assets/inc.libs.css.php');
270
  require_once($GLOBALS['DUPX_INIT'] . '/assets/inc.css.php');
@@ -272,7 +275,7 @@ if (!empty($unespectOutput)) {
272
  require_once($GLOBALS['DUPX_INIT'] . '/assets/inc.js.php');
273
  ?>
274
  </head>
275
- <body>
276
 
277
  <div id="content">
278
 
@@ -320,6 +323,8 @@ if (!empty($unespectOutput)) {
320
  //DUPX_NOTICE_MANAGER::testFinalReportFullMessages();
321
  /****************************/
322
 
 
 
323
  DUPX_NOTICE_MANAGER::getInstance()->displayStepMessages();
324
  ?>
325
 
183
  }
184
  }
185
 
186
+ // for ngrok url and Local by Flywheel Live URL
187
+ if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) {
188
+ $host = $_SERVER['HTTP_X_ORIGINAL_HOST'];
189
+ } else {
190
+ $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];//WAS SERVER_NAME and caused problems on some boxes
191
+ }
192
+ $GLOBALS['_CURRENT_URL_PATH'] = $host . dirname($_SERVER['PHP_SELF']);
193
  $GLOBALS['NOW_TIME'] = @date("His");
194
 
195
  if (!chdir($GLOBALS['DUPX_INIT'])) {
204
  DUPX_Log::error("An invalid request was made to '{$post_ctrl_action}'. In order to protect this request from unauthorized access please "
205
  . "<a href='../{$GLOBALS['BOOTLOADER_NAME']}'>restart this install process</a>.");
206
  }
 
 
207
  //PASSWORD CHECK
208
  if ($GLOBALS['DUPX_AC']->secure_on) {
209
  $pass_hasher = new DUPX_PasswordHash(8, FALSE);
258
  <title>Duplicator</title>
259
  <link rel='stylesheet' href='assets/font-awesome/css/all.min.css' type='text/css' media='all' />
260
 
261
+ <link rel="apple-touch-icon" sizes="180x180" href="favicon/lite01_apple-touch-icon.png">
262
+ <link rel="icon" type="image/png" sizes="32x32" href="favicon/lite01_favicon-32x32.png">
263
+ <link rel="icon" type="image/png" sizes="16x16" href="favicon/lite01_favicon-16x16.png">
264
+ <link rel="manifest" href="favicon/site.webmanifest">
265
+ <link rel="mask-icon" href="favicon/lite01_safari-pinned-tab.svg" color="#5bbad5">
266
+ <link rel="shortcut icon" href="favicon/lite01_favicon.ico">
267
  <meta name="msapplication-TileColor" content="#da532c">
268
+ <meta name="msapplication-config" content="favicon/browserconfig.xml">
269
  <meta name="theme-color" content="#ffffff">
270
 
 
271
  <?php
272
  require_once($GLOBALS['DUPX_INIT'] . '/assets/inc.libs.css.php');
273
  require_once($GLOBALS['DUPX_INIT'] . '/assets/inc.css.php');
275
  require_once($GLOBALS['DUPX_INIT'] . '/assets/inc.js.php');
276
  ?>
277
  </head>
278
+ <body id="body-<?php echo $GLOBALS["VIEW"]; ?>" >
279
 
280
  <div id="content">
281
 
323
  //DUPX_NOTICE_MANAGER::testFinalReportFullMessages();
324
  /****************************/
325
 
326
+ DUPX_NOTICE_MANAGER::getInstance()->nextStepLog();
327
+ // display and remove next step notices
328
  DUPX_NOTICE_MANAGER::getInstance()->displayStepMessages();
329
  ?>
330
 
installer/dup-installer/views/view.help.php CHANGED
@@ -1,12 +1,15 @@
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
- //The help for both pro and lite are shared. Pro is where the master lives. Use the flag below to
4
- //indicate if this help lives in lite or pro
5
- //$pro_version = true;
6
 
7
  $open_section = filter_input(INPUT_GET, 'open_section', FILTER_SANITIZE_STRING, array('options' => array('default' => '')));
8
 
9
  ?>
 
 
 
10
  <!-- =========================================
11
  HELP FORM -->
12
  <div id="main-help">
@@ -35,18 +38,18 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
35
 
36
  <table class="help-opt">
37
  <tr>
38
- <th>Option</th>
39
  <th>Details</th>
40
  </tr>
41
  <tr>
42
- <td>Locked</td>
43
  <td>
44
  "Locked" means a password is protecting each step of the installer. This option is recommended on all installers
45
  that are accessible via a public URL but not required.
46
  </td>
47
  </tr>
48
  <tr>
49
- <td>Unlocked</td>
50
  <td>
51
  "Unlocked" means that if your installer is on a public server that anyone can access it. This is a less secure way to run your installer. If you are running the
52
  installer very quickly then removing all the installer files, then the chances of exposing it is going to be low depending on your sites access history.
@@ -82,25 +85,25 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
82
 
83
  <table class="help-opt">
84
  <tr>
85
- <th>Option</th>
86
  <th>Details</th>
87
  </tr>
88
  <tr>
89
- <td>Standard Install</td>
90
  <td>
91
  This mode indicates that the installer and archive have been placed into an empty directory and the site is ready for a fresh/new redeployment.
92
  This is the most common mode and the mode that has been around the longest.
93
  </td>
94
  </tr>
95
  <tr>
96
- <td>Standard Install <br/> Database Only</td>
97
  <td>
98
  This mode indicates that the installer and archive were manually moved or transferred to a location and that only the Database will be installed
99
  at this location.
100
  </td>
101
  </tr>
102
  <tr>
103
- <td>Overwrite Install <sup>pro</sup></td>
104
  <td>
105
  This mode indicates that the installer was started in a location that contains an existing site. With this mode <b>the existing site will be overwritten</b> with
106
  the contents of the archive.zip/daf and the database.sql file. This is an advanced option and users should be pre-paired to know that state of their database
@@ -108,7 +111,7 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
108
  </td>
109
  </tr>
110
  <tr>
111
- <td>Overwrite Install <br/> Database Only <sup>pro</sup></td>
112
  <td>
113
  This mode indicates that the installer was started in a location that contains an existing site. With this mode <b>the existing site will be overwritten</b> with
114
  the contents of the database.sql file. This is an advanced option and users should be pre-paired to know that state of their database and site files ahead of time.
@@ -148,14 +151,14 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
148
  The options for step 1 can help better prepare your site should your server need additional settings beyond most general configuration.
149
  <table class="help-opt">
150
  <tr>
151
- <th>Option</th>
152
  <th>Details</th>
153
  </tr>
154
  <tr>
155
  <td colspan="2" class="section">General Options</td>
156
  </tr>
157
  <tr>
158
- <td>Extraction</td>
159
  <td>
160
  <b>Manual Archive Extraction</b><br/>
161
  Set the Extraction value to "Manual Archive Extraction" when the archive file has already been manually extracted on the server. This can be done through your hosts
@@ -175,7 +178,7 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
175
  </td>
176
  </tr>
177
  <tr>
178
- <td>Permissions</td>
179
  <td>
180
  <b>All Files:</b> Check the 'All Files' check-box and enter in the desired <a href="http://php.net/manual/en/function.chmod.php" target="_blank">chmod command</a>
181
  to recursively set the octal value on all the files being extracted. Typically this value is 644 on most servers and hosts.
@@ -191,7 +194,7 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
191
  <td colspan="2" class="section">Advanced Options</td>
192
  </tr>
193
  <tr>
194
- <td>Safe Mode</td>
195
  <td>
196
  Safe mode is designed to configure the site with specific options at install time to help over come issues that may happen during the install were the site
197
  is having issues. These options should only be used if you run into issues after you have tried to run an install.
@@ -205,7 +208,7 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
205
  </td>
206
  </tr>
207
  <tr>
208
- <td>Config Files </td>
209
  <td>
210
  When dealing with configuration files (.htaccess, web.config and .user.ini) the installer can apply different modes:
211
  <br/><br/>
@@ -234,12 +237,12 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
234
  </tr>
235
 
236
  <tr>
237
- <td>File Times</td>
238
  <td>When the archive is extracted should it show the current date-time or keep the original time it had when it was built. This setting will be applied to
239
  all files and directories.</td>
240
  </tr>
241
  <tr>
242
- <td>Logging</td>
243
  <td>
244
  The level of detail that will be sent to the log file (installer-log.txt). The recommend setting for most installs should be 'Light'.
245
  Note if you use Debug the amount of data written can be very large. Debug is only recommended for support.
@@ -280,27 +283,27 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
280
  <i>The cPanel connectivity option is only available for Duplicator Pro.</i>
281
  <table class="help-opt">
282
  <tr>
283
- <th>Option</th>
284
  <th>Details</th>
285
  </tr>
286
  <tr>
287
- <td>Host</td>
288
  <td>This should be the primary domain account URL that is associated with your host. Most hosts will require you to register a primary domain name.
289
  This should be the URL that you place in the host field. For example if your primary domain name is "mysite.com" then you would enter in
290
  "https://mysite.com:2083". The port 2038 is the common port number that cPanel works on. If you do not know your primary domain name please contact your
291
  hosting provider or server administrator.</td>
292
  </tr>
293
  <tr>
294
- <td>Username</td>
295
  <td>The cPanel username used to login to your cPanel account. <i>This is <b>not</b> the same thing as your WordPress administrator account</i>.
296
  If your unsure of this name please contact your hosting provider or server administrator.</td>
297
  </tr>
298
  <tr>
299
- <td>Password</td>
300
  <td>The password of the cPanel user</td>
301
  </tr>
302
  <tr>
303
- <td>Troubleshoot</td>
304
  <td>
305
  <b>Common cPanel Connection Issues:</b><br/>
306
  - Your host does not use <a href="http://cpanel.com/" target="_blank">cPanel Software</a> <br/>
@@ -317,11 +320,11 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
317
  The database setup options allow you to connect to an existing database or in the case of cPanel connect or create a new database.
318
  <table class="help-opt">
319
  <tr>
320
- <th>Option</th>
321
  <th>Details</th>
322
  </tr>
323
  <tr>
324
- <td>Action</td>
325
  <td>
326
  <b>Create New Database:</b> Will attempt to create a new database if it does not exist. When using the 'Basic' option this option will not work on many
327
  hosting providers as the ability to create new databases is normally locked down. If the database does not exist then you will need to login to your
@@ -345,23 +348,23 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
345
  </td>
346
  </tr>
347
  <tr>
348
- <td>Host</td>
349
  <td>The name of the host server that the database resides on. Many times this will be 'localhost', however each hosting provider will have it's own naming
350
  convention please check with your server administrator or host to valid for sure the name needed. To add a port number just append it to the host i.e.
351
  'localhost:3306'.</td>
352
  </tr>
353
  <tr>
354
- <td>Database</td>
355
  <td>The name of the database to which this installation will connect and install the new tables and data into. Some hosts will require a prefix while others
356
  do not. Be sure to know exactly how your host requires the database name to be entered.</td>
357
  </tr>
358
  <tr>
359
- <td>User</td>
360
  <td>The name of a MySQL database server user. This is special account that has privileges to access a database and can read from or write to that database.
361
  <i>This is <b>not</b> the same thing as your WordPress administrator account</i>.</td>
362
  </tr>
363
  <tr>
364
- <td>Password</td>
365
  <td>The password of the MySQL database server user.</td>
366
  </tr>
367
 
@@ -372,18 +375,18 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
372
  <h3>Options</h3>
373
  <table class="help-opt">
374
  <tr>
375
- <th>Option</th>
376
  <th>Details</th>
377
  </tr>
378
  <tr>
379
- <td>Prefix<sup>pro*</sup></td>
380
  <td>By default, databases are prefixed with the cPanel account's username (for example, myusername_databasename). However you can ignore this option if
381
  your host does not use the default cPanel username prefix schema. Check the 'Ignore cPanel Prefix' and the username prefixes will be ignored.
382
  This will still require you to enter in the cPanels required setup prefix if they require one. The checkbox will be set to read-only if your host has
383
  disabled prefix settings. Please see your host full requirements when using the cPanel options.</td>
384
  </tr>
385
  <tr>
386
- <td>Legacy</td>
387
  <td>When creating a database table, the Mysql version being used may not support the collation type of the Mysql version where the table was created.
388
  In this scenario, the installer will fallback to a legacy collation type to try and create the table. This value should only be checked if you receive an error when
389
  testing the database.
@@ -397,22 +400,22 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
397
  </td>
398
  </tr>
399
  <tr>
400
- <td>Spacing</td>
401
  <td>The process will remove utf8 characters represented as 'xC2' 'xA0' and replace with a uniform space. Use this option if you find strange question
402
  marks in you posts</td>
403
  </tr>
404
  <tr>
405
- <td>Mode</td>
406
  <td>The MySQL mode option will allow you to set the mode for this session. It is very useful when running into conversion issues. For a full overview please
407
  see the <a href="https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html" target="_blank">MySQL mode documentation</a> specific to your version.</td>
408
  </tr>
409
  <tr>
410
- <td>Charset</td>
411
  <td>When the database is populated from the SQL script it will use this value as part of its connection. Only change this value if you know what your
412
  databases character set should be.</td>
413
  </tr>
414
  <tr>
415
- <td>Collation</td>
416
  <td>When the database is populated from the SQL script it will use this value as part of its connection. Only change this value if you know what your
417
  databases collation set should be.</td>
418
  </tr>
@@ -425,18 +428,18 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
425
 
426
  <table class="help-opt">
427
  <tr>
428
- <th>Option</th>
429
  <th>Details</th>
430
  </tr>
431
  <tr>
432
- <td>Test<br/>Database</td>
433
  <td>
434
  The 'Test Database' button will help validate if the connection parameters are correct for this server and help with details about any issues
435
  that may arise.
436
  </td>
437
  </tr>
438
  <tr>
439
- <td>Troubleshoot</td>
440
  <td>
441
  <b>Common Database Connection Issues:</b><br/>
442
  - Double check case sensitive values 'User', 'Password' &amp; the 'Database Name' <br/>
@@ -481,78 +484,92 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
481
  <h3>Options</h3>
482
  <table class="help-opt">
483
  <tr>
484
- <th>Option</th>
485
  <th>Details</th>
486
  </tr>
487
  <tr>
488
  <td colspan="2" class="section">New Admin Account</td>
489
  </tr>
490
  <tr>
491
- <td>Username</td>
492
  <td>A new WordPress username to create. This will create a new WordPress administrator account. Please note that usernames are not changeable from the within the UI.</td>
493
  </tr>
494
  <tr>
495
- <td>Password</td>
496
  <td>The new password for the new user. Must be at least 6 characters long.</td>
497
  </tr>
498
  <tr>
499
  <td colspan="2" class="section">Scan Options</td>
500
  </tr>
501
  <tr>
502
- <td>Cleanup <sup>pro</sup></td>
503
  <td>The checkbox labeled Remove schedules &amp; storage endpoints will empty the Duplicator schedule and storage settings. This is recommended to keep enabled so that you do not have unwanted schedules and storage options enabled.</td>
504
  </tr>
505
  <tr>
506
- <td>Old URL</td>
507
  <td>The old URL of the original values that the package was created with. These values should not be changed, unless you know the underlying reasons</td>
508
  </tr>
509
  <tr>
510
- <td>Old Path</td>
511
  <td>The old path of the original values that the package was created with. These values should not be changed, unless you know the underlying reasons</td>
512
  </tr>
513
  <tr>
514
- <td>Site URL</td>
515
  <td> For details see WordPress <a href="http://codex.wordpress.org/Changing_The_Site_URL" target="_blank">Site URL</a> &amp; <a href="http://codex.wordpress.org/Giving_WordPress_Its_Own_Directory" target="_blank">Alternate Directory</a>. If you're not sure about this value then leave it the same as the new settings URL.</td>
516
  </tr>
517
  <tr>
518
- <td>Scan Tables</td>
519
  <td>Select the tables to be updated. This process will update all of the 'Old Settings' with the 'New Settings'. Hold down the 'ctrl key' to select/deselect multiple.</td>
520
  </tr>
521
  <tr>
522
- <td>Activate Plugins</td>
523
  <td>These plug-ins are the plug-ins that were activated when the package was created and represent the plug-ins that will be activated after the install.</td>
524
  </tr>
525
  <tr>
526
- <td>Update email domains</td>
527
  <td>The domain portion of all email addresses will be updated if this option is enabled.</td>
528
  </tr>
529
  <tr>
530
- <td>Full Search</td>
531
  <td>Full search forces a scan of every single cell in the database. If it is not checked then only text based columns are searched which makes the update process much faster.
532
  Use this option if you have issues with data not updating correctly.</td>
533
  </tr>
534
  <tr>
535
- <td>Post GUID</td>
536
  <td>If your moving a site keep this value checked. For more details see the <a href="http://codex.wordpress.org/Changing_The_Site_URL#Important_GUID_Note" target="_blank">notes on GUIDS</a>. Changing values in the posts table GUID column can change RSS readers to evaluate that the posts are new and may show them in feeds again.</td>
537
  </tr>
538
  <tr>
539
- <td>Cross search <sup>pro</sup></td>
540
  <td>
541
  This option enables the searching and replacing of subsite domains and paths that link to each other. <br>
542
  Check this option if hyperlinks of at least one subsite point to another subsite.<br>
543
  Uncheck this option there if there are at least <?php echo MAX_SITES_TO_DEFAULT_ENABLE_CORSS_SEARCH ?> subsites and no subsites hyperlinking to each other (Checking this option in this scenario would unnecessarily load your server).<br><br>
544
  Check this option If you unsure if you need this option.<br></td>
545
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
546
  <tr>
547
  <td colspan="2" class="section">WP-Config File</td>
548
  </tr>
549
  <tr>
550
- <td>Config SSL</td>
551
  <td>Turn off SSL support for WordPress. This sets FORCE_SSL_ADMIN in your wp-config file to false if true, otherwise it will create the setting if not set. The "Enforce on Login"
552
  will turn off SSL support for WordPress Logins.</td>
553
  </tr>
554
  <tr>
555
- <td>Config Cache</td>
556
  <td>Turn off Cache support for WordPress. This sets WP_CACHE in your wp-config file to false if true, otherwise it will create the setting if not set. The "Keep Home Path"
557
  sets WPCACHEHOME in your wp-config file to nothing if true, otherwise nothing is changed.</td>
558
  </tr>
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+ //The help for both pro and lite are shared. Pro is where the master lives. Use the flag below to
4
+ //indicate if this help lives in lite or pro
5
+ //$pro_version = true;
6
 
7
  $open_section = filter_input(INPUT_GET, 'open_section', FILTER_SANITIZE_STRING, array('options' => array('default' => '')));
8
 
9
  ?>
10
+ <div class="hdr-main">
11
+ HELP
12
+ </div>
13
  <!-- =========================================
14
  HELP FORM -->
15
  <div id="main-help">
38
 
39
  <table class="help-opt">
40
  <tr>
41
+ <th class="col-opt">Option</th>
42
  <th>Details</th>
43
  </tr>
44
  <tr>
45
+ <td class="col-opt">Locked</td>
46
  <td>
47
  "Locked" means a password is protecting each step of the installer. This option is recommended on all installers
48
  that are accessible via a public URL but not required.
49
  </td>
50
  </tr>
51
  <tr>
52
+ <td class="col-opt">Unlocked</td>
53
  <td>
54
  "Unlocked" means that if your installer is on a public server that anyone can access it. This is a less secure way to run your installer. If you are running the
55
  installer very quickly then removing all the installer files, then the chances of exposing it is going to be low depending on your sites access history.
85
 
86
  <table class="help-opt">
87
  <tr>
88
+ <th class="col-opt">Option</th>
89
  <th>Details</th>
90
  </tr>
91
  <tr>
92
+ <td class="col-opt">Standard Install</td>
93
  <td>
94
  This mode indicates that the installer and archive have been placed into an empty directory and the site is ready for a fresh/new redeployment.
95
  This is the most common mode and the mode that has been around the longest.
96
  </td>
97
  </tr>
98
  <tr>
99
+ <td class="col-opt">Standard Install <br/> Database Only</td>
100
  <td>
101
  This mode indicates that the installer and archive were manually moved or transferred to a location and that only the Database will be installed
102
  at this location.
103
  </td>
104
  </tr>
105
  <tr>
106
+ <td class="col-opt">Overwrite Install <sup>pro</sup></td>
107
  <td>
108
  This mode indicates that the installer was started in a location that contains an existing site. With this mode <b>the existing site will be overwritten</b> with
109
  the contents of the archive.zip/daf and the database.sql file. This is an advanced option and users should be pre-paired to know that state of their database
111
  </td>
112
  </tr>
113
  <tr>
114
+ <td class="col-opt">Overwrite Install <br/> Database Only <sup>pro</sup></td>
115
  <td>
116
  This mode indicates that the installer was started in a location that contains an existing site. With this mode <b>the existing site will be overwritten</b> with
117
  the contents of the database.sql file. This is an advanced option and users should be pre-paired to know that state of their database and site files ahead of time.
151
  The options for step 1 can help better prepare your site should your server need additional settings beyond most general configuration.
152
  <table class="help-opt">
153
  <tr>
154
+ <th class="col-opt">Option</th>
155
  <th>Details</th>
156
  </tr>
157
  <tr>
158
  <td colspan="2" class="section">General Options</td>
159
  </tr>
160
  <tr>
161
+ <td class="col-opt">Extraction</td>
162
  <td>
163
  <b>Manual Archive Extraction</b><br/>
164
  Set the Extraction value to "Manual Archive Extraction" when the archive file has already been manually extracted on the server. This can be done through your hosts
178
  </td>
179
  </tr>
180
  <tr>
181
+ <td class="col-opt">Permissions</td>
182
  <td>
183
  <b>All Files:</b> Check the 'All Files' check-box and enter in the desired <a href="http://php.net/manual/en/function.chmod.php" target="_blank">chmod command</a>
184
  to recursively set the octal value on all the files being extracted. Typically this value is 644 on most servers and hosts.
194
  <td colspan="2" class="section">Advanced Options</td>
195
  </tr>
196
  <tr>
197
+ <td class="col-opt">Safe Mode</td>
198
  <td>
199
  Safe mode is designed to configure the site with specific options at install time to help over come issues that may happen during the install were the site
200
  is having issues. These options should only be used if you run into issues after you have tried to run an install.
208
  </td>
209
  </tr>
210
  <tr>
211
+ <td class="col-opt">Config Files </td>
212
  <td>
213
  When dealing with configuration files (.htaccess, web.config and .user.ini) the installer can apply different modes:
214
  <br/><br/>
237
  </tr>
238
 
239
  <tr>
240
+ <td class="col-opt">File Times</td>
241
  <td>When the archive is extracted should it show the current date-time or keep the original time it had when it was built. This setting will be applied to
242
  all files and directories.</td>
243
  </tr>
244
  <tr>
245
+ <td class="col-opt">Logging</td>
246
  <td>
247
  The level of detail that will be sent to the log file (installer-log.txt). The recommend setting for most installs should be 'Light'.
248
  Note if you use Debug the amount of data written can be very large. Debug is only recommended for support.
283
  <i>The cPanel connectivity option is only available for Duplicator Pro.</i>
284
  <table class="help-opt">
285
  <tr>
286
+ <th class="col-opt">Option</th>
287
  <th>Details</th>
288
  </tr>
289
  <tr>
290
+ <td class="col-opt">Host</td>
291
  <td>This should be the primary domain account URL that is associated with your host. Most hosts will require you to register a primary domain name.
292
  This should be the URL that you place in the host field. For example if your primary domain name is "mysite.com" then you would enter in
293
  "https://mysite.com:2083". The port 2038 is the common port number that cPanel works on. If you do not know your primary domain name please contact your
294
  hosting provider or server administrator.</td>
295
  </tr>
296
  <tr>
297
+ <td class="col-opt">Username</td>
298
  <td>The cPanel username used to login to your cPanel account. <i>This is <b>not</b> the same thing as your WordPress administrator account</i>.
299
  If your unsure of this name please contact your hosting provider or server administrator.</td>
300
  </tr>
301
  <tr>
302
+ <td class="col-opt">Password</td>
303
  <td>The password of the cPanel user</td>
304
  </tr>
305
  <tr>
306
+ <td class="col-opt">Troubleshoot</td>
307
  <td>
308
  <b>Common cPanel Connection Issues:</b><br/>
309
  - Your host does not use <a href="http://cpanel.com/" target="_blank">cPanel Software</a> <br/>
320
  The database setup options allow you to connect to an existing database or in the case of cPanel connect or create a new database.
321
  <table class="help-opt">
322
  <tr>
323
+ <th class="col-opt">Option</th>
324
  <th>Details</th>
325
  </tr>
326
  <tr>
327
+ <td class="col-opt">Action</td>
328
  <td>
329
  <b>Create New Database:</b> Will attempt to create a new database if it does not exist. When using the 'Basic' option this option will not work on many
330
  hosting providers as the ability to create new databases is normally locked down. If the database does not exist then you will need to login to your
348
  </td>
349
  </tr>
350
  <tr>
351
+ <td class="col-opt">Host</td>
352
  <td>The name of the host server that the database resides on. Many times this will be 'localhost', however each hosting provider will have it's own naming
353
  convention please check with your server administrator or host to valid for sure the name needed. To add a port number just append it to the host i.e.
354
  'localhost:3306'.</td>
355
  </tr>
356
  <tr>
357
+ <td class="col-opt">Database</td>
358
  <td>The name of the database to which this installation will connect and install the new tables and data into. Some hosts will require a prefix while others
359
  do not. Be sure to know exactly how your host requires the database name to be entered.</td>
360
  </tr>
361
  <tr>
362
+ <td class="col-opt">User</td>
363
  <td>The name of a MySQL database server user. This is special account that has privileges to access a database and can read from or write to that database.
364
  <i>This is <b>not</b> the same thing as your WordPress administrator account</i>.</td>
365
  </tr>
366
  <tr>
367
+ <td class="col-opt">Password</td>
368
  <td>The password of the MySQL database server user.</td>
369
  </tr>
370
 
375
  <h3>Options</h3>
376
  <table class="help-opt">
377
  <tr>
378
+ <th class="col-opt">Option</th>
379
  <th>Details</th>
380
  </tr>
381
  <tr>
382
+ <td class="col-opt">Prefix<sup>pro*</sup></td>
383
  <td>By default, databases are prefixed with the cPanel account's username (for example, myusername_databasename). However you can ignore this option if
384
  your host does not use the default cPanel username prefix schema. Check the 'Ignore cPanel Prefix' and the username prefixes will be ignored.
385
  This will still require you to enter in the cPanels required setup prefix if they require one. The checkbox will be set to read-only if your host has
386
  disabled prefix settings. Please see your host full requirements when using the cPanel options.</td>
387
  </tr>
388
  <tr>
389
+ <td class="col-opt">Legacy</td>
390
  <td>When creating a database table, the Mysql version being used may not support the collation type of the Mysql version where the table was created.
391
  In this scenario, the installer will fallback to a legacy collation type to try and create the table. This value should only be checked if you receive an error when
392
  testing the database.
400
  </td>
401
  </tr>
402
  <tr>
403
+ <td class="col-opt">Spacing</td>
404
  <td>The process will remove utf8 characters represented as 'xC2' 'xA0' and replace with a uniform space. Use this option if you find strange question
405
  marks in you posts</td>
406
  </tr>
407
  <tr>
408
+ <td class="col-opt">Mode</td>
409
  <td>The MySQL mode option will allow you to set the mode for this session. It is very useful when running into conversion issues. For a full overview please
410
  see the <a href="https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html" target="_blank">MySQL mode documentation</a> specific to your version.</td>
411
  </tr>
412
  <tr>
413
+ <td class="col-opt">Charset</td>
414
  <td>When the database is populated from the SQL script it will use this value as part of its connection. Only change this value if you know what your
415
  databases character set should be.</td>
416
  </tr>
417
  <tr>
418
+ <td class="col-opt">Collation</td>
419
  <td>When the database is populated from the SQL script it will use this value as part of its connection. Only change this value if you know what your
420
  databases collation set should be.</td>
421
  </tr>
428
 
429
  <table class="help-opt">
430
  <tr>
431
+ <th class="col-opt">Option</th>
432
  <th>Details</th>
433
  </tr>
434
  <tr>
435
+ <td class="col-opt">Test<br/>Database</td>
436
  <td>
437
  The 'Test Database' button will help validate if the connection parameters are correct for this server and help with details about any issues
438
  that may arise.
439
  </td>
440
  </tr>
441
  <tr>
442
+ <td class="col-opt">Troubleshoot</td>
443
  <td>
444
  <b>Common Database Connection Issues:</b><br/>
445
  - Double check case sensitive values 'User', 'Password' &amp; the 'Database Name' <br/>
484
  <h3>Options</h3>
485
  <table class="help-opt">
486
  <tr>
487
+ <th class="col-opt">Option</th>
488
  <th>Details</th>
489
  </tr>
490
  <tr>
491
  <td colspan="2" class="section">New Admin Account</td>
492
  </tr>
493
  <tr>
494
+ <td class="col-opt">Username</td>
495
  <td>A new WordPress username to create. This will create a new WordPress administrator account. Please note that usernames are not changeable from the within the UI.</td>
496
  </tr>
497
  <tr>
498
+ <td class="col-opt">Password</td>
499
  <td>The new password for the new user. Must be at least 6 characters long.</td>
500
  </tr>
501
  <tr>
502
  <td colspan="2" class="section">Scan Options</td>
503
  </tr>
504
  <tr>
505
+ <td class="col-opt">Cleanup <sup>pro</sup></td>
506
  <td>The checkbox labeled Remove schedules &amp; storage endpoints will empty the Duplicator schedule and storage settings. This is recommended to keep enabled so that you do not have unwanted schedules and storage options enabled.</td>
507
  </tr>
508
  <tr>
509
+ <td class="col-opt">Old URL</td>
510
  <td>The old URL of the original values that the package was created with. These values should not be changed, unless you know the underlying reasons</td>
511
  </tr>
512
  <tr>
513
+ <td class="col-opt">Old Path</td>
514
  <td>The old path of the original values that the package was created with. These values should not be changed, unless you know the underlying reasons</td>
515
  </tr>
516
  <tr>
517
+ <td class="col-opt">Site URL</td>
518
  <td> For details see WordPress <a href="http://codex.wordpress.org/Changing_The_Site_URL" target="_blank">Site URL</a> &amp; <a href="http://codex.wordpress.org/Giving_WordPress_Its_Own_Directory" target="_blank">Alternate Directory</a>. If you're not sure about this value then leave it the same as the new settings URL.</td>
519
  </tr>
520
  <tr>
521
+ <td class="col-opt">Scan Tables</td>
522
  <td>Select the tables to be updated. This process will update all of the 'Old Settings' with the 'New Settings'. Hold down the 'ctrl key' to select/deselect multiple.</td>
523
  </tr>
524
  <tr>
525
+ <td class="col-opt">Activate Plugins</td>
526
  <td>These plug-ins are the plug-ins that were activated when the package was created and represent the plug-ins that will be activated after the install.</td>
527
  </tr>
528
  <tr>
529
+ <td class="col-opt">Update email domains</td>
530
  <td>The domain portion of all email addresses will be updated if this option is enabled.</td>
531
  </tr>
532
  <tr>
533
+ <td class="col-opt">Full Search</td>
534
  <td>Full search forces a scan of every single cell in the database. If it is not checked then only text based columns are searched which makes the update process much faster.
535
  Use this option if you have issues with data not updating correctly.</td>
536
  </tr>
537
  <tr>
538
+ <td class="col-opt">Post GUID</td>
539
  <td>If your moving a site keep this value checked. For more details see the <a href="http://codex.wordpress.org/Changing_The_Site_URL#Important_GUID_Note" target="_blank">notes on GUIDS</a>. Changing values in the posts table GUID column can change RSS readers to evaluate that the posts are new and may show them in feeds again.</td>
540
  </tr>
541
  <tr>
542
+ <td class="col-opt">Cross search <sup>pro</sup></td>
543
  <td>
544
  This option enables the searching and replacing of subsite domains and paths that link to each other. <br>
545
  Check this option if hyperlinks of at least one subsite point to another subsite.<br>
546
  Uncheck this option there if there are at least <?php echo MAX_SITES_TO_DEFAULT_ENABLE_CORSS_SEARCH ?> subsites and no subsites hyperlinking to each other (Checking this option in this scenario would unnecessarily load your server).<br><br>
547
  Check this option If you unsure if you need this option.<br></td>
548
  </tr>
549
+ <tr>
550
+ <td class="col-opt"> Max size check for serialize objects</td>
551
+ <td>
552
+ Large serialized objects can cause a fatal error when Duplicator attempts to transform them. <br>
553
+ If a fatal error is generated, lower this limit. <br>
554
+ If a warning of this type appears in the final report <br>
555
+ <pre style="white-space: pre-line;">
556
+ DATA-REPLACE ERROR: Serialization
557
+ ENGINE: serialize data too big to convert; data len: XXX Max size: YYY
558
+ DATA: .....
559
+ </pre>
560
+ And you think that the serialized object is necessary you can increase the limit or <b>set it to 0 to have no limit</b>.
561
+ </td>
562
+ </tr>
563
  <tr>
564
  <td colspan="2" class="section">WP-Config File</td>
565
  </tr>
566
  <tr>
567
+ <td class="col-opt">Config SSL</td>
568
  <td>Turn off SSL support for WordPress. This sets FORCE_SSL_ADMIN in your wp-config file to false if true, otherwise it will create the setting if not set. The "Enforce on Login"
569
  will turn off SSL support for WordPress Logins.</td>
570
  </tr>
571
  <tr>
572
+ <td class="col-opt">Config Cache</td>
573
  <td>Turn off Cache support for WordPress. This sets WP_CACHE in your wp-config file to false if true, otherwise it will create the setting if not set. The "Keep Home Path"
574
  sets WPCACHEHOME in your wp-config file to nothing if true, otherwise nothing is changed.</td>
575
  </tr>
installer/dup-installer/views/view.s1.base.php CHANGED
@@ -658,9 +658,10 @@ OPTIONS
658
  <tr>
659
  <td>Logging:</td>
660
  <td>
661
- <input type="radio" name="logging" id="logging-light" value="1" checked="true"> <label for="logging-light" class="radio">Light</label> &nbsp;
662
- <input type="radio" name="logging" id="logging-detailed" value="2"> <label for="logging-detailed" class="radio">Detailed</label> &nbsp;
663
- <input type="radio" name="logging" id="logging-debug" value="3"> <label for="logging-debug" class="radio">Debug</label>
 
664
  </td>
665
  </tr>
666
  <?php if(!$archive_config->isZipArchive()): ?>
658
  <tr>
659
  <td>Logging:</td>
660
  <td>
661
+ <input type="radio" name="logging" id="logging-light" value="<?php echo DUPX_Log::LV_DEFAULT; ?>" checked="true"> <label for="logging-light" class="radio">Light</label> &nbsp;
662
+ <input type="radio" name="logging" id="logging-detailed" value="<?php echo DUPX_Log::LV_DETAILED; ?>"> <label for="logging-detailed" class="radio">Detailed</label> &nbsp;
663
+ <input type="radio" name="logging" id="logging-debug" value="<?php echo DUPX_Log::LV_DEBUG; ?>"> <label for="logging-debug" class="radio">Debug</label> &nbsp;
664
+ <input type="radio" name="logging" id="logging-h-debug" value="<?php echo DUPX_Log::LV_HARD_DEBUG; ?>"> <label for="logging-h-debug" class="radio">Hard debug</label>
665
  </td>
666
  </tr>
667
  <?php if(!$archive_config->isZipArchive()): ?>
installer/dup-installer/views/view.s3.php CHANGED
@@ -281,6 +281,14 @@ VIEW: STEP 3- INPUT -->
281
  <input type="checkbox" name="search_replace_email_domain" id="search_replace_email_domain" value="1" /> <label for="search_replace_email_domain">Update email domains</label><br/>
282
  <input type="checkbox" name="fullsearch" id="fullsearch" value="1" /> <label for="fullsearch">Use Database Full Search Mode</label><br/>
283
  <input type="checkbox" name="postguid" id="postguid" value="1" /> <label for="postguid">Keep Post GUID Unchanged</label><br/>
 
 
 
 
 
 
 
 
284
  <br/><br/>
285
  </div>
286
 
@@ -594,6 +602,8 @@ DUPX.hideErrorResult2 = function()
594
  //DOCUMENT LOAD
595
  $(document).ready(function()
596
  {
 
 
597
  $("#tabs").tabs();
598
  DUPX.getNewURL('url_new');
599
  DUPX.getNewURL('siteurl');
281
  <input type="checkbox" name="search_replace_email_domain" id="search_replace_email_domain" value="1" /> <label for="search_replace_email_domain">Update email domains</label><br/>
282
  <input type="checkbox" name="fullsearch" id="fullsearch" value="1" /> <label for="fullsearch">Use Database Full Search Mode</label><br/>
283
  <input type="checkbox" name="postguid" id="postguid" value="1" /> <label for="postguid">Keep Post GUID Unchanged</label><br/>
284
+ <label>
285
+ <B>Max size check for serialize objects:</b>
286
+ <input type="number"
287
+ name="<?php echo DUPX_CTRL::NAME_MAX_SERIALIZE_STRLEN_IN_M; ?>"
288
+ value="<?php echo DUPX_Constants::DEFAULT_MAX_STRLEN_SERIALIZED_CHECK_IN_M; ?>"
289
+ min="0" max="99" step="1" size="2"
290
+ style="width: 40px;width: 50px; text-align: center;" /> MB
291
+ </label>
292
  <br/><br/>
293
  </div>
294
 
602
  //DOCUMENT LOAD
603
  $(document).ready(function()
604
  {
605
+ $('#wp_username').val('');
606
+ $('#wp_password').val('');
607
  $("#tabs").tabs();
608
  DUPX.getNewURL('url_new');
609
  DUPX.getNewURL('siteurl');
installer/dup-installer/views/view.s4.php CHANGED
@@ -285,6 +285,7 @@ LONGMSG;
285
  }
286
 
287
  $nManager->sortFinalReport();
 
288
  ?>
289
 
290
  <div class="s4-go-back">
285
  }
286
 
287
  $nManager->sortFinalReport();
288
+ $nManager->finalReportLog(array('general','files','database','search_replace'));
289
  ?>
290
 
291
  <div class="s4-go-back">
installer/installer.tpl CHANGED
@@ -1,9 +1,13 @@
1
  <?php
 
2
 
3
- if ( !defined('DUPXABSPATH') ) {
4
- define('DUPXABSPATH', dirname(__FILE__));
5
- }
6
 
 
 
 
 
7
  if (!defined('KB_IN_BYTES')) { define('KB_IN_BYTES', 1024); }
8
  if (!defined('MB_IN_BYTES')) { define('MB_IN_BYTES', 1024 * KB_IN_BYTES); }
9
  if (!defined('GB_IN_BYTES')) { define('GB_IN_BYTES', 1024 * MB_IN_BYTES); }
@@ -25,7 +29,6 @@ if (!function_exists('wp_is_ini_value_changeable')) {
25
  */
26
  function wp_is_ini_value_changeable( $setting ) {
27
  static $ini_all;
28
-
29
  if ( ! isset( $ini_all ) ) {
30
  $ini_all = false;
31
  // Sometimes `ini_get_all()` is disabled via the `disable_functions` option for "security purposes".
@@ -57,132 +60,8 @@ if (wp_is_ini_value_changeable('pcre.backtrack_limit'))
57
  @ini_set('pcre.backtrack_limit', PHP_INT_MAX);
58
  if (wp_is_ini_value_changeable('default_socket_timeout'))
59
  @ini_set('default_socket_timeout', 3600);
60
-
61
- class DUPX_CSRF {
62
-
63
- /** Session var name
64
- * @var string
65
- */
66
- public static $prefix = '_DUPX_CSRF';
67
- private static $CSRFVars;
68
-
69
- public static function setKeyVal($key, $val) {
70
- $CSRFVars = self::getCSRFVars();
71
- $CSRFVars[$key] = $val;
72
- self::saveCSRFVars($CSRFVars);
73
- self::$CSRFVars = false;
74
- }
75
-
76
- public static function getVal($key) {
77
- $CSRFVars = self::getCSRFVars();
78
- if (isset($CSRFVars[$key])) {
79
- return $CSRFVars[$key];
80
- } else {
81
- return false;
82
- }
83
-
84
- }
85
-
86
- /** Generate DUPX_CSRF value for form
87
- * @param string $form - Form name as session key
88
- * @return string - token
89
- */
90
- public static function generate($form = NULL) {
91
- $keyName = self::getKeyName($form);
92
-
93
- $existingToken = self::getVal($keyName);
94
- if (false !== $existingToken) {
95
- $token = $existingToken;
96
- } else {
97
- $token = DUPX_CSRF::token() . DUPX_CSRF::fingerprint();
98
- }
99
-
100
- self::setKeyVal($keyName, $token);
101
- return $token;
102
- }
103
-
104
- /** Check DUPX_CSRF value of form
105
- * @param string $token - Token
106
- * @param string $form - Form name as session key
107
- * @return boolean
108
- */
109
- public static function check($token, $form = NULL) {
110
- $keyName = self::getKeyName($form);
111
- $CSRFVars = self::getCSRFVars();
112
- if (isset($CSRFVars[$keyName]) && $CSRFVars[$keyName] == $token) { // token OK
113
- return true;
114
- }
115
- return FALSE;
116
- }
117
-
118
- /** Generate token
119
- * @param void
120
- * @return string
121
- */
122
- protected static function token() {
123
- mt_srand((double) microtime() * 10000);
124
- $charid = strtoupper(md5(uniqid(rand(), TRUE)));
125
- return substr($charid, 0, 8) . substr($charid, 8, 4) . substr($charid, 12, 4) . substr($charid, 16, 4) . substr($charid, 20, 12);
126
- }
127
-
128
- /** Returns "digital fingerprint" of user
129
- * @param void
130
- * @return string - MD5 hashed data
131
- */
132
- protected static function fingerprint() {
133
- return strtoupper(md5(implode('|', array($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']))));
134
- }
135
-
136
- private static function getKeyName($form) {
137
- return DUPX_CSRF::$prefix . '_' . $form;
138
- }
139
-
140
- private static function getPackageHash() {
141
- if (class_exists('DUPX_Bootstrap')) {
142
- return DUPX_Bootstrap::PACKAGE_HASH;
143
- } else {
144
- return $GLOBALS['DUPX_AC']->package_hash;
145
- }
146
- }
147
-
148
- private static function getFilePath() {
149
- if (class_exists('DUPX_Bootstrap')) {
150
- $dupInstallerfolderPath = dirname(__FILE__).'/dup-installer/';
151
- } else {
152
- $dupInstallerfolderPath = $GLOBALS['DUPX_INIT'].'/';
153
- }
154
- $packageHash = self::getPackageHash();
155
- $fileName = 'dup-installer-csrf__'.$packageHash.'.txt';
156
- $filePath = $dupInstallerfolderPath.$fileName;
157
- return $filePath;
158
- }
159
-
160
- private static function getCSRFVars() {
161
- if (!isset(self::$CSRFVars) || false === self::$CSRFVars) {
162
- $filePath = self::getFilePath();
163
- if (file_exists($filePath)) {
164
- $contents = file_get_contents($filePath);
165
- if (empty($contents)) {
166
- self::$CSRFVars = array();
167
- } else {
168
- $CSRFobjs = json_decode($contents);
169
- foreach ($CSRFobjs as $key => $value) {
170
- self::$CSRFVars[$key] = $value;
171
- }
172
- }
173
- } else {
174
- self::$CSRFVars = array();
175
- }
176
- }
177
- return self::$CSRFVars;
178
- }
179
-
180
- private static function saveCSRFVars($CSRFVars) {
181
- $contents = json_encode($CSRFVars);
182
- $filePath = self::getFilePath();
183
- file_put_contents($filePath, $contents);
184
- }
185
- }
186
 
187
  /**
188
  * Bootstrap utility to exatract the core installer
@@ -197,6 +76,8 @@ class DUPX_CSRF {
197
  * installer.php?unzipmode=ziparchive
198
  * installer.php?unzipmode=shellexec
199
  */
 
 
200
 
201
  abstract class DUPX_Bootstrap_Zip_Mode
202
  {
@@ -205,13 +86,6 @@ abstract class DUPX_Bootstrap_Zip_Mode
205
  const ShellExec = 2;
206
  }
207
 
208
- abstract class DUPX_Connectivity
209
- {
210
- const OK = 0;
211
- const Error = 1;
212
- const Unknown = 2;
213
- }
214
-
215
  class DUPX_Bootstrap
216
  {
217
  //@@ Params get dynamically swapped when package is built
@@ -237,6 +111,9 @@ class DUPX_Bootstrap
237
  */
238
  public function __construct()
239
  {
 
 
 
240
  //ARCHIVE_SIZE will be blank with a root filter so we can estimate
241
  //the default size of the package around 17.5MB (18088000)
242
  $archiveActualSize = @filesize(self::ARCHIVE_FILENAME);
@@ -266,7 +143,7 @@ class DUPX_Bootstrap
266
  public function run()
267
  {
268
  date_default_timezone_set('UTC'); // Some machines don't have this set so just do it here
269
- @unlink('./dup-installer-bootlog__'.self::PACKAGE_HASH.'.txt');
270
  self::log('==DUPLICATOR INSTALLER BOOTSTRAP v@@VERSION@@==');
271
  self::log('----------------------------------------------------');
272
  self::log('Installer bootstrap start');
@@ -298,7 +175,7 @@ class DUPX_Bootstrap
298
 
299
  //MISSING ARCHIVE FILE
300
  if (! file_exists($archive_filepath)) {
301
- self::log("ERROR: Archive file not found!");
302
  $archive_candidates = ($isZip) ? $this->getFilesWithExtension('zip') : $this->getFilesWithExtension('daf');
303
  $candidate_count = count($archive_candidates);
304
  $candidate_html = "- No {$archive_extension} files found -";
@@ -306,12 +183,17 @@ class DUPX_Bootstrap
306
  if ($candidate_count >= 1) {
307
  $candidate_html = "<ol>";
308
  foreach($archive_candidates as $archive_candidate) {
309
- $candidate_html .= "<li> {$archive_candidate}</li>";
 
310
  }
311
  $candidate_html .= "</ol>";
312
  }
313
 
314
- $error = "<b>Archive not found!</b> The <i>'Required File'</i> below should be present in the <i>'Extraction Path'</i>. "
 
 
 
 
315
  . "The archive file name must be the <u>exact</u> name of the archive file placed in the extraction path character for character.<br/><br/> "
316
  . "If the file does not have the correct name then rename it to the <i>'Required File'</i> below. When downloading the package files make "
317
  . "sure both files are from the same package line in the packages view. If the archive is not finished downloading please wait for it to complete.<br/><br/>"
@@ -324,33 +206,34 @@ class DUPX_Bootstrap
324
  return $error;
325
  }
326
 
327
- if (!filter_var(self::ARCHIVE_SIZE, FILTER_VALIDATE_INT) || self::ARCHIVE_SIZE > 2147483647) {
328
-
329
- $os_first_three_chars = substr(PHP_OS, 0, 3);
330
- $os_first_three_chars = strtoupper($os_first_three_chars);
331
  $no_of_bits = PHP_INT_SIZE * 8;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
 
333
- if ($no_of_bits == 32) {
334
- if ($isZip) { // ZIP
335
- if ('WIN' === $os_first_three_chars) {
336
- $error = "This package is currently {$archiveExpectedEasy} and it's on a Windows OS. PHP on Windows does not support files larger than 2GB. Please use the file filters to get your package lower to support this server or try the package on a Linux server.";
337
- return $error;
338
- }
339
- } else { // DAF
340
- if ('WIN' === $os_first_three_chars) {
341
- $error = 'Windows PHP limitations prevents extraction of archives larger than 2GB. Please do the following: <ol><li>Download and use the <a target="_blank" href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-052-q">Windows DupArchive extractor</a> to extract all files from the archive.</li><li>Perform a <a target="_blank" href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q">Manual Extract Install</a> starting at step 4.</li></ol>';
342
- } else {
343
- $error = 'This archive is too large for 32-bit PHP. Ask your host to upgrade the server to 64-bit PHP or install on another system has 64-bit PHP.';
344
- }
345
- return $error;
346
- }
347
- }
348
  }
349
 
350
  //SIZE CHECK ERROR
351
  if (($this->archiveRatio < 90) && ($this->archiveActualSize > 0) && ($this->archiveExpectedSize > 0)) {
352
  $this->log("ERROR: The expected archive size should be around [{$archiveExpectedEasy}]. The actual size is currently [{$archiveActualEasy}].");
353
- $this->log("The archive file may not have fully been downloaded to the server");
354
  $percent = round($this->archiveRatio);
355
 
356
  $autochecked = isset($_POST['auto-fresh']) ? "checked='true'" : '';
@@ -373,20 +256,18 @@ class DUPX_Bootstrap
373
  if ($manual_extract_found) {
374
  // INSTALL DIRECTORY: Check if its setup correctly AND we are not in overwrite mode
375
  if (isset($_GET['force-extract-installer']) && ('1' == $_GET['force-extract-installer'] || 'enable' == $_GET['force-extract-installer'] || 'false' == $_GET['force-extract-installer'])) {
376
-
377
  self::log("Manual extract found with force extract installer get parametr");
378
  $extract_installer = true;
379
-
380
  } else {
381
  $extract_installer = false;
382
  self::log("Manual extract found so not going to extract dup-installer dir");
383
  }
384
  } else {
385
  $extract_installer = true;
386
- self::log("Manual extract didn't found so going to extract dup-installer dir");
387
  }
388
 
389
  if ($extract_installer && file_exists($installer_directory)) {
 
390
  $scanned_directory = array_diff(scandir($installer_directory), array('..', '.'));
391
  foreach ($scanned_directory as $object) {
392
  $object_file_path = $installer_directory.'/'.$object;
@@ -394,7 +275,7 @@ class DUPX_Bootstrap
394
  if (unlink($object_file_path)) {
395
  self::log('Successfully deleted the file '.$object_file_path);
396
  } else {
397
- $error .= 'Error deleting the file '.$object_file_path.' Please manually delete it and try again.';
398
  self::log($error);
399
  }
400
  }
@@ -410,20 +291,20 @@ class DUPX_Bootstrap
410
  $destination = dirname(__FILE__);
411
  if (!is_writable($destination)) {
412
  self::log("destination folder for extraction is not writable");
413
- if (@chmod($destination, 0755)) {
414
- self::log("Permission of destination folder changed to 0755");
415
  } else {
416
- self::log("Permission of destination folder failed to change to 0755");
417
  }
418
  }
419
 
420
  if (!is_writable($destination)) {
 
421
  $error = "NOTICE: The {$destination} directory is not writable on this server please talk to your host or server admin about making ";
422
  $error .= "<a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-055-q'>writable {$destination} directory</a> on this server. <br/>";
423
  return $error;
424
  }
425
 
426
-
427
  if ($isZip) {
428
  $zip_mode = $this->getZipMode();
429
 
@@ -436,11 +317,11 @@ class DUPX_Bootstrap
436
  self::log('Successfully extracted with ZipArchive');
437
  } else {
438
  if (0 == $this->installer_files_found) {
439
- $error = "This archive is not properly formatted and does not contain a dup-installer directory. Please make sure you are attempting to install the original archive and not one that has been reconstructed.";
440
  self::log($error);
441
  return $error;
442
  } else {
443
- $error = 'Error extracting with ZipArchive. ';
444
  self::log($error);
445
  }
446
  }
@@ -460,7 +341,7 @@ class DUPX_Bootstrap
460
  self::log('Successfully extracted with Shell Exec');
461
  $error = null;
462
  } else {
463
- $error .= 'Error extracting with Shell Exec. Please manually extract archive then choose Advanced > Manual Extract in installer.';
464
  self::log($error);
465
  }
466
  } else {
@@ -475,6 +356,7 @@ class DUPX_Bootstrap
475
  if (!$extract_success && $zip_mode == DUPX_Bootstrap_Zip_Mode::AutoUnzip) {
476
  $unzip_filepath = $this->getUnzipFilePath();
477
  if (!class_exists('ZipArchive') && empty($unzip_filepath)) {
 
478
  $error = "NOTICE: ZipArchive and Shell Exec are not enabled on this server please talk to your host or server admin about enabling ";
479
  $error .= "<a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-060-q'>ZipArchive</a> or <a target='_blank' href='http://php.net/manual/en/function.shell-exec.php'>Shell Exec</a> on this server or manually extract archive then choose Advanced > Manual Extract in installer.";
480
  }
@@ -484,7 +366,7 @@ class DUPX_Bootstrap
484
  try {
485
  DupArchiveMiniExpander::expandDirectory($archive_filepath, self::INSTALLER_DIR_NAME, dirname(__FILE__));
486
  } catch (Exception $ex) {
487
- self::log("Error expanding installer subdirectory:".$ex->getMessage());
488
  throw $ex;
489
  }
490
  }
@@ -553,10 +435,10 @@ class DUPX_Bootstrap
553
  }
554
  } else {
555
  self::log("No need to create dup-installer/.htaccess or dup-installer/.user.ini");
556
- self::log("SAPI: Unrecognized");
557
  }
558
  } else {
559
- self::log("Didn't need to extract the installer.");
560
  }
561
 
562
  if (empty($error)) {
@@ -583,9 +465,13 @@ class DUPX_Bootstrap
583
  $server_port = $_SERVER['SERVER_PORT'];
584
  }
585
 
586
-
587
- //$current_url .= $_SERVER['HTTP_HOST'];//WAS SERVER_NAME and caused problems on some boxes
588
- $current_url .= isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];//WAS SERVER_NAME and caused problems on some boxes
 
 
 
 
589
  if(strpos($current_url,':') === false) {
590
  $current_url = $current_url.':'.$server_port;
591
  }
@@ -612,7 +498,7 @@ class DUPX_Bootstrap
612
  $this->mainInstallerURL .= '?'.$_SERVER['QUERY_STRING'];
613
  }
614
 
615
- self::log("No detected errors so redirecting to the main installer. Main Installer URI = {$this->mainInstallerURL}");
616
  }
617
  }
618
 
@@ -639,7 +525,7 @@ class DUPX_Bootstrap
639
  }
640
  }
641
  }
642
-
643
  /**
644
  * Indicates if site is running https or not
645
  *
@@ -665,13 +551,9 @@ class DUPX_Bootstrap
665
  */
666
  private function fixInstallerPerms()
667
  {
668
- $file_perms = substr(sprintf('%o', fileperms(__FILE__)), -4);
669
- $file_perms = octdec($file_perms);
670
- //$dir_perms = substr(sprintf('%o', fileperms(dirname(__FILE__))), -4);
671
 
672
- // No longer using existing directory permissions since that can cause problems. Just set it to 755
673
- $dir_perms = '755';
674
- $dir_perms = octdec($dir_perms);
675
  $installer_dir_path = $this->installerContentsPath;
676
 
677
  $this->setPerms($installer_dir_path, $dir_perms, false);
@@ -682,7 +564,7 @@ class DUPX_Bootstrap
682
  * Set the permissions of a given directory and optionally all files
683
  *
684
  * @param string $directory The full path to the directory where perms will be set
685
- * @param string $perms The given permission sets to use such as '0755'
686
  * @param string $do_files Also set the permissions of all the files in the directory
687
  *
688
  * @return null
@@ -708,34 +590,41 @@ class DUPX_Bootstrap
708
  * Set the permissions of a single directory or file
709
  *
710
  * @param string $path The full path to the directory or file where perms will be set
711
- * @param string $perms The given permission sets to use such as '0755'
712
  *
713
  * @return bool Returns true if the permission was properly set
714
  */
715
  private function setPermsOnItem($path, $perms)
716
  {
717
- $result = @chmod($path, $perms);
718
  $perms_display = decoct($perms);
719
  if ($result === false) {
720
- self::log("Couldn't set permissions of $path to {$perms_display}<br/>");
721
  } else {
722
  self::log("Set permissions of $path to {$perms_display}<br/>");
723
  }
724
  return $result;
725
  }
726
 
727
-
728
- /**
729
  * Logs a string to the dup-installer-bootlog__[HASH].txt file
730
  *
731
  * @param string $s The string to log to the log file
732
  *
733
- * @return null
734
  */
735
- public static function log($s)
736
  {
737
- $timestamp = date('M j H:i:s');
738
- file_put_contents('./dup-installer-bootlog__'.self::PACKAGE_HASH.'.txt', "$timestamp $s\n", FILE_APPEND);
 
 
 
 
 
 
 
739
  }
740
 
741
  /**
@@ -751,7 +640,7 @@ class DUPX_Bootstrap
751
  $zipArchive = new ZipArchive();
752
  $subFolderArchiveList = array();
753
 
754
- if ($zipArchive->open($archive_filepath) === true) {
755
  self::log("Successfully opened $archive_filepath");
756
  $destination = dirname(__FILE__);
757
  $folder_prefix = self::INSTALLER_DIR_NAME.'/';
@@ -790,7 +679,7 @@ class DUPX_Bootstrap
790
  if ($zipArchive->extractTo($destination, $filename) === true) {
791
  self::log("Success: {$filename} >>> {$destination}");
792
  } else {
793
- self::log("Error extracting {$filename} from archive archive file");
794
  $success = false;
795
  break;
796
  }
@@ -824,7 +713,7 @@ class DUPX_Bootstrap
824
  if ($zipArchive->extractTo($destination, $filename) === true) {
825
  self::log("Success: {$filename} >>> {$destination}");
826
  } else {
827
- self::log("Error extracting {$filename} from archive archive file");
828
  $success = false;
829
  break;
830
  }
@@ -836,27 +725,227 @@ class DUPX_Bootstrap
836
  if ($zipArchive->close() === true) {
837
  self::log("Successfully closed archive file");
838
  } else {
839
- self::log("Problem closing archive file");
840
  $success = false;
841
  }
842
 
843
  if ($success != false && $this->installer_files_found < 10) {
844
  if ($checkSubFolder) {
845
- self::log("Couldn't find the installer directory in the archive!");
846
  $success = false;
847
  } else {
848
- self::log("Couldn't find the installer directory in archive root! Check subfolder");
849
  $this->extractInstallerZipArchive($archive_filepath, true);
850
  }
851
  }
852
  } else {
853
- self::log("Couldn't open archive archive file with ZipArchive");
854
  $success = false;
855
  }
856
 
857
  return $success;
858
  }
859
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
860
  /**
861
  * move all folder content up to parent
862
  *
@@ -878,7 +967,7 @@ class DUPX_Bootstrap
878
 
879
  $success = true;
880
  if (($subList = glob(rtrim($subFolderName, '/').'/*', GLOB_NOSORT)) === false) {
881
- self::log("Problem glob folder ".$subFolderName);
882
  return false;
883
  } else {
884
  foreach ($subList as $cName) {
@@ -900,7 +989,7 @@ class DUPX_Bootstrap
900
  }
901
 
902
  if (!$success) {
903
- self::log("Problem om moveUpfromSubFolder subFolder:".$subFolderName);
904
  }
905
 
906
  return $success;
@@ -934,7 +1023,7 @@ class DUPX_Bootstrap
934
  $unzip_command = "$unzip_filepath -q $archive_filepath snaplib/* 2>&1";
935
  self::log("Executing $unzip_command");
936
  $stderr .= shell_exec($unzip_command);
937
- mkdir($lib_directory);
938
  rename($local_lib_directory, $snaplib_directory);
939
  }
940
 
@@ -942,7 +1031,7 @@ class DUPX_Bootstrap
942
  self::log("Shell exec unzip succeeded");
943
  $success = true;
944
  } else {
945
- self::log("Shell exec unzip failed. Output={$stderr}");
946
  }
947
  }
948
 
@@ -1144,12 +1233,12 @@ class DUPX_Bootstrap
1144
  } else {
1145
  $success = @unlink($fullPath);
1146
  if ($success === false) {
1147
- self::log( __FUNCTION__.": Problem deleting file:".$fullPath);
1148
  }
1149
  }
1150
 
1151
  if ($success === false) {
1152
- self::log("Problem deleting dir:".$directory);
1153
  break;
1154
  }
1155
  }
@@ -1174,7 +1263,7 @@ class DUPX_Bootstrap
1174
  $success = @unlink($path);
1175
 
1176
  if ($success === false) {
1177
- self::log( __FUNCTION__.": Problem deleting file:".$path);
1178
  }
1179
  }
1180
 
@@ -1198,6 +1287,696 @@ class DUPX_Bootstrap
1198
  }
1199
  }
1200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1201
  try {
1202
  $boot = new DUPX_Bootstrap();
1203
  $boot_error = $boot->run();
1
  <?php
2
+ /* ------------------------------ NOTICE ----------------------------------
3
 
4
+ If you're seeing this text when browsing to the installer, it means your
5
+ web server is not set up properly.
 
6
 
7
+ Please contact your host and ask them to enable "PHP" processing on your
8
+ account.
9
+ ----------------------------- NOTICE ---------------------------------*/
10
+
11
  if (!defined('KB_IN_BYTES')) { define('KB_IN_BYTES', 1024); }
12
  if (!defined('MB_IN_BYTES')) { define('MB_IN_BYTES', 1024 * KB_IN_BYTES); }
13
  if (!defined('GB_IN_BYTES')) { define('GB_IN_BYTES', 1024 * MB_IN_BYTES); }
29
  */
30
  function wp_is_ini_value_changeable( $setting ) {
31
  static $ini_all;
 
32
  if ( ! isset( $ini_all ) ) {
33
  $ini_all = false;
34
  // Sometimes `ini_get_all()` is disabled via the `disable_functions` option for "security purposes".
60
  @ini_set('pcre.backtrack_limit', PHP_INT_MAX);
61
  if (wp_is_ini_value_changeable('default_socket_timeout'))
62
  @ini_set('default_socket_timeout', 3600);
63
+
64
+ DUPX_Handler::init_error_handler();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  /**
67
  * Bootstrap utility to exatract the core installer
76
  * installer.php?unzipmode=ziparchive
77
  * installer.php?unzipmode=shellexec
78
  */
79
+
80
+ /*** CLASS DEFINITION START ***/
81
 
82
  abstract class DUPX_Bootstrap_Zip_Mode
83
  {
86
  const ShellExec = 2;
87
  }
88
 
 
 
 
 
 
 
 
89
  class DUPX_Bootstrap
90
  {
91
  //@@ Params get dynamically swapped when package is built
111
  */
112
  public function __construct()
113
  {
114
+ // clean log file
115
+ self::log('', true);
116
+
117
  //ARCHIVE_SIZE will be blank with a root filter so we can estimate
118
  //the default size of the package around 17.5MB (18088000)
119
  $archiveActualSize = @filesize(self::ARCHIVE_FILENAME);
143
  public function run()
144
  {
145
  date_default_timezone_set('UTC'); // Some machines don't have this set so just do it here
146
+
147
  self::log('==DUPLICATOR INSTALLER BOOTSTRAP v@@VERSION@@==');
148
  self::log('----------------------------------------------------');
149
  self::log('Installer bootstrap start');
175
 
176
  //MISSING ARCHIVE FILE
177
  if (! file_exists($archive_filepath)) {
178
+ self::log("[ERROR] Archive file not found!");
179
  $archive_candidates = ($isZip) ? $this->getFilesWithExtension('zip') : $this->getFilesWithExtension('daf');
180
  $candidate_count = count($archive_candidates);
181
  $candidate_html = "- No {$archive_extension} files found -";
183
  if ($candidate_count >= 1) {
184
  $candidate_html = "<ol>";
185
  foreach($archive_candidates as $archive_candidate) {
186
+ $fineDiffObj = new FineDiff($archive_candidate, $archive_filename, FineDiff::$characterGranularity);
187
+ $candidate_html .= '<li class="diff-list"> '.$fineDiffObj->renderDiffToHTML().'</li>';
188
  }
189
  $candidate_html .= "</ol>";
190
  }
191
 
192
+ $error = "<style>
193
+ .diff-list del { color: red; background: #fdd; text-decoration: none; }
194
+ .diff-list ins { color: green; background: #dfd; text-decoration: none; }
195
+ </style>
196
+ <b>Archive not found!</b> The <i>'Required File'</i> below should be present in the <i>'Extraction Path'</i>. "
197
  . "The archive file name must be the <u>exact</u> name of the archive file placed in the extraction path character for character.<br/><br/> "
198
  . "If the file does not have the correct name then rename it to the <i>'Required File'</i> below. When downloading the package files make "
199
  . "sure both files are from the same package line in the packages view. If the archive is not finished downloading please wait for it to complete.<br/><br/>"
206
  return $error;
207
  }
208
 
209
+ if (!self::checkInputVaslidInt(self::ARCHIVE_SIZE)) {
 
 
 
210
  $no_of_bits = PHP_INT_SIZE * 8;
211
+ $error = 'Current is a '.$no_of_bits.'-bit SO. This archive is too large for '.$no_of_bits.'-bit PHP.'.'<br>';
212
+ $this->log('[ERROR] '.$error);
213
+ $error .= 'Possibibles solutions:<br>';
214
+ $error .= '- Use the file filters to get your package lower to support this server or try the package on a Linux server.'.'<br>';
215
+ $error .= '- Perform a <a target="_blank" href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q">Manual Extract Install</a>'.'<br>';
216
+
217
+ switch ($no_of_bits == 32) {
218
+ case 32:
219
+ $error .= '- Ask your host to upgrade the server to 64-bit PHP or install on another system has 64-bit PHP'.'<br>';
220
+ break;
221
+ case 64:
222
+ $error .= '- Ask your host to upgrade the server to 128-bit PHP or install on another system has 128-bit PHP'.'<br>';
223
+ break;
224
+ }
225
 
226
+ if (self::isWindows()) {
227
+ $error .= '- <a target="_blank" href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-052-q">Windows DupArchive extractor</a> to extract all files from the archive.'.'<br>';
228
+ }
229
+
230
+ return $error;
 
 
 
 
 
 
 
 
 
 
231
  }
232
 
233
  //SIZE CHECK ERROR
234
  if (($this->archiveRatio < 90) && ($this->archiveActualSize > 0) && ($this->archiveExpectedSize > 0)) {
235
  $this->log("ERROR: The expected archive size should be around [{$archiveExpectedEasy}]. The actual size is currently [{$archiveActualEasy}].");
236
+ $this->log("ERROR: The archive file may not have fully been downloaded to the server");
237
  $percent = round($this->archiveRatio);
238
 
239
  $autochecked = isset($_POST['auto-fresh']) ? "checked='true'" : '';
256
  if ($manual_extract_found) {
257
  // INSTALL DIRECTORY: Check if its setup correctly AND we are not in overwrite mode
258
  if (isset($_GET['force-extract-installer']) && ('1' == $_GET['force-extract-installer'] || 'enable' == $_GET['force-extract-installer'] || 'false' == $_GET['force-extract-installer'])) {
 
259
  self::log("Manual extract found with force extract installer get parametr");
260
  $extract_installer = true;
 
261
  } else {
262
  $extract_installer = false;
263
  self::log("Manual extract found so not going to extract dup-installer dir");
264
  }
265
  } else {
266
  $extract_installer = true;
 
267
  }
268
 
269
  if ($extract_installer && file_exists($installer_directory)) {
270
+ self::log("EXTRACT dup-installer dir");
271
  $scanned_directory = array_diff(scandir($installer_directory), array('..', '.'));
272
  foreach ($scanned_directory as $object) {
273
  $object_file_path = $installer_directory.'/'.$object;
275
  if (unlink($object_file_path)) {
276
  self::log('Successfully deleted the file '.$object_file_path);
277
  } else {
278
+ $error .= '[ERROR] Error deleting the file '.$object_file_path.' Please manually delete it and try again.';
279
  self::log($error);
280
  }
281
  }
291
  $destination = dirname(__FILE__);
292
  if (!is_writable($destination)) {
293
  self::log("destination folder for extraction is not writable");
294
+ if (self::chmod($destination, 'u+rwx')) {
295
+ self::log("Permission of destination folder changed to u+rwx");
296
  } else {
297
+ self::log("[ERROR] Permission of destination folder failed to change to u+rwx");
298
  }
299
  }
300
 
301
  if (!is_writable($destination)) {
302
+ self::log("WARNING: The {$destination} directory is not writable.");
303
  $error = "NOTICE: The {$destination} directory is not writable on this server please talk to your host or server admin about making ";
304
  $error .= "<a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-055-q'>writable {$destination} directory</a> on this server. <br/>";
305
  return $error;
306
  }
307
 
 
308
  if ($isZip) {
309
  $zip_mode = $this->getZipMode();
310
 
317
  self::log('Successfully extracted with ZipArchive');
318
  } else {
319
  if (0 == $this->installer_files_found) {
320
+ $error = "[ERROR] This archive is not properly formatted and does not contain a dup-installer directory. Please make sure you are attempting to install the original archive and not one that has been reconstructed.";
321
  self::log($error);
322
  return $error;
323
  } else {
324
+ $error = '[ERROR] Error extracting with ZipArchive. ';
325
  self::log($error);
326
  }
327
  }
341
  self::log('Successfully extracted with Shell Exec');
342
  $error = null;
343
  } else {
344
+ $error .= '[ERROR] Error extracting with Shell Exec. Please manually extract archive then choose Advanced > Manual Extract in installer.';
345
  self::log($error);
346
  }
347
  } else {
356
  if (!$extract_success && $zip_mode == DUPX_Bootstrap_Zip_Mode::AutoUnzip) {
357
  $unzip_filepath = $this->getUnzipFilePath();
358
  if (!class_exists('ZipArchive') && empty($unzip_filepath)) {
359
+ self::log("WARNING: ZipArchive and Shell Exec are not enabled on this server.");
360
  $error = "NOTICE: ZipArchive and Shell Exec are not enabled on this server please talk to your host or server admin about enabling ";
361
  $error .= "<a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-060-q'>ZipArchive</a> or <a target='_blank' href='http://php.net/manual/en/function.shell-exec.php'>Shell Exec</a> on this server or manually extract archive then choose Advanced > Manual Extract in installer.";
362
  }
366
  try {
367
  DupArchiveMiniExpander::expandDirectory($archive_filepath, self::INSTALLER_DIR_NAME, dirname(__FILE__));
368
  } catch (Exception $ex) {
369
+ self::log("[ERROR] Error expanding installer subdirectory:".$ex->getMessage());
370
  throw $ex;
371
  }
372
  }
435
  }
436
  } else {
437
  self::log("No need to create dup-installer/.htaccess or dup-installer/.user.ini");
438
+ self::log("ERROR: SAPI: Unrecognized");
439
  }
440
  } else {
441
+ self::log("ERROR: Didn't need to extract the installer.");
442
  }
443
 
444
  if (empty($error)) {
465
  $server_port = $_SERVER['SERVER_PORT'];
466
  }
467
 
468
+ // for ngrok url and Local by Flywheel Live URL
469
+ if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) {
470
+ $host = $_SERVER['HTTP_X_ORIGINAL_HOST'];
471
+ } else {
472
+ $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];//WAS SERVER_NAME and caused problems on some boxes
473
+ }
474
+ $current_url .= $host;
475
  if(strpos($current_url,':') === false) {
476
  $current_url = $current_url.':'.$server_port;
477
  }
498
  $this->mainInstallerURL .= '?'.$_SERVER['QUERY_STRING'];
499
  }
500
 
501
+ self::log("DONE: No detected errors so redirecting to the main installer. Main Installer URI = {$this->mainInstallerURL}");
502
  }
503
  }
504
 
525
  }
526
  }
527
  }
528
+
529
  /**
530
  * Indicates if site is running https or not
531
  *
551
  */
552
  private function fixInstallerPerms()
553
  {
554
+ $file_perms = 'u+rw';
555
+ $dir_perms = 'u+rwx';
 
556
 
 
 
 
557
  $installer_dir_path = $this->installerContentsPath;
558
 
559
  $this->setPerms($installer_dir_path, $dir_perms, false);
564
  * Set the permissions of a given directory and optionally all files
565
  *
566
  * @param string $directory The full path to the directory where perms will be set
567
+ * @param string $perms The given permission sets to use such as '0755' or 'u+rw'
568
  * @param string $do_files Also set the permissions of all the files in the directory
569
  *
570
  * @return null
590
  * Set the permissions of a single directory or file
591
  *
592
  * @param string $path The full path to the directory or file where perms will be set
593
+ * @param string $perms The given permission sets to use such as '0755' or 'u+rw'
594
  *
595
  * @return bool Returns true if the permission was properly set
596
  */
597
  private function setPermsOnItem($path, $perms)
598
  {
599
+ $result = self::chmod($path, $perms);
600
  $perms_display = decoct($perms);
601
  if ($result === false) {
602
+ self::log("ERROR: Couldn't set permissions of $path to {$perms_display}<br/>");
603
  } else {
604
  self::log("Set permissions of $path to {$perms_display}<br/>");
605
  }
606
  return $result;
607
  }
608
 
609
+
610
+ /**
611
  * Logs a string to the dup-installer-bootlog__[HASH].txt file
612
  *
613
  * @param string $s The string to log to the log file
614
  *
615
+ * @return boog|int // This function returns the number of bytes that were written to the file, or FALSE on failure.
616
  */
617
+ public static function log($s, $deleteOld = false)
618
  {
619
+ static $logfile = null;
620
+ if (is_null($logfile)) {
621
+ $logfile = dirname(__FILE__).'/dup-installer-bootlog__'.self::PACKAGE_HASH.'.txt';
622
+ }
623
+ if ($deleteOld && file_exists($logfile)) {
624
+ @unlink($logfile);
625
+ }
626
+ $timestamp = date('M j H:i:s');
627
+ return @file_put_contents($logfile, '['.$timestamp.'] '.$s."\n", FILE_APPEND);
628
  }
629
 
630
  /**
640
  $zipArchive = new ZipArchive();
641
  $subFolderArchiveList = array();
642
 
643
+ if (($zipOpenRes = $zipArchive->open($archive_filepath)) === true) {
644
  self::log("Successfully opened $archive_filepath");
645
  $destination = dirname(__FILE__);
646
  $folder_prefix = self::INSTALLER_DIR_NAME.'/';
679
  if ($zipArchive->extractTo($destination, $filename) === true) {
680
  self::log("Success: {$filename} >>> {$destination}");
681
  } else {
682
+ self::log("[ERROR] Error extracting {$filename} from archive archive file");
683
  $success = false;
684
  break;
685
  }
713
  if ($zipArchive->extractTo($destination, $filename) === true) {
714
  self::log("Success: {$filename} >>> {$destination}");
715
  } else {
716
+ self::log("[ERROR] Error extracting {$filename} from archive archive file");
717
  $success = false;
718
  break;
719
  }
725
  if ($zipArchive->close() === true) {
726
  self::log("Successfully closed archive file");
727
  } else {
728
+ self::log("[ERROR] Problem closing archive file");
729
  $success = false;
730
  }
731
 
732
  if ($success != false && $this->installer_files_found < 10) {
733
  if ($checkSubFolder) {
734
+ self::log("[ERROR] Couldn't find the installer directory in the archive!");
735
  $success = false;
736
  } else {
737
+ self::log("[ERROR] Couldn't find the installer directory in archive root! Check subfolder");
738
  $this->extractInstallerZipArchive($archive_filepath, true);
739
  }
740
  }
741
  } else {
742
+ self::log("[ERROR] Couldn't open archive archive file with ZipArchive CODE[".$zipOpenRes."]");
743
  $success = false;
744
  }
745
 
746
  return $success;
747
  }
748
 
749
+ /**
750
+ * return true if current SO is windows
751
+ *
752
+ * @staticvar bool $isWindows
753
+ * @return bool
754
+ */
755
+ public static function isWindows()
756
+ {
757
+ static $isWindows = null;
758
+ if (is_null($isWindows)) {
759
+ $isWindows = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
760
+ }
761
+ return $isWindows;
762
+ }
763
+
764
+ /**
765
+ * return current SO path path len
766
+ * @staticvar int $maxPath
767
+ * @return int
768
+ */
769
+ public static function maxPathLen()
770
+ {
771
+ static $maxPath = null;
772
+ if (is_null($maxPath)) {
773
+ if (defined('PHP_MAXPATHLEN')) {
774
+ $maxPath = PHP_MAXPATHLEN;
775
+ } else {
776
+ // for PHP < 5.3.0
777
+ $maxPath = self::isWindows() ? 260 : 4096;
778
+ }
779
+ }
780
+ return $maxPath;
781
+ }
782
+
783
+ /**
784
+ * this function make a chmod only if the are different from perms input and if chmod function is enabled
785
+ *
786
+ * this function handles the variable MODE in a way similar to the chmod of lunux
787
+ * So the MODE variable can be
788
+ * 1) an octal number (0755)
789
+ * 2) a string that defines an octal number ("644")
790
+ * 3) a string with the following format [ugoa]*([-+=]([rwx]*)+
791
+ *
792
+ * examples
793
+ * u+rw add read and write at the user
794
+ * u+rw,uo-wx add read and write ad the user and remove wx at groupd and other
795
+ * a=rw is equal at 666
796
+ * u=rwx,go-rwx is equal at 700
797
+ *
798
+ * @param string $file
799
+ * @param int|string $mode
800
+ * @return boolean
801
+ */
802
+ public static function chmod($file, $mode)
803
+ {
804
+ if (!file_exists($file)) {
805
+ return false;
806
+ }
807
+
808
+ $octalMode = 0;
809
+
810
+ if (is_int($mode)) {
811
+ $octalMode = $mode;
812
+ } else if (is_string($mode)) {
813
+ $mode = trim($mode);
814
+ if (preg_match('/([0-7]{1,3})/', $mode)) {
815
+ $octalMode = intval(('0'.$mode), 8);
816
+ } else if (preg_match_all('/(a|[ugo]{1,3})([-=+])([rwx]{1,3})/', $mode, $gMatch, PREG_SET_ORDER)) {
817
+ if (!function_exists('fileperms')) {
818
+ return false;
819
+ }
820
+
821
+ // start by file permission
822
+ $octalMode = (fileperms($file) & 0777);
823
+
824
+ foreach ($gMatch as $matches) {
825
+ // [ugo] or a = ugo
826
+ $group = $matches[1];
827
+ if ($group === 'a') {
828
+ $group = 'ugo';
829
+ }
830
+ // can be + - =
831
+ $action = $matches[2];
832
+ // [rwx]
833
+ $gPerms = $matches[3];
834
+
835
+ // reset octal group perms
836
+ $octalGroupMode = 0;
837
+
838
+ // Init sub perms
839
+ $subPerm = 0;
840
+ $subPerm += strpos($gPerms, 'x') !== false ? 1 : 0; // mask 001
841
+ $subPerm += strpos($gPerms, 'w') !== false ? 2 : 0; // mask 010
842
+ $subPerm += strpos($gPerms, 'r') !== false ? 4 : 0; // mask 100
843
+
844
+ $ugoLen = strlen($group);
845
+
846
+ if ($action === '=') {
847
+ // generate octal group permsissions and ugo mask invert
848
+ $ugoMaskInvert = 0777;
849
+ for ($i = 0; $i < $ugoLen; $i++) {
850
+ switch ($group[$i]) {
851
+ case 'u':
852
+ $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
853
+ $ugoMaskInvert = $ugoMaskInvert & 077;
854
+ break;
855
+ case 'g':
856
+ $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
857
+ $ugoMaskInvert = $ugoMaskInvert & 0707;
858
+ break;
859
+ case 'o':
860
+ $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
861
+ $ugoMaskInvert = $ugoMaskInvert & 0770;
862
+ break;
863
+ }
864
+ }
865
+ // apply = action
866
+ $octalMode = $octalMode & ($ugoMaskInvert | $octalGroupMode);
867
+ } else {
868
+ // generate octal group permsissions
869
+ for ($i = 0; $i < $ugoLen; $i++) {
870
+ switch ($group[$i]) {
871
+ case 'u':
872
+ $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
873
+ break;
874
+ case 'g':
875
+ $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
876
+ break;
877
+ case 'o':
878
+ $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
879
+ break;
880
+ }
881
+ }
882
+ // apply + or - action
883
+ switch ($action) {
884
+ case '+':
885
+ $octalMode = $octalMode | $octalGroupMode;
886
+ break;
887
+ case '-':
888
+ $octalMode = $octalMode & ~$octalGroupMode;
889
+ break;
890
+ }
891
+ }
892
+ }
893
+ }
894
+ }
895
+
896
+ // if input permissions are equal at file permissions return true without performing chmod
897
+ if (function_exists('fileperms') && $octalMode === (fileperms($file) & 0777)) {
898
+ return true;
899
+ }
900
+
901
+ if (!function_exists('chmod')) {
902
+ return false;
903
+ }
904
+
905
+ return @chmod($file, $octalMode);
906
+ }
907
+
908
+ public static function checkInputVaslidInt($input) {
909
+ return (filter_var($input, FILTER_VALIDATE_INT) === 0 || filter_var($input, FILTER_VALIDATE_INT));
910
+ }
911
+
912
+
913
+ /**
914
+ * this function creates a folder if it does not exist and performs a chmod.
915
+ * it is different from the normal mkdir function to which an umask is applied to the input permissions.
916
+ *
917
+ * this function handles the variable MODE in a way similar to the chmod of lunux
918
+ * So the MODE variable can be
919
+ * 1) an octal number (0755)
920
+ * 2) a string that defines an octal number ("644")
921
+ * 3) a string with the following format [ugoa]*([-+=]([rwx]*)+
922
+ *
923
+ * @param string $path
924
+ * @param int|string $mode
925
+ * @param bool $recursive
926
+ * @param resource $context // not used for windows bug
927
+ * @return boolean bool TRUE on success or FALSE on failure.
928
+ *
929
+ * @todo check recursive true and multiple chmod
930
+ */
931
+ public static function mkdir($path, $mode = 0777, $recursive = false, $context = null)
932
+ {
933
+ if (strlen($path) > self::maxPathLen()) {
934
+ throw new Exception('Skipping a file that exceeds allowed max path length ['.self::maxPathLen().']. File: '.$filepath);
935
+ }
936
+
937
+ if (!file_exists($path)) {
938
+ if (!function_exists('mkdir')) {
939
+ return false;
940
+ }
941
+ if (!@mkdir($path, 0777, $recursive)) {
942
+ return false;
943
+ }
944
+ }
945
+
946
+ return self::chmod($path, $mode);
947
+ }
948
+
949
  /**
950
  * move all folder content up to parent
951
  *
967
 
968
  $success = true;
969
  if (($subList = glob(rtrim($subFolderName, '/').'/*', GLOB_NOSORT)) === false) {
970
+ self::log("[ERROR] Problem glob folder ".$subFolderName);
971
  return false;
972
  } else {
973
  foreach ($subList as $cName) {
989
  }
990
 
991
  if (!$success) {
992
+ self::log("[ERROR] Problem om moveUpfromSubFolder subFolder:".$subFolderName);
993
  }
994
 
995
  return $success;
1023
  $unzip_command = "$unzip_filepath -q $archive_filepath snaplib/* 2>&1";
1024
  self::log("Executing $unzip_command");
1025
  $stderr .= shell_exec($unzip_command);
1026
+ self::mkdir($lib_directory,'u+rwx');
1027
  rename($local_lib_directory, $snaplib_directory);
1028
  }
1029
 
1031
  self::log("Shell exec unzip succeeded");
1032
  $success = true;
1033
  } else {
1034
+ self::log("[ERROR] Shell exec unzip failed. Output={$stderr}");
1035
  }
1036
  }
1037
 
1233
  } else {
1234
  $success = @unlink($fullPath);
1235
  if ($success === false) {
1236
+ self::log('[ERROR] '.__FUNCTION__.": Problem deleting file:".$fullPath);
1237
  }
1238
  }
1239
 
1240
  if ($success === false) {
1241
+ self::log("[ERROR] Problem deleting dir:".$directory);
1242
  break;
1243
  }
1244
  }
1263
  $success = @unlink($path);
1264
 
1265
  if ($success === false) {
1266
+ self::log('[ERROR] '. __FUNCTION__.": Problem deleting file:".$path);
1267
  }
1268
  }
1269
 
1287
  }
1288
  }
1289
 
1290
+ class DUPX_Handler
1291
+ {
1292
+ /**
1293
+ *
1294
+ * @var bool
1295
+ */
1296
+ private static $inizialized = false;
1297
+
1298
+ /**
1299
+ * This function only initializes the error handler the first time it is called
1300
+ */
1301
+ public static function init_error_handler()
1302
+ {
1303
+ if (!self::$inizialized) {
1304
+ @set_error_handler(array(__CLASS__, 'error'));
1305
+ @register_shutdown_function(array(__CLASS__, 'shutdown'));
1306
+ self::$inizialized = true;
1307
+ }
1308
+ }
1309
+
1310
+ /**
1311
+ * Error handler
1312
+ *
1313
+ * @param integer $errno Error level
1314
+ * @param string $errstr Error message
1315
+ * @param string $errfile Error file
1316
+ * @param integer $errline Error line
1317
+ * @return void
1318
+ */
1319
+ public static function error($errno, $errstr, $errfile, $errline)
1320
+ {
1321
+ switch ($errno) {
1322
+ case E_ERROR :
1323
+ $log_message = self::getMessage($errno, $errstr, $errfile, $errline);
1324
+ if (DUPX_Bootstrap::log($log_message) === false) {
1325
+ $log_message = "Can\'t wrinte logfile\n\n".$log_message;
1326
+ }
1327
+ die('<pre>'.htmlspecialchars($log_message).'</pre>');
1328
+ break;
1329
+ case E_NOTICE :
1330
+ case E_WARNING :
1331
+ default :
1332
+ $log_message = self::getMessage($errno, $errstr, $errfile, $errline);
1333
+ DUPX_Bootstrap::log($log_message);
1334
+ break;
1335
+ }
1336
+ }
1337
+
1338
+ private static function getMessage($errno, $errstr, $errfile, $errline)
1339
+ {
1340
+ $result = '[PHP ERR]';
1341
+ switch ($errno) {
1342
+ case E_ERROR :
1343
+ $result .= '[FATAL]';
1344
+ break;
1345
+ case E_WARNING :
1346
+ $result .= '[WARN]';
1347
+ break;
1348
+ case E_NOTICE :
1349
+ $result .= '[NOTICE]';
1350
+ break;
1351
+ default :
1352
+ $result .= '[ISSUE]';
1353
+ break;
1354
+ }
1355
+ $result .= ' MSG:';
1356
+ $result .= $errstr;
1357
+ $result .= ' [CODE:'.$errno.'|FILE:'.$errfile.'|LINE:'.$errline.']';
1358
+ return $result;
1359
+ }
1360
+
1361
+ /**
1362
+ * Shutdown handler
1363
+ *
1364
+ * @return void
1365
+ */
1366
+ public static function shutdown()
1367
+ {
1368
+ if (($error = error_get_last())) {
1369
+ DUPX_Handler::error($error['type'], $error['message'], $error['file'], $error['line']);
1370
+ }
1371
+ }
1372
+ }
1373
+
1374
+ class DUPX_CSRF {
1375
+
1376
+ /** Session var name
1377
+ * @var string
1378
+ */
1379
+ public static $prefix = '_DUPX_CSRF';
1380
+ private static $CSRFVars;
1381
+
1382
+ public static function setKeyVal($key, $val) {
1383
+ $CSRFVars = self::getCSRFVars();
1384
+ $CSRFVars[$key] = $val;
1385
+ self::saveCSRFVars($CSRFVars);
1386
+ self::$CSRFVars = false;
1387
+ }
1388
+
1389
+ public static function getVal($key) {
1390
+ $CSRFVars = self::getCSRFVars();
1391
+ if (isset($CSRFVars[$key])) {
1392
+ return $CSRFVars[$key];
1393
+ } else {
1394
+ return false;
1395
+ }
1396
+
1397
+ }
1398
+
1399
+ /** Generate DUPX_CSRF value for form
1400
+ * @param string $form - Form name as session key
1401
+ * @return string - token
1402
+ */
1403
+ public static function generate($form = NULL) {
1404
+ $keyName = self::getKeyName($form);
1405
+
1406
+ $existingToken = self::getVal($keyName);
1407
+ if (false !== $existingToken) {
1408
+ $token = $existingToken;
1409
+ } else {
1410
+ $token = self::token() . self::fingerprint();
1411
+ }
1412
+
1413
+ self::setKeyVal($keyName, $token);
1414
+ return $token;
1415
+ }
1416
+
1417
+ /** Check DUPX_CSRF value of form
1418
+ * @param string $token - Token
1419
+ * @param string $form - Form name as session key
1420
+ * @return boolean
1421
+ */
1422
+ public static function check($token, $form = NULL) {
1423
+ $keyName = self::getKeyName($form);
1424
+ $CSRFVars = self::getCSRFVars();
1425
+ if (isset($CSRFVars[$keyName]) && $CSRFVars[$keyName] == $token) { // token OK
1426
+ return true;
1427
+ }
1428
+ return FALSE;
1429
+ }
1430
+
1431
+ /** Generate token
1432
+ * @param void
1433
+ * @return string
1434
+ */
1435
+ protected static function token() {
1436
+ mt_srand((double) microtime() * 10000);
1437
+ $charid = strtoupper(md5(uniqid(rand(), TRUE)));
1438
+ return substr($charid, 0, 8) . substr($charid, 8, 4) . substr($charid, 12, 4) . substr($charid, 16, 4) . substr($charid, 20, 12);
1439
+ }
1440
+
1441
+ /** Returns "digital fingerprint" of user
1442
+ * @param void
1443
+ * @return string - MD5 hashed data
1444
+ */
1445
+ protected static function fingerprint() {
1446
+ return strtoupper(md5(implode('|', array($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']))));
1447
+ }
1448
+
1449
+ private static function getKeyName($form) {
1450
+ return self::$prefix . '_' . $form;
1451
+ }
1452
+
1453
+ private static function getPackageHash() {
1454
+ if (class_exists('DUPX_Bootstrap')) {
1455
+ return DUPX_Bootstrap::PACKAGE_HASH;
1456
+ } else {
1457
+ return $GLOBALS['DUPX_AC']->package_hash;
1458
+ }
1459
+ }
1460
+
1461
+ private static function getFilePath() {
1462
+ if (class_exists('DUPX_Bootstrap')) {
1463
+ $dupInstallerfolderPath = dirname(__FILE__).'/dup-installer/';
1464
+ } else {
1465
+ $dupInstallerfolderPath = $GLOBALS['DUPX_INIT'].'/';
1466
+ }
1467
+ $packageHash = self::getPackageHash();
1468
+ $fileName = 'dup-installer-csrf__'.$packageHash.'.txt';
1469
+ $filePath = $dupInstallerfolderPath.$fileName;
1470
+ return $filePath;
1471
+ }
1472
+
1473
+ private static function getCSRFVars() {
1474
+ if (!isset(self::$CSRFVars) || false === self::$CSRFVars) {
1475
+ $filePath = self::getFilePath();
1476
+ if (file_exists($filePath)) {
1477
+ $contents = file_get_contents($filePath);
1478
+ if (empty($contents)) {
1479
+ self::$CSRFVars = array();
1480
+ } else {
1481
+ $CSRFobjs = json_decode($contents);
1482
+ foreach ($CSRFobjs as $key => $value) {
1483
+ self::$CSRFVars[$key] = $value;
1484
+ }
1485
+ }
1486
+ } else {
1487
+ self::$CSRFVars = array();
1488
+ }
1489
+ }
1490
+ return self::$CSRFVars;
1491
+ }
1492
+
1493
+ private static function saveCSRFVars($CSRFVars) {
1494
+ $contents = json_encode($CSRFVars);
1495
+ $filePath = self::getFilePath();
1496
+ file_put_contents($filePath, $contents);
1497
+ }
1498
+ }
1499
+
1500
+ /**
1501
+ * Copyright (c) 2011 Raymond Hill (http://raymondhill.net/blog/?p=441)
1502
+ * @copyright Copyright 2011 (c) Raymond Hill (http://raymondhill.net/blog/?p=441)
1503
+ * @link http://www.raymondhill.net/finediff/
1504
+ * @version 0.6
1505
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
1506
+ */
1507
+ abstract class FineDiffOp
1508
+ {
1509
+
1510
+ abstract public function getFromLen();
1511
+
1512
+ abstract public function getToLen();
1513
+
1514
+ abstract public function getOpcode();
1515
+ }
1516
+
1517
+ class FineDiffDeleteOp extends FineDiffOp
1518
+ {
1519
+
1520
+ public function __construct($len)
1521
+ {
1522
+ $this->fromLen = $len;
1523
+ }
1524
+
1525
+ public function getFromLen()
1526
+ {
1527
+ return $this->fromLen;
1528
+ }
1529
+
1530
+ public function getToLen()
1531
+ {
1532
+ return 0;
1533
+ }
1534
+
1535
+ public function getOpcode()
1536
+ {
1537
+ if ($this->fromLen === 1) {
1538
+ return 'd';
1539
+ }
1540
+ return "d{$this->fromLen}";
1541
+ }
1542
+ }
1543
+
1544
+ class FineDiffInsertOp extends FineDiffOp
1545
+ {
1546
+
1547
+ public function __construct($text)
1548
+ {
1549
+ $this->text = $text;
1550
+ }
1551
+
1552
+ public function getFromLen()
1553
+ {
1554
+ return 0;
1555
+ }
1556
+
1557
+ public function getToLen()
1558
+ {
1559
+ return strlen($this->text);
1560
+ }
1561
+
1562
+ public function getText()
1563
+ {
1564
+ return $this->text;
1565
+ }
1566
+
1567
+ public function getOpcode()
1568
+ {
1569
+ $to_len = strlen($this->text);
1570
+ if ($to_len === 1) {
1571
+ return "i:{$this->text}";
1572
+ }
1573
+ return "i{$to_len}:{$this->text}";
1574
+ }
1575
+ }
1576
+
1577
+ class FineDiffReplaceOp extends FineDiffOp
1578
+ {
1579
+
1580
+ public function __construct($fromLen, $text)
1581
+ {
1582
+ $this->fromLen = $fromLen;
1583
+ $this->text = $text;
1584
+ }
1585
+
1586
+ public function getFromLen()
1587
+ {
1588
+ return $this->fromLen;
1589
+ }
1590
+
1591
+ public function getToLen()
1592
+ {
1593
+ return strlen($this->text);
1594
+ }
1595
+
1596
+ public function getText()
1597
+ {
1598
+ return $this->text;
1599
+ }
1600
+
1601
+ public function getOpcode()
1602
+ {
1603
+ if ($this->fromLen === 1) {
1604
+ $del_opcode = 'd';
1605
+ } else {
1606
+ $del_opcode = "d{$this->fromLen}";
1607
+ }
1608
+ $to_len = strlen($this->text);
1609
+ if ($to_len === 1) {
1610
+ return "{$del_opcode}i:{$this->text}";
1611
+ }
1612
+ return "{$del_opcode}i{$to_len}:{$this->text}";
1613
+ }
1614
+ }
1615
+
1616
+ class FineDiffCopyOp extends FineDiffOp
1617
+ {
1618
+
1619
+ public function __construct($len)
1620
+ {
1621
+ $this->len = $len;
1622
+ }
1623
+
1624
+ public function getFromLen()
1625
+ {
1626
+ return $this->len;
1627
+ }
1628
+
1629
+ public function getToLen()
1630
+ {
1631
+ return $this->len;
1632
+ }
1633
+
1634
+ public function getOpcode()
1635
+ {
1636
+ if ($this->len === 1) {
1637
+ return 'c';
1638
+ }
1639
+ return "c{$this->len}";
1640
+ }
1641
+
1642
+ public function increase($size)
1643
+ {
1644
+ return $this->len += $size;
1645
+ }
1646
+ }
1647
+
1648
+ class FineDiffOps
1649
+ {
1650
+
1651
+ public function appendOpcode($opcode, $from, $from_offset, $from_len)
1652
+ {
1653
+ if ($opcode === 'c') {
1654
+ $edits[] = new FineDiffCopyOp($from_len);
1655
+ } else if ($opcode === 'd') {
1656
+ $edits[] = new FineDiffDeleteOp($from_len);
1657
+ } else /* if ( $opcode === 'i' ) */ {
1658
+ $edits[] = new FineDiffInsertOp(substr($from, $from_offset, $from_len));
1659
+ }
1660
+ }
1661
+
1662
+ public $edits = array();
1663
+
1664
+ }
1665
+
1666
+ class FineDiff
1667
+ {
1668
+
1669
+ public function __construct($from_text = '', $to_text = '', $granularityStack = null)
1670
+ {
1671
+ // setup stack for generic text documents by default
1672
+ $this->granularityStack = $granularityStack ? $granularityStack : FineDiff::$characterGranularity;
1673
+ $this->edits = array();
1674
+ $this->from_text = $from_text;
1675
+ $this->doDiff($from_text, $to_text);
1676
+ }
1677
+
1678
+ public function getOps()
1679
+ {
1680
+ return $this->edits;
1681
+ }
1682
+
1683
+ public function renderDiffToHTML()
1684
+ {
1685
+ $in_offset = 0;
1686
+ ob_start();
1687
+ foreach ($this->edits as $edit) {
1688
+ $n = $edit->getFromLen();
1689
+ if ($edit instanceof FineDiffCopyOp) {
1690
+ FineDiff::renderDiffToHTMLFromOpcode('c', $this->from_text, $in_offset, $n);
1691
+ } else if ($edit instanceof FineDiffDeleteOp) {
1692
+ FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n);
1693
+ } else if ($edit instanceof FineDiffInsertOp) {
1694
+ FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen());
1695
+ } else /* if ( $edit instanceof FineDiffReplaceOp ) */ {
1696
+ FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n);
1697
+ FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen());
1698
+ }
1699
+ $in_offset += $n;
1700
+ }
1701
+ return ob_get_clean();
1702
+ }
1703
+
1704
+ const characterDelimiters = "";
1705
+
1706
+ public static $characterGranularity = array(
1707
+ FineDiff::characterDelimiters
1708
+ );
1709
+
1710
+ private function doDiff($from_text, $to_text)
1711
+ {
1712
+ $this->last_edit = false;
1713
+ $this->stackpointer = 0;
1714
+ $this->from_text = $from_text;
1715
+ $this->from_offset = 0;
1716
+ // can't diff without at least one granularity specifier
1717
+ if (empty($this->granularityStack)) {
1718
+ return;
1719
+ }
1720
+ $this->_processGranularity($from_text, $to_text);
1721
+ }
1722
+
1723
+ private function _processGranularity($from_segment, $to_segment)
1724
+ {
1725
+ $delimiters = $this->granularityStack[$this->stackpointer++];
1726
+ $has_next_stage = $this->stackpointer < count($this->granularityStack);
1727
+ foreach (FineDiff::doFragmentDiff($from_segment, $to_segment, $delimiters) as $fragment_edit) {
1728
+ // increase granularity
1729
+ if ($fragment_edit instanceof FineDiffReplaceOp && $has_next_stage) {
1730
+ $this->_processGranularity(
1731
+ substr($this->from_text, $this->from_offset, $fragment_edit->getFromLen()), $fragment_edit->getText()
1732
+ );
1733
+ }
1734
+ // fuse copy ops whenever possible
1735
+ else if ($fragment_edit instanceof FineDiffCopyOp && $this->last_edit instanceof FineDiffCopyOp) {
1736
+ $this->edits[count($this->edits) - 1]->increase($fragment_edit->getFromLen());
1737
+ $this->from_offset += $fragment_edit->getFromLen();
1738
+ } else {
1739
+ /* $fragment_edit instanceof FineDiffCopyOp */
1740
+ /* $fragment_edit instanceof FineDiffDeleteOp */
1741
+ /* $fragment_edit instanceof FineDiffInsertOp */
1742
+ $this->edits[] = $this->last_edit = $fragment_edit;
1743
+ $this->from_offset += $fragment_edit->getFromLen();
1744
+ }
1745
+ }
1746
+ $this->stackpointer--;
1747
+ }
1748
+
1749
+ private static function doFragmentDiff($from_text, $to_text, $delimiters)
1750
+ {
1751
+ // Empty delimiter means character-level diffing.
1752
+ // In such case, use code path optimized for character-level
1753
+ // diffing.
1754
+ if (empty($delimiters)) {
1755
+ return FineDiff::doCharDiff($from_text, $to_text);
1756
+ }
1757
+
1758
+ $result = array();
1759
+
1760
+ // fragment-level diffing
1761
+ $from_text_len = strlen($from_text);
1762
+ $to_text_len = strlen($to_text);
1763
+ $from_fragments = FineDiff::extractFragments($from_text, $delimiters);
1764
+ $to_fragments = FineDiff::extractFragments($to_text, $delimiters);
1765
+
1766
+ $jobs = array(array(0, $from_text_len, 0, $to_text_len));
1767
+
1768
+ $cached_array_keys = array();
1769
+
1770
+ while ($job = array_pop($jobs)) {
1771
+
1772
+ // get the segments which must be diff'ed
1773
+ list($from_segment_start, $from_segment_end, $to_segment_start, $to_segment_end) = $job;
1774
+
1775
+ // catch easy cases first
1776
+ $from_segment_length = $from_segment_end - $from_segment_start;
1777
+ $to_segment_length = $to_segment_end - $to_segment_start;
1778
+ if (!$from_segment_length || !$to_segment_length) {
1779
+ if ($from_segment_length) {
1780
+ $result[$from_segment_start * 4] = new FineDiffDeleteOp($from_segment_length);
1781
+ } else if ($to_segment_length) {
1782
+ $result[$from_segment_start * 4 + 1] = new FineDiffInsertOp(substr($to_text, $to_segment_start, $to_segment_length));
1783
+ }
1784
+ continue;
1785
+ }
1786
+
1787
+ // find longest copy operation for the current segments
1788
+ $best_copy_length = 0;
1789
+
1790
+ $from_base_fragment_index = $from_segment_start;
1791
+
1792
+ $cached_array_keys_for_current_segment = array();
1793
+
1794
+ while ($from_base_fragment_index < $from_segment_end) {
1795
+ $from_base_fragment = $from_fragments[$from_base_fragment_index];
1796
+ $from_base_fragment_length = strlen($from_base_fragment);
1797
+ // performance boost: cache array keys
1798
+ if (!isset($cached_array_keys_for_current_segment[$from_base_fragment])) {
1799
+ if (!isset($cached_array_keys[$from_base_fragment])) {
1800
+ $to_all_fragment_indices = $cached_array_keys[$from_base_fragment] = array_keys($to_fragments, $from_base_fragment, true);
1801
+ } else {
1802
+ $to_all_fragment_indices = $cached_array_keys[$from_base_fragment];
1803
+ }
1804
+ // get only indices which falls within current segment
1805
+ if ($to_segment_start > 0 || $to_segment_end < $to_text_len) {
1806
+ $to_fragment_indices = array();
1807
+ foreach ($to_all_fragment_indices as $to_fragment_index) {
1808
+ if ($to_fragment_index < $to_segment_start) {
1809
+ continue;
1810
+ }
1811
+ if ($to_fragment_index >= $to_segment_end) {
1812
+ break;
1813
+ }
1814
+ $to_fragment_indices[] = $to_fragment_index;
1815
+ }
1816
+ $cached_array_keys_for_current_segment[$from_base_fragment] = $to_fragment_indices;
1817
+ } else {
1818
+ $to_fragment_indices = $to_all_fragment_indices;
1819
+ }
1820
+ } else {
1821
+ $to_fragment_indices = $cached_array_keys_for_current_segment[$from_base_fragment];
1822
+ }
1823
+ // iterate through collected indices
1824
+ foreach ($to_fragment_indices as $to_base_fragment_index) {
1825
+ $fragment_index_offset = $from_base_fragment_length;
1826
+ // iterate until no more match
1827
+ for (;;) {
1828
+ $fragment_from_index = $from_base_fragment_index + $fragment_index_offset;
1829
+ if ($fragment_from_index >= $from_segment_end) {
1830
+ break;
1831
+ }
1832
+ $fragment_to_index = $to_base_fragment_index + $fragment_index_offset;
1833
+ if ($fragment_to_index >= $to_segment_end) {
1834
+ break;
1835
+ }
1836
+ if ($from_fragments[$fragment_from_index] !== $to_fragments[$fragment_to_index]) {
1837
+ break;
1838
+ }
1839
+ $fragment_length = strlen($from_fragments[$fragment_from_index]);
1840
+ $fragment_index_offset += $fragment_length;
1841
+ }
1842
+ if ($fragment_index_offset > $best_copy_length) {
1843
+ $best_copy_length = $fragment_index_offset;
1844
+ $best_from_start = $from_base_fragment_index;
1845
+ $best_to_start = $to_base_fragment_index;
1846
+ }
1847
+ }
1848
+ $from_base_fragment_index += strlen($from_base_fragment);
1849
+ // If match is larger than half segment size, no point trying to find better
1850
+ // TODO: Really?
1851
+ if ($best_copy_length >= $from_segment_length / 2) {
1852
+ break;
1853
+ }
1854
+ // no point to keep looking if what is left is less than
1855
+ // current best match
1856
+ if ($from_base_fragment_index + $best_copy_length >= $from_segment_end) {
1857
+ break;
1858
+ }
1859
+ }
1860
+
1861
+ if ($best_copy_length) {
1862
+ $jobs[] = array($from_segment_start, $best_from_start, $to_segment_start, $best_to_start);
1863
+ $result[$best_from_start * 4 + 2] = new FineDiffCopyOp($best_copy_length);
1864
+ $jobs[] = array($best_from_start + $best_copy_length, $from_segment_end, $best_to_start + $best_copy_length, $to_segment_end);
1865
+ } else {
1866
+ $result[$from_segment_start * 4] = new FineDiffReplaceOp($from_segment_length, substr($to_text, $to_segment_start, $to_segment_length));
1867
+ }
1868
+ }
1869
+
1870
+ ksort($result, SORT_NUMERIC);
1871
+ return array_values($result);
1872
+ }
1873
+
1874
+ private static function doCharDiff($from_text, $to_text)
1875
+ {
1876
+ $result = array();
1877
+ $jobs = array(array(0, strlen($from_text), 0, strlen($to_text)));
1878
+ while ($job = array_pop($jobs)) {
1879
+ // get the segments which must be diff'ed
1880
+ list($from_segment_start, $from_segment_end, $to_segment_start, $to_segment_end) = $job;
1881
+ $from_segment_len = $from_segment_end - $from_segment_start;
1882
+ $to_segment_len = $to_segment_end - $to_segment_start;
1883
+
1884
+ // catch easy cases first
1885
+ if (!$from_segment_len || !$to_segment_len) {
1886
+ if ($from_segment_len) {
1887
+ $result[$from_segment_start * 4 + 0] = new FineDiffDeleteOp($from_segment_len);
1888
+ } else if ($to_segment_len) {
1889
+ $result[$from_segment_start * 4 + 1] = new FineDiffInsertOp(substr($to_text, $to_segment_start, $to_segment_len));
1890
+ }
1891
+ continue;
1892
+ }
1893
+ if ($from_segment_len >= $to_segment_len) {
1894
+ $copy_len = $to_segment_len;
1895
+ while ($copy_len) {
1896
+ $to_copy_start = $to_segment_start;
1897
+ $to_copy_start_max = $to_segment_end - $copy_len;
1898
+ while ($to_copy_start <= $to_copy_start_max) {
1899
+ $from_copy_start = strpos(substr($from_text, $from_segment_start, $from_segment_len), substr($to_text, $to_copy_start, $copy_len));
1900
+ if ($from_copy_start !== false) {
1901
+ $from_copy_start += $from_segment_start;
1902
+ break 2;
1903
+ }
1904
+ $to_copy_start++;
1905
+ }
1906
+ $copy_len--;
1907
+ }
1908
+ } else {
1909
+ $copy_len = $from_segment_len;
1910
+ while ($copy_len) {
1911
+ $from_copy_start = $from_segment_start;
1912
+ $from_copy_start_max = $from_segment_end - $copy_len;
1913
+ while ($from_copy_start <= $from_copy_start_max) {
1914
+ $to_copy_start = strpos(substr($to_text, $to_segment_start, $to_segment_len), substr($from_text, $from_copy_start, $copy_len));
1915
+ if ($to_copy_start !== false) {
1916
+ $to_copy_start += $to_segment_start;
1917
+ break 2;
1918
+ }
1919
+ $from_copy_start++;
1920
+ }
1921
+ $copy_len--;
1922
+ }
1923
+ }
1924
+ // match found
1925
+ if ($copy_len) {
1926
+ $jobs[] = array($from_segment_start, $from_copy_start, $to_segment_start, $to_copy_start);
1927
+ $result[$from_copy_start * 4 + 2] = new FineDiffCopyOp($copy_len);
1928
+ $jobs[] = array($from_copy_start + $copy_len, $from_segment_end, $to_copy_start + $copy_len, $to_segment_end);
1929
+ }
1930
+ // no match, so delete all, insert all
1931
+ else {
1932
+ $result[$from_segment_start * 4] = new FineDiffReplaceOp($from_segment_len, substr($to_text, $to_segment_start, $to_segment_len));
1933
+ }
1934
+ }
1935
+ ksort($result, SORT_NUMERIC);
1936
+ return array_values($result);
1937
+ }
1938
+
1939
+ private static function extractFragments($text, $delimiters)
1940
+ {
1941
+ // special case: split into characters
1942
+ if (empty($delimiters)) {
1943
+ $chars = str_split($text, 1);
1944
+ $chars[strlen($text)] = '';
1945
+ return $chars;
1946
+ }
1947
+ $fragments = array();
1948
+ $start = $end = 0;
1949
+ for (;;) {
1950
+ $end += strcspn($text, $delimiters, $end);
1951
+ $end += strspn($text, $delimiters, $end);
1952
+ if ($end === $start) {
1953
+ break;
1954
+ }
1955
+ $fragments[$start] = substr($text, $start, $end - $start);
1956
+ $start = $end;
1957
+ }
1958
+ $fragments[$start] = '';
1959
+ return $fragments;
1960
+ }
1961
+
1962
+ private static function renderDiffToHTMLFromOpcode($opcode, $from, $from_offset, $from_len)
1963
+ {
1964
+ if ($opcode === 'c') {
1965
+ echo htmlspecialchars(substr($from, $from_offset, $from_len));
1966
+ } else if ($opcode === 'd') {
1967
+ $deletion = substr($from, $from_offset, $from_len);
1968
+ if (strcspn($deletion, " \n\r") === 0) {
1969
+ $deletion = str_replace(array("\n", "\r"), array('\n', '\r'), $deletion);
1970
+ }
1971
+ echo '<del>', htmlspecialchars($deletion), '</del>';
1972
+ } else /* if ( $opcode === 'i' ) */ {
1973
+ echo '<ins>', htmlspecialchars(substr($from, $from_offset, $from_len)), '</ins>';
1974
+ }
1975
+ }
1976
+ }
1977
+
1978
+ /*** CLASS DEFINITION END ***/
1979
+
1980
  try {
1981
  $boot = new DUPX_Bootstrap();
1982
  $boot_error = $boot->run();
lib/config/class.wp.config.tranformer.php CHANGED
@@ -7,6 +7,8 @@ if (!class_exists('WPConfigTransformer')):
7
  */
8
  class WPConfigTransformer {
9
 
 
 
10
  /**
11
  * Path to the wp-config.php file.
12
  *
@@ -93,7 +95,7 @@ class WPConfigTransformer {
93
  *
94
  * @return array
95
  */
96
- public function get_value( $type, $name ) {
97
  $wp_config_src = file_get_contents( $this->wp_config_path );
98
  if ( ! trim( $wp_config_src ) ) {
99
  throw new Exception( 'wp-config.php file is empty.' );
@@ -113,15 +115,40 @@ class WPConfigTransformer {
113
 
114
  // Duplicator Extra
115
  $val = $this->wp_configs[ $type ][ $name ]['value'];
116
- if (is_string($val)) {
117
- $val = trim($val, '"');
118
- $val = trim($val, "'");
119
- }
 
120
 
121
  return $val;
122
  }
123
 
124
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  * Adds a config to the wp-config.php file.
126
  *
127
  * @throws Exception If the config value provided is not a string.
@@ -275,16 +302,12 @@ class WPConfigTransformer {
275
  $new_src = implode( '', $new_parts );
276
  }
277
 
278
- // regex: (^\$|^(?:\\\\)+|[^\\](?:\\\\)+|[^\\])\$
279
- // subst: $1\\$
280
- $safe_new_src = preg_replace('/(^\$|^(?:\\\\\\\\)+|[^\\\\](?:\\\\\\\\)+|[^\\\\])\$/m', '$1\\\\$' , trim($new_src));
281
-
282
- $contents = preg_replace(
283
  sprintf( '/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote( trim( $old_src ), '/' ) ),
284
- '$1' . $safe_new_src,
285
  $this->wp_config_src
286
  );
287
-
288
  return $this->save( $contents );
289
  }
290
 
@@ -433,4 +456,4 @@ class WPConfigTransformer {
433
 
434
  }
435
 
436
- endif;
7
  */
8
  class WPConfigTransformer {
9
 
10
+ const REPLACE_TEMP_STIRNG = '_1_2_RePlAcE_3_4_TeMp_5_6_StRiNg_7_8_';
11
+
12
  /**
13
  * Path to the wp-config.php file.
14
  *
95
  *
96
  * @return array
97
  */
98
+ public function get_value( $type, $name, $get_real_value = true) {
99
  $wp_config_src = file_get_contents( $this->wp_config_path );
100
  if ( ! trim( $wp_config_src ) ) {
101
  throw new Exception( 'wp-config.php file is empty.' );
115
 
116
  // Duplicator Extra
117
  $val = $this->wp_configs[ $type ][ $name ]['value'];
118
+ if ($get_real_value) {
119
+ return self::getRealValFromVal($val);
120
+ } else {
121
+ return $val;
122
+ }
123
 
124
  return $val;
125
  }
126
 
127
+ public static function getRealValFromVal($val)
128
+ {
129
+ if ($val[0] == '\'') {
130
+ // string with '
131
+ $result = substr($val, 1, strlen($val) - 2);
132
+ return str_replace(array('\\\'' , '\\\\'), array('\'', '\\'), $result);
133
+ } else if ($val[0] == '"') {
134
+ // string with "
135
+ return json_decode(str_replace('\\$', '$', $val));
136
+ } else if (strcasecmp($val, 'true')) {
137
+ return true;
138
+ } else if (strcasecmp($val, 'false')) {
139
+ return false;
140
+ } else if (strcasecmp($val, 'null')) {
141
+ return null;
142
+ } else if (preg_match('/^[-+]?[0-9]+$/', $val)) {
143
+ return (int) $val;
144
+ } else if (preg_match('/^[-+]?[0-9]+\.[0-9]+$/', $val)) {
145
+ return (float) $val;
146
+ } else {
147
+ return $val;
148
+ }
149
+ }
150
+
151
+ /**
152
  * Adds a config to the wp-config.php file.
153
  *
154
  * @throws Exception If the config value provided is not a string.
302
  $new_src = implode( '', $new_parts );
303
  }
304
 
305
+ $contents = preg_replace(
 
 
 
 
306
  sprintf( '/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote( trim( $old_src ), '/' ) ),
307
+ '$1' . self::REPLACE_TEMP_STIRNG ,
308
  $this->wp_config_src
309
  );
310
+ $contents = str_replace(self::REPLACE_TEMP_STIRNG, trim($new_src), $contents);
311
  return $this->save( $contents );
312
  }
313
 
456
 
457
  }
458
 
459
+ endif;
lib/config/class.wp.config.tranformer.src.php CHANGED
@@ -59,7 +59,7 @@ if (!class_exists('WPConfigTransformerSrc')):
59
  *
60
  * @return array
61
  */
62
- public function get_value($type, $name)
63
  {
64
  $this->wp_configs = $this->parse_wp_config($this->wp_config_src);
65
 
@@ -69,17 +69,16 @@ if (!class_exists('WPConfigTransformerSrc')):
69
 
70
  // Duplicator Extra
71
  $val = $this->wp_configs[$type][$name]['value'];
72
- if (is_string($val)) {
73
- $val = trim($val, '"');
74
- $val = trim($val, "'");
 
75
  }
76
-
77
- return $val;
78
  }
79
 
80
  /**
81
  * update wp_config_src
82
- *
83
  * @param string $contents
84
  * @return boolean
85
  */
@@ -89,5 +88,5 @@ if (!class_exists('WPConfigTransformerSrc')):
89
  return true;
90
  }
91
  }
92
-
93
  endif;
59
  *
60
  * @return array
61
  */
62
+ public function get_value($type, $name, $get_real_value = true)
63
  {
64
  $this->wp_configs = $this->parse_wp_config($this->wp_config_src);
65
 
69
 
70
  // Duplicator Extra
71
  $val = $this->wp_configs[$type][$name]['value'];
72
+ if ($get_real_value) {
73
+ return self::getRealValFromVal($val);
74
+ } else {
75
+ return $val;
76
  }
 
 
77
  }
78
 
79
  /**
80
  * update wp_config_src
81
+ *
82
  * @param string $contents
83
  * @return boolean
84
  */
88
  return true;
89
  }
90
  }
91
+
92
  endif;
lib/dup_archive/classes/class.duparchive.engine.php CHANGED
@@ -575,18 +575,11 @@ class DupArchiveEngine
575
 
576
  if (!$expandState->validateOnly) {
577
  $directory = $expandState->basePath . '/' . $directoryHeader->relativePath;
578
-
579
- $mode = $directoryHeader->permissions;
580
-
581
  if ($expandState->directoryModeOverride != -1) {
582
  $mode = $expandState->directoryModeOverride;
583
  }
584
-
585
- if (!file_exists($directory)) {
586
- $createdDirectory = @mkdir($directory, $mode, true);
587
- } else {
588
- $createdDirectory = true;
589
- }
590
  }
591
 
592
  if ($createdDirectory) {
575
 
576
  if (!$expandState->validateOnly) {
577
  $directory = $expandState->basePath . '/' . $directoryHeader->relativePath;
578
+ $mode = 'u+rwx';
 
 
579
  if ($expandState->directoryModeOverride != -1) {
580
  $mode = $expandState->directoryModeOverride;
581
  }
582
+ $createdDirectory = DupLiteSnapLibIOU::dirWriteCheckOrMkdir($directory, $mode, true);
 
 
 
 
 
583
  }
584
 
585
  if ($createdDirectory) {
lib/dup_archive/classes/class.duparchive.mini.expander.php CHANGED
@@ -148,6 +148,9 @@ class DupArchiveMiniHeader
148
  private function __construct()
149
  {
150
  // Prevent instantiation
 
 
 
151
  }
152
 
153
  public static function readFromArchive($archiveHandle)
@@ -293,7 +296,7 @@ class DupArchiveMiniExpander
293
  // $mode = $directoryHeader->permissions;
294
 
295
  // rodo handle this more elegantly @mkdir($directory, $directoryHeader->permissions, true);
296
- @mkdir($directory, 0755, true);
297
 
298
 
299
  $writeInfo->directoryWriteCount++;
@@ -349,19 +352,13 @@ class DupArchiveMiniExpander
349
  {
350
  /* @var $writeInfo DupArchiveMiniWriteInfo */
351
  $parentDir = dirname($destFilePath);
352
-
353
  if (!file_exists($parentDir)) {
 
 
 
 
354
 
355
- $r = @mkdir($parentDir, 0755, true);
356
-
357
- if(!$r)
358
- {
359
- throw new Exception("Couldn't create {$parentDir}");
360
- }
361
- }
362
-
363
- $destFileHandle = fopen($destFilePath, 'wb+');
364
-
365
  if ($destFileHandle === false) {
366
  throw new Exception("Couldn't open {$destFilePath} for writing.");
367
  }
@@ -377,14 +374,14 @@ class DupArchiveMiniExpander
377
 
378
  fclose($destFileHandle);
379
 
380
- @chmod($destFilePath, 0644);
381
 
382
  self::validateExpandedFile($writeInfo);
383
  } else {
384
  if(touch($destFilePath) === false) {
385
  throw new Exception("Couldn't create $destFilePath");
386
  }
387
- @chmod($destFilePath, 0644);
388
  }
389
  }
390
 
148
  private function __construct()
149
  {
150
  // Prevent instantiation
151
+ if (!class_exists('DUPX_Bootstrap')) {
152
+ throw new Exception('Class DUPX_Bootstrap not found');
153
+ }
154
  }
155
 
156
  public static function readFromArchive($archiveHandle)
296
  // $mode = $directoryHeader->permissions;
297
 
298
  // rodo handle this more elegantly @mkdir($directory, $directoryHeader->permissions, true);
299
+ DUPX_Bootstrap::mkdir($directory, 'u+rwx', true);
300
 
301
 
302
  $writeInfo->directoryWriteCount++;
352
  {
353
  /* @var $writeInfo DupArchiveMiniWriteInfo */
354
  $parentDir = dirname($destFilePath);
 
355
  if (!file_exists($parentDir)) {
356
+ if (!DUPX_Bootstrap::mkdir($parentDir, 'u+rwx', true)) {
357
+ throw new Exception("Couldn't create {$parentDir}");
358
+ }
359
+ }
360
 
361
+ $destFileHandle = fopen($destFilePath, 'wb+');
 
 
 
 
 
 
 
 
 
362
  if ($destFileHandle === false) {
363
  throw new Exception("Couldn't open {$destFilePath} for writing.");
364
  }
374
 
375
  fclose($destFileHandle);
376
 
377
+ DUPX_Bootstrap::chmod($destFilePath, 'u+rw');
378
 
379
  self::validateExpandedFile($writeInfo);
380
  } else {
381
  if(touch($destFilePath) === false) {
382
  throw new Exception("Couldn't create $destFilePath");
383
  }
384
+ DUPX_Bootstrap::chmod($destFilePath, 'u+rw');
385
  }
386
  }
387
 
lib/dup_archive/classes/processors/class.duparchive.processor.file.php CHANGED
@@ -113,10 +113,7 @@ class DupArchiveFileProcessor
113
 
114
  $moreGlobstoProcess = true;
115
 
116
- if (!file_exists($parentDir)) {
117
-
118
- DupLiteSnapLibIOU::mkdir($parentDir, 0755, true);
119
- }
120
 
121
  if ($expandState->currentFileHeader->fileSize > 0) {
122
 
@@ -192,9 +189,9 @@ class DupArchiveFileProcessor
192
  }
193
 
194
  if (!$moreGlobstoProcess && $expandState->validateOnly && ($expandState->validationType == DupArchiveValidationTypes::Full)) {
195
-
196
- @chmod($destFilepath, 0644);
197
-
198
  if (@unlink($destFilepath) === false) {
199
  // $expandState->addFailure(DupArchiveFailureTypes::File, $destFilepath, "Couldn't delete {$destFilepath} during validation", false);
200
  // TODO: Have to know how to handle this - want to report it but don’t want to mess up validation - some non critical errors could be important to validation
@@ -256,14 +253,11 @@ class DupArchiveFileProcessor
256
 
257
  public static function setFileMode($expandState, $filePath)
258
  {
259
- $mode = $expandState->currentFileHeader->permissions;
260
-
261
- if($expandState->fileModeOverride != -1) {
262
-
263
  $mode = $expandState->fileModeOverride;
264
  }
265
-
266
- @chmod($filePath, $mode);
267
  }
268
 
269
  public static function standardValidateFileEntry(&$expandState, $archiveHandle)
113
 
114
  $moreGlobstoProcess = true;
115
 
116
+ DupLiteSnapLibIOU::dirWriteCheckOrMkdir($parentDir, 'u+rwx');
 
 
 
117
 
118
  if ($expandState->currentFileHeader->fileSize > 0) {
119
 
189
  }
190
 
191
  if (!$moreGlobstoProcess && $expandState->validateOnly && ($expandState->validationType == DupArchiveValidationTypes::Full)) {
192
+ if (!is_writable($destFilepath)) {
193
+ DupLiteSnapLibIOU::chmod($destFilepath, 'u+rw');
194
+ }
195
  if (@unlink($destFilepath) === false) {
196
  // $expandState->addFailure(DupArchiveFailureTypes::File, $destFilepath, "Couldn't delete {$destFilepath} during validation", false);
197
  // TODO: Have to know how to handle this - want to report it but don’t want to mess up validation - some non critical errors could be important to validation
253
 
254
  public static function setFileMode($expandState, $filePath)
255
  {
256
+ $mode = 'u+rw';
257
+ if($expandState->fileModeOverride !== -1) {
 
 
258
  $mode = $expandState->fileModeOverride;
259
  }
260
+ DupLiteSnapLibIOU::chmod($filePath, $mode);
 
261
  }
262
 
263
  public static function standardValidateFileEntry(&$expandState, $archiveHandle)
lib/dup_archive/daws/daws.php CHANGED
@@ -131,7 +131,7 @@ class DAWS
131
  $expandState->filteredFiles = $filteredFiles;
132
  $expandState->fileRenames = $fileRenames;
133
  $expandState->fileModeOverride = 0644;
134
- $expandState->directoryModeOverride = 0755;
135
 
136
  $expandState->save();
137
  }
131
  $expandState->filteredFiles = $filteredFiles;
132
  $expandState->fileRenames = $fileRenames;
133
  $expandState->fileModeOverride = 0644;
134
+ $expandState->directoryModeOverride = 'u+rwx';
135
 
136
  $expandState->save();
137
  }
lib/snaplib/class.snaplib.u.io.php CHANGED
@@ -37,8 +37,7 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
37
  foreach ($filePaths as $filePath) {
38
  $modes[] = $mode;
39
  }
40
-
41
- @array_map('chmod', $filePaths, $modes);
42
  }
43
 
44
  public static function copy($source, $dest, $overwriteIfExists = true)
@@ -71,8 +70,8 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
71
 
72
  $destination = rtrim($destination, '/\\');
73
 
74
- if (!file_exists($destination)) {
75
- self::mkdir($destination);
76
  }
77
 
78
  foreach ($fileSystemObjects as $fileSystemObject) {
@@ -126,11 +125,8 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
126
 
127
  public static function fopen($filepath, $mode, $throwOnError = true)
128
  {
129
- if (DupLiteSnapLibOSU::$isWindows) {
130
-
131
- if (strlen($filepath) > DupLiteSnapLibOSU::WindowsMaxPathLength) {
132
- throw new Exception("Skipping a file that exceeds allowed Windows path length. File: {$filepath}");
133
- }
134
  }
135
 
136
  if (DupLiteSnapLibStringU::startsWith($mode, 'w') || DupLiteSnapLibStringU::startsWith($mode, 'c') || file_exists($filepath)) {
@@ -168,7 +164,7 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
168
  public static function rmdir($dirname, $mustExist = false)
169
  {
170
  if (file_exists($dirname)) {
171
- @chmod($dirname, 0755);
172
  if (@rmdir($dirname) === false) {
173
  throw new Exception("Couldn't remove {$dirname}");
174
  }
@@ -180,7 +176,7 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
180
  public static function rm($filepath, $mustExist = false)
181
  {
182
  if (file_exists($filepath)) {
183
- @chmod($filepath, 0644);
184
  if (@unlink($filepath) === false) {
185
  throw new Exception("Couldn't remove {$filepath}");
186
  }
@@ -296,31 +292,33 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
296
  return $mtime;
297
  }
298
 
299
- public static function mkdir($pathname, $mode = 0755, $recursive = false)
 
 
 
 
 
 
 
 
300
  {
301
- if (DupLiteSnapLibOSU::$isWindows) {
302
-
303
- if (strlen($pathname) > DupLiteSnapLibOSU::WindowsMaxPathLength) {
304
- throw new Exception("Skipping creating directory that exceeds allowed Windows path length. File: {$pathname}");
305
- }
306
  }
307
-
308
- if (!file_exists($pathname)) {
309
- if (@mkdir($pathname, $mode, $recursive) === false) {
310
- throw new Exception("Error creating directory {$pathname}");
311
- }
312
- } else {
313
- if (@chmod($pathname, $mode) === false) {
314
- throw new Exception("Error setting mode on directory {$pathname}");
315
- }
316
  }
317
- }
318
-
319
- public static function filePutContents($filename, $data)
320
- {
321
  if (file_put_contents($filename, $data) === false) {
322
- throw new Exception("Couldn't write data to {$filename}");
323
  }
 
324
  }
325
 
326
  public static function getFileName($file_path)
@@ -334,5 +332,187 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
334
  $info = new SplFileInfo($file_path);
335
  return $info->getPath();
336
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  }
338
  }
37
  foreach ($filePaths as $filePath) {
38
  $modes[] = $mode;
39
  }
40
+ array_map(array(__CLASS__, 'chmod'), $filePaths, $modes);
 
41
  }
42
 
43
  public static function copy($source, $dest, $overwriteIfExists = true)
70
 
71
  $destination = rtrim($destination, '/\\');
72
 
73
+ if (!file_exists($destination) || !is_writeable($destination)) {
74
+ self::mkdir($destination, 'u+rwx');
75
  }
76
 
77
  foreach ($fileSystemObjects as $fileSystemObject) {
125
 
126
  public static function fopen($filepath, $mode, $throwOnError = true)
127
  {
128
+ if (strlen($filepath) > DupLiteSnapLibOSU::maxPathLen()) {
129
+ throw new Exception('Skipping a file that exceeds allowed max path length ['.DupLiteSnapLibOSU::maxPathLen().']. File: '.$filepath);
 
 
 
130
  }
131
 
132
  if (DupLiteSnapLibStringU::startsWith($mode, 'w') || DupLiteSnapLibStringU::startsWith($mode, 'c') || file_exists($filepath)) {
164
  public static function rmdir($dirname, $mustExist = false)
165
  {
166
  if (file_exists($dirname)) {
167
+ self::chmod($dirname, 'u+rwx');
168
  if (@rmdir($dirname) === false) {
169
  throw new Exception("Couldn't remove {$dirname}");
170
  }
176
  public static function rm($filepath, $mustExist = false)
177
  {
178
  if (file_exists($filepath)) {
179
+ self::chmod($filepath, 'u+rw');
180
  if (@unlink($filepath) === false) {
181
  throw new Exception("Couldn't remove {$filepath}");
182
  }
292
  return $mtime;
293
  }
294
 
295
+ /**
296
+ * exetute a file put contents after some checks. throw exception if fail.
297
+ *
298
+ * @param string $filename
299
+ * @param mixed $data
300
+ * @return boolean
301
+ * @throws Exception if putcontents fails
302
+ */
303
+ public static function filePutContents($filename, $data)
304
  {
305
+ if (($dirFile = realpath(dirname($filename))) === false) {
306
+ throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [realpath fail]');
 
 
 
307
  }
308
+ if (!is_dir($dirFile)) {
309
+ throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [dir '.$dirFile.' don\'t exists]');
310
+ }
311
+ if (!is_writable($dirFile)) {
312
+ throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [dir '.$dirFile.' exists but isn\'t writable]');
313
+ }
314
+ $realFileName = $dirFile.basename($filename);
315
+ if (file_exists($realFileName) && !is_writable($realFileName)) {
316
+ throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [file exist '.$realFileName.' but isn\'t writable');
317
  }
 
 
 
 
318
  if (file_put_contents($filename, $data) === false) {
319
+ throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [Couldn\'t write data to '.$realFileName.']');
320
  }
321
+ return true;
322
  }
323
 
324
  public static function getFileName($file_path)
332
  $info = new SplFileInfo($file_path);
333
  return $info->getPath();
334
  }
335
+
336
+ /**
337
+ * this function make a chmod only if the are different from perms input and if chmod function is enabled
338
+ *
339
+ * this function handles the variable MODE in a way similar to the chmod of lunux
340
+ * So the MODE variable can be
341
+ * 1) an octal number (0755)
342
+ * 2) a string that defines an octal number ("644")
343
+ * 3) a string with the following format [ugoa]*([-+=]([rwx]*)+
344
+ *
345
+ * examples
346
+ * u+rw add read and write at the user
347
+ * u+rw,uo-wx add read and write ad the user and remove wx at groupd and other
348
+ * a=rw is equal at 666
349
+ * u=rwx,go-rwx is equal at 700
350
+ *
351
+ * @param string $file
352
+ * @param int|string $mode
353
+ * @return boolean
354
+ */
355
+ public static function chmod($file, $mode)
356
+ {
357
+ if (!file_exists($file)) {
358
+ return false;
359
+ }
360
+
361
+ $octalMode = 0;
362
+
363
+ if (is_int($mode)) {
364
+ $octalMode = $mode;
365
+ } else if (is_string($mode)) {
366
+ $mode = trim($mode);
367
+ if (preg_match('/([0-7]{1,3})/', $mode)) {
368
+ $octalMode = intval(('0'.$mode), 8);
369
+ } else if (preg_match_all('/(a|[ugo]{1,3})([-=+])([rwx]{1,3})/', $mode, $gMatch, PREG_SET_ORDER)) {
370
+ if (!function_exists('fileperms')) {
371
+ return false;
372
+ }
373
+
374
+ // start by file permission
375
+ $octalMode = (fileperms($file) & 0777);
376
+
377
+ foreach ($gMatch as $matches) {
378
+ // [ugo] or a = ugo
379
+ $group = $matches[1];
380
+ if ($group === 'a') {
381
+ $group = 'ugo';
382
+ }
383
+ // can be + - =
384
+ $action = $matches[2];
385
+ // [rwx]
386
+ $gPerms = $matches[3];
387
+
388
+ // reset octal group perms
389
+ $octalGroupMode = 0;
390
+
391
+ // Init sub perms
392
+ $subPerm = 0;
393
+ $subPerm += strpos($gPerms, 'x') !== false ? 1 : 0; // mask 001
394
+ $subPerm += strpos($gPerms, 'w') !== false ? 2 : 0; // mask 010
395
+ $subPerm += strpos($gPerms, 'r') !== false ? 4 : 0; // mask 100
396
+
397
+ $ugoLen = strlen($group);
398
+
399
+ if ($action === '=') {
400
+ // generate octal group permsissions and ugo mask invert
401
+ $ugoMaskInvert = 0777;
402
+ for ($i = 0; $i < $ugoLen; $i++) {
403
+ switch ($group[$i]) {
404
+ case 'u':
405
+ $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
406
+ $ugoMaskInvert = $ugoMaskInvert & 077;
407
+ break;
408
+ case 'g':
409
+ $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
410
+ $ugoMaskInvert = $ugoMaskInvert & 0707;
411
+ break;
412
+ case 'o':
413
+ $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
414
+ $ugoMaskInvert = $ugoMaskInvert & 0770;
415
+ break;
416
+ }
417
+ }
418
+ // apply = action
419
+ $octalMode = $octalMode & ($ugoMaskInvert | $octalGroupMode);
420
+ } else {
421
+ // generate octal group permsissions
422
+ for ($i = 0; $i < $ugoLen; $i++) {
423
+ switch ($group[$i]) {
424
+ case 'u':
425
+ $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
426
+ break;
427
+ case 'g':
428
+ $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
429
+ break;
430
+ case 'o':
431
+ $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
432
+ break;
433
+ }
434
+ }
435
+ // apply + or - action
436
+ switch ($action) {
437
+ case '+':
438
+ $octalMode = $octalMode | $octalGroupMode;
439
+ break;
440
+ case '-':
441
+ $octalMode = $octalMode & ~$octalGroupMode;
442
+ break;
443
+ }
444
+ }
445
+ }
446
+ }
447
+ }
448
+
449
+ // if input permissions are equal at file permissions return true without performing chmod
450
+ if (function_exists('fileperms') && $octalMode === (fileperms($file) & 0777)) {
451
+ return true;
452
+ }
453
+
454
+ if (!function_exists('chmod')) {
455
+ return false;
456
+ }
457
+
458
+ return @chmod($file, $octalMode);
459
+ }
460
+
461
+ /**
462
+ * this function creates a folder if it does not exist and performs a chmod.
463
+ * it is different from the normal mkdir function to which an umask is applied to the input permissions.
464
+ *
465
+ * this function handles the variable MODE in a way similar to the chmod of lunux
466
+ * So the MODE variable can be
467
+ * 1) an octal number (0755)
468
+ * 2) a string that defines an octal number ("644")
469
+ * 3) a string with the following format [ugoa]*([-+=]([rwx]*)+
470
+ *
471
+ * @param string $path
472
+ * @param int|string $mode
473
+ * @param bool $recursive
474
+ * @param resource $context // not used fo windows bug
475
+ * @return boolean bool TRUE on success or FALSE on failure.
476
+ *
477
+ * @todo check recursive true and multiple chmod
478
+ */
479
+ public static function mkdir($path, $mode = 0777, $recursive = false, $context = null)
480
+ {
481
+ if (strlen($path) > DupLiteSnapLibOSU::maxPathLen()) {
482
+ throw new Exception('Skipping a file that exceeds allowed max path length ['.DupLiteSnapLibOSU::maxPathLen().']. File: '.$filepath);
483
+ }
484
+
485
+ if (!file_exists($path)) {
486
+ if (!function_exists('mkdir')) {
487
+ return false;
488
+ }
489
+ if (!@mkdir($path, 0777, $recursive)) {
490
+ return false;
491
+ }
492
+ }
493
+
494
+ return self::chmod($path, $mode);
495
+ }
496
+
497
+ /**
498
+ * this function call snap mkdir if te folder don't exists od don't have write or exec permissions
499
+ *
500
+ * this function handles the variable MODE in a way similar to the chmod of lunux
501
+ * The mode variable can be set to have more flexibility but not giving the user write and read and exec permissions doesn't make much sense
502
+ *
503
+ * @param string $path
504
+ * @param int|string $mode
505
+ * @param bool $recursive
506
+ * @param resource $context
507
+ * @return boolean
508
+ */
509
+ public static function dirWriteCheckOrMkdir($path, $mode = 'u+rwx', $recursive = false, $context = null)
510
+ {
511
+ if (!is_writable($path) || !is_executable($path)) {
512
+ return self::mkdir($path, $mode, $recursive, $context);
513
+ } else {
514
+ return true;
515
+ }
516
+ }
517
  }
518
  }
lib/snaplib/class.snaplib.u.os.php CHANGED
@@ -16,15 +16,41 @@ if (!class_exists('DupLiteSnapLibOSU', false)) {
16
 
17
  class DupLiteSnapLibOSU
18
  {
19
- const WindowsMaxPathLength = 259;
 
20
 
21
- public static $isWindows;
22
-
23
- public static function init()
 
 
 
 
24
  {
 
 
 
 
 
 
25
 
26
- self::$isWindows = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
  }
29
- DupLiteSnapLibOSU::init();
30
  }
16
 
17
  class DupLiteSnapLibOSU
18
  {
19
+ const DEFAULT_WINDOWS_MAXPATH = 260;
20
+ const DEFAULT_LINUX_MAXPATH = 4096;
21
 
22
+ /**
23
+ * return true if current SO is windows
24
+ *
25
+ * @staticvar bool $isWindows
26
+ * @return bool
27
+ */
28
+ public static function isWindows()
29
  {
30
+ static $isWindows = null;
31
+ if (is_null($isWindows)) {
32
+ $isWindows = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
33
+ }
34
+ return $isWindows;
35
+ }
36
 
37
+ /**
38
+ * return current SO path path len
39
+ * @staticvar int $maxPath
40
+ * @return int
41
+ */
42
+ public static function maxPathLen()
43
+ {
44
+ static $maxPath = null;
45
+ if (is_null($maxPath)) {
46
+ if (defined('PHP_MAXPATHLEN')) {
47
+ $maxPath = PHP_MAXPATHLEN;
48
+ } else {
49
+ // for PHP < 5.3.0
50
+ $maxPath = self::isWindows() ? self::DEFAULT_WINDOWS_MAXPATH : self::DEFAULT_LINUX_MAXPATH;
51
+ }
52
+ }
53
+ return $maxPath;
54
  }
55
  }
 
56
  }
lib/snaplib/class.snaplib.u.util.php CHANGED
@@ -62,7 +62,7 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
62
  public static function getWorkPercent($startingPercent, $endingPercent, $totalTaskCount, $currentTaskCount)
63
  {
64
  if ($totalTaskCount > 0) {
65
- $percent = floor($startingPercent + (($endingPercent - $startingPercent) * ($currentTaskCount / (float) $totalTaskCount)));
66
  } else {
67
  $percent = 0;
68
  }
62
  public static function getWorkPercent($startingPercent, $endingPercent, $totalTaskCount, $currentTaskCount)
63
  {
64
  if ($totalTaskCount > 0) {
65
+ $percent = ($startingPercent + (($endingPercent - $startingPercent) * ($currentTaskCount / (float) $totalTaskCount)));
66
  } else {
67
  $percent = 0;
68
  }
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.2
6
  Requires PHP: 5.2.17
7
- Stable tag: 1.3.14
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.2
6
  Requires PHP: 5.2.17
7
+ Stable tag: 1.3.16
8
  License: GPLv2
9
 
10
  WordPress migration and backups are much easier with Duplicator! Clone, backup, move and transfer an entire site from one location to another.
views/packages/controller.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
 
 
3
  DUP_Util::hasCapability('export');
4
 
5
  global $wpdb;
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+
4
+ DUP_Handler::init_error_handler();
5
  DUP_Util::hasCapability('export');
6
 
7
  global $wpdb;
views/packages/main/controller.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
 
3
  require_once(DUPLICATOR_PLUGIN_PATH . '/classes/ui/class.ui.dialog.php');
 
4
  $current_tab = isset($_REQUEST['tab']) ? sanitize_text_field($_REQUEST['tab']) : 'list';
5
  $_GET['_wpnonce'] = isset($_GET['_wpnonce']) ? $_GET['_wpnonce'] : null;
6
 
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+
4
  require_once(DUPLICATOR_PLUGIN_PATH . '/classes/ui/class.ui.dialog.php');
5
+
6
  $current_tab = isset($_REQUEST['tab']) ? sanitize_text_field($_REQUEST['tab']) : 'list';
7
  $_GET['_wpnonce'] = isset($_GET['_wpnonce']) ? $_GET['_wpnonce'] : null;
8
 
views/packages/main/packages.php CHANGED
@@ -278,7 +278,7 @@ $alert2->initAlert();
278
 
279
  $confirm1 = new DUP_UI_Dialog();
280
  $confirm1->title = __('Delete Packages?', 'duplicator');
281
- $confirm1->message = __('Are you sure, you want to delete the selected package(s)?', 'duplicator');
282
  $confirm1->progressText = __('Removing Packages, Please Wait...', 'duplicator');
283
  $confirm1->jscallback = 'Duplicator.Pack.Delete()';
284
  $confirm1->initConfirm();
278
 
279
  $confirm1 = new DUP_UI_Dialog();
280
  $confirm1->title = __('Delete Packages?', 'duplicator');
281
+ $confirm1->message = __('Are you sure you want to delete the selected package(s)?', 'duplicator');
282
  $confirm1->progressText = __('Removing Packages, Please Wait...', 'duplicator');
283
  $confirm1->jscallback = 'Duplicator.Pack.Delete()';
284
  $confirm1->initConfirm();
views/packages/main/s1.setup2.php CHANGED
@@ -663,5 +663,7 @@ jQuery(document).ready(function ($)
663
  Duplicator.Pack.ToggleDBFilters();
664
  Duplicator.Pack.ExportOnlyDB();
665
  Duplicator.Pack.EnableInstallerPassword();
 
 
666
  });
667
  </script>
663
  Duplicator.Pack.ToggleDBFilters();
664
  Duplicator.Pack.ExportOnlyDB();
665
  Duplicator.Pack.EnableInstallerPassword();
666
+ $('input#package-name').focus().select();
667
+
668
  });
669
  </script>
views/packages/main/s3.build.php CHANGED
@@ -502,7 +502,7 @@ jQuery(document).ready(function ($)
502
 
503
  for (var j = 0; j < len; j++) {
504
  failure = data.failures[j];
505
- errorMessage += failure.subject + ":" + failure.description + "\n";
506
  }
507
  alert(errorMessage);
508
  }
502
 
503
  for (var j = 0; j < len; j++) {
504
  failure = data.failures[j];
505
+ errorMessage += failure + "\n";
506
  }
507
  alert(errorMessage);
508
  }
views/settings/controller.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
 
 
4
  DUP_Util::hasCapability('manage_options');
5
 
6
  global $wpdb;
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
 
4
+ DUP_Handler::init_error_handler();
5
  DUP_Util::hasCapability('manage_options');
6
 
7
  global $wpdb;
views/settings/gopro.php CHANGED
@@ -216,7 +216,7 @@ require_once(DUPLICATOR_PLUGIN_PATH . '/views/inc.header.php');
216
  <?php esc_html_e('Active Customer Support', 'duplicator') ?>
217
  <sup><i class="fa fa-question-circle dup-gopro-help"
218
  data-tooltip-title="<?php esc_attr_e("Support", 'duplicator'); ?>"
219
- data-tooltip="<?php esc_attr_e('Pro users get top priority for any requestst to our support desk. In most cases responses will be answered in under 24 hours.', 'duplicator'); ?>"/></i></sup>
220
  </td>
221
  <td class="check-column"></td>
222
  <td class="check-column"><i class="fa fa-check"></i></td>
@@ -236,4 +236,4 @@ require_once(DUPLICATOR_PLUGIN_PATH . '/views/inc.header.php');
236
  </p>
237
  <br/><br/>
238
  </div>
239
- <br/><br/>
216
  <?php esc_html_e('Active Customer Support', 'duplicator') ?>
217
  <sup><i class="fa fa-question-circle dup-gopro-help"
218
  data-tooltip-title="<?php esc_attr_e("Support", 'duplicator'); ?>"
219
+ data-tooltip="<?php esc_attr_e('Pro users get top priority for any requests to our support desk. In most cases responses will be answered in under 24 hours.', 'duplicator'); ?>"/></i></sup>
220
  </td>
221
  <td class="check-column"></td>
222
  <td class="check-column"><i class="fa fa-check"></i></td>
236
  </p>
237
  <br/><br/>
238
  </div>
239
+ <br/><br/>
views/tools/controller.php CHANGED
@@ -6,6 +6,8 @@ require_once(DUPLICATOR_PLUGIN_PATH . '/views/inc.header.php');
6
 
7
  global $wpdb;
8
  global $wp_version;
 
 
9
  DUP_Util::hasCapability('manage_options');
10
  $current_tab = isset($_REQUEST['tab']) ? esc_html($_REQUEST['tab']) : 'diagnostics';
11
  if ('d' == $current_tab) {
6
 
7
  global $wpdb;
8
  global $wp_version;
9
+
10
+ DUP_Handler::init_error_handler();
11
  DUP_Util::hasCapability('manage_options');
12
  $current_tab = isset($_REQUEST['tab']) ? esc_html($_REQUEST['tab']) : 'diagnostics';
13
  if ('d' == $current_tab) {