· 5 years ago · Apr 20, 2020, 12:00 PM
1<?php
2
3if ( !defined('DUPXABSPATH') ) {
4 define('DUPXABSPATH', dirname(__FILE__));
5}
6
7if (!defined('KB_IN_BYTES')) { define('KB_IN_BYTES', 1024); }
8if (!defined('MB_IN_BYTES')) { define('MB_IN_BYTES', 1024 * KB_IN_BYTES); }
9if (!defined('GB_IN_BYTES')) { define('GB_IN_BYTES', 1024 * MB_IN_BYTES); }
10if (!defined('DUPLICATOR_PHP_MAX_MEMORY')) { define('DUPLICATOR_PHP_MAX_MEMORY', 4096 * MB_IN_BYTES); }
11
12date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here.
13@ignore_user_abort(true);
14
15if (!function_exists('wp_is_ini_value_changeable')) {
16 /**
17 * Determines whether a PHP ini value is changeable at runtime.
18 *
19 * @staticvar array $ini_all
20 *
21 * @link https://secure.php.net/manual/en/function.ini-get-all.php
22 *
23 * @param string $setting The name of the ini setting to check.
24 * @return bool True if the value is changeable at runtime. False otherwise.
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".
32 if ( function_exists( 'ini_get_all' ) ) {
33 $ini_all = ini_get_all();
34 }
35 }
36
37 // Bit operator to workaround https://bugs.php.net/bug.php?id=44936 which changes access level to 63 in PHP 5.2.6 - 5.2.17.
38 if ( isset( $ini_all[ $setting ]['access'] ) && ( INI_ALL === ( $ini_all[ $setting ]['access'] & 7 ) || INI_USER === ( $ini_all[ $setting ]['access'] & 7 ) ) ) {
39 return true;
40 }
41
42 // If we were unable to retrieve the details, fail gracefully to assume it's changeable.
43 if ( ! is_array( $ini_all ) ) {
44 return true;
45 }
46
47 return false;
48 }
49}
50
51@set_time_limit(3600);
52if (wp_is_ini_value_changeable('memory_limit'))
53 @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY);
54if (wp_is_ini_value_changeable('max_input_time'))
55 @ini_set('max_input_time', '-1');
56if (wp_is_ini_value_changeable('pcre.backtrack_limit'))
57 @ini_set('pcre.backtrack_limit', PHP_INT_MAX);
58if (wp_is_ini_value_changeable('default_socket_timeout'))
59 @ini_set('default_socket_timeout', 3600);
60
61class 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
189 *
190 * Standard: PSR-2
191 *
192 * @package SC\DUPX\Bootstrap
193 * @link http://www.php-fig.org/psr/psr-2/
194 *
195 * To force extraction mode:
196 * installer.php?unzipmode=auto
197 * installer.php?unzipmode=ziparchive
198 * installer.php?unzipmode=shellexec
199 */
200
201abstract class DUPX_Bootstrap_Zip_Mode
202{
203 const AutoUnzip = 0;
204 const ZipArchive = 1;
205 const ShellExec = 2;
206}
207
208abstract class DUPX_Connectivity
209{
210 const OK = 0;
211 const Error = 1;
212 const Unknown = 2;
213}
214
215class DUPX_Bootstrap
216{
217 //@@ Params get dynamically swapped when package is built
218 const ARCHIVE_FILENAME = '20191011_koleksifilmdewasaonline_0ab7c0640585ac929146_20191011162617_archive.zip';
219 const ARCHIVE_SIZE = '211267807';
220 const INSTALLER_DIR_NAME = 'dup-installer';
221 const PACKAGE_HASH = '0ab7c06-11162617';
222 const VERSION = '1.3.14';
223
224 public $hasZipArchive = false;
225 public $hasShellExecUnzip = false;
226 public $mainInstallerURL;
227 public $installerContentsPath;
228 public $installerExtractPath;
229 public $archiveExpectedSize = 0;
230 public $archiveActualSize = 0;
231 public $activeRatio = 0;
232
233 /**
234 * Instantiate the Bootstrap Object
235 *
236 * @return null
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);
243 $archiveActualSize = ($archiveActualSize !== false) ? $archiveActualSize : 0;
244 $this->hasZipArchive = class_exists('ZipArchive');
245 $this->hasShellExecUnzip = $this->getUnzipFilePath() != null ? true : false;
246 $this->installerContentsPath = str_replace("\\", '/', (dirname(__FILE__). '/' .self::INSTALLER_DIR_NAME));
247 $this->installerExtractPath = str_replace("\\", '/', (dirname(__FILE__)));
248 $this->archiveExpectedSize = strlen(self::ARCHIVE_SIZE) ? self::ARCHIVE_SIZE : 0 ;
249 $this->archiveActualSize = $archiveActualSize;
250
251 if($this->archiveExpectedSize > 0) {
252 $this->archiveRatio = (((1.0) * $this->archiveActualSize) / $this->archiveExpectedSize) * 100;
253 } else {
254 $this->archiveRatio = 100;
255 }
256
257 $this->overwriteMode = (isset($_GET['mode']) && ($_GET['mode'] == 'overwrite'));
258 }
259
260 /**
261 * Run the bootstrap process which includes checking for requirements and running
262 * the extraction process
263 *
264 * @return null | string Returns null if the run was successful otherwise an error message
265 */
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 v1.3.14==');
271 self::log('----------------------------------------------------');
272 self::log('Installer bootstrap start');
273
274 $archive_filepath = $this->getArchiveFilePath();
275 $archive_filename = self::ARCHIVE_FILENAME;
276
277 $error = null;
278 $extract_installer = true;
279 $installer_directory = dirname(__FILE__).'/'.self::INSTALLER_DIR_NAME;
280 $extract_success = false;
281 $archiveExpectedEasy = $this->readableByteSize($this->archiveExpectedSize);
282 $archiveActualEasy = $this->readableByteSize($this->archiveActualSize);
283
284 //$archive_extension = strtolower(pathinfo($archive_filepath)['extension']);
285 $archive_extension = strtolower(pathinfo($archive_filepath, PATHINFO_EXTENSION));
286 $manual_extract_found = (
287 file_exists($installer_directory."/main.installer.php")
288 &&
289 file_exists($installer_directory."/dup-archive__".self::PACKAGE_HASH.".txt")
290 &&
291 file_exists($installer_directory."/dup-database__".self::PACKAGE_HASH.".sql")
292 );
293
294 $isZip = ($archive_extension == 'zip');
295
296 //MANUAL EXTRACTION NOT FOUND
297 if (! $manual_extract_found) {
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 -";
305
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/>"
318 . "If this message continues even with a valid archive file, consider clearing your browsers cache and refreshing, trying another browser or change the browsers "
319 . "URL from http to https or vice versa.<br/><br/> "
320 . "<b>Required File:</b> <span class='file-info'>{$archive_filename}</span> <br/>"
321 . "<b>Extraction Path:</b> <span class='file-info'>{$this->installerExtractPath}/</span><br/><br/>"
322 . "Potential archives found at extraction path: <br/>{$candidate_html}<br/><br/>";
323
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'" : '';
357 $error = "<b>Archive file size warning.</b><br/> The expected archive size should be around <b class='pass'>[{$archiveExpectedEasy}]</b>. "
358 . "The actual size is currently <b class='fail'>[{$archiveActualEasy}]</b>. The archive file may not have fully been downloaded to the server. "
359 . "Please validate that the file sizes are close to the same size and that the file has been completely downloaded to the destination server. If the archive is still "
360 . "downloading then refresh this page to get an update on the download size.<br/><br/>";
361
362 return $error;
363 }
364
365 }
366
367
368 // OLD COMPATIBILITY MODE
369 if (isset($_GET['extract-installer']) && !isset($_GET['force-extract-installer'])) {
370 $_GET['force-extract-installer'] = $_GET['extract-installer'];
371 }
372
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;
393 if (is_file($object_file_path)) {
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 }
401 }
402 }
403
404 //ATTEMPT EXTRACTION:
405 //ZipArchive and Shell Exec
406 if ($extract_installer) {
407 self::log("Ready to extract the installer");
408
409 self::log("Checking permission of destination folder");
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
430 if (($zip_mode == DUPX_Bootstrap_Zip_Mode::AutoUnzip) || ($zip_mode == DUPX_Bootstrap_Zip_Mode::ZipArchive) && class_exists('ZipArchive')) {
431 if ($this->hasZipArchive) {
432 self::log("ZipArchive exists so using that");
433 $extract_success = $this->extractInstallerZipArchive($archive_filepath);
434
435 if ($extract_success) {
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 }
447 } else {
448 self::log("WARNING: ZipArchive is not enabled.");
449 $error = "NOTICE: ZipArchive is not enabled on this server please talk to your host or server admin about enabling ";
450 $error .= "<a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-060-q'>ZipArchive</a> on this server. <br/>";
451 }
452 }
453
454 if (!$extract_success) {
455 if (($zip_mode == DUPX_Bootstrap_Zip_Mode::AutoUnzip) || ($zip_mode == DUPX_Bootstrap_Zip_Mode::ShellExec)) {
456 $unzip_filepath = $this->getUnzipFilePath();
457 if ($unzip_filepath != null) {
458 $extract_success = $this->extractInstallerShellexec($archive_filepath);
459 if ($extract_success) {
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 {
467 self::log('WARNING: Shell Exec Zip is not available');
468 $error .= "NOTICE: Shell Exec is not enabled on this server please talk to your host or server admin about enabling ";
469 $error .= "<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.";
470 }
471 }
472 }
473
474 // If both ZipArchive and ShellZip are not available, Error message should be combined for both
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 }
481 }
482 } else {
483 DupArchiveMiniExpander::init("DUPX_Bootstrap::log");
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 }
491
492 $is_apache = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false);
493 $is_nginx = (strpos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false);
494
495 $sapi_type = php_sapi_name();
496 $php_ini_data = array(
497 'max_execution_time' => 3600,
498 'max_input_time' => -1,
499 'ignore_user_abort' => 'On',
500 'post_max_size' => '4096M',
501 'upload_max_filesize' => '4096M',
502 'memory_limit' => DUPLICATOR_PHP_MAX_MEMORY,
503 'default_socket_timeout' => 3600,
504 'pcre.backtrack_limit' => 99999999999,
505 );
506 $sapi_type_first_three_chars = substr($sapi_type, 0, 3);
507 if ('fpm' === $sapi_type_first_three_chars) {
508 self::log("SAPI: FPM");
509 if ($is_apache) {
510 self::log('Server: Apache');
511 } elseif ($is_nginx) {
512 self::log('Server: Nginx');
513 }
514
515 if (($is_apache && function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules())) || $is_nginx) {
516 $htaccess_data = array();
517 foreach ($php_ini_data as $php_ini_key=>$php_ini_val) {
518 if ($is_apache) {
519 $htaccess_data[] = 'SetEnv PHP_VALUE "'.$php_ini_key.' = '.$php_ini_val.'"';
520 } elseif ($is_nginx) {
521 if ('On' == $php_ini_val || 'Off' == $php_ini_val) {
522 $htaccess_data[] = 'php_flag '.$php_ini_key.' '.$php_ini_val;
523 } else {
524 $htaccess_data[] = 'php_value '.$php_ini_key.' '.$php_ini_val;
525 }
526 }
527 }
528
529 $htaccess_text = implode("\n", $htaccess_data);
530 $htaccess_file_path = dirname(__FILE__).'/dup-installer/.htaccess';
531 self::log("creating {$htaccess_file_path} with the content:");
532 self::log($htaccess_text);
533 @file_put_contents($htaccess_file_path, $htaccess_text);
534 }
535 } elseif ('cgi' === $sapi_type_first_three_chars || 'litespeed' === $sapi_type) {
536 if ('cgi' === $sapi_type_first_three_chars) {
537 self::log("SAPI: CGI");
538 } else {
539 self::log("SAPI: litespeed");
540 }
541 if (version_compare(phpversion(), 5.5) >= 0 && (!$is_apache || 'litespeed' === $sapi_type)) {
542 $ini_data = array();
543 foreach ($php_ini_data as $php_ini_key=>$php_ini_val) {
544 $ini_data[] = $php_ini_key.' = '.$php_ini_val;
545 }
546 $ini_text = implode("\n", $ini_data);
547 $ini_file_path = dirname(__FILE__).'/dup-installer/.user.ini';
548 self::log("creating {$ini_file_path} with the content:");
549 self::log($ini_text);
550 @file_put_contents($ini_file_path, $ini_text);
551 } else{
552 self::log("No need to create dup-installer/.htaccess or dup-installer/.user.ini");
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)) {
563 $config_files = glob('./dup-installer/dup-archive__*.txt');
564 $config_file_absolute_path = array_pop($config_files);
565 if (!file_exists($config_file_absolute_path)) {
566 $error = '<b>Archive config file not found in dup-installer folder.</b> <br><br>';
567 return $error;
568 }
569 }
570
571 $is_https = $this->isHttps();
572
573 if($is_https) {
574 $current_url = 'https://';
575 } else {
576 $current_url = 'http://';
577 }
578
579 if(($_SERVER['SERVER_PORT'] == 80) && ($is_https)) {
580 // Fixing what appears to be a bad server setting
581 $server_port = 443;
582 } else {
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 }
592
593 $current_url .= $_SERVER['REQUEST_URI'];
594 $uri_start = dirname($current_url);
595
596 $encoded_archive_path = urlencode($archive_filepath);
597
598 if ($error === null) {
599 $error = $this->postExtractProcessing();
600
601 if($error == null) {
602
603 $bootloader_name = basename(__FILE__);
604 $this->mainInstallerURL = $uri_start.'/'.self::INSTALLER_DIR_NAME.'/main.installer.php';
605
606 $this->fixInstallerPerms($this->mainInstallerURL);
607
608 $this->archive = $archive_filepath;
609 $this->bootloader = $bootloader_name;
610
611 if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
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
619 return $error;
620 }
621
622 public function postExtractProcessing()
623 {
624 $dproInstallerDir = dirname(__FILE__) . '/dup-installer';
625 $libDir = $dproInstallerDir . '/lib';
626 $fileopsDir = $libDir . '/fileops';
627
628 if(!file_exists($dproInstallerDir)) {
629
630 return 'Can\'t extract installer directory. See <a target="_blank" href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-022-q">this FAQ item</a> for details on how to resolve.</a>';
631 }
632
633 $sourceFilepath = "{$fileopsDir}/fileops.ppp";
634 $destFilepath = "{$fileopsDir}/fileops.php";
635
636 if(file_exists($sourceFilepath) && (!file_exists($destFilepath))) {
637 if(@rename($sourceFilepath, $destFilepath) === false) {
638 return "Error renaming {$sourceFilepath}";
639 }
640 }
641 }
642
643 /**
644 * Indicates if site is running https or not
645 *
646 * @return bool Returns true if https, false if not
647 */
648 public function isHttps()
649 {
650 $retVal = true;
651
652 if (isset($_SERVER['HTTPS'])) {
653 $retVal = ($_SERVER['HTTPS'] !== 'off');
654 } else {
655 $retVal = ($_SERVER['SERVER_PORT'] == 443);
656 }
657
658 return $retVal;
659 }
660
661 /**
662 * Attempts to set the 'dup-installer' directory permissions
663 *
664 * @return null
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);
678 $this->setPerms($installer_dir_path, $file_perms, true);
679 }
680
681 /**
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
689 */
690 private function setPerms($directory, $perms, $do_files)
691 {
692 if (!$do_files) {
693 // If setting a directory hiearchy be sure to include the base directory
694 $this->setPermsOnItem($directory, $perms);
695 }
696
697 $item_names = array_diff(scandir($directory), array('.', '..'));
698
699 foreach ($item_names as $item_name) {
700 $path = "$directory/$item_name";
701 if (($do_files && is_file($path)) || (!$do_files && !is_file($path))) {
702 $this->setPermsOnItem($path, $perms);
703 }
704 }
705 }
706
707 /**
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 /**
742 * Extracts only the 'dup-installer' files using ZipArchive
743 *
744 * @param string $archive_filepath The path to the archive file.
745 *
746 * @return bool Returns true if the data was properly extracted
747 */
748 private function extractInstallerZipArchive($archive_filepath, $checkSubFolder = false)
749 {
750 $success = true;
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.'/';
758 self::log("Extracting all files from archive within ".self::INSTALLER_DIR_NAME);
759
760 $this->installer_files_found = 0;
761
762 for ($i = 0; $i < $zipArchive->numFiles; $i++) {
763 $stat = $zipArchive->statIndex($i);
764 if ($checkSubFolder == false) {
765 $filenameCheck = $stat['name'];
766 $filename = $stat['name'];
767 $tmpSubFolder = null;
768 } else {
769 $safePath = rtrim(self::setSafePath($stat['name']) , '/');
770 $tmpArray = explode('/' , $safePath);
771
772 if (count($tmpArray) < 2) {
773 continue;
774 }
775
776 $tmpSubFolder = $tmpArray[0];
777 array_shift($tmpArray);
778 $filenameCheck = implode('/' , $tmpArray);
779 $filename = $stat['name'];
780 }
781
782
783 if ($this->startsWith($filenameCheck , $folder_prefix)) {
784 $this->installer_files_found++;
785
786 if (!empty($tmpSubFolder) && !in_array($tmpSubFolder , $subFolderArchiveList)) {
787 $subFolderArchiveList[] = $tmpSubFolder;
788 }
789
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 }
797 }
798 }
799
800 if ($checkSubFolder && count($subFolderArchiveList) !== 1) {
801 self::log("Error: Multiple dup subfolder archive");
802 $success = false;
803 } else {
804 if ($checkSubFolder) {
805 $this->moveUpfromSubFolder(dirname(__FILE__).'/'.$subFolderArchiveList[0] , true);
806 }
807
808 $lib_directory = dirname(__FILE__).'/'.self::INSTALLER_DIR_NAME.'/lib';
809 $snaplib_directory = $lib_directory.'/snaplib';
810
811 // If snaplib files aren't present attempt to extract and copy those
812 if(!file_exists($snaplib_directory))
813 {
814 $folder_prefix = 'snaplib/';
815 $destination = $lib_directory;
816
817 for ($i = 0; $i < $zipArchive->numFiles; $i++) {
818 $stat = $zipArchive->statIndex($i);
819 $filename = $stat['name'];
820
821 if ($this->startsWith($filename, $folder_prefix)) {
822 $this->installer_files_found++;
823
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 }
831 }
832 }
833 }
834 }
835
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 *
863 * @param string $subFolderName full path
864 * @param boolean $deleteSubFolder if true delete subFolder after moved all
865 * @return boolean
866 *
867 */
868 private function moveUpfromSubFolder($subFolderName, $deleteSubFolder = false)
869 {
870 if (!is_dir($subFolderName)) {
871 return false;
872 }
873
874 $parentFolder = dirname($subFolderName);
875 if (!is_writable($parentFolder)) {
876 return false;
877 }
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) {
885 $destination = $parentFolder.'/'.basename($cName);
886 if (file_exists($destination)) {
887 $success = self::deletePath($destination);
888 }
889
890 if ($success) {
891 $success = rename($cName, $destination);
892 } else {
893 break;
894 }
895 }
896
897 if ($success && $deleteSubFolder) {
898 $success = self::deleteDirectory($subFolderName, true);
899 }
900 }
901
902 if (!$success) {
903 self::log("Problem om moveUpfromSubFolder subFolder:".$subFolderName);
904 }
905
906 return $success;
907 }
908
909 /**
910 * Extracts only the 'dup-installer' files using Shell-Exec Unzip
911 *
912 * @param string $archive_filepath The path to the archive file.
913 *
914 * @return bool Returns true if the data was properly extracted
915 */
916 private function extractInstallerShellexec($archive_filepath)
917 {
918 $success = false;
919 self::log("Attempting to use Shell Exec");
920 $unzip_filepath = $this->getUnzipFilePath();
921
922 if ($unzip_filepath != null) {
923 $unzip_command = "$unzip_filepath -q $archive_filepath ".self::INSTALLER_DIR_NAME.'/* 2>&1';
924 self::log("Executing $unzip_command");
925 $stderr = shell_exec($unzip_command);
926
927 $lib_directory = dirname(__FILE__).'/'.self::INSTALLER_DIR_NAME.'/lib';
928 $snaplib_directory = $lib_directory.'/snaplib';
929
930 // If snaplib files aren't present attempt to extract and copy those
931 if(!file_exists($snaplib_directory))
932 {
933 $local_lib_directory = dirname(__FILE__).'/snaplib';
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
941 if ($stderr == '') {
942 self::log("Shell exec unzip succeeded");
943 $success = true;
944 } else {
945 self::log("Shell exec unzip failed. Output={$stderr}");
946 }
947 }
948
949 return $success;
950 }
951
952 /**
953 * Attempts to get the archive file path
954 *
955 * @return string The full path to the archive file
956 */
957 private function getArchiveFilePath()
958 {
959 if (isset($_GET['archive'])) {
960 $archive_filepath = $_GET['archive'];
961 } else {
962 $archive_filename = self::ARCHIVE_FILENAME;
963 $archive_filepath = str_replace("\\", '/', dirname(__FILE__) . '/' . $archive_filename);
964 }
965
966 self::log("Using archive $archive_filepath");
967 return $archive_filepath;
968 }
969
970 /**
971 * Gets the DUPX_Bootstrap_Zip_Mode enum type that should be used
972 *
973 * @return DUPX_Bootstrap_Zip_Mode Returns the current mode of the bootstrapper
974 */
975 private function getZipMode()
976 {
977 $zip_mode = DUPX_Bootstrap_Zip_Mode::AutoUnzip;
978
979 if (isset($_GET['zipmode'])) {
980 $zipmode_string = $_GET['zipmode'];
981 self::log("Unzip mode specified in querystring: $zipmode_string");
982
983 switch ($zipmode_string) {
984 case 'autounzip':
985 $zip_mode = DUPX_Bootstrap_Zip_Mode::AutoUnzip;
986 break;
987
988 case 'ziparchive':
989 $zip_mode = DUPX_Bootstrap_Zip_Mode::ZipArchive;
990 break;
991
992 case 'shellexec':
993 $zip_mode = DUPX_Bootstrap_Zip_Mode::ShellExec;
994 break;
995 }
996 }
997
998 return $zip_mode;
999 }
1000
1001 /**
1002 * Checks to see if a string starts with specific characters
1003 *
1004 * @return bool Returns true if the string starts with a specific format
1005 */
1006 private function startsWith($haystack, $needle)
1007 {
1008 return $needle === "" || strrpos($haystack, $needle, - strlen($haystack)) !== false;
1009 }
1010
1011 /**
1012 * Checks to see if the server supports issuing commands to shell_exex
1013 *
1014 * @return bool Returns true shell_exec can be ran on this server
1015 */
1016 public function hasShellExec()
1017 {
1018 $cmds = array('shell_exec', 'escapeshellarg', 'escapeshellcmd', 'extension_loaded');
1019
1020 //Function disabled at server level
1021 if (array_intersect($cmds, array_map('trim', explode(',', @ini_get('disable_functions'))))) return false;
1022
1023 //Suhosin: http://www.hardened-php.net/suhosin/
1024 //Will cause PHP to silently fail
1025 if (extension_loaded('suhosin')) {
1026 $suhosin_ini = @ini_get("suhosin.executor.func.blacklist");
1027 if (array_intersect($cmds, array_map('trim', explode(',', $suhosin_ini)))) return false;
1028 }
1029 // Can we issue a simple echo command?
1030 if (!@shell_exec('echo duplicator')) return false;
1031
1032 return true;
1033 }
1034
1035 /**
1036 * Gets the possible system commands for unzip on Linux
1037 *
1038 * @return string Returns unzip file path that can execute the unzip command
1039 */
1040 public function getUnzipFilePath()
1041 {
1042 $filepath = null;
1043
1044 if ($this->hasShellExec()) {
1045 if (shell_exec('hash unzip 2>&1') == NULL) {
1046 $filepath = 'unzip';
1047 } else {
1048 $possible_paths = array(
1049 '/usr/bin/unzip',
1050 '/opt/local/bin/unzip',
1051 '/bin/unzip',
1052 '/usr/local/bin/unzip',
1053 '/usr/sfw/bin/unzip',
1054 '/usr/xdg4/bin/unzip',
1055 '/opt/bin/unzip',
1056 // RSR TODO put back in when we support shellexec on windows,
1057 );
1058
1059 foreach ($possible_paths as $path) {
1060 if (file_exists($path)) {
1061 $filepath = $path;
1062 break;
1063 }
1064 }
1065 }
1066 }
1067
1068 return $filepath;
1069 }
1070
1071 /**
1072 * Display human readable byte sizes such as 150MB
1073 *
1074 * @param int $size The size in bytes
1075 *
1076 * @return string A readable byte size format such as 100MB
1077 */
1078 public function readableByteSize($size)
1079 {
1080 try {
1081 $units = array('B', 'KB', 'MB', 'GB', 'TB');
1082 for ($i = 0; $size >= 1024 && $i < 4; $i++)
1083 $size /= 1024;
1084 return round($size, 2).$units[$i];
1085 } catch (Exception $e) {
1086 return "n/a";
1087 }
1088 }
1089
1090 /**
1091 * Returns an array of zip files found in the current executing directory
1092 *
1093 * @return array of zip files
1094 */
1095 public static function getFilesWithExtension($extension)
1096 {
1097 $files = array();
1098 foreach (glob("*.{$extension}") as $name) {
1099 if (file_exists($name)) {
1100 $files[] = $name;
1101 }
1102 }
1103
1104 if (count($files) > 0) {
1105 return $files;
1106 }
1107
1108 //FALL BACK: Windows XP has bug with glob,
1109 //add secondary check for PHP lameness
1110 if ($dh = opendir('.')) {
1111 while (false !== ($name = readdir($dh))) {
1112 $ext = substr($name, strrpos($name, '.') + 1);
1113 if (in_array($ext, array($extension))) {
1114 $files[] = $name;
1115 }
1116 }
1117 closedir($dh);
1118 }
1119
1120 return $files;
1121 }
1122
1123 /**
1124 * Safely remove a directory and recursively if needed
1125 *
1126 * @param string $directory The full path to the directory to remove
1127 * @param string $recursive recursively remove all items
1128 *
1129 * @return bool Returns true if all content was removed
1130 */
1131 public static function deleteDirectory($directory, $recursive)
1132 {
1133 $success = true;
1134
1135 $filenames = array_diff(scandir($directory), array('.', '..'));
1136
1137 foreach ($filenames as $filename) {
1138 $fullPath = $directory.'/'.$filename;
1139
1140 if (is_dir($fullPath)) {
1141 if ($recursive) {
1142 $success = self::deleteDirectory($fullPath, true);
1143 }
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 }
1156
1157 return $success && rmdir($directory);
1158 }
1159
1160 /**
1161 * Safely remove a file or directory and recursively if needed
1162 *
1163 * @param string $directory The full path to the directory to remove
1164 *
1165 * @return bool Returns true if all content was removed
1166 */
1167 public static function deletePath($path)
1168 {
1169 $success = true;
1170
1171 if (is_dir($path)) {
1172 $success = self::deleteDirectory($path, true);
1173 } else {
1174 $success = @unlink($path);
1175
1176 if ($success === false) {
1177 self::log( __FUNCTION__.": Problem deleting file:".$path);
1178 }
1179 }
1180
1181 return $success;
1182 }
1183
1184 /**
1185 * Makes path safe for any OS for PHP
1186 *
1187 * Paths should ALWAYS READ be "/"
1188 * uni: /home/path/file.txt
1189 * win: D:/home/path/file.txt
1190 *
1191 * @param string $path The path to make safe
1192 *
1193 * @return string The original $path with a with all slashes facing '/'.
1194 */
1195 public static function setSafePath($path)
1196 {
1197 return str_replace("\\", "/", $path);
1198 }
1199}
1200
1201try {
1202 $boot = new DUPX_Bootstrap();
1203 $boot_error = $boot->run();
1204 $auto_refresh = isset($_POST['auto-fresh']) ? true : false;
1205} catch (Exception $e) {
1206 $boot_error = $e->getMessage();
1207}
1208
1209if ($boot_error == null) {
1210 $step1_csrf_token = DUPX_CSRF::generate('step1');
1211 DUPX_CSRF::setKeyVal('archive', $boot->archive);
1212 DUPX_CSRF::setKeyVal('bootloader', $boot->bootloader);
1213}
1214?>
1215
1216<html>
1217<?php if ($boot_error == null) :?>
1218 <head>
1219 <meta name="robots" content="noindex,nofollow">
1220 <title>Duplicator Installer</title>
1221 </head>
1222 <body>
1223 <?php
1224 $id = uniqid();
1225 $html = "<form id='{$id}' method='post' action='{$boot->mainInstallerURL}' />\n";
1226 $data = array(
1227 'archive' => $boot->archive,
1228 'bootloader' => $boot->bootloader,
1229 'csrf_token' => $step1_csrf_token,
1230 );
1231 foreach ($data as $name => $value) {
1232 $html .= "<input type='hidden' name='{$name}' value='{$value}' />\n";
1233 }
1234 $html .= "</form>\n";
1235 $html .= "<script>window.onload = function() { document.getElementById('{$id}').submit(); }</script>";
1236 echo $html;
1237 ?>
1238 </body>
1239<?php else :?>
1240 <head>
1241 <style>
1242 body {font-family:Verdana,Arial,sans-serif; line-height:18px; font-size: 12px}
1243 h2 {font-size:20px; margin:5px 0 5px 0; border-bottom:1px solid #dfdfdf; padding:3px}
1244 div#content {border:1px solid #CDCDCD; width:750px; min-height:550px; margin:auto; margin-top:18px; border-radius:5px; box-shadow:0 8px 6px -6px #333; font-size:13px}
1245 div#content-inner {padding:10px 30px; min-height:550px}
1246
1247 /* Header */
1248 table.header-wizard {border-top-left-radius:5px; border-top-right-radius:5px; width:100%; box-shadow:0 5px 3px -3px #999; background-color:#F1F1F1; font-weight:bold}
1249 table.header-wizard td.header {font-size:24px; padding:7px 0 7px 0; width:100%;}
1250 div.dupx-logfile-link {float:right; font-weight:normal; font-size:12px}
1251 .dupx-version {white-space:nowrap; color:#999; font-size:11px; font-style:italic; text-align:right; padding:0 15px 5px 0; line-height:14px; font-weight:normal}
1252 .dupx-version a { color:#999; }
1253
1254 div.errror-notice {text-align:center; font-style:italic; font-size:11px}
1255 div.errror-msg { color:maroon; padding: 10px 0 5px 0}
1256 .pass {color:green}
1257 .fail {color:red}
1258 span.file-info {font-size: 11px; font-style: italic}
1259 div.skip-not-found {padding:10px 0 5px 0;}
1260 div.skip-not-found label {cursor: pointer}
1261 table.settings {width:100%; font-size:12px}
1262 table.settings td {padding: 4px}
1263 table.settings td:first-child {font-weight: bold}
1264 .w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
1265 .w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
1266 .w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after
1267 {content:"";display:table;clear:both}
1268 .w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
1269 .w3-container{padding:0.01em 16px}
1270 .w3-center{display:inline-block;width:auto; text-align: center !important}
1271 </style>
1272 </head>
1273 <body>
1274 <div id="content">
1275
1276 <table cellspacing="0" class="header-wizard">
1277 <tr>
1278 <td class="header"> Duplicator - Bootloader</td>
1279 <td class="dupx-version">
1280 version: <?php echo DUPX_Bootstrap::VERSION ?> <br/>
1281 </td>
1282 </tr>
1283 </table>
1284
1285 <form id="error-form" method="post">
1286 <div id="content-inner">
1287 <h2 style="color:maroon">Setup Notice:</h2>
1288 <div class="errror-notice">An error has occurred. In order to load the full installer please resolve the issue below.</div>
1289 <div class="errror-msg">
1290 <?php echo $boot_error ?>
1291 </div>
1292 <br/><br/>
1293
1294 <h2>Server Settings:</h2>
1295 <table class='settings'>
1296 <tr>
1297 <td>ZipArchive:</td>
1298 <td><?php echo $boot->hasZipArchive ? '<i class="pass">Enabled</i>' : '<i class="fail">Disabled</i>'; ?> </td>
1299 </tr>
1300 <tr>
1301 <td>ShellExec Unzip:</td>
1302 <td><?php echo $boot->hasShellExecUnzip ? '<i class="pass">Enabled</i>' : '<i class="fail">Disabled</i>'; ?> </td>
1303 </tr>
1304 <tr>
1305 <td>Extraction Path:</td>
1306 <td><?php echo $boot->installerExtractPath; ?></td>
1307 </tr>
1308 <tr>
1309 <td>Installer Path:</td>
1310 <td><?php echo $boot->installerContentsPath; ?></td>
1311 </tr>
1312 <tr>
1313 <td>Archive Name:</td>
1314 <td>
1315 [HASH]_archive.zip or [HASH]_archive.daf<br/>
1316 <small>This is based on the format used to build the archive</small>
1317 </td>
1318 </tr>
1319 <tr>
1320 <td>Archive Size:</td>
1321 <td>
1322 <b>Expected Size:</b> <?php echo $boot->readableByteSize($boot->archiveExpectedSize); ?>
1323 <b>Actual Size:</b> <?php echo $boot->readableByteSize($boot->archiveActualSize); ?>
1324 </td>
1325 </tr>
1326 <tr>
1327 <td>Boot Log</td>
1328 <td>dup-installer-bootlog__[HASH].txt</td>
1329 </tr>
1330 </table>
1331 <br/><br/>
1332
1333 <div style="font-size:11px">
1334 Please Note: Either ZipArchive or Shell Exec will need to be enabled for the installer to run automatically otherwise a manual extraction
1335 will need to be performed. In order to run the installer manually follow the instructions to
1336 <a href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q' target='_blank'>manually extract</a> before running the installer.
1337 </div>
1338 <br/><br/>
1339
1340 </div>
1341 </form>
1342
1343 </div>
1344 </body>
1345
1346 <script>
1347 function AutoFresh() {
1348 document.getElementById('error-form').submit();
1349 }
1350 <?php if ($auto_refresh) :?>
1351 var duration = 10000; //10 seconds
1352 var counter = 10;
1353 var countElement = document.getElementById('count-down');
1354
1355 setTimeout(function(){window.location.reload(1);}, duration);
1356 setInterval(function() {
1357 counter--;
1358 countElement.innerHTML = (counter > 0) ? counter.toString() : "0";
1359 }, 1000);
1360
1361 <?php endif; ?>
1362 </script>
1363
1364
1365<?php endif; ?>
1366
1367
1368
1369<!--
1370Used for integrity check do not remove:
1371DUPLICATOR_INSTALLER_EOF -->
1372</html>