forked from LiveCarta/LiveCartaWP
Changed source root directory
This commit is contained in:
@@ -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" > "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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 > Try Again > Options > 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');
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
//silent
|
||||
Reference in New Issue
Block a user