Advertisement
Guest User

Untitled

a guest
Jan 9th, 2019
496
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 36.55 KB | None | 0 0
  1. <?php
  2. date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here.
  3.  
  4. class DUPX_CSRF {
  5.  
  6. /** Session var name
  7. * @var string
  8. */
  9. public static $prefix = '_DUPX_CSRF';
  10.  
  11. /** Generate DUPX_CSRF value for form
  12. * @param string $form - Form name as session key
  13. * @return string - token
  14. */
  15. public static function generate($form = NULL) {
  16. if (!empty($_COOKIE[DUPX_CSRF::$prefix . '_' . $form])) {
  17. $token = $_COOKIE[DUPX_CSRF::$prefix . '_' . $form];
  18. } else {
  19. $token = DUPX_CSRF::token() . DUPX_CSRF::fingerprint();
  20. }
  21. $cookieName = DUPX_CSRF::$prefix . '_' . $form;
  22. $ret = DUPX_CSRF::setCookie($cookieName, $token);
  23. return $token;
  24. }
  25.  
  26. /** Check DUPX_CSRF value of form
  27. * @param string $token - Token
  28. * @param string $form - Form name as session key
  29. * @return boolean
  30. */
  31. public static function check($token, $form = NULL) {
  32. if (!self::isCookieEnabled()) {
  33. return true;
  34. }
  35. if (isset($_COOKIE[DUPX_CSRF::$prefix . '_' . $form]) && $_COOKIE[DUPX_CSRF::$prefix . '_' . $form] == $token) { // token OK
  36. return (substr($token, -32) == DUPX_CSRF::fingerprint()); // fingerprint OK?
  37. }
  38. return FALSE;
  39. }
  40.  
  41. /** Generate token
  42. * @param void
  43. * @return string
  44. */
  45. protected static function token() {
  46. mt_srand((double) microtime() * 10000);
  47. $charid = strtoupper(md5(uniqid(rand(), TRUE)));
  48. return substr($charid, 0, 8) . substr($charid, 8, 4) . substr($charid, 12, 4) . substr($charid, 16, 4) . substr($charid, 20, 12);
  49. }
  50.  
  51. /** Returns "digital fingerprint" of user
  52. * @param void
  53. * @return string - MD5 hashed data
  54. */
  55. protected static function fingerprint() {
  56. return strtoupper(md5(implode('|', array($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']))));
  57. }
  58.  
  59. public static function setCookie($cookieName, $cookieVal) {
  60. $_COOKIE[$cookieName] = $cookieVal;
  61. return setcookie($cookieName, $cookieVal, time() + 10800, '/');
  62. }
  63.  
  64. /**
  65. * @return bool
  66. */
  67. protected static function isCookieEnabled() {
  68. return (count($_COOKIE) > 0);
  69. }
  70.  
  71. public static function resetAllTokens() {
  72. foreach ($_COOKIE as $cookieName => $cookieVal) {
  73. if (0 === strpos($cookieName, DUPX_CSRF::$prefix) || 'archive' == $cookieName || 'bootloader' == $cookieName) {
  74. $baseUrl = self::getBaseUrl();
  75. setcookie($cookieName, '', time() - 86400, $baseUrl);
  76. }
  77. }
  78. $_COOKIE = array();
  79. }
  80.  
  81. private static function getBaseUrl() {
  82. // output: /myproject/index.php
  83. $currentPath = $_SERVER['PHP_SELF'];
  84.  
  85. // output: Array ( [dirname] => /myproject [basename] => index.php [extension] => php [filename] => index )
  86. $pathInfo = pathinfo($currentPath);
  87.  
  88. // output: localhost
  89. $hostName = $_SERVER['HTTP_HOST'];
  90.  
  91. // output: http://
  92. $protocol = strtolower(substr($_SERVER["SERVER_PROTOCOL"],0,5))=='https://'?'https://':'http://';
  93.  
  94. // return: http://localhost/myproject/
  95. return $protocol.$hostName.$pathInfo['dirname']."/";
  96. }
  97. }
  98.  
  99. /**
  100. * Bootstrap utility to exatract the core installer
  101. *
  102. * Standard: PSR-2
  103. *
  104. * @package SC\DUPX\Bootstrap
  105. * @link http://www.php-fig.org/psr/psr-2/
  106. *
  107. * To force extraction mode:
  108. * installer.php?unzipmode=auto
  109. * installer.php?unzipmode=ziparchive
  110. * installer.php?unzipmode=shellexec
  111. */
  112.  
  113. abstract class DUPX_Bootstrap_Zip_Mode
  114. {
  115. const AutoUnzip = 0;
  116. const ZipArchive = 1;
  117. const ShellExec = 2;
  118. }
  119.  
  120. abstract class DUPX_Connectivity
  121. {
  122. const OK = 0;
  123. const Error = 1;
  124. const Unknown = 2;
  125. }
  126.  
  127. class DUPX_Bootstrap
  128. {
  129. //@@ Params get dynamically swapped when package is built
  130. const ARCHIVE_FILENAME = '@@ARCHIVE@@';
  131. const ARCHIVE_SIZE = '@@ARCHIVE_SIZE@@';
  132. const INSTALLER_DIR_NAME = 'dup-installer';
  133. const PACKAGE_HASH = '@@PACKAGE_HASH@@';
  134. const VERSION = '@@VERSION@@';
  135.  
  136. public $hasZipArchive = false;
  137. public $hasShellExecUnzip = false;
  138. public $mainInstallerURL;
  139. public $installerContentsPath;
  140. public $installerExtractPath;
  141. public $archiveExpectedSize = 0;
  142. public $archiveActualSize = 0;
  143. public $activeRatio = 0;
  144.  
  145. /**
  146. * Instantiate the Bootstrap Object
  147. *
  148. * @return null
  149. */
  150. public function __construct()
  151. {
  152. //ARCHIVE_SIZE will be blank with a root filter so we can estimate
  153. //the default size of the package around 17.5MB (18088000)
  154. $archiveActualSize = @filesize(self::ARCHIVE_FILENAME);
  155. $archiveActualSize = ($archiveActualSize !== false) ? $archiveActualSize : 0;
  156. $this->hasZipArchive = class_exists('ZipArchive');
  157. $this->hasShellExecUnzip = $this->getUnzipFilePath() != null ? true : false;
  158. $this->installerContentsPath = str_replace("\\", '/', (dirname(__FILE__). '/' .self::INSTALLER_DIR_NAME));
  159. $this->installerExtractPath = str_replace("\\", '/', (dirname(__FILE__)));
  160. $this->archiveExpectedSize = strlen(self::ARCHIVE_SIZE) ? self::ARCHIVE_SIZE : 0 ;
  161. $this->archiveActualSize = $archiveActualSize;
  162.  
  163. if($this->archiveExpectedSize > 0) {
  164. $this->archiveRatio = (((1.0) * $this->archiveActualSize) / $this->archiveExpectedSize) * 100;
  165. } else {
  166. $this->archiveRatio = 100;
  167. }
  168. }
  169.  
  170. /**
  171. * Run the bootstrap process which includes checking for requirements and running
  172. * the extraction process
  173. *
  174. * @return null | string Returns null if the run was successful otherwise an error message
  175. */
  176. public function run()
  177. {
  178. date_default_timezone_set('UTC'); // Some machines don't have this set so just do it here
  179. @unlink('./dup-installer-bootlog__'.self::PACKAGE_HASH.'.txt');
  180. self::log('==DUPLICATOR INSTALLER BOOTSTRAP v@@VERSION@@==');
  181. self::log('----------------------------------------------------');
  182. self::log('Installer bootstrap start');
  183.  
  184. $archive_filepath = $this->getArchiveFilePath();
  185. $archive_filename = self::ARCHIVE_FILENAME;
  186.  
  187. $error = null;
  188. $extract_installer = true;
  189. $installer_directory = dirname(__FILE__).'/'.self::INSTALLER_DIR_NAME;
  190. $extract_success = false;
  191. $archiveExpectedEasy = $this->readableByteSize($this->archiveExpectedSize);
  192. $archiveActualEasy = $this->readableByteSize($this->archiveActualSize);
  193.  
  194. //$archive_extension = strtolower(pathinfo($archive_filepath)['extension']);
  195. $archive_extension = strtolower(pathinfo($archive_filepath, PATHINFO_EXTENSION));
  196. $manual_extract_found = (
  197. file_exists($installer_directory."/main.installer.php")
  198. &&
  199. file_exists($installer_directory."/dup-archive__".self::PACKAGE_HASH.".txt")
  200. &&
  201. file_exists($installer_directory."/dup-database__".self::PACKAGE_HASH.".sql")
  202. );
  203.  
  204. $isZip = ($archive_extension == 'zip');
  205.  
  206. //MANUAL EXTRACTION NOT FOUND
  207. if (! $manual_extract_found) {
  208.  
  209. //MISSING ARCHIVE FILE
  210. if (! file_exists($archive_filepath)) {
  211. self::log("ERROR: Archive file not found!");
  212. $archive_candidates = ($isZip) ? $this->getFilesWithExtension('zip') : $this->getFilesWithExtension('daf');
  213. $candidate_count = count($archive_candidates);
  214. $candidate_html = "- No {$archive_extension} files found -";
  215.  
  216. if ($candidate_count >= 1) {
  217. $candidate_html = "<ol>";
  218. foreach($archive_candidates as $archive_candidate) {
  219. $candidate_html .= "<li> {$archive_candidate}</li>";
  220. }
  221. $candidate_html .= "</ol>";
  222. }
  223.  
  224. $error = "<b>Archive not found!</b> The <i>'Required File'</i> below should be present in the <i>'Extraction Path'</i>. "
  225. . "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/> "
  226. . "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 "
  227. . "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/>"
  228. . "<b>Required File:</b> <span class='file-info'>{$archive_filename}</span> <br/>"
  229. . "<b>Extraction Path:</b> <span class='file-info'>{$this->installerExtractPath}/</span><br/><br/>"
  230. . "Potential archives found at extraction path: <br/>{$candidate_html}<br/><br/>";
  231.  
  232. return $error;
  233. }
  234.  
  235. // For .daf
  236. if (!$isZip) {
  237.  
  238. if (!filter_var(self::ARCHIVE_SIZE, FILTER_VALIDATE_INT) || self::ARCHIVE_SIZE > 2147483647) {
  239.  
  240. $os_first_three_chars = substr(PHP_OS, 0, 3);
  241. $os_first_three_chars = strtoupper($os_first_three_chars);
  242. $no_of_bits = PHP_INT_SIZE * 8;
  243.  
  244. if ($no_of_bits == 32) {
  245.  
  246. if ('WIN' === $os_first_three_chars) {
  247. $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>';
  248. } else {
  249. $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.';
  250. }
  251.  
  252. return $error;
  253. }
  254. }
  255. }
  256.  
  257. //SIZE CHECK ERROR
  258. if (($this->archiveRatio < 90) && ($this->archiveActualSize > 0) && ($this->archiveExpectedSize > 0)) {
  259. $this->log("ERROR: The expected archive size should be around [{$archiveExpectedEasy}]. The actual size is currently [{$archiveActualEasy}].");
  260. $this->log("The archive file may not have fully been downloaded to the server");
  261. $percent = round($this->archiveRatio);
  262.  
  263. $autochecked = isset($_POST['auto-fresh']) ? "checked='true'" : '';
  264. $error = "<b>Archive file size warning.</b><br/> The expected archive size should be around <b class='pass'>[{$archiveExpectedEasy}]</b>. "
  265. . "The actual size is currently <b class='fail'>[{$archiveActualEasy}]</b>. The archive file may not have fully been downloaded to the server. "
  266. . "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 "
  267. . "downloading then refresh this page to get an update on the download size.<br/><br/>";
  268.  
  269. return $error;
  270. }
  271.  
  272. }
  273.  
  274.  
  275.  
  276. if ($manual_extract_found) {
  277. // INSTALL DIRECTORY: Check if its setup correctly AND we are not in overwrite mode
  278. if (isset($_GET['force-extract-installer']) && ('1' == $_GET['force-extract-installer'] || 'enable' == $_GET['force-extract-installer'] || 'false' == $_GET['force-extract-installer'])) {
  279.  
  280. self::log("Manual extract found with force extract installer get parametr");
  281. $extract_installer = true;
  282.  
  283. } else {
  284. $extract_installer = false;
  285. self::log("Manual extract found so not going to extract dup-installer dir");
  286. }
  287. } else {
  288. $extract_installer = true;
  289. self::log("Manual extract didn't found so going to extract dup-installer dir");
  290. }
  291.  
  292. // if ($extract_installer && file_exists($installer_directory)) {
  293. if (file_exists($installer_directory)) {
  294. $hash_pattern = '[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]';
  295. $file_patterns_with_hash_file = array(
  296. // file pattern => hash file
  297. 'dup-archive__'.$hash_pattern.'.txt' => 'dup-archive__'.self::PACKAGE_HASH.'.txt',
  298. 'dup-database__'.$hash_pattern.'.sql' => 'dup-database__'.self::PACKAGE_HASH.'.sql',
  299. 'dup-installer-data__'.$hash_pattern.'.sql' => 'dup-installer-data__'.self::PACKAGE_HASH.'.sql',
  300. 'dup-installer-log__'.$hash_pattern.'.txt' => 'dup-installer-log__'.self::PACKAGE_HASH.'.txt',
  301. 'dup-scan__'.$hash_pattern.'.json' => 'dup-scan__'.self::PACKAGE_HASH.'.json',
  302. 'dup-scanned-dirs__'.$hash_pattern.'.txt' => 'dup-scanned-dirs__'.self::PACKAGE_HASH.'.txt',
  303. 'dup-scanned-files__'.$hash_pattern.'.txt' => 'dup-scanned-files__'.self::PACKAGE_HASH.'.txt',
  304. );
  305. foreach ($file_patterns_with_hash_file as $file_pattern => $hash_file) {
  306. $globs = glob($installer_directory.'/'.$file_pattern);
  307. if (!empty($globs)) {
  308. foreach ($globs as $glob) {
  309. $file = basename($glob);
  310. if ($file != $hash_file) {
  311. if (unlink($glob)) {
  312. self::log('Successfully deleted the file '.$glob);
  313. } else {
  314. $error .= 'Error deleting the file '.$glob.'. Please manually delete it and try again.';
  315. self::log($error);
  316. }
  317. }
  318. }
  319. }
  320. }
  321. }
  322.  
  323. //ATTEMPT EXTRACTION:
  324. //ZipArchive and Shell Exec
  325. if ($extract_installer) {
  326.  
  327. self::log("Ready to extract the installer");
  328.  
  329. if ($isZip) {
  330. $zip_mode = $this->getZipMode();
  331.  
  332. if (($zip_mode == DUPX_Bootstrap_Zip_Mode::AutoUnzip) || ($zip_mode == DUPX_Bootstrap_Zip_Mode::ZipArchive) && class_exists('ZipArchive')) {
  333. if ($this->hasZipArchive) {
  334. self::log("ZipArchive exists so using that");
  335. $extract_success = $this->extractInstallerZipArchive($archive_filepath);
  336.  
  337. if ($extract_success) {
  338. self::log('Successfully extracted with ZipArchive');
  339. } else {
  340. $error = 'Error extracting with ZipArchive. ';
  341. self::log($error);
  342. }
  343. } else {
  344. self::log("WARNING: ZipArchive is not enabled.");
  345. $error = "NOTICE: ZipArchive is not enabled on this server please talk to your host or server admin about enabling ";
  346. $error .= "<a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-060-q'>ZipArchive</a> on this server. <br/>";
  347. }
  348. }
  349.  
  350. if (!$extract_success) {
  351. if (($zip_mode == DUPX_Bootstrap_Zip_Mode::AutoUnzip) || ($zip_mode == DUPX_Bootstrap_Zip_Mode::ShellExec)) {
  352. $unzip_filepath = $this->getUnzipFilePath();
  353. if ($unzip_filepath != null) {
  354. $extract_success = $this->extractInstallerShellexec($archive_filepath);
  355. if ($extract_success) {
  356. self::log('Successfully extracted with Shell Exec');
  357. $error = null;
  358. } else {
  359. $error .= 'Error extracting with Shell Exec. Please manually extract archive then choose Advanced > Manual Extract in installer.';
  360. self::log($error);
  361. }
  362. } else {
  363. self::log('WARNING: Shell Exec Zip is not available');
  364. $error .= "NOTICE: Shell Exec is not enabled on this server please talk to your host or server admin about enabling ";
  365. $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.";
  366. }
  367. }
  368. }
  369.  
  370. // If both ZipArchive and ShellZip are not available, Error message should be combined for both
  371. if (!$extract_success && $zip_mode == DUPX_Bootstrap_Zip_Mode::AutoUnzip) {
  372. $unzip_filepath = $this->getUnzipFilePath();
  373. if (!class_exists('ZipArchive') && empty($unzip_filepath)) {
  374. $error = "NOTICE: ZipArchive and Shell Exec are not enabled on this server please talk to your host or server admin about enabling ";
  375. $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.";
  376. }
  377. }
  378. } else {
  379. DupArchiveMiniExpander::init("DUPX_Bootstrap::log");
  380. try {
  381. DupArchiveMiniExpander::expandDirectory($archive_filepath, self::INSTALLER_DIR_NAME, dirname(__FILE__));
  382. } catch (Exception $ex) {
  383. self::log("Error expanding installer subdirectory:".$ex->getMessage());
  384. throw $ex;
  385. }
  386. }
  387. } else {
  388. self::log("Didn't need to extract the installer.");
  389. }
  390.  
  391. if (empty($error)) {
  392. $config_files = glob('./dup-installer/dup-archive__*.txt');
  393. $config_file_absolute_path = array_pop($config_files);
  394. if (!file_exists($config_file_absolute_path)) {
  395. $error = 'NOTICE: Archive config file not found in dup-installer folder. Please ensure that your archive file is valid.</b>';
  396. }
  397. }
  398.  
  399. $is_https = $this->isHttps();
  400.  
  401. if($is_https) {
  402. $current_url = 'https://';
  403. } else {
  404. $current_url = 'http://';
  405. }
  406.  
  407. if(($_SERVER['SERVER_PORT'] == 80) && ($is_https)) {
  408. // Fixing what appears to be a bad server setting
  409. $server_port = 443;
  410. } else {
  411. $server_port = $_SERVER['SERVER_PORT'];
  412. }
  413.  
  414.  
  415. //$current_url .= $_SERVER['HTTP_HOST'];//WAS SERVER_NAME and caused problems on some boxes
  416. $current_url .= isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];//WAS SERVER_NAME and caused problems on some boxes
  417. if(strpos($current_url,':') === false) {
  418. $current_url = $current_url.':'.$server_port;
  419. }
  420.  
  421. if (!isset($_SERVER['REQUEST_URI'])) {
  422.  
  423. $_SERVER['REQUEST_URI'] = substr($_SERVER['PHP_SELF'], 0);
  424.  
  425. if (isset($_SERVER['QUERY_STRING']) AND $_SERVER['QUERY_STRING'] != "") {
  426.  
  427. $_SERVER['REQUEST_URI'] .= '?'.$_SERVER['QUERY_STRING'];
  428. }
  429. }
  430.  
  431. $current_url .= $_SERVER['REQUEST_URI'];
  432. $uri_start = dirname($current_url);
  433.  
  434. if ($error === null) {
  435.  
  436. if(!file_exists($installer_directory)) {
  437.  
  438. $error = '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>';
  439. }
  440.  
  441. if($error == null) {
  442.  
  443. $bootloader_name = basename(__FILE__);
  444. $this->mainInstallerURL = $uri_start.'/'.self::INSTALLER_DIR_NAME.'/main.installer.php';
  445.  
  446. $this->archive = $archive_filepath;
  447. $this->bootloader = $bootloader_name;
  448.  
  449. $this->fixInstallerPerms($this->mainInstallerURL);
  450. // $this->mainInstallerURL = $this->mainInstallerURL . "?archive=$encoded_archive_path&bootloader=$bootloader_name";
  451.  
  452. if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
  453. $this->mainInstallerURL .= '?'.$_SERVER['QUERY_STRING'];
  454. }
  455.  
  456. self::log("No detected errors so redirecting to the main installer. Main Installer URI = {$this->mainInstallerURL}");
  457. }
  458. }
  459.  
  460. return $error;
  461. }
  462.  
  463. /**
  464. * Indicates if site is running https or not
  465. *
  466. * @return bool Returns true if https, false if not
  467. */
  468. public function isHttps()
  469. {
  470. $retVal = true;
  471.  
  472. if (isset($_SERVER['HTTPS'])) {
  473. $retVal = ($_SERVER['HTTPS'] !== 'off');
  474. } else {
  475. $retVal = ($_SERVER['SERVER_PORT'] == 443);
  476. }
  477.  
  478. // nginx
  479. if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
  480. $retVal = ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https');
  481. }
  482.  
  483.  
  484. return $retVal;
  485. }
  486.  
  487. /**
  488. * Attempts to set the 'dup-installer' directory permissions
  489. *
  490. * @return null
  491. */
  492. private function fixInstallerPerms()
  493. {
  494. $file_perms = substr(sprintf('%o', fileperms(__FILE__)), -4);
  495. $file_perms = octdec($file_perms);
  496. //$dir_perms = substr(sprintf('%o', fileperms(dirname(__FILE__))), -4);
  497.  
  498. // No longer using existing directory permissions since that can cause problems. Just set it to 755
  499. $dir_perms = '755';
  500. $dir_perms = octdec($dir_perms);
  501. $installer_dir_path = $this->installerContentsPath;
  502.  
  503. $this->setPerms($installer_dir_path, $dir_perms, false);
  504. $this->setPerms($installer_dir_path, $file_perms, true);
  505. }
  506.  
  507. /**
  508. * Set the permissions of a given directory and optionally all files
  509. *
  510. * @param string $directory The full path to the directory where perms will be set
  511. * @param string $perms The given permission sets to use such as '0755'
  512. * @param string $do_files Also set the permissions of all the files in the directory
  513. *
  514. * @return null
  515. */
  516. private function setPerms($directory, $perms, $do_files)
  517. {
  518. if (!$do_files) {
  519. // If setting a directory hiearchy be sure to include the base directory
  520. $this->setPermsOnItem($directory, $perms);
  521. }
  522.  
  523. $item_names = array_diff(scandir($directory), array('.', '..'));
  524.  
  525. foreach ($item_names as $item_name) {
  526. $path = "$directory/$item_name";
  527. if (($do_files && is_file($path)) || (!$do_files && !is_file($path))) {
  528. $this->setPermsOnItem($path, $perms);
  529. }
  530. }
  531. }
  532.  
  533. /**
  534. * Set the permissions of a single directory or file
  535. *
  536. * @param string $path The full path to the directory or file where perms will be set
  537. * @param string $perms The given permission sets to use such as '0755'
  538. *
  539. * @return bool Returns true if the permission was properly set
  540. */
  541. private function setPermsOnItem($path, $perms)
  542. {
  543. $result = @chmod($path, $perms);
  544. $perms_display = decoct($perms);
  545. if ($result === false) {
  546. self::log("Couldn't set permissions of $path to {$perms_display}<br/>");
  547. } else {
  548. self::log("Set permissions of $path to {$perms_display}<br/>");
  549. }
  550. return $result;
  551. }
  552.  
  553.  
  554. /**
  555. * Logs a string to the dup-installer-bootlog__[HASH].txt file
  556. *
  557. * @param string $s The string to log to the log file
  558. *
  559. * @return null
  560. */
  561. public static function log($s)
  562. {
  563. $timestamp = date('M j H:i:s');
  564. file_put_contents('./dup-installer-bootlog__'.self::PACKAGE_HASH.'.txt', "$timestamp $s\n", FILE_APPEND);
  565. }
  566.  
  567. /**
  568. * Extracts only the 'dup-installer' files using ZipArchive
  569. *
  570. * @param string $archive_filepath The path to the archive file.
  571. *
  572. * @return bool Returns true if the data was properly extracted
  573. */
  574. private function extractInstallerZipArchive($archive_filepath)
  575. {
  576. $success = true;
  577. $zipArchive = new ZipArchive();
  578.  
  579. if ($zipArchive->open($archive_filepath) === true) {
  580. self::log("Successfully opened $archive_filepath");
  581. $destination = dirname(__FILE__);
  582. $folder_prefix = self::INSTALLER_DIR_NAME.'/';
  583. self::log("Extracting all files from archive within ".self::INSTALLER_DIR_NAME);
  584.  
  585. $installer_files_found = 0;
  586.  
  587. for ($i = 0; $i < $zipArchive->numFiles; $i++) {
  588. $stat = $zipArchive->statIndex($i);
  589. $filename = $stat['name'];
  590.  
  591. if ($this->startsWith($filename, $folder_prefix)) {
  592. $installer_files_found++;
  593.  
  594. if ($zipArchive->extractTo($destination, $filename) === true) {
  595. self::log("Success: {$filename} >>> {$destination}");
  596. } else {
  597. self::log("Error extracting {$filename} from archive file");
  598. $success = false;
  599. break;
  600. }
  601. }
  602. }
  603.  
  604. $lib_directory = dirname(__FILE__).'/'.self::INSTALLER_DIR_NAME.'/lib';
  605. $snaplib_directory = $lib_directory.'/snaplib';
  606.  
  607. // If snaplib files aren't present attempt to extract and copy those
  608. if(!file_exists($snaplib_directory))
  609. {
  610. $folder_prefix = 'snaplib/';
  611. $destination = $lib_directory;
  612.  
  613. for ($i = 0; $i < $zipArchive->numFiles; $i++) {
  614. $stat = $zipArchive->statIndex($i);
  615. $filename = $stat['name'];
  616.  
  617. if ($this->startsWith($filename, $folder_prefix)) {
  618. $installer_files_found++;
  619.  
  620. if ($zipArchive->extractTo($destination, $filename) === true) {
  621. self::log("Success: {$filename} >>> {$destination}");
  622. } else {
  623. self::log("Error extracting {$filename} from archive file");
  624. $success = false;
  625. break;
  626. }
  627. }
  628. }
  629. }
  630.  
  631. if ($zipArchive->close() === true) {
  632. self::log("Successfully closed archive file");
  633. } else {
  634. self::log("Problem closing archive file");
  635. $success = false;
  636. }
  637.  
  638. if ($installer_files_found < 10) {
  639. self::log("Couldn't find the installer directory in the archive!");
  640.  
  641. $success = false;
  642. }
  643. } else {
  644. self::log("Couldn't open archive file with ZipArchive");
  645. $success = false;
  646. }
  647. return $success;
  648. }
  649.  
  650. /**
  651. * Extracts only the 'dup-installer' files using Shell-Exec Unzip
  652. *
  653. * @param string $archive_filepath The path to the archive file.
  654. *
  655. * @return bool Returns true if the data was properly extracted
  656. */
  657. private function extractInstallerShellexec($archive_filepath)
  658. {
  659. $success = false;
  660. self::log("Attempting to use Shell Exec");
  661. $unzip_filepath = $this->getUnzipFilePath();
  662.  
  663. if ($unzip_filepath != null) {
  664. $unzip_command = "$unzip_filepath -q $archive_filepath ".self::INSTALLER_DIR_NAME.'/* 2>&1';
  665. self::log("Executing $unzip_command");
  666. $stderr = shell_exec($unzip_command);
  667.  
  668. $lib_directory = dirname(__FILE__).'/'.self::INSTALLER_DIR_NAME.'/lib';
  669. $snaplib_directory = $lib_directory.'/snaplib';
  670.  
  671. // If snaplib files aren't present attempt to extract and copy those
  672. if(!file_exists($snaplib_directory))
  673. {
  674. $local_lib_directory = dirname(__FILE__).'/snaplib';
  675. $unzip_command = "$unzip_filepath -q $archive_filepath snaplib/* 2>&1";
  676. self::log("Executing $unzip_command");
  677. $stderr .= shell_exec($unzip_command);
  678. mkdir($lib_directory);
  679. rename($local_lib_directory, $snaplib_directory);
  680. }
  681.  
  682. if ($stderr == '') {
  683. self::log("Shell exec unzip succeeded");
  684. $success = true;
  685. } else {
  686. self::log("Shell exec unzip failed. Output={$stderr}");
  687. }
  688. }
  689.  
  690. return $success;
  691. }
  692.  
  693. /**
  694. * Attempts to get the archive file path
  695. *
  696. * @return string The full path to the archive file
  697. */
  698. private function getArchiveFilePath()
  699. {
  700. if (isset($_GET['archive'])) {
  701. $archive_filepath = $_GET['archive'];
  702. } else {
  703. $archive_filename = self::ARCHIVE_FILENAME;
  704. $archive_filepath = str_replace("\\", '/', dirname(__FILE__) . '/' . $archive_filename);
  705. }
  706.  
  707. self::log("Using archive $archive_filepath");
  708. return $archive_filepath;
  709. }
  710.  
  711. /**
  712. * Gets the DUPX_Bootstrap_Zip_Mode enum type that should be used
  713. *
  714. * @return DUPX_Bootstrap_Zip_Mode Returns the current mode of the bootstrapper
  715. */
  716. private function getZipMode()
  717. {
  718. $zip_mode = DUPX_Bootstrap_Zip_Mode::AutoUnzip;
  719.  
  720. if (isset($_GET['zipmode'])) {
  721. $zipmode_string = $_GET['zipmode'];
  722. self::log("Unzip mode specified in querystring: $zipmode_string");
  723.  
  724. switch ($zipmode_string) {
  725. case 'autounzip':
  726. $zip_mode = DUPX_Bootstrap_Zip_Mode::AutoUnzip;
  727. break;
  728.  
  729. case 'ziparchive':
  730. $zip_mode = DUPX_Bootstrap_Zip_Mode::ZipArchive;
  731. break;
  732.  
  733. case 'shellexec':
  734. $zip_mode = DUPX_Bootstrap_Zip_Mode::ShellExec;
  735. break;
  736. }
  737. }
  738.  
  739. return $zip_mode;
  740. }
  741.  
  742. /**
  743. * Checks to see if a string starts with specific characters
  744. *
  745. * @return bool Returns true if the string starts with a specific format
  746. */
  747. private function startsWith($haystack, $needle)
  748. {
  749. return $needle === "" || strrpos($haystack, $needle, - strlen($haystack)) !== false;
  750. }
  751.  
  752. /**
  753. * Checks to see if the server supports issuing commands to shell_exex
  754. *
  755. * @return bool Returns true shell_exec can be ran on this server
  756. */
  757. public function hasShellExec()
  758. {
  759. $cmds = array('shell_exec', 'escapeshellarg', 'escapeshellcmd', 'extension_loaded');
  760.  
  761. //Function disabled at server level
  762. if (array_intersect($cmds, array_map('trim', explode(',', @ini_get('disable_functions'))))) return false;
  763.  
  764. //Suhosin: http://www.hardened-php.net/suhosin/
  765. //Will cause PHP to silently fail
  766. if (extension_loaded('suhosin')) {
  767. $suhosin_ini = @ini_get("suhosin.executor.func.blacklist");
  768. if (array_intersect($cmds, array_map('trim', explode(',', $suhosin_ini)))) return false;
  769. }
  770. // Can we issue a simple echo command?
  771. if (!@shell_exec('echo duplicator')) return false;
  772.  
  773. return true;
  774. }
  775.  
  776. /**
  777. * Gets the possible system commands for unzip on Linux
  778. *
  779. * @return string Returns unzip file path that can execute the unzip command
  780. */
  781. public function getUnzipFilePath()
  782. {
  783. $filepath = null;
  784.  
  785. if ($this->hasShellExec()) {
  786. if (shell_exec('hash unzip 2>&1') == NULL) {
  787. $filepath = 'unzip';
  788. } else {
  789. $possible_paths = array(
  790. '/usr/bin/unzip',
  791. '/opt/local/bin/unzip',
  792. '/bin/unzip',
  793. '/usr/local/bin/unzip',
  794. '/usr/sfw/bin/unzip',
  795. '/usr/xdg4/bin/unzip',
  796. '/opt/bin/unzip',
  797. // RSR TODO put back in when we support shellexec on windows,
  798. );
  799.  
  800. foreach ($possible_paths as $path) {
  801. if (file_exists($path)) {
  802. $filepath = $path;
  803. break;
  804. }
  805. }
  806. }
  807. }
  808.  
  809. return $filepath;
  810. }
  811.  
  812. /**
  813. * Display human readable byte sizes such as 150MB
  814. *
  815. * @param int $size The size in bytes
  816. *
  817. * @return string A readable byte size format such as 100MB
  818. */
  819. public function readableByteSize($size)
  820. {
  821. try {
  822. $units = array('B', 'KB', 'MB', 'GB', 'TB');
  823. for ($i = 0; $size >= 1024 && $i < 4; $i++)
  824. $size /= 1024;
  825. return round($size, 2).$units[$i];
  826. } catch (Exception $e) {
  827. return "n/a";
  828. }
  829. }
  830.  
  831. /**
  832. * Returns an array of zip files found in the current executing directory
  833. *
  834. * @return array of zip files
  835. */
  836. public static function getFilesWithExtension($extension)
  837. {
  838. $files = array();
  839. foreach (glob("*.{$extension}") as $name) {
  840. if (file_exists($name)) {
  841. $files[] = $name;
  842. }
  843. }
  844.  
  845. if (count($files) > 0) {
  846. return $files;
  847. }
  848.  
  849. //FALL BACK: Windows XP has bug with glob,
  850. //add secondary check for PHP lameness
  851. if ($dh = opendir('.')) {
  852. while (false !== ($name = readdir($dh))) {
  853. $ext = substr($name, strrpos($name, '.') + 1);
  854. if (in_array($ext, array($extension))) {
  855. $files[] = $name;
  856. }
  857. }
  858. closedir($dh);
  859. }
  860.  
  861. return $files;
  862. }
  863. }
  864.  
  865. $boot = new DUPX_Bootstrap();
  866. $boot_error = $boot->run();
  867. $auto_refresh = isset($_POST['auto-fresh']) ? true : false;
  868. DUPX_CSRF::resetAllTokens();
  869.  
  870. if ($boot_error == null) {
  871. $secure_csrf_token = DUPX_CSRF::generate('secure');
  872. DUPX_CSRF::setCookie('archive', $boot->archive);
  873. DUPX_CSRF::setCookie('bootloader', $boot->bootloader);
  874. }
  875. ?>
  876.  
  877. <html>
  878. <?php if ($boot_error == null) :?>
  879.  
  880. <head>
  881. <meta name="robots" content="noindex,nofollow">
  882. <title>Duplicator Pro Installer</title>
  883. </head>
  884. <body>
  885. <?php
  886. $id = uniqid();
  887. $html = "<form id='{$id}' method='post' action='{$boot->mainInstallerURL}' />\n";
  888. $data = array(
  889. 'archive' => $boot->archive,
  890. 'bootloader' => $boot->bootloader,
  891. 'csrf_token' => $secure_csrf_token,
  892. );
  893. foreach ($data as $name => $value) {
  894. if ('csrf_token' != $name) $_SESSION[$name] = $value;
  895. $html .= "<input type='hidden' name='{$name}' value='{$value}' />\n";
  896. }
  897. $html .= "</form>\n";
  898. $html .= "<script>window.onload = function() { document.getElementById('{$id}').submit(); }</script>";
  899. echo $html;
  900. ?>
  901. </body>
  902. <?php else :?>
  903.  
  904. <head>
  905. <style>
  906. body {font-family:Verdana,Arial,sans-serif; line-height:18px; font-size: 12px}
  907. h2 {font-size:20px; margin:5px 0 5px 0; border-bottom:1px solid #dfdfdf; padding:3px}
  908. 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}
  909. div#content-inner {padding:10px 30px; min-height:550px}
  910.  
  911. /* Header */
  912. 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}
  913. table.header-wizard td.header {font-size:24px; padding:7px 0 7px 0; width:100%;}
  914. div.dupx-logfile-link {float:right; font-weight:normal; font-size:12px}
  915. .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}
  916. .dupx-version a { color:#999; }
  917.  
  918. div.errror-notice {text-align:center; font-style:italic; font-size:11px}
  919. div.errror-msg { color:maroon; padding: 10px 0 5px 0}
  920. .pass {color:green}
  921. .fail {color:red}
  922. span.file-info {font-size: 11px; font-style: italic}
  923. div.skip-not-found {padding:10px 0 5px 0;}
  924. div.skip-not-found label {cursor: pointer}
  925. table.settings {width:100%; font-size:12px}
  926. table.settings td {padding: 4px}
  927. table.settings td:first-child {font-weight: bold}
  928. .w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
  929. .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,
  930. .w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after
  931. {content:"";display:table;clear:both}
  932. .w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
  933. .w3-container{padding:0.01em 16px}
  934. .w3-center{display:inline-block;width:auto; text-align: center !important}
  935. </style>
  936. </head>
  937. <body>
  938. <div id="content">
  939.  
  940. <table cellspacing="0" class="header-wizard">
  941. <tr>
  942. <td class="header"> &nbsp; Duplicator Pro - Bootloader</div</td>
  943. <td class="dupx-version">
  944. version: <?php echo htmlentities(DUPX_Bootstrap::VERSION); ?> <br/>
  945. &raquo; <a target='_blank' href='dup-installer-bootlog__<?php echo DUPX_Bootstrap::PACKAGE_HASH; ?>.txt'>dup-installer-bootlog__[HASH].txt</a>
  946. </td>
  947. </tr>
  948. </table>
  949.  
  950. <form id="error-form" method="post">
  951. <div id="content-inner">
  952. <h2 style="color:maroon">Setup Notice:</h2>
  953. <div class="errror-notice">An error has occurred. In order to load the full installer please resolve the issue below.</div>
  954. <div class="errror-msg">
  955. <?php echo $boot_error ?>
  956. </div>
  957. <br/><br/>
  958.  
  959. <h2>Server Settings:</h2>
  960. <table class='settings'>
  961. <tr>
  962. <td>ZipArchive:</td>
  963. <td><?php echo $boot->hasZipArchive ? '<i class="pass">Enabled</i>' : '<i class="fail">Disabled</i>'; ?> </td>
  964. </tr>
  965. <tr>
  966. <td>ShellExec&nbsp;Unzip:</td>
  967. <td><?php echo $boot->hasShellExecUnzip ? '<i class="pass">Enabled</i>' : '<i class="fail">Disabled</i>'; ?> </td>
  968. </tr>
  969. <tr>
  970. <td>Extraction&nbsp;Path:</td>
  971. <td><?php echo $boot->installerExtractPath; ?></td>
  972. </tr>
  973. <tr>
  974. <td>Installer Path:</td>
  975. <td><?php echo $boot->installerContentsPath; ?></td>
  976. </tr>
  977. <tr>
  978. <td>Archive Name:</td>
  979. <td><?php echo DUPX_Bootstrap::ARCHIVE_FILENAME ?></td>
  980. </tr>
  981. <tr>
  982. <td>Archive Size:</td>
  983. <td>
  984. <b>Expected Size:</b> <?php echo $boot->readableByteSize($boot->archiveExpectedSize); ?> &nbsp;
  985. <b>Actual Size:</b> <?php echo $boot->readableByteSize($boot->archiveActualSize); ?>
  986. </td>
  987. </tr>
  988. <tr>
  989. <td>Boot Log</td>
  990. <td><a target='_blank' href='dup-installer-bootlog__<?php echo DUPX_Bootstrap::PACKAGE_HASH; ?>.txt'>dup-installer-bootlog__[HASH].txt</a></td>
  991. </tr>
  992. </table>
  993. <br/><br/>
  994.  
  995. <div style="font-size:11px">
  996. Please Note: Either ZipArchive or Shell Exec will need to be enabled for the installer to run automatically otherwise a manual extraction
  997. will need to be performed. In order to run the installer manually follow the instructions to
  998. <a href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q' target='_blank'>manually extract</a> before running the installer.
  999. </div>
  1000. <br/><br/>
  1001.  
  1002. </div>
  1003. </form>
  1004.  
  1005. </div>
  1006. </body>
  1007.  
  1008. <script>
  1009. function AutoFresh() {
  1010. document.getElementById('error-form').submit();
  1011. }
  1012. <?php if ($auto_refresh) :?>
  1013. var duration = 10000; //10 seconds
  1014. var counter = 10;
  1015. var countElement = document.getElementById('count-down');
  1016.  
  1017. setTimeout(function(){window.location.reload(1);}, duration);
  1018. setInterval(function() {
  1019. counter--;
  1020. countElement.innerHTML = (counter > 0) ? counter.toString() : "0";
  1021. }, 1000);
  1022.  
  1023. <?php endif; ?>
  1024. </script>
  1025.  
  1026.  
  1027. <?php endif; ?>
  1028.  
  1029.  
  1030. @@DUPARCHIVE_MINI_EXPANDER@@
  1031. <!--
  1032. Used for integrity check do not remove:
  1033. DUPLICATOR_PRO_INSTALLER_EOF -->
  1034. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement