SHARE
TWEET

Untitled

a guest Jan 9th, 2019 203 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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>
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top