Changed source root directory

This commit is contained in:
2026-03-05 16:30:11 +01:00
parent dc85447ee1
commit 538f85d7a2
5868 changed files with 749734 additions and 99 deletions

View File

@@ -0,0 +1,782 @@
<?php
/**
* Class used to control values about the package meta data
*
* Standard: PSR-2
*
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
*
* @package SC\DUPX\ArchiveConfig
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
use Duplicator\Installer\Utils\Log\Log;
use Duplicator\Installer\Core\Params\PrmMng;
use Duplicator\Libs\Snap\SnapIO;
use Duplicator\Libs\Snap\SnapURL;
use Duplicator\Libs\Snap\SnapDB;
use Duplicator\Libs\Snap\SnapString;
use Duplicator\Libs\WpConfig\WPConfigTransformer;
/**
* singleton class
*/
class DUPX_ArchiveConfig
{
const NOTICE_ID_PARAM_EMPTY = 'param_empty_to_validate';
// READ-ONLY: COMPARE VALUES
public $dup_type;
public $created;
public $version_dup;
public $version_wp;
public $version_db;
public $version_php;
public $version_os;
public $packInfo;
public $fileInfo;
public $dbInfo;
public $wpInfo;
/** @var int<-1,max> */
public $defaultStorageId = -1;
/** @var string[] */
public $components = array();
// GENERAL
public $secure_on;
public $secure_pass;
public $installer_base_name = '';
public $installer_backup_name = '';
public $package_name;
public $package_hash;
public $package_notes;
public $wp_tableprefix;
public $blogname;
public $blogNameSafe;
public $exportOnlyDB;
//ADV OPTS
public $opts_delete;
//MULTISITE
public $mu_mode;
public $mu_generation;
/** @var mixed[] */
public $subsites = array();
public $main_site_id = 1;
public $mu_is_filtered;
public $mu_siteadmins = array();
//LICENSING
/** @var int<0, max> */
public $license_limit = 0;
/** @var int ENUM LICENSE TYPE */
public $license_type = 0;
//PARAMS
public $overwriteInstallerParams = array();
/** @var ?string */
public $dbhost = null;
/** @var ?string */
public $dbname = null;
/** @var ?string */
public $dbuser = null;
/** @var object */
public $brand = null;
/** @var ?string */
public $cpnl_host;
/** @var ?string */
public $cpnl_user;
/** @var ?string */
public $cpnl_pass;
/** @var ?string */
public $cpnl_enable;
/** @var self */
private static $instance = null;
/**
* Get instance
*
* @return self
*/
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Singleton class constructor
*/
protected function __construct()
{
$config_filepath = DUPX_Package::getPackageArchivePath();
if (!file_exists($config_filepath)) {
throw new Exception("Archive file $config_filepath doesn't exist");
}
if (($file_contents = file_get_contents($config_filepath)) === false) {
throw new Exception("Can\'t read Archive file $config_filepath");
}
if (($data = json_decode($file_contents)) === null) {
throw new Exception("Can\'t decode archive json");
}
foreach ($data as $key => $value) {
$this->{$key} = $value;
}
//Instance Updates:
$this->blogNameSafe = preg_replace("/[^A-Za-z0-9?!]/", '', $this->blogname);
}
/**
*
* @return bool
*/
public function isZipArchive()
{
$extension = strtolower(pathinfo($this->package_name, PATHINFO_EXTENSION));
return ($extension == 'zip');
}
/**
*
* @param string $define
*
* @return bool // return true if define value exists
*/
public function defineValueExists($define)
{
return isset($this->wpInfo->configs->defines->{$define});
}
public function getUsersLists()
{
$result = array();
foreach ($this->wpInfo->adminUsers as $user) {
$result[$user->ID] = $user->user_login;
}
return $result;
}
/**
*
* @param string $define
* @param array $default
*
* @return array
*/
public function getDefineArrayValue($define, $default = array(
'value' => false,
'inWpConfig' => false
))
{
$defines = $this->wpInfo->configs->defines;
if (isset($defines->{$define})) {
return (array) $defines->{$define};
} else {
return $default;
}
}
/**
* return define value from archive or default value if don't exists
*
* @param string $define
* @param mixed $default
*
* @return mixed
*/
public function getDefineValue($define, $default = false)
{
$defines = $this->wpInfo->configs->defines;
if (isset($defines->{$define})) {
return $defines->{$define}->value;
} else {
return $default;
}
}
/**
* return define value from archive or default value if don't exists in wp-config
*
* @param string $define
* @param mixed $default
*
* @return mixed
*/
public function getWpConfigDefineValue($define, $default = false)
{
$defines = $this->wpInfo->configs->defines;
if (isset($defines->{$define}) && $defines->{$define}->inWpConfig) {
return $defines->{$define}->value;
} else {
return $default;
}
}
public function inWpConfigDefine($define)
{
$defines = $this->wpInfo->configs->defines;
if (isset($defines->{$define})) {
return $defines->{$define}->inWpConfig;
} else {
return false;
}
}
/**
*
* @param string $key
*
* @return boolean
*/
public function realValueExists($key)
{
return isset($this->wpInfo->configs->realValues->{$key});
}
/**
* return read value from archive if exists of default if don't exists
*
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function getRealValue($key, $default = false)
{
$values = $this->wpInfo->configs->realValues;
if (isset($values->{$key})) {
return $values->{$key};
} else {
return $default;
}
}
/**
* in hours
*
* @return int
*/
public function getPackageLife()
{
$packageTime = strtotime($this->created);
$currentTime = strtotime('now');
return ceil(($currentTime - $packageTime) / 60 / 60);
}
/**
*
* @return int
*/
public function totalArchiveItemsCount()
{
return $this->fileInfo->dirCount + $this->fileInfo->fileCount;
}
public function setNewPathsAndUrlParamsByMainNew()
{
self::manageEmptyPathAndUrl(PrmMng::PARAM_PATH_WP_CORE_NEW, PrmMng::PARAM_SITE_URL);
self::manageEmptyPathAndUrl(PrmMng::PARAM_PATH_CONTENT_NEW, PrmMng::PARAM_URL_CONTENT_NEW);
self::manageEmptyPathAndUrl(PrmMng::PARAM_PATH_UPLOADS_NEW, PrmMng::PARAM_URL_UPLOADS_NEW);
self::manageEmptyPathAndUrl(PrmMng::PARAM_PATH_PLUGINS_NEW, PrmMng::PARAM_URL_PLUGINS_NEW);
self::manageEmptyPathAndUrl(PrmMng::PARAM_PATH_MUPLUGINS_NEW, PrmMng::PARAM_URL_MUPLUGINS_NEW);
$paramsManager = PrmMng::getInstance();
$noticeManager = DUPX_NOTICE_MANAGER::getInstance();
$noticeManager->addNextStepNotice(array(
'shortMsg' => '',
'level' => DUPX_NOTICE_ITEM::NOTICE,
'longMsg' => '<span class="green">If desired, you can change the default values in "Advanced install" &gt; "Other options"</span>.',
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML
), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND_IF_EXISTS, self::NOTICE_ID_PARAM_EMPTY);
$paramsManager->save();
$noticeManager->saveNotices();
}
protected static function manageEmptyPathAndUrl($pathKey, $urlKey)
{
$paramsManager = PrmMng::getInstance();
$validPath = (strlen($paramsManager->getValue($pathKey)) > 0);
$validUrl = (strlen($paramsManager->getValue($urlKey)) > 0);
if ($validPath && $validUrl) {
return true;
}
$paramsManager->setValue($pathKey, self::getDefaultPathUrlValueFromParamKey($pathKey));
$paramsManager->setValue($urlKey, self::getDefaultPathUrlValueFromParamKey($urlKey));
$noticeManager = DUPX_NOTICE_MANAGER::getInstance();
$msg = '<b>' . $paramsManager->getLabel($pathKey) . ' and/or ' . $paramsManager->getLabel($urlKey) . '</b> can\'t be generated automatically so they are set to their default value.' . "<br>\n";
$msg .= $paramsManager->getLabel($pathKey) . ': ' . $paramsManager->getValue($pathKey) . "<br>\n";
$msg .= $paramsManager->getLabel($urlKey) . ': ' . $paramsManager->getValue($urlKey) . "<br>\n";
$noticeManager->addNextStepNotice(array(
'shortMsg' => 'URLs and/or PATHs set automatically to their default value.',
'level' => DUPX_NOTICE_ITEM::NOTICE,
'longMsg' => $msg . "<br>\n",
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML
), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, self::NOTICE_ID_PARAM_EMPTY);
}
public static function getDefaultPathUrlValueFromParamKey($paramKey)
{
$paramsManager = PrmMng::getInstance();
switch ($paramKey) {
case PrmMng::PARAM_SITE_URL:
return $paramsManager->getValue(PrmMng::PARAM_URL_NEW);
case PrmMng::PARAM_URL_CONTENT_NEW:
return $paramsManager->getValue(PrmMng::PARAM_URL_NEW) . '/wp-content';
case PrmMng::PARAM_URL_UPLOADS_NEW:
return $paramsManager->getValue(PrmMng::PARAM_URL_CONTENT_NEW) . '/uploads';
case PrmMng::PARAM_URL_PLUGINS_NEW:
return $paramsManager->getValue(PrmMng::PARAM_URL_CONTENT_NEW) . '/plugins';
case PrmMng::PARAM_URL_MUPLUGINS_NEW:
return $paramsManager->getValue(PrmMng::PARAM_URL_CONTENT_NEW) . '/mu-plugins';
case PrmMng::PARAM_PATH_WP_CORE_NEW:
return $paramsManager->getValue(PrmMng::PARAM_PATH_NEW);
case PrmMng::PARAM_PATH_CONTENT_NEW:
return $paramsManager->getValue(PrmMng::PARAM_PATH_NEW) . '/wp-content';
case PrmMng::PARAM_PATH_UPLOADS_NEW:
return $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW) . '/uploads';
case PrmMng::PARAM_PATH_PLUGINS_NEW:
return $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW) . '/plugins';
case PrmMng::PARAM_PATH_MUPLUGINS_NEW:
return $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW) . '/mu-plugins';
default:
throw new Exception('Invalid URL or PATH param');
}
}
/**
*
* @param string $oldMain
* @param string $newMain
* @param string $subOld
*
* @return boolean|string return false if cant generate new sub string
*/
public static function getNewSubString($oldMain, $newMain, $subOld)
{
if (($relativePath = SnapIO::getRelativePath($subOld, $oldMain)) === false) {
return false;
}
return $newMain . '/' . $relativePath;
}
/**
*
* @param string $oldMain
* @param string $newMain
* @param string $subOld
*
* @return boolean|string return false if cant generate new sub string
*/
public static function getNewSubUrl($oldMain, $newMain, $subOld)
{
$parsedOldMain = SnapURL::parseUrl($oldMain);
$parsedNewMain = SnapURL::parseUrl($newMain);
$parsedSubOld = SnapURL::parseUrl($subOld);
$parsedSubNew = $parsedSubOld;
$parsedSubNew['scheme'] = $parsedNewMain['scheme'];
$parsedSubNew['port'] = $parsedNewMain['port'];
if ($parsedOldMain['host'] !== $parsedSubOld['host']) {
return false;
}
$parsedSubNew['host'] = $parsedNewMain['host'];
if (($newPath = self::getNewSubString($parsedOldMain['path'], $parsedNewMain['path'], $parsedSubOld['path'])) === false) {
return false;
}
$parsedSubNew['path'] = $newPath;
return SnapURL::buildUrl($parsedSubNew);
}
/**
* Returns case insensitive duplicate tables from source site
*
* @return array<string[]>
*/
public function getDuplicateTableNames()
{
$tableList = (array) $this->dbInfo->tablesList;
$allTables = array_keys($tableList);
$duplicates = SnapString::getCaseInsesitiveDuplicates($allTables);
return $duplicates;
}
/**
* Returns list of redundant duplicates
*
* @return string[]
*/
public function getRedundantDuplicateTableNames()
{
$duplicateTables = $this->getDuplicateTableNames();
$prefix = DUPX_ArchiveConfig::getInstance()->wp_tableprefix;
$redundantTables = array();
foreach ($duplicateTables as $tables) {
$redundantTables = array_merge($redundantTables, SnapDB::getRedundantDuplicateTables($prefix, $tables));
}
return $redundantTables;
}
/**
*
* @return bool
*/
public function isTablesCaseSensitive()
{
return $this->dbInfo->isTablesUpperCase;
}
public function isTablePrefixChanged()
{
return $this->wp_tableprefix != PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_TABLE_PREFIX);
}
public function getTableWithNewPrefix($table)
{
$search = '/^' . preg_quote($this->wp_tableprefix, '/') . '(.*)/';
$replace = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_TABLE_PREFIX) . '$1';
return preg_replace($search, $replace, $table, 1);
}
public function getOldUrlScheme()
{
static $oldScheme = null;
if (is_null($oldScheme)) {
$siteUrl = $this->getRealValue('siteUrl');
$oldScheme = parse_url($siteUrl, PHP_URL_SCHEME);
if ($oldScheme === false) {
$oldScheme = 'http';
}
}
return $oldScheme;
}
/**
* get relative path in archive of wordpress main paths
*
* @param string $pathKey (abs,home,plugins ...)
*
* @return string
*/
public function getRelativePathsInArchive($pathKey = null)
{
static $realtviePaths = null;
if (is_null($realtviePaths)) {
$realtviePaths = (array) $this->getRealValue('archivePaths');
foreach ($realtviePaths as $key => $path) {
$realtviePaths[$key] = SnapIO::getRelativePath($path, $this->wpInfo->targetRoot);
}
}
if (!empty($pathKey)) {
if (array_key_exists($pathKey, $realtviePaths)) {
return $realtviePaths[$pathKey];
} else {
return false;
}
} else {
return $realtviePaths;
}
}
/**
*
* @param string $path
* @param string|string[] $pathKeys
*
* @return boolean
*/
public function isChildOfArchivePath($path, $pathKeys = array())
{
if (is_scalar($pathKeys)) {
$pathKeys = array($pathKeys);
}
$mainPaths = $this->getRelativePathsInArchive();
foreach ($pathKeys as $key) {
if (!isset($mainPaths[$key])) {
continue;
}
if (strlen($mainPaths[$key]) == 0) {
return true;
}
if (strpos($path, $mainPaths[$key]) === 0) {
return true;
}
}
return false;
}
/**
*
* @staticvar string|bool $relativePath return false if PARAM_PATH_MUPLUGINS_NEW isn't a sub path of PARAM_PATH_NEW
* @return string
*/
public function getRelativeMuPlugins()
{
static $relativePath = null;
if (is_null($relativePath)) {
$relativePath = SnapIO::getRelativePath(
PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_MUPLUGINS_NEW),
PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW)
);
}
return $relativePath;
}
/**
* return the mapping paths from relative path of archive zip and target folder
* if exist only one entry return the target folter string
*
* @param bool $reset // if true recalculater path mappintg
*
* @return string|array
*/
public function getPathsMapping($reset = false)
{
static $pathsMapping = null;
if (is_null($pathsMapping) || $reset) {
$paramsManager = PrmMng::getInstance();
$pathsMapping = array();
$targeRootPath = $this->wpInfo->targetRoot;
$paths = (array) $this->getRealValue('archivePaths');
foreach ($paths as $key => $path) {
if (($relativePath = SnapIO::getRelativePath($path, $targeRootPath)) !== false) {
$paths[$key] = $relativePath;
}
}
$pathsMapping[$paths['home']] = $paramsManager->getValue(PrmMng::PARAM_PATH_NEW);
if ($paths['home'] !== $paths['abs']) {
$pathsMapping[$paths['abs']] = $paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW);
}
$pathsMapping[$paths['wpcontent']] = $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW);
$pathsMapping[$paths['plugins']] = $paramsManager->getValue(PrmMng::PARAM_PATH_PLUGINS_NEW);
$pathsMapping[$paths['muplugins']] = $paramsManager->getValue(PrmMng::PARAM_PATH_MUPLUGINS_NEW);
switch (DUPX_InstallerState::getInstType()) {
case DUPX_InstallerState::INSTALL_SINGLE_SITE:
case DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE:
$pathsMapping[$paths['uploads']] = $paramsManager->getValue(PrmMng::PARAM_PATH_UPLOADS_NEW);
break;
case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBDOMAIN:
case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBFOLDER:
throw new Exception('Mode not avaiable');
case DUPX_InstallerState::INSTALL_NOT_SET:
throw new Exception('Cannot change setup with current installation type [' . DUPX_InstallerState::getInstType() . ']');
default:
throw new Exception('Unknown mode');
}
// remove all empty values for safe,
// This should never happen, but if it does, there is a risk that the installer will remove all the files in the server root.
$pathsMapping = array_filter($pathsMapping, function ($value) {
return strlen($value) > 0;
});
$pathsMapping = SnapIO::sortBySubfoldersCount($pathsMapping, true, false, true);
$unsetKeys = array();
foreach (array_reverse($pathsMapping) as $oldPathA => $newPathA) {
foreach ($pathsMapping as $oldPathB => $newPathB) {
if ($oldPathA == $oldPathB) {
continue;
}
if (
($relativePathOld = SnapIO::getRelativePath($oldPathA, $oldPathB)) === false ||
($relativePathNew = SnapIO::getRelativePath($newPathA, $newPathB)) === false
) {
continue;
}
if ($relativePathOld == $relativePathNew) {
$unsetKeys[] = $oldPathA;
break;
}
}
}
foreach (array_unique($unsetKeys) as $unsetKey) {
unset($pathsMapping[$unsetKey]);
}
$tempArray = $pathsMapping;
$pathsMapping = array();
foreach ($tempArray as $key => $val) {
$pathsMapping['/' . $key] = $val;
}
switch (count($pathsMapping)) {
case 0:
throw new Exception('Paths archive mapping is inconsistent');
break;
case 1:
$pathsMapping = reset($pathsMapping);
break;
default:
}
Log::info("--------------------------------------");
Log::info('PATHS MAPPING : ' . Log::v2str($pathsMapping));
Log::info("--------------------------------------");
}
return $pathsMapping;
}
/**
* get absolute target path from archive relative path
*
* @param string $pathInArchive
*
* @return string
*/
public function destFileFromArchiveName($pathInArchive)
{
$pathsMapping = $this->getPathsMapping();
if (is_string($pathsMapping)) {
return $pathsMapping . '/' . ltrim($pathInArchive, '\\/');
}
if (strlen($pathInArchive) === 0) {
$pathInArchive = '/';
} elseif ($pathInArchive[0] != '/') {
$pathInArchive = '/' . $pathInArchive;
}
foreach ($pathsMapping as $archiveMainPath => $newMainPath) {
if (($relative = SnapIO::getRelativePath($pathInArchive, $archiveMainPath)) !== false) {
return $newMainPath . '/' . $relative;
}
}
// if don't find corrispondance in mapping get the path new as default (this should never happen)
return PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW) . '/' . ltrim($pathInArchive, '\\/');
}
/**
*
* @return string[]
*/
public function invalidCharsets()
{
return array_diff($this->dbInfo->charSetList, DUPX_DB_Functions::getInstance()->getCharsetsList());
}
/**
*
* @return string[]
*/
public function invalidCollations()
{
return array_diff($this->dbInfo->collationList, DUPX_DB_Functions::getInstance()->getCollationsList());
}
/**
*
* @return string[] list of MySQL engines in source site not supported by the current database
* @throws Exception
*/
public function invalidEngines()
{
return array_diff($this->dbInfo->engineList, DUPX_DB_Functions::getInstance()->getSupportedEngineList());
}
/**
*
* @param WPConfigTransformer $confTrans
* @param string $defineKey
* @param string $paramKey
*/
public static function updateWpConfigByParam(WPConfigTransformer $confTrans, $defineKey, $paramKey)
{
$paramsManager = PrmMng::getInstance();
$wpConfVal = $paramsManager->getValue($paramKey);
return self::updateWpConfigByValue($confTrans, $defineKey, $wpConfVal);
}
/**
*
* @param WPConfigTransformer $confTrans
* @param string $defineKey
* @param mixed $wpConfVal
*/
/**
* Update wp conf
*
* @param WPConfigTransformer $confTrans
* @param string $defineKey
* @param array $wpConfVal
* @param mixed $customValue if is not null custom value overwrite value
*
* @return void
*/
public static function updateWpConfigByValue(WPConfigTransformer $confTrans, $defineKey, $wpConfVal, $customValue = null)
{
if ($wpConfVal['inWpConfig']) {
$stringVal = '';
if ($customValue !== null) {
$stringVal = $customValue;
$updParam = array('raw' => true, 'normalize' => true);
} else {
switch (gettype($wpConfVal['value'])) {
case "boolean":
$stringVal = $wpConfVal['value'] ? 'true' : 'false';
$updParam = array('raw' => true, 'normalize' => true);
break;
case "integer":
case "double":
$stringVal = (string) $wpConfVal['value'];
$updParam = array('raw' => true, 'normalize' => true);
break;
case "string":
$stringVal = $wpConfVal['value'];
$updParam = array('raw' => false, 'normalize' => true);
break;
case "NULL":
$stringVal = 'null';
$updParam = array('raw' => true, 'normalize' => true);
break;
case "array":
case "object":
case "resource":
case "resource (closed)":
case "unknown type":
default:
$stringVal = '';
$updParam = array('raw' => true, 'normalize' => true);
break;
}
}
Log::info('WP CONFIG UPDATE ' . $defineKey . ' ' . Log::v2str($stringVal));
$confTrans->update('constant', $defineKey, $stringVal, $updParam);
} else {
if ($confTrans->exists('constant', $defineKey)) {
Log::info('WP CONFIG REMOVE ' . $defineKey);
$confTrans->remove('constant', $defineKey);
}
}
}
}

View File

@@ -0,0 +1,471 @@
<?php
/**
* Class used to update and edit web server configuration files
* for .htaccess, web.config and user.ini
*
* Standard: PSR-2
*
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
*
* @package SC\DUPX\ServerConfig
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
use Duplicator\Installer\Utils\Log\Log;
use Duplicator\Installer\Core\Params\PrmMng;
use Duplicator\Libs\Snap\SnapIO;
class DUPX_ServerConfig
{
const INSTALLER_HOST_ENTITY_PREFIX = 'installer_host_';
const CONFIG_ORIG_FILE_USERINI_ID = 'userini';
const CONFIG_ORIG_FILE_HTACCESS_ID = 'htaccess';
const CONFIG_ORIG_FILE_WPCONFIG_ID = 'wpconfig';
const CONFIG_ORIG_FILE_PHPINI_ID = 'phpini';
const CONFIG_ORIG_FILE_WEBCONFIG_ID = 'webconfig';
const CONFIG_ORIG_FILE_USERINI_ID_OVERWRITE_SITE = 'installer_host_userini';
const CONFIG_ORIG_FILE_HTACCESS_ID_OVERWRITE_SITE = 'installer_host_htaccess';
const CONFIG_ORIG_FILE_WPCONFIG_ID_OVERWRITE_SITE = 'installer_host_wpconfig';
const CONFIG_ORIG_FILE_PHPINI_ID_OVERWRITE_SITE = 'installer_host_phpini';
const CONFIG_ORIG_FILE_WEBCONFIG_ID_OVERWRITE_SITE = 'installer_host_webconfig';
/**
* Common timestamp of all members of this class
*
* @staticvar type $time
* @return type
*/
public static function getFixedTimestamp()
{
static $time = null;
if (is_null($time)) {
$time = date("ymdHis");
}
return $time;
}
/**
* Creates a copy of the original server config file and resets the original to blank
*
* @param string $rootPath The root path to the location of the server config files
*
* @return null
* @throws Exception
*/
public static function reset($rootPath)
{
$rootPath = SnapIO::trailingslashit($rootPath);
$paramsManager = PrmMng::getInstance();
Log::info("\n*** RESET CONFIG FILES IN CURRENT HOSTING >>> START");
switch ($paramsManager->getValue(PrmMng::PARAM_WP_CONFIG)) {
case 'modify':
case 'new':
if (self::runReset($rootPath . 'wp-config.php', self::CONFIG_ORIG_FILE_WPCONFIG_ID) === false) {
$paramsManager->setValue(PrmMng::PARAM_WP_CONFIG, 'nothing');
}
break;
case 'nothing':
break;
}
switch ($paramsManager->getValue(PrmMng::PARAM_HTACCESS_CONFIG)) {
case 'new':
case 'original':
if (self::runReset($rootPath . '.htaccess', self::CONFIG_ORIG_FILE_HTACCESS_ID) === false) {
$paramsManager->setValue(PrmMng::PARAM_HTACCESS_CONFIG, 'nothing');
}
break;
case 'nothing':
break;
}
switch ($paramsManager->getValue(PrmMng::PARAM_OTHER_CONFIG)) {
case 'new':
case 'original':
if (self::runReset($rootPath . 'web.config', self::CONFIG_ORIG_FILE_WEBCONFIG_ID) === false) {
$paramsManager->setValue(PrmMng::PARAM_OTHER_CONFIG, 'nothing');
}
if (self::runReset($rootPath . '.user.ini', self::CONFIG_ORIG_FILE_USERINI_ID) === false) {
$paramsManager->setValue(PrmMng::PARAM_OTHER_CONFIG, 'nothing');
}
if (self::runReset($rootPath . 'php.ini', self::CONFIG_ORIG_FILE_PHPINI_ID) === false) {
$paramsManager->setValue(PrmMng::PARAM_OTHER_CONFIG, 'nothing');
}
break;
case 'nothing':
break;
}
$paramsManager->save();
Log::info("\n*** RESET CONFIG FILES IN CURRENT HOSTING >>> END");
}
public static function setFiles($rootPath)
{
$paramsManager = PrmMng::getInstance();
$origFiles = DUPX_Orig_File_Manager::getInstance();
Log::info("SET CONFIG FILES");
$entryKey = self::CONFIG_ORIG_FILE_WPCONFIG_ID;
switch ($paramsManager->getValue(PrmMng::PARAM_WP_CONFIG)) {
case 'new':
if (SnapIO::copy(DUPX_Package::getWpconfigSamplePath(), DUPX_WPConfig::getWpConfigPath()) === false) {
DUPX_NOTICE_MANAGER::getInstance()->addFinalReportNotice(array(
'shortMsg' => 'Can\' reset wp-config to wp-config-sample',
'level' => DUPX_NOTICE_ITEM::CRITICAL,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Target file entry ' . Log::v2str(DUPX_WPConfig::getWpConfigPath()),
'sections' => 'general'
));
} else {
Log::info("Copy wp-config-sample.php to target:" . DUPX_WPConfig::getWpConfigPath());
}
break;
case 'modify':
if (SnapIO::copy($origFiles->getEntryStoredPath($entryKey), DUPX_WPConfig::getWpConfigPath()) === false) {
DUPX_NOTICE_MANAGER::getInstance()->addFinalReportNotice(array(
'shortMsg' => 'Can\' restore oirg file entry ' . $entryKey,
'level' => DUPX_NOTICE_ITEM::CRITICAL,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Target file entry ' . Log::v2str(DUPX_WPConfig::getWpConfigPath()),
'sections' => 'general'
));
} else {
Log::info("Retained original entry " . $entryKey . " target:" . DUPX_WPConfig::getWpConfigPath());
}
break;
case 'nothing':
break;
}
$entryKey = self::CONFIG_ORIG_FILE_HTACCESS_ID;
switch ($paramsManager->getValue(PrmMng::PARAM_HTACCESS_CONFIG)) {
case 'new':
$targetHtaccess = self::getHtaccessTargetPath();
if (SnapIO::touch($targetHtaccess) === false) {
DUPX_NOTICE_MANAGER::getInstance()->addFinalReportNotice(array(
'shortMsg' => 'Can\'t create new htaccess file',
'level' => DUPX_NOTICE_ITEM::CRITICAL,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Target file entry ' . $targetHtaccess,
'sections' => 'general'
));
} else {
Log::info("New htaccess file created:" . $targetHtaccess);
}
break;
case 'original':
if (($storedHtaccess = $origFiles->getEntryStoredPath($entryKey)) === false) {
Log::info("Retained original entry. htaccess doesn\'t exist in original site");
break;
}
$targetHtaccess = self::getHtaccessTargetPath();
if (SnapIO::copy($storedHtaccess, $targetHtaccess) === false) {
DUPX_NOTICE_MANAGER::getInstance()->addFinalReportNotice(array(
'shortMsg' => 'Can\' restore oirg file entry ' . $entryKey,
'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Target file entry ' . Log::v2str($targetHtaccess),
'sections' => 'general'
));
} else {
Log::info("Retained original entry " . $entryKey . " target:" . $targetHtaccess);
}
break;
case 'nothing':
break;
}
switch ($paramsManager->getValue(PrmMng::PARAM_OTHER_CONFIG)) {
case 'new':
if ($origFiles->getEntry(self::CONFIG_ORIG_FILE_WEBCONFIG_ID_OVERWRITE_SITE)) {
//IIS: This is reset because on some instances of IIS having old values cause issues
//Recommended fix for users who want it because errors are triggered is to have
//them check the box for ignoring the web.config files on step 1 of installer
$xml_contents = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$xml_contents .= "<!-- Reset by Duplicator Installer. Original can be found in the original_files_ folder-->\n";
$xml_contents .= "<configuration></configuration>\n";
if (file_put_contents($rootPath . "/web.config", $xml_contents) === false) {
Log::info('RESET: can\'t create a new empty web.config');
}
}
break;
case 'original':
$entries = array(
self::CONFIG_ORIG_FILE_USERINI_ID,
self::CONFIG_ORIG_FILE_WEBCONFIG_ID,
self::CONFIG_ORIG_FILE_PHPINI_ID
);
foreach ($entries as $entryKey) {
if ($origFiles->getEntry($entryKey) !== false) {
if (SnapIO::copy($origFiles->getEntryStoredPath($entryKey), $origFiles->getEntryTargetPath($entryKey, false)) === false) {
DUPX_NOTICE_MANAGER::getInstance()->addFinalReportNotice(array(
'shortMsg' => 'Notice: Cannot restore original file entry ' . $entryKey,
'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Target file entry ' . Log::v2str($origFiles->getEntryTargetPath($entryKey, false)),
'sections' => 'general'
));
} else {
Log::info("Retained original entry " . $entryKey . " target:" . $origFiles->getEntryTargetPath($entryKey, false));
}
}
}
break;
case 'nothing':
break;
}
DUPX_NOTICE_MANAGER::getInstance()->saveNotices();
}
public static function getHtaccessTargetPath()
{
if (($targetEnty = DUPX_Orig_File_Manager::getInstance()->getEntryTargetPath(self::CONFIG_ORIG_FILE_HTACCESS_ID, false)) !== false) {
return $targetEnty;
} else {
return PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW) . '/.htaccess';
}
}
/**
* Moves the configuration file to the dup_installer/original_files_[hash] folder
*
* @param string $filePath file path to store
* @param string $storedName if not false rename
*
* @return bool Returns true if the file was backed-up and reset or there was no file to reset
*/
private static function runReset($filePath, $storedName)
{
$fileName = basename($filePath);
try {
if (file_exists($filePath)) {
if (!SnapIO::chmod($filePath, 'u+rw') || !is_readable($filePath) || !is_writable($filePath)) {
throw new Exception("RESET CONFIG FILES: permissions error on file config path " . $filePath);
}
$origFiles = DUPX_Orig_File_Manager::getInstance();
$filePath = SnapIO::safePathUntrailingslashit($filePath);
Log::info("RESET CONFIG FILES: I'M GOING TO MOVE CONFIG FILE " . Log::v2str($fileName) . " IN ORIGINAL FOLDER");
if (
$origFiles->addEntry(
self::INSTALLER_HOST_ENTITY_PREFIX . $storedName,
$filePath,
DUPX_Orig_File_Manager::MODE_MOVE,
self::INSTALLER_HOST_ENTITY_PREFIX . $storedName
)
) {
Log::info("\tCONFIG FILE HAS BEEN RESET");
} else {
throw new Exception("cannot store file " . Log::v2str($fileName) . " in orginal file folder");
}
} else {
Log::info("RESET CONFIG FILES: " . Log::v2str($fileName) . " does not exist, no need for reset", Log::LV_DETAILED);
}
} catch (Exception $e) {
Log::logException($e, Log::LV_DEFAULT, 'RESET CONFIG FILES ERROR: ');
DUPX_NOTICE_MANAGER::getInstance()->addBothNextAndFinalReportNotice(array(
'shortMsg' => 'Can\'t reset config file ' . Log::v2str($fileName) . ' so it will not be modified.',
'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Message: ' . $e->getMessage(),
'sections' => 'general'
));
return false;
} catch (Error $e) {
Log::logException($e, Log::LV_DEFAULT, 'RESET CONFIG FILES ERROR: ');
DUPX_NOTICE_MANAGER::getInstance()->addBothNextAndFinalReportNotice(array(
'shortMsg' => 'Can\'t reset config file ' . Log::v2str($fileName) . ' so it will not be modified.',
'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Message: ' . $e->getMessage(),
'sections' => 'general'
));
return false;
}
return true;
}
/**
*
* @return boolean|string false if loca config don't exists or path of store local config
*/
public static function getWpConfigLocalStoredPath()
{
$origFiles = DUPX_Orig_File_Manager::getInstance();
$entry = self::CONFIG_ORIG_FILE_WPCONFIG_ID_OVERWRITE_SITE;
if ($origFiles->getEntry($entry)) {
return $origFiles->getEntryStoredPath($entry);
} else {
return false;
}
}
/**
* Get AddHandler line from existing WP .htaccess file
*
* @return string
* @throws Exception
*/
private static function getOldHtaccessAddhandlerLine()
{
$origFiles = DUPX_Orig_File_Manager::getInstance();
$backupHtaccessPath = $origFiles->getEntryStoredPath(self::CONFIG_ORIG_FILE_HTACCESS_ID_OVERWRITE_SITE);
Log::info("Installer Host Htaccess path: " . $backupHtaccessPath, Log::LV_DEBUG);
if ($backupHtaccessPath !== false && file_exists($backupHtaccessPath)) {
$htaccessContent = file_get_contents($backupHtaccessPath);
if (!empty($htaccessContent)) {
// match and trim non commented line "AddHandler application/x-httpd-XXXX .php" case insenstive
$re = '/^[\s\t]*[^#]?[\s\t]*(AddHandler[\s\t]+.+\.php[ \t]?.*?)[\s\t]*$/mi';
$matches = array();
if (preg_match($re, $htaccessContent, $matches)) {
return "\n" . $matches[1];
}
}
}
return '';
}
/**
* Sets up the web config file based on the inputs from the installer forms.
*
* @param int $mu_mode Is this site a specific multi-site mode
* @param object $dbh The database connection handle for this request
* @param string $path The path to the config file
*
* @return null
*/
public static function setup($dbh, $path)
{
Log::info("\nWEB SERVER CONFIGURATION FILE UPDATED:");
$paramsManager = PrmMng::getInstance();
$htAccessPath = "{$path}/.htaccess";
$mu_generation = DUPX_ArchiveConfig::getInstance()->mu_generation;
// SKIP HTACCESS
$skipHtaccessConfigVals = array('nothing', 'original');
if (in_array($paramsManager->getValue(PrmMng::PARAM_HTACCESS_CONFIG), $skipHtaccessConfigVals)) {
if (!DUPX_InstallerState::isRestoreBackup()) {
// on restore packup mode no warning needed
$longMsg = 'Retaining the original .htaccess file from the old site or not creating a new one may cause issues with the initial setup '
. 'of this site. If you encounter any issues, validate the contents of the .htaccess file or reinstall the site again using the '
. 'Step 1 Options Advanced Configuration Files Apache .htaccess Create New option. If your site works as expected this '
. 'message can be ignored.';
DUPX_NOTICE_MANAGER::getInstance()->addFinalReportNotice(array(
'shortMsg' => 'Notice: A new .htaccess file was not created',
'level' => DUPX_NOTICE_ITEM::NOTICE,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => $longMsg,
'sections' => 'general'
));
}
return;
}
$timestamp = date("Y-m-d H:i:s");
$post_url_new = $paramsManager->getValue(PrmMng::PARAM_URL_NEW);
$newdata = parse_url($post_url_new);
$newpath = DUPX_U::addSlash(isset($newdata['path']) ? $newdata['path'] : "");
$update_msg = "# This file was updated by Duplicator on {$timestamp}.\n";
$update_msg .= "# See the original_files_ folder for the original source_site_htaccess file.";
$update_msg .= self::getOldHtaccessAddhandlerLine();
switch (DUPX_InstallerState::getInstType()) {
case DUPX_InstallerState::INSTALL_SINGLE_SITE:
case DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE:
$tmp_htaccess = self::htAcccessNoMultisite($update_msg, $newpath, $dbh);
Log::info("- Preparing .htaccess file with basic setup.");
break;
case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBDOMAIN:
case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBFOLDER:
case DUPX_InstallerState::INSTALL_NOT_SET:
throw new Exception('Cannot change setup with current installation type [' . DUPX_InstallerState::getInstType() . ']');
default:
throw new Exception('Unknown mode');
}
if (file_exists($htAccessPath) && SnapIO::chmod($htAccessPath, 'u+rw') === false) {
Log::info("WARNING: Unable to update htaccess file permessition.");
DUPX_NOTICE_MANAGER::getInstance()->addFinalReportNotice(array(
'shortMsg' => 'Notice: Unable to update new .htaccess file',
'level' => DUPX_NOTICE_ITEM::CRITICAL,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Unable to update the .htaccess file! Please check the permission on the root directory and make sure the .htaccess exists.',
'sections' => 'general'
));
} elseif (file_put_contents($htAccessPath, $tmp_htaccess) === false) {
Log::info("WARNING: Unable to update the .htaccess file! Please check the permission on the root directory and make sure the .htaccess exists.");
DUPX_NOTICE_MANAGER::getInstance()->addFinalReportNotice(array(
'shortMsg' => 'Noitice: Unable to update new .htaccess file',
'level' => DUPX_NOTICE_ITEM::CRITICAL,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
'longMsg' => 'Unable to update the .htaccess file! Please check the permission on the root directory and make sure the .htaccess exists.',
'sections' => 'general'
));
} else {
DUP_Extraction::setPermsFromParams($htAccessPath);
Log::info("HTACCESS FILE - Successfully updated the .htaccess file setting.");
}
}
private static function htAcccessNoMultisite($update_msg, $newpath, $dbh)
{
$result = '';
// no multisite
$empty_htaccess = false;
$optonsTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getOptionsTableName());
$query_result = DUPX_DB::mysqli_query($dbh, "SELECT option_value FROM `" . $optonsTable . "` WHERE option_name = 'permalink_structure' ");
if ($query_result) {
$row = @mysqli_fetch_array($query_result);
if ($row != null) {
$permalink_structure = trim($row[0]);
$empty_htaccess = empty($permalink_structure);
}
}
if ($empty_htaccess) {
Log::info('NO PERMALINK STRUCTURE FOUND: set htaccess without directives');
$result = <<<EMPTYHTACCESS
{$update_msg}
# BEGIN WordPress
# The directives (lines) between `BEGIN WordPress` and `END WordPress` are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
# END WordPress
EMPTYHTACCESS;
} else {
$result = <<<HTACCESS
{$update_msg}
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase {$newpath}
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . {$newpath}index.php [L]
</IfModule>
# END WordPress
HTACCESS;
}
return $result;
}
}

View File

@@ -0,0 +1,97 @@
<?php
/**
* Standard: PSR-2
*
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
*
* @package SC\DUPX
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* In this class all the utility functions related to the wordpress configuration and the package are defined.
*/
class DUPX_Conf_Utils
{
/**
*
* @staticvar null|bool $present
* @return bool
*/
public static function isConfArkPresent()
{
static $present = null;
if (is_null($present)) {
$present = file_exists(DUPX_Package::getWpconfigArkPath());
}
return $present;
}
/**
*
* @staticvar bool $present
* @return bool
*/
public static function isManualExtractFilePresent()
{
static $present = null;
if (is_null($present)) {
$present = file_exists(DUPX_Package::getManualExtractFile());
}
return $present;
}
/**
*
* @staticvar null|bool $enable
* @return bool
*/
public static function shellExecUnzipEnable()
{
static $enable = null;
if (is_null($enable)) {
$enable = DUPX_Server::get_unzip_filepath() != null;
}
return $enable;
}
/**
*
* @return bool
*/
public static function classZipArchiveEnable()
{
return class_exists('ZipArchive');
}
/**
*
* @staticvar bool $exists
* @return bool
*/
public static function archiveExists()
{
static $exists = null;
if (is_null($exists)) {
$exists = file_exists(DUPX_Security::getInstance()->getArchivePath());
}
return $exists;
}
/**
*
* @staticvar bool $arcSize
* @return bool
*/
public static function archiveSize()
{
static $arcSize = null;
if (is_null($arcSize)) {
$archivePath = DUPX_Security::getInstance()->getArchivePath();
$arcSize = file_exists($archivePath) ? (int) @filesize($archivePath) : 0;
}
return $arcSize;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* Class used to update and edit web server configuration files
* for both Apache and IIS files .htaccess and web.config
*
* Standard: PSR-2
*
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
*
* @package SC\DUPX\WPConfig
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
use Duplicator\Installer\Core\Params\PrmMng;
use Duplicator\Libs\Snap\SnapIO;
use Duplicator\Libs\WpConfig\WPConfigTransformer;
class DUPX_WPConfig
{
const ADMIN_SERIALIZED_SECURITY_STRING = 'a:1:{s:13:"administrator";b:1;}';
const ADMIN_LEVEL = 10;
/**
* get wp-config default path (not relative to orig file manger)
*
* @return string
*/
public static function getWpConfigDeafultPath()
{
return PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW) . '/wp-config.php';
}
/**
*
* @return bool|string false if fail
*/
public static function getWpConfigPath()
{
$origWpConfTarget = DUPX_Orig_File_Manager::getInstance()->getEntryTargetPath(DUPX_ServerConfig::CONFIG_ORIG_FILE_WPCONFIG_ID, self::getWpConfigDeafultPath());
$origWpDir = SnapIO::safePath(dirname($origWpConfTarget));
if ($origWpDir === PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW)) {
return $origWpConfTarget;
} else {
return PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW) . "/wp-config.php";
}
}
/**
*
* @staticvar boolean|WPConfigTransformer $confTransformer
*
* @return boolean|WPConfigTransformer
*/
public static function getLocalConfigTransformer()
{
static $confTransformer = null;
if (is_null($confTransformer)) {
try {
if (($wpConfigPath = DUPX_ServerConfig::getWpConfigLocalStoredPath()) === false) {
$wpConfigPath = DUPX_WPConfig::getWpConfigPath();
}
if (is_readable($wpConfigPath)) {
$confTransformer = new WPConfigTransformer($wpConfigPath);
} else {
$confTransformer = false;
}
} catch (Exception $e) {
$confTransformer = false;
}
}
return $confTransformer;
}
/**
*
* @param string $name
* @param string $type // constant | variable
* @param mixed $default
*
* @return mixed
*/
public static function getValueFromLocalWpConfig($name, $type = 'constant', $default = '')
{
if (($confTransformer = self::getLocalConfigTransformer()) !== false) {
return $confTransformer->exists($type, $name) ? $confTransformer->getValue($type, $name) : $default;
} else {
return null;
}
}
}

View File

@@ -0,0 +1,195 @@
<?php
/**
* Class used to group all global constants
*
* Standard: PSR-2
*
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
*
* @package SC\DUPX\Constants
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
use Duplicator\Installer\Core\Bootstrap;
use Duplicator\Installer\Utils\InstallerLinkManager;
class DUPX_Constants
{
const CHUNK_EXTRACTION_TIMEOUT_TIME_ZIP = 5;
const CHUNK_EXTRACTION_TIMEOUT_TIME_DUP = 5;
const CHUNK_DBINSTALL_TIMEOUT_TIME = 5;
const CHUNK_MAX_TIMEOUT_TIME = 5;
const DEFAULT_MAX_STRLEN_SERIALIZED_CHECK_IN_M = 4; // 0 no limit
const DUP_SITE_URL = 'https://duplicator.com/';
const FAQ_URL = 'https://duplicator.com/knowledge-base/';
const URL_SUBSCRIBE = 'https://duplicator.com/?lite_email_signup=1';
const MIN_NEW_PASSWORD_LEN = 6;
const BACKUP_RENAME_PREFIX = 'dp___bk_';
const UPSELL_DEFAULT_DISCOUNT = 50; // Default discount for upsell
/**
* Init method used to auto initialize the global params
* This function init all params before read from request
*
* @return null
*/
public static function init()
{
//DATABASE SETUP: all time in seconds
//max_allowed_packet: max value 1073741824 (1268MB) see my.ini
$GLOBALS['DB_MAX_TIME'] = 5000;
$GLOBALS['DATABASE_PAGE_SIZE'] = 3500;
$GLOBALS['DB_MAX_PACKETS'] = 268435456;
$GLOBALS['DBCHARSET_DEFAULT'] = 'utf8';
$GLOBALS['DBCOLLATE_DEFAULT'] = 'utf8_general_ci';
$GLOBALS['DB_RENAME_PREFIX'] = self::BACKUP_RENAME_PREFIX . date("dHi") . '_';
$GLOBALS['DB_INSTALL_MULTI_THREADED_MAX_RETRIES'] = 3;
if (!defined('MAX_SITES_TO_DEFAULT_ENABLE_CORSS_SEARCH')) {
define('MAX_SITES_TO_DEFAULT_ENABLE_CORSS_SEARCH', 10);
}
//UPDATE TABLE SETTINGS
$GLOBALS['REPLACE_LIST'] = array();
$GLOBALS['DEBUG_JS'] = false;
//GLOBALS
$GLOBALS["NOTICES_FILE_PATH"] = DUPX_INIT . '/' . "dup-installer-notices__" . Bootstrap::getPackageHash() . ".json";
$GLOBALS["CHUNK_DATA_FILE_PATH"] = DUPX_INIT . '/' . "dup-installer-chunk__" . Bootstrap::getPackageHash() . ".json";
$GLOBALS['PHP_MEMORY_LIMIT'] = ini_get('memory_limit') === false ? 'n/a' : ini_get('memory_limit');
$GLOBALS['PHP_SUHOSIN_ON'] = extension_loaded('suhosin') ? 'enabled' : 'disabled';
$GLOBALS['DISPLAY_MAX_OBJECTS_FAILED_TO_SET_PERM'] = 5;
// Displaying notice for slow zip chunk extraction
$GLOBALS['ZIP_ARC_CHUNK_EXTRACT_DISP_NOTICE_AFTER'] = 5 * 60 * 60; // 5 minutes
$GLOBALS['ZIP_ARC_CHUNK_EXTRACT_DISP_NOTICE_MIN_EXPECTED_EXTRACT_TIME'] = 10 * 60 * 60; // 10 minutes
$GLOBALS['ZIP_ARC_CHUNK_EXTRACT_DISP_NEXT_NOTICE_INTERVAL'] = 5 * 60 * 60; // 5 minutes
$helpUrl = InstallerLinkManager::getDocUrl('how-to-handle-various-install-scenarios', 'install', 'additional help');
$additional_msg = ' for additional details ';
$additional_msg .= '<a href="' . $helpUrl . '" target="_blank">click here</a>.';
$GLOBALS['ZIP_ARC_CHUNK_EXTRACT_NOTICES'] = array(
'This server looks to be under load or throttled, the extraction process may take some time',
'This host is currently experiencing very slow I/O. You can continue to wait or try a manual extraction.',
'This host I/O is currently having issues. It is recommended to try a manual extraction.',
);
foreach ($GLOBALS['ZIP_ARC_CHUNK_EXTRACT_NOTICES'] as $key => $val) {
$GLOBALS['ZIP_ARC_CHUNK_EXTRACT_NOTICES'][$key] = $val . $additional_msg;
}
$GLOBALS['FW_USECDN'] = false;
$GLOBALS['NOW_TIME'] = @date("His");
self::initErrDefines();
}
protected static function initErrDefines()
{
define('ERR_CONFIG_FOUND', 'A wp-config.php already exists in this location. ' .
'This error prevents users from accidentally overwriting a WordPress site or trying to install on top of an existing one. ' .
'When the archive file is extracted it can overwrite existing items if they have the same name. ' .
'If you have already manually extracted the installer then choose #1 other-wise consider these options: ' .
'<ol><li>Click &gt; Try Again &gt; Options &gt; choose "Manual Archive Extraction".</li>' .
'<li>Delete the wp-config.php file and try again.</li>' .
'<li>Empty the root directory except for the package and installer and try again.</li></ol>');
define('ERR_ZIPNOTFOUND', 'The packaged zip file was not found or has become unreadable. ' .
'Be sure the zip package is in the same directory as the installer file. ' .
'If you are trying to reinstall a package you can copy the package from the source site, ' .
' back up to your root which is the same location as your installer file.');
define('ERR_SHELLEXEC_ZIPOPEN', 'Failed to extract the archive using shell_exec unzip');
define(
'ERR_ZIPOPEN',
'Failed to open the zip archive file. Please be sure the archive is completely downloaded before running the installer. ' .
'Try to extract the archive manually to make sure the file is not corrupted.'
);
define(
'ERR_ZIPEXTRACTION',
'Errors extracting the zip file. Portions or part of the zip archive did not extract correctly.' .
' Try to extract the archive manually with a client side program like unzip/win-zip/winrar to make sure the file is not corrupted.' .
' If the file extracts correctly then there is an invalid file or directory that PHP is unable to extract.' .
'This can happen if you are moving from one operating system to another where certain naming ' .
'conventions work on one environment and not another. <br/><br/> Workarounds: <br/> 1. ' .
'Create a new package and be sure to exclude any directories that have name checks or files in them.' .
'This warning will be displayed on the scan results under "Name Checks". <br/> 2. Manually extract the zip file with a client side program.' .
'Then under options in step 1 of the installer select the "Manual Archive Extraction" option and perform the install.'
);
define(
'ERR_ZIPMANUAL',
'When choosing "Manual Archive Extraction", the contents of the package must already be extracted for the process to continue.' .
'Please manually extract the package into the current directory before continuing in manual extraction mode.'
);
define(
'ERR_MAKELOG',
'PHP is having issues writing to the log file <b>' . DUPX_INIT . '\dup-installer-log__[HASH].txt .</b>' .
'In order for the Duplicator to proceed to validate your owner/group and permission settings for PHP on this path. ' .
'Try temporarily setting you permissions to 777 to see if the issue gets resolved. ' .
'If you are on a shared hosting environment please contact your hosting company and tell ' .
'them you are getting errors writing files to the path above when using PHP.'
);
define(
'ERR_ZIPARCHIVE',
'In order to extract the archive.zip file, the PHP ZipArchive module must be installed.' .
'Please read the FAQ for more details. You can still install this package but you will need to select the ' .
'"Manual Archive Extraction" options found under Options. ' .
'Please read the online user guide for details in performing a manual archive extraction.'
);
define(
'ERR_MYSQLI_SUPPORT',
'In order to complete an install the mysqli extension for PHP is required.' .
'If you are on a hosted server please contact your host and request that mysqli be enabled.' .
' For more information visit: http://php.net/manual/en/mysqli.installation.php'
);
define(
'ERR_DBCONNECT',
'DATABASE CONNECTION FAILED!<br/>'
);
define(
'ERR_DBCONNECT_CREATE',
'DATABASE CREATION FAILURE!<br/> Unable to create database "%s". ' .
'Check to make sure the user has "Create" privileges. ' .
'Some hosts will restrict the creation of a database only through the cpanel. ' .
'Try creating the database manually to proceed with the installation. ' .
'If the database already exists select the action "Connect and Remove All Data" which will remove all existing tables.'
);
define('ERR_DROP_TABLE_TRYCLEAN', 'TABLE CLEAN FAILURE'
. 'Unable to remove TABLE "%s" from database "%s".<br/>'
. 'Please remove all tables from this database and try the installation again. '
. 'If no tables show in the database, then Drop the database and re-create it.<br/>'
. 'ERROR MESSAGE: %s');
define('ERR_DROP_PROCEDURE_TRYCLEAN', 'PROCEDURE CLEAN FAILURE. '
. 'Please remove all procedures from this database and try the installation again. '
. 'If no procedures show in the database, then Drop the database and re-create it.<br/>'
. 'ERROR MESSAGE: %s <br/><br/>');
define('ERR_DROP_FUNCTION_TRYCLEAN', 'FUNCTION CLEAN FAILURE. '
. 'Please remove all functions from this database and try the installation again. '
. 'If no functions show in the database, then Drop the database and re-create it.<br/>'
. 'ERROR MESSAGE: %s <br/><br/>');
define('ERR_DROP_VIEW_TRYCLEAN', 'VIEW CLEAN FAILURE. '
. 'Please remove all views from this database and try the installation again. '
. 'If no views show in the database, then Drop the database and re-create it.<br/>'
. 'ERROR MESSAGE: %s <br/><br/>');
define(
'ERR_DBCREATE',
'The database "%s" does not exist.<br/> Change the action to create in order ' .
'to "Create New Database" to create the database. ' .
'Some hosting providers do not allow database creation except through their control panels. ' .
' In this case, you will need to log in to your hosting providers control panel and create the database manually. ' .
'Please contact your hosting provider for further details on how to create the database.'
);
define(
'ERR_DBEMPTY',
'The database "%s" already exists and has "%s" tables. ' .
' When using the "Create New Database" action the database should not exist. ' .
' Select the action "Connect and Remove All Data" or "Connect and Backup Any Existing Data" ' .
'to remove or backup the existing tables or choose a database name that does not already exist. ' .
'Some hosting providers do not allow table removal or renaming from scripts. ' .
'In this case, you will need to log in to your hosting providers\' control panel and remove or rename the tables manually. ' .
' Please contact your hosting provider for further details. Always backup all your data before proceeding!'
);
define('ERR_CPNL_API', 'The cPanel API had the following issues when trying to communicate on this host: <br/> %s');
}
}

View File

@@ -0,0 +1,361 @@
<?php
/**
* Security class
*
* Standard: PSR-2
*
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
*
* @package SC\DUPX\Constants
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
use Duplicator\Installer\Utils\Log\Log;
use Duplicator\Installer\Core\Bootstrap;
use Duplicator\Installer\Core\Params\PrmMng;
use Duplicator\Installer\Core\Params\Items\ParamItem;
use Duplicator\Libs\Snap\SnapIO;
use Duplicator\Libs\Snap\SnapUtil;
/**
* singleton class
*
* In this class all installer security checks are performed. If the security checks are not passed, an exception is thrown and the installer is stopped.
* This happens before anything else so the class must work without the initialization of all global duplicator variables.
*/
class DUPX_Security
{
const CTRL_TOKEN = 'ctrl_csrf_token';
const ROUTER_TOKEN = 'router_csrf_token';
const SECURITY_NONE = 'none';
const SECURITY_PASSWORD = 'pwd';
const SECURITY_ARCHIVE = 'archive';
/**
*
* @var self
*/
private static $instance = null;
/**
* archive path read from csrf file
*
* @var string
*/
private $archivePath = null;
/**
* installer name read from csrf file
*
* @var string
*/
private $bootloader = null;
/**
* installer url path read from csrf file
*
* @var string
*/
private $bootUrl = null;
/**
* boot log file full path read from csrf file
*
* @var string
*/
private $bootFilePath = null;
/**
* boot log file full path read from csrf file
*
* @var string
*/
private $bootLogFile = null;
/**
* package hash read from csrf file
*
* @var string
*/
private $packageHash = null;
/**
* public package hash read from csrf file
*
* @var string
*/
private $secondaryPackageHash = null;
/**
*
* @return self
*/
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct()
{
DUPX_CSRF::init(DUPX_INIT, Bootstrap::getPackageHash());
if (!file_exists(DUPX_CSRF::getFilePath())) {
throw new Exception("CSRF FILE NOT FOUND\n"
. "Please, check webroot file permsission and dup-installer folder permission");
}
$this->bootloader = DUPX_CSRF::getVal('bootloader');
$this->bootUrl = DUPX_CSRF::getVal('booturl');
$this->bootLogFile = SnapIO::safePath(DUPX_CSRF::getVal('bootLogFile'));
$this->bootFilePath = SnapIO::safePath(DUPX_CSRF::getVal('installerOrigPath'));
$this->archivePath = SnapIO::safePath(DUPX_CSRF::getVal('archive'));
$this->packageHash = DUPX_CSRF::getVal('package_hash');
$this->secondaryPackageHash = DUPX_CSRF::getVal('secondaryHash');
}
/**
* archive path read from intaller.php passed by DUPX_CSFR
*
* @return string
*/
public function getArchivePath()
{
return $this->archivePath;
}
/**
* installer full path read from intaller.php passed by DUPX_CSFR
*
* @return string
*/
public function getBootFilePath()
{
return $this->bootFilePath;
}
/**
* boot log file full path read from intaller.php passed by DUPX_CSFR
*
* @return string
*/
public function getBootLogFile()
{
return $this->bootLogFile;
}
/**
* bootloader path read from intaller.php passed by DUPX_CSFR
*
* @return string
*/
public function getBootloader()
{
return $this->bootloader;
}
/**
* bootloader path read from intaller.php passed by DUPX_CSFR
*
* @return string
*/
public function getBootUrl()
{
return $this->bootUrl;
}
/**
* package hash read from intaller.php passed by DUPX_CSFR
*
* @return string
*/
public function getPackageHash()
{
return $this->packageHash;
}
/**
* package public hash read from intaller.php passed by DUPX_CSFR
*
* @return string
*/
public function getSecondaryPackageHash()
{
return $this->secondaryPackageHash;
}
/**
*
* @return boolean
* @throws Exception // if fail throw exception of return true
*/
public function check()
{
try {
// check if current package hash is equal at bootloader package hash
if ($this->packageHash !== Bootstrap::getPackageHash()) {
throw new Exception('Incorrect hash package');
}
// checks if the version of the package descriptor is consistent with the version of the files.
if (DUPX_ArchiveConfig::getInstance()->version_dup !== DUPX_VERSION) {
throw new Exception('The version of the archive is different from the version of the PHP scripts');
}
$token_tested = false;
// @todo connect with global debug
$debug = false;
$action = null;
if (DUPX_Ctrl_ajax::isAjax($action) == true) {
if (($token = self::getTokenFromInput(DUPX_Ctrl_ajax::TOKEN_NAME)) === false) {
$msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . DUPX_Ctrl_ajax::TOKEN_NAME : '');
throw new Exception($msg);
}
if (!DUPX_CSRF::check(self::getTokenFromInput(DUPX_Ctrl_ajax::TOKEN_NAME), DUPX_Ctrl_ajax::getTokenKeyByAction($action))) {
$msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . DUPX_Ctrl_ajax::getTokenKeyByAction($action) . ' KEY VALUE ' . DUPX_Ctrl_ajax::getTokenKeyByAction($action) : '');
throw new Exception($msg);
}
$token_tested = true;
} elseif (($token = self::getTokenFromInput(self::CTRL_TOKEN)) !== false) {
if (!isset($_REQUEST[PrmMng::PARAM_CTRL_ACTION])) {
$msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . PrmMng::PARAM_CTRL_ACTION : '');
throw new Exception($msg);
}
if (!DUPX_CSRF::check($token, $_REQUEST[PrmMng::PARAM_CTRL_ACTION])) {
$msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . PrmMng::PARAM_CTRL_ACTION . ' KEY VALUE ' . $_REQUEST[PrmMng::PARAM_CTRL_ACTION] : '');
throw new Exception($msg);
}
$token_tested = true;
}
if (($token = self::getTokenFromInput(self::ROUTER_TOKEN)) !== false) {
if (!isset($_REQUEST[PrmMng::PARAM_ROUTER_ACTION])) {
$msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . PrmMng::PARAM_ROUTER_ACTION : '');
throw new Exception($msg);
}
if (!DUPX_CSRF::check($token, $_REQUEST[PrmMng::PARAM_ROUTER_ACTION])) {
$msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . PrmMng::PARAM_ROUTER_ACTION . ' KEY VALUE ' . $_REQUEST[PrmMng::PARAM_ROUTER_ACTION] : '');
throw new Exception($msg);
}
$token_tested = true;
}
// At least one token must always and in any case be tested
if (!$token_tested) {
throw new Exception('Security Check Validation - No Token Found');
}
} catch (Exception $e) {
if (function_exists('error_clear_last')) {
/**
* comment error_clear_last if you want see te exception html on shutdown
*/
error_clear_last(); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.error_clear_lastFound
}
Log::logException($e, Log::LV_DEFAULT, 'SECURITY CHECK: ');
dupxTplRender('page-security-error', array(
'message' => $e->getMessage()
));
die();
}
return true;
}
/**
* get sanitized token frominput
*
* @param string $tokenName
*
* @return string
*/
protected static function getTokenFromInput($tokenName)
{
return SnapUtil::filterInputDefaultSanitizeString(SnapUtil::INPUT_REQUEST, $tokenName, false);
}
/**
* Get security tipe (NONE, PASSWORD, ARCHIVE)
*
* @return string enum type
*/
public function getSecurityType()
{
if (PrmMng::getInstance()->getValue(PrmMng::PARAM_SECURE_OK) == true) {
return self::SECURITY_NONE;
}
$archiveConfig = DUPX_ArchiveConfig::getInstance();
if ($archiveConfig->secure_on) {
return self::SECURITY_PASSWORD;
}
if (
DUPX_InstallerState::isOverwrite() &&
basename($this->bootFilePath) == 'installer.php' &&
!in_array($_SERVER['REMOTE_ADDR'], self::getSecurityAddrWhitelist())
) {
return self::SECURITY_ARCHIVE;
}
return self::SECURITY_NONE;
}
/**
* Get IPs white list for remote requests
*
* @return string[]
*/
private static function getSecurityAddrWhitelist()
{
// uncomment this to test security archive on localhost
// return array();
// -------
return array(
'127.0.0.1',
'::1'
);
}
/**
* return true if security check is passed
*
* @return bool
*/
public function securityCheck()
{
$paramsManager = PrmMng::getInstance();
$archiveConfig = DUPX_ArchiveConfig::getInstance();
$result = false;
switch ($this->getSecurityType()) {
case self::SECURITY_NONE:
$result = true;
break;
case self::SECURITY_PASSWORD:
$paramsManager->setValueFromInput(PrmMng::PARAM_SECURE_PASS);
$pass_hasher = new DUPX_PasswordHash(8, false);
$base64Pass = base64_encode($paramsManager->getValue(PrmMng::PARAM_SECURE_PASS));
$result = $pass_hasher->CheckPassword($base64Pass, $archiveConfig->secure_pass);
break;
case self::SECURITY_ARCHIVE:
$paramsManager->setValueFromInput(PrmMng::PARAM_SECURE_ARCHIVE_HASH);
$result = (strcmp(basename($this->archivePath), $paramsManager->getValue(PrmMng::PARAM_SECURE_ARCHIVE_HASH)) == 0);
break;
default:
throw new Exception('Security type not valid ' . $this->getSecurityType());
break;
}
$paramsManager->setValue(PrmMng::PARAM_SECURE_OK, $result);
$paramsManager->save();
return $result;
}
}

View File

@@ -0,0 +1,3 @@
<?php
//silent