This commit is contained in:
cutemeli
2025-12-22 10:35:30 +00:00
parent 0bfc6c8425
commit 5ce7ca2c5d
38927 changed files with 0 additions and 4594700 deletions

View File

@@ -1,25 +0,0 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitf73eddf6851cd0a7c79469f3bca5c5a7::getLoader();

View File

@@ -1,579 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var string|null */
private $apcuPrefix;
/**
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return list<string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
$paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

View File

@@ -1,359 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
if (self::$installed !== array()) {
$installed[] = self::$installed;
}
return $installed;
}
}

View File

@@ -1,21 +0,0 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,10 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@@ -1,9 +0,0 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));
return array(
);

View File

@@ -1,11 +0,0 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));
return array(
'Plesk\\MigrationLibV8\\' => array($baseDir . '/modules/panel-migrator/vendor/plesk/migration-lib-code/src', $vendorDir . '/plesk/migration-lib/src'),
'PleskExt\\PanelMigrator\\' => array($baseDir . '/modules/panel-migrator/library'),
);

View File

@@ -1,36 +0,0 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitf73eddf6851cd0a7c79469f3bca5c5a7
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitf73eddf6851cd0a7c79469f3bca5c5a7', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitf73eddf6851cd0a7c79469f3bca5c5a7', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitf73eddf6851cd0a7c79469f3bca5c5a7::getInitializer($loader));
$loader->register(true);
return $loader;
}
}

View File

@@ -1,42 +0,0 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitf73eddf6851cd0a7c79469f3bca5c5a7
{
public static $prefixLengthsPsr4 = array (
'P' =>
array (
'Plesk\\MigrationLibV8\\' => 21,
'PleskExt\\PanelMigrator\\' => 23,
),
);
public static $prefixDirsPsr4 = array (
'Plesk\\MigrationLibV8\\' =>
array (
0 => __DIR__ . '/../../../..' . '/modules/panel-migrator/vendor/plesk/migration-lib-code/src',
1 => __DIR__ . '/..' . '/plesk/migration-lib/src',
),
'PleskExt\\PanelMigrator\\' =>
array (
0 => __DIR__ . '/../../../..' . '/modules/panel-migrator/library',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitf73eddf6851cd0a7c79469f3bca5c5a7::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitf73eddf6851cd0a7c79469f3bca5c5a7::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitf73eddf6851cd0a7c79469f3bca5c5a7::$classMap;
}, null, ClassLoader::class);
}
}

View File

@@ -1,74 +0,0 @@
{
"packages": [
{
"name": "plesk/migration-backend",
"version": "dev-master",
"version_normalized": "dev-master",
"source": {
"type": "git",
"url": "git@github.com:webpros-plesk/ext-panel-migrator-backend.git",
"reference": "3674897a60c55b78ca2e2a446459c15417d91b6d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webpros-plesk/ext-panel-migrator-backend/zipball/3674897a60c55b78ca2e2a446459c15417d91b6d",
"reference": "3674897a60c55b78ca2e2a446459c15417d91b6d",
"shasum": ""
},
"time": "2025-10-30T13:50:36+00:00",
"default-branch": true,
"type": "migration-backend",
"installation-source": "dist",
"description": "Plesk Migrator backend",
"support": {
"source": "https://github.com/webpros-plesk/ext-panel-migrator-backend/tree/master",
"issues": "https://github.com/webpros-plesk/ext-panel-migrator-backend/issues"
},
"install-path": "../plesk/migration-backend"
},
{
"name": "plesk/migration-lib",
"version": "dev-master",
"version_normalized": "dev-master",
"source": {
"type": "git",
"url": "git@github.com:webpros-plesk/ext-panel-migrator-lib.git",
"reference": "090c441575e9bdc28f837510dda70cb159a39085"
},
"dist": {
"type": "zip",
"url": "https://packagist.pp.plesk.tech/dist/plesk/migration-lib/plesk-migration-lib-090c441575e9bdc28f837510dda70cb159a39085-zip-913144.zip",
"reference": "090c441575e9bdc28f837510dda70cb159a39085"
},
"require-dev": {
"phpunit/phpunit": "^11.4",
"plesk/pm-api-stubs": "dev-master"
},
"time": "2025-09-05T07:48:06+00:00",
"default-branch": true,
"type": "migration-lib",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Plesk\\MigrationLibV8\\": "src/"
}
},
"scripts": {
"test": [
"phpunit"
]
},
"license": [
"proprietary"
],
"description": "PHP library to perform migrations of data between servers",
"support": {
"source": "https://github.com/webpros-plesk/ext-panel-migrator-lib/tree/master",
"issues": "https://github.com/webpros-plesk/ext-panel-migrator-lib/issues"
},
"install-path": "../plesk/migration-lib"
}
],
"dev": false,
"dev-package-names": []
}

View File

@@ -1,45 +0,0 @@
<?php return array(
'root' => array(
'name' => 'plesk/ext-panel-migrator',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '7ddbf66ba125e148bb00f1229a707698f7b8187b',
'type' => 'library',
'install_path' => __DIR__ . '/../../../../',
'aliases' => array(),
'dev' => false,
),
'versions' => array(
'plesk/ext-panel-migrator' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '7ddbf66ba125e148bb00f1229a707698f7b8187b',
'type' => 'library',
'install_path' => __DIR__ . '/../../../../',
'aliases' => array(),
'dev_requirement' => false,
),
'plesk/migration-backend' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '3674897a60c55b78ca2e2a446459c15417d91b6d',
'type' => 'migration-backend',
'install_path' => __DIR__ . '/../plesk/migration-backend',
'aliases' => array(
0 => '9999999-dev',
),
'dev_requirement' => false,
),
'plesk/migration-lib' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '090c441575e9bdc28f837510dda70cb159a39085',
'type' => 'migration-lib',
'install_path' => __DIR__ . '/../plesk/migration-lib',
'aliases' => array(
0 => '9999999-dev',
),
'dev_requirement' => false,
),
),
);

View File

@@ -1,357 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Common\Backend\Files;
use Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\File;
use Plesk\MigrationLibV8\Utils\FileUtils;
use Plesk\MigrationLibV8\Plesk\PleskFunctions;
/**
* @property mixed GLOBAL "[GLOBAL]" section of configuration file
* @property mixed plesk "[plesk]" section of configuration file
* @property mixed source "[source]" section of configuration file
*/
class Config extends \Zend_Config_Ini
{
/** @var string */
private $_path;
private $_defaultSourceSectionName;
/**
* \Plesk\MigrationLibV8\Common\Backend\Files\Config constructor.
*
* @param string $path
*/
public function __construct($path)
{
$this->_path = $path;
if (!FileUtils::fileExists($this->_path)) {
FileUtils::putFileContents($this->_path, '');
}
parent::__construct($this->getPath(), null, true);
}
/**
* Get path to the configuration file.
*
* @return string
*/
public function getPath()
{
return $this->_path;
}
/**
* Save configuration file to file.
* Do not forget to call that function if you performed changes - they are not written automatically.
*/
public function save()
{
$writer = new \Zend_Config_Writer_Ini([
'config' => $this,
'filename' => $this->getPath()
]);
$iniFileContents = $writer->render();
if (!FileUtils::fileExists($this->getPath())) {
FileUtils::putFileContents($this->getPath(), $iniFileContents);
} else {
# Overwrite only if content differs, to reduce probability of certain race conditions,
# (race conditions are still possible!) when one process tries to read the config
# while another one overwrites it even if the file was not changed.
$oldIniFileContents = FileUtils::fileGetContents($this->getPath());
if ($oldIniFileContents != $iniFileContents) {
FileUtils::putFileContents($this->getPath(), $iniFileContents);
}
}
}
/**
* Initialize default options, that do not depend on user's input and should be always presented
*/
public function initDefaultOptions()
{
// do not check log priority of Plesk: that check stops migration if verbose logging is enabled
$this->setGlobalValue('skip-log-priority-check', $this->_encodeBooleanValue(true));
// do not set directory permissions - there were issues with them on Windows
$this->setGlobalValue('skip-set-session-directory-permissions', $this->_encodeBooleanValue(true));
// use per-session logs
$this->setGlobalValue('use-separate-log', $this->_encodeBooleanValue(true));
$this->setTargetValue('ip', PleskFunctions::getDefaultIPAddress());
}
/**
* Set source panel type.
*
* @param $sourceType string
*/
public function setSourceType($sourceType)
{
$this->setGlobalValue('source-type', $sourceType);
}
/**
* Get source panel type.
*
* @return string
*/
public function getSourceType()
{
return $this->_getGlobalValue('source-type');
}
/**
* Set directory to store session files.
*
* @param $sessionDirectory string
*/
public function setSessionDirectory($sessionDirectory)
{
$this->setGlobalValue('session-dir', $sessionDirectory);
}
/**
* Set OS of the target server.
*
* @param $os string
*/
public function setTargetOS($os)
{
$this->setTargetValue('os', $os);
}
/**
* Set name of configuration file section where source server settings are stored.
*
* @param $sectionName string
*/
public function setDefaultSourceSectionName($sectionName)
{
$this->_defaultSourceSectionName = $sectionName;
}
/**
* Set global configuration option.
*
* @param $name string name of the option
* @param $value string value of the option
*/
public function setGlobalValue($name, $value)
{
if (is_null($this->GLOBAL)) {
$this->GLOBAL = [];
}
$this->GLOBAL->$name = $value;
}
/**
* Set configuration option for the target server.
*
* @param $name string name of the option
* @param $value string value of the option
*/
public function setTargetValue($name, $value)
{
if (is_null($this->plesk)) {
$this->plesk = [];
}
$this->plesk->$name = $value;
}
/**
* Get global configuration option.
*
* @param $name string
* @param null $default
* @return string
*/
protected function _getGlobalValue($name, $default=null)
{
if (is_null($this->GLOBAL)) {
return $default;
} else {
if (!is_null($this->GLOBAL->$name)) {
return $this->GLOBAL->$name;
} else {
return $default;
}
}
}
/**
* Get configuration option for the target server.
*
* @param $name string name of the option
* @param null $default
* @return string
*/
protected function _getTargetValue($name, $default=null)
{
if (!is_null($this->plesk->$name)) {
return $this->plesk->$name;
} else {
return $default;
}
}
/**
* Set configuration option for the main source server.
*
* @param $name string name of the option
* @param $value string value of the option
* @throws \Exception
*/
public function setSourceValue($name, $value)
{
$sourceSection = $this->_getSourceSection();
$sourceSection->$name = $value;
}
/**
* Get configuration option for the main source server.
*
* @param $name string
* @param null $default
* @return string
*/
public function getSourceValue($name, $default=null)
{
$sourceSection = $this->_getSourceSection();
if (!is_null($sourceSection->$name)) {
return $sourceSection->$name;
} else {
return $default;
}
}
protected function _getSourceSection()
{
$sourceSectionName = $this->_getSourceSectionName();
if (is_null($sourceSectionName)) {
throw new \pm_Exception(
"Internal error: the source section name is not set. " .
"Call the 'setSourceSectionName' function before setting any source parameters."
);
}
if (is_null($this->$sourceSectionName)) {
$this->$sourceSectionName = [];
}
return $this->$sourceSectionName;
}
protected function _getSourceSectionName()
{
// First, try to read source section name from config file.
$configSourceSections = $this->_getGlobalValue('sources');
if ($configSourceSections !== null) {
$sources = explode(",", $configSourceSections);
foreach ($sources as $source) {
$source = trim($source);
if ($source !== '') {
return $source;
}
}
}
// Then, fallback to default section name.
return $this->_defaultSourceSectionName;
}
/**
* Parse boolean configuration value from string.
*
* @param $value string
* @return bool
*/
protected function _parseBooleanValue($value)
{
return in_array($value, ['true', '1', 'on']);
}
/**
* Encode boolean value to a string that could be put to configuration file.
*
* @param $value bool
* @return string
*/
protected function _encodeBooleanValue($value)
{
if ($value) {
return 'true';
} else {
return 'false';
}
}
/**
* Parse simple list value from string.
*
* @param $value string
* @return array
*/
protected function _parseListValue($value)
{
$result = [];
foreach (explode(',', $value) as $item) {
$result[] = trim($item);
}
return $result;
}
/**
* Encode list value to a string that could be put to configuration file.
*
* @param $value
* @return string
*/
protected function _encodeListValue($value)
{
return implode(', ', $value);
}
/**
* Overridden parse INI file function to allow other INI syntax supported by backend.
*
* The original function was taken and modified in the following way: instead of plain parse_ini_file,
* we read file contents as string, then perform replacements, and call parse_ini_string function.
* Other aspects (like error handling) are left as they were in the original function.
*
* @param string $filename
* @return array
* @throws \Zend_Config_Exception
*/
protected function _parseIniFile($filename)
{
set_error_handler(array($this, '_loadFileErrorHandler'));
// MODIFICATIONS START
$iniFileContents = FileUtils::fileGetContents($filename);
// Replace 'param: value' with 'param = "value"', as 'param: value' syntax is not supported by PHP
$iniFileContents = preg_replace('/^\s*([-a-zA-Z0-9]+)\s*:\s*(.*?)(\s*)$/m', '$1 = "$2"$3', $iniFileContents);
// Remove comments starting with "#", which are not supported by PHP
$iniFileContents = preg_replace('/^\s*#.*$/m', '', $iniFileContents);
// Raw read mode is used instead of normal to avoid converting boolean 'true' -> string '1' and boolean 'false' -> empty string ''
$iniArray = parse_ini_string($iniFileContents, true, INI_SCANNER_RAW); // Warnings and errors are suppressed
// MODIFICATIONS END
restore_error_handler();
// Check if there was a error while loading file
if ($this->_loadFileErrorStr !== null) {
/**
* @see Zend_Config_Exception
*/
/** @noinspection PhpIncludeInspection */
require_once 'Zend/Config/Exception.php';
throw new \Zend_Config_Exception($this->_loadFileErrorStr);
}
return $iniArray;
}
}

View File

@@ -1,127 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Common\Backend\Files;
use Plesk\MigrationLibV8\Utils\ArrayUtils;
use Plesk\MigrationLibV8\Utils\FileUtils;
class Progress
{
const OVERALL_STATUS_FINISHED_ERRORS = 'finished-errors';
const OVERALL_STATUS_FINISHED_OK = 'finished-ok';
const OVERALL_STATUS_IN_PROGRESS = 'in-progress';
const GET_PROGRESS_ATTEMPTS_COUNT = 5;
const GET_PROGRESS_ATTEMPTS_INTERVAL = 1;
protected $_progressFilePath;
protected $_data;
public function __construct($progressFilePath)
{
$this->_progressFilePath = $progressFilePath;
$this->_data = [];
for ($i = 0; $i < self::GET_PROGRESS_ATTEMPTS_COUNT; $i++) {
if (FileUtils::fileExists($this->_progressFilePath)) {
$this->_data = @json_decode(
FileUtils::fileGetContents($this->_progressFilePath), true
);
if ($this->_data) {
break;
}
}
sleep(self::GET_PROGRESS_ATTEMPTS_INTERVAL);
}
}
/**
* Cleanup progress file, so it looks like migrator was not started yet.
*
* Run this function before scheduling migrator asynchronous operations,
* so you when retrieving/polling progress, you don't get progress of a previously
* executed operation.
*/
public function cleanup()
{
if (FileUtils::fileExists($this->_progressFilePath)) {
unlink($this->_progressFilePath);
}
}
/**
* Get overall status of command execution, as string. Compare with OVERALL_STATUS_* constants.
*
* @return string | null
*/
public function getOverallStatus()
{
return ArrayUtils::getElementDefaultNull($this->_data, 'status');
}
/**
* Get action description that is currently executed for all subscriptions.
*
* @return string | null
*/
public function getOverallAction()
{
return ArrayUtils::getElementDefaultNull($this->_data, 'action');
}
public function getServerConfigurationStatus()
{
return ArrayUtils::getElementDefaultNull($this->_data, 'server_configuration_status');
}
public function getExtensionsStatus()
{
return ArrayUtils::getElementDefaultNull($this->_data, 'extensions_status');
}
/**
* Get overall error message of command execution. This error message could be displayed to customer.
*
* @return string | null
*/
public function getOverallErrorMessage()
{
return ArrayUtils::getElementDefaultNull($this->_data, 'error_message');
}
/**
* Get overall error ID of command execution.
*
* @return string | null
*/
public function getOverallErrorId()
{
return ArrayUtils::getElementDefaultNull($this->_data, 'error_id');
}
/**
* Whether the command was executed successfully or not.
*
* If not - use getOverallErrorMessage function to get details.
*
* @return bool
*/
public function isOverallFinishedOk()
{
return $this->getOverallStatus() == self::OVERALL_STATUS_FINISHED_OK;
}
/**
* Whether the command was finished or not.
*
* @return bool
*/
public function isOverallFinished()
{
return in_array($this->getOverallStatus(), [
self::OVERALL_STATUS_FINISHED_OK,
self::OVERALL_STATUS_FINISHED_ERRORS
]);
}
}

View File

@@ -1,46 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Common\Backend;
use Plesk\MigrationLibV8\Plesk\PleskFunctions;
class ToolUtils
{
/**
* Prepare set of environment variables
*
* @param \Zend_Config $config
* @param string|null $sectionName
* @return array
*/
public static function getEnvVarsByConfig(?\Zend_Config $config = null, $sectionName = null)
{
$env = [];
if ($config !== null) {
foreach ($config as $key => $value) {
if ($value instanceof \Zend_Config) {
$env += self::getEnvVarsByConfig($value, $key);
continue;
}
if (!in_array($key, ['ssh-password', 'windows-password', 'ftp-password', 'password'])) {
continue;
}
$rawVarName = ($sectionName ? $sectionName . '_' : '') . $key;
$varName = str_replace('-', '_', strtoupper($rawVarName));
$env[$varName] = PleskFunctions::decryptPassword($value);
}
if (false !== getenv('HOME')) {
$env['HOME'] = getenv('HOME');
}
}
$env['MIGRATOR_MESSAGES_UI'] = 'gui';
$env['MIGRATOR_MESSAGES_LANG'] = \pm_Locale::getCode();
// The Plesk SDK does not support parallel running of CU utilities, the mechanism used in panel-migration
// disrupts the normal operation of the lock manager in Plesk, as it send the current token lock manager
// to child processes. It is necessary to reset the token there.
$env['LOCKMANAGER_CLIENT_TOKEN'] = '';
return $env;
}
}

View File

@@ -1,77 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Common\Exception;
/**
* Exception which means that executed program failed with non-zero exit code
*/
class NonZeroExitCode extends \Exception
{
/** @var string|null */
private $_command;
/** @var int|null */
private $_exitCode;
/** @var string|null */
private $_stdout;
/** @var string|null */
private $_stderr;
/**
* Class constructor.
* @param string|null $command command as a single string (optional)
* @param int|null $exitCode exit code of the command (optional)
* @param string|null $stdout stdout of the command (optional)
* @param string|null $stderr stderr of the command (optional)
*/
public function __construct($command=null, $exitCode=null, $stdout=null, $stderr=null)
{
$message = 'Command returned non-zero exit code.';
if ($command !== null) {
$message .= "\n\nCommand: $command";
}
if ($exitCode !== null) {
$message .= "\n\nExit code: $exitCode";
}
if ($stdout !== null) {
$message .= "\n\nstdout:\n$stdout";
}
if ($stderr !== null) {
$message .= "\n\nstderr:\n$stderr";
}
parent::__construct($message);
}
/**
* @return string|null
*/
public function getCommand()
{
return $this->_command;
}
/**
* @return int|null
*/
public function getExitCode()
{
return $this->_exitCode;
}
/**
* @return string|null
*/
public function getStdout()
{
return $this->_stdout;
}
/**
* @return string|null
*/
public function getStderr()
{
return $this->_stderr;
}
}

View File

@@ -1,108 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Common;
use Plesk\MigrationLibV8\Utils\FileUtils;
class SessionDirectory
{
/**
* @var \Plesk\MigrationLibV8\Common\SessionDirectory[]
*/
private static array $_instances = [];
/**
* @var string
*/
private string $_path;
/**
* @var string
*/
private string $_id;
/**
* SessionDirectory constructor.
*
* @param string $id
* @param string $path
*/
private function __construct($id, $path)
{
$this->_id = $id;
$this->_path = $path;
}
/**
* Get session directory for the current extension.
*
* @param string $sessionId string identifier of the session; as example you could use date when migration was
* started, e.g. "20170815101733"
* @param bool $isInExtensionRoot
* @return SessionDirectory
*/
public static function getForCurrentExtension($sessionId, $isInExtensionRoot=false)
{
if ($isInExtensionRoot) {
$sessionsDir = \pm_Context::getVarDir() . 'sessions';
} else {
$sessionsDir = \pm_Context::getVarDir() . 'plesk-migrator' . DIRECTORY_SEPARATOR . 'sessions';
}
$path = $sessionsDir . DIRECTORY_SEPARATOR . $sessionId;
if (!array_key_exists($path, self::$_instances)) {
self::$_instances[$path] = new self($sessionId, $path);
}
return self::$_instances[$path];
}
/**
* Get path to the session directory.
*
* @return string
*/
public function getPath()
{
return $this->_path;
}
/**
* Get string identifier of the session.
*
* @return string
*/
public function getId()
{
return $this->_id;
}
/**
* Create session directory if it does not exist.
*/
public function initialize()
{
if (!FileUtils::fileExists($this->getPath())) {
FileUtils::createDirectory($this->getPath());
}
}
/**
* Whether migration session directory exists.
*
* @return bool
*/
public function isExists()
{
return FileUtils::fileExists($this->getPath());
}
/**
* Remove session directory with all files.
*/
public function remove()
{
if (FileUtils::fileExists($this->getPath())) {
FileUtils::removeDirectory($this->getPath());
}
}
}

View File

@@ -1,43 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Common;
class SessionFiles
{
protected SessionDirectory $_session;
public function __construct(SessionDirectory $session)
{
$this->_session = $session;
}
/**
* @return string
*/
public function getConfigPath()
{
return $this->_session->getPath() . DIRECTORY_SEPARATOR . 'config.ini';
}
/**
* @return string
*/
public function getSubscriptionsStatusPath()
{
return $this->_session->getPath() . DIRECTORY_SEPARATOR . 'subscriptions-status.json';
}
/**
* @param string|null $taskId
* @return string
*/
public function getProgressPath($taskId=null)
{
if (is_null($taskId)) {
return $this->_session->getPath() . DIRECTORY_SEPARATOR . 'progress.json';
} else {
return $this->_session->getPath() . DIRECTORY_SEPARATOR . "progress.$taskId.json";
}
}
}

View File

@@ -1,34 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Backend\Files;
use pm_Config;
class Config extends \Plesk\MigrationLibV8\Common\Backend\Files\Config
{
public function initDefaultOptions() {
parent::initDefaultOptions();
$this->setGlobalValue(
'mail-migrator-log-enabled',
$this->_encodeBooleanValue(pm_Config::get('mailMigratorLogEnabled')),
);
$this->setGlobalValue(
'mail-migrator-use-hash-as-message-id',
$this->_encodeBooleanValue(pm_Config::get('mailMigratorUseHashAsMessageId')),
);
}
/**
* Set domain name to which mail should be transferred.
*
* @param $domain string
*/
public function setSourceTargetDomain($domain)
{
// Target domain is inside of source section (not inside of target section as you could expect)
// just for consistency with web import.
$this->setSourceValue('target-domain', $domain);
}
}

View File

@@ -1,72 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Backend\Files;
use Plesk\MigrationLibV8\Plesk\PleskFunctions;
use Plesk\MigrationLibV8\Utils\FileUtils;
class MigrationList
{
private $_migrationListFilePath;
/**
* MigrationList constructor.
* @param string $migrationListFilePath
*/
public function __construct($migrationListFilePath)
{
$this->_migrationListFilePath = $migrationListFilePath;
}
/**
* @param \Plesk\MigrationLibV8\MailImport\Entity\ImportOperation\MailAddressPair[] $mailAddressPairs
*/
public function write($mailAddressPairs)
{
$siteMigrationListContents = [
'mail_address_pairs' => [],
];
foreach ($mailAddressPairs as $mailAddressPair) {
if ($mailAddressPair->getSourcePassword() === null) {
$sourcePassword = null;
} else {
$sourcePassword = PleskFunctions::encryptPassword($mailAddressPair->getSourcePassword());
}
if ($mailAddressPair->getTargetPassword() === null) {
$targetPassword = null;
} else {
$targetPassword = PleskFunctions::encryptPassword($mailAddressPair->getTargetPassword());
}
$siteMigrationListContents['mail_address_pairs'][] = [
'source_email' => $mailAddressPair->getSourceEmail(),
'source_password' => $sourcePassword,
'target_mailname' => $mailAddressPair->getTargetMailname(),
'target_password' => $targetPassword,
'imap_host' => $mailAddressPair->getImapHost(),
'imap_port' => $mailAddressPair->getImapPort(),
'ignore_security_warnings' => $mailAddressPair->getIgnoreSecurityWarnings(),
'imap_encryption' => $mailAddressPair->getImapEncryption(),
'imap_timeout' => $mailAddressPair->getImapTimeout(),
'imap_folder_separator' => $mailAddressPair->getImapFolderSeparator()
];
}
FileUtils::putFileContents(
$this->getFilePath(),
\Zend_Json::prettyPrint(\Zend_Json::encode($siteMigrationListContents))
);
}
/**
* Get full path to file with the migration list.
*
* @return string
*/
public function getFilePath()
{
return $this->_migrationListFilePath;
}
}

View File

@@ -1,80 +0,0 @@
<?php
// Copyright 1999-2024. WebPros International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Backend\Files;
use Plesk\MigrationLibV8\Utils\FileUtils;
class Status
{
private $_statusData;
private string $_statusFilePath;
public function __construct($statusFilePath)
{
$this->_statusFilePath = $statusFilePath;
$this->_read();
}
/**
* Get whole set of site status data as array.
*
* @return array
*/
public function getStatusData()
{
return $this->_statusData;
}
/**
* Get full path to file with the mail import status info.
*
* @return string
*/
private function getFilePath()
{
return $this->_statusFilePath;
}
private function _read()
{
if (FileUtils::fileExists($this->getFilePath())) {
$data = json_decode(FileUtils::fileGetContents($this->getFilePath()), true);
// Leave issue details only for administrator:
// - for better security (details could accidentally contain sensitive data)
// - for better user experience (in most cases user won't understood the details, and there is no sense
// to show that useless info).
// So, only administrator could see logs, stack traces, etc.
if (!\pm_Session::getClient()->isAdmin()) {
$data = $this->_filterOutDetails($data);
}
} else {
$data = [];
}
$this->_statusData = $data;
}
/**
* Remove issue details from migration status data structure
*
* @param mixed $data
* @return mixed
*/
private function _filterOutDetails($data)
{
if (is_array($data)) {
$result = [];
foreach ($data as $key => $value) {
if ($key !== 'details_text' && $key !== 'error_details') {
$result[$key] = $this->_filterOutDetails($value);
}
}
return $result;
} else {
return $data;
}
}
}

View File

@@ -1,116 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Backend;
use Plesk\MigrationLibV8\Common\Exception\NonZeroExitCode;
use Plesk\MigrationLibV8\MailImport\Backend\Files\Config;
/**
* Wrapper around "plesk-migrator" utility (which is backend entry point) for mail import.
*/
class Tool
{
/**
* Mail migration: schedule mail migration tasks.
* Once the tasks are scheduled, start them with 'runSiteMigrationTasks' function.
*
* @param Config $config
* @param string $migrationListFile full path to file with migration list
* @param bool $isAsyncStatusReport
* @return string ID of the task scheduled for the last mail address pair in the specified migration list
*/
public function addMailMigrationTasks(
Config $config, $migrationListFile, $isAsyncStatusReport
) {
$command = 'add-mail-migration-tasks';
$args = [
"--mail-migration-list=$migrationListFile",
];
if ($isAsyncStatusReport) {
$args[] = '--async-status-report';
}
$args[] = '--quiet';
$stdout = $this->_exec($command, $args, $config);
$taskInfo = json_decode(trim($stdout), true);
return $taskInfo['task_id'];
}
/**
* Mail migration: cancel mail migration tasks related to mail address pairs specified by migration list.
*
* @param Files\Config $config
* @param string $migrationListFile full path to file with migration list
*/
public function cancelMailMigrationTasks(
Config $config, $migrationListFile
) {
$command = 'cancel-mail-migration-tasks';
$args = [
"--mail-migration-list=$migrationListFile",
];
$this->_exec($command, $args, $config);
}
/**
* Mail migration: run previously scheduled mail migration tasks.
* Schedule site migration tasks with 'addMailMigrationTasks' function.
*
* On Unix this function returns once the task runner was started (asynchronously).
* On Windows this function returns only once the task runner was finished (synchronously).
* The difference is caused by difficulties implementing asynchronous command execution on Windows.
*
* @param Config $config
*/
public function runMailMigrationTasks(Config $config)
{
// Start task queue runner for mail migration.
// If it is already running, this call will simply do nothing -
// "run-mail-migration-tasks" will exit immediately.
$this->_exec('run-mail-migration-tasks', ['--async'], $config);
}
/**
* Execute backend action for mail migration.
*
* Backend for mail migration runs under superuser (root on Linux, SYSTEM on Windows)
* with Plesk 17.0 SDK features, which are not available on Plesk 12.5. No Administrator password is
* required on Windows comparing to regular migration, so mail migration could be launched by customer,
* not only by server administrator.
*
* @param string $action
* @param string[] $args
* @param Config $config
* @return mixed
* @throws \Exception
*/
private function _exec($action, $args, ?Config $config=null)
{
// Execute the backend under superuser
$params = [$action];
if (!is_null($config)) {
$params[] = $config->getPath();
}
$params = array_merge($params, $args);
if (\pm_ProductInfo::isWindows()) {
$sbinExecutable = 'plesk-migrator.bat';
} else {
$sbinExecutable = 'plesk-migrator';
}
$result = \pm_ApiCli::callSbin($sbinExecutable, $params, \pm_ApiCli::RESULT_FULL, []);
if ($result['code'] !== 0) {
$commandParts = ['plesk-migrator'];
$commandParts = array_merge($commandParts, $params);
foreach ($commandParts as &$commandPart) {
$commandPart = escapeshellarg($commandPart);
}
throw new NonZeroExitCode(
implode(" ", $commandParts), $result['code'], $result['stdout'], $result['stderr']
);
}
return $result['stdout'];
}
}

View File

@@ -1,139 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Entity\ImportOperation;
class MailAddressPair
{
/** @var string */
private $_sourceEmail;
/** @var string */
private $_sourcePassword;
/** @var string */
private $_targetMailname;
/** @var string|null */
private $_targetPassword;
/** @var string|null */
private $_imapHost;
/** @var int */
private $_imapPort;
/** @var bool */
private $_ignoreSecurityWarnings;
/** @var string|null */
private $_imapEncryption;
/** @var int|null */
private $_imapTimeout;
/** @var string|null */
private $_imapFolderSeparator;
/**
* Mail address pair constructor.
*
* @param $sourceEmail string
* @param $sourcePassword string
* @param $targetMailname string
* @param $targetPassword string|null
* @param $imapHost string|null
* @param $imapPort int|null
* @param $ignoreSecurityWarnings bool
* @param $imapEncryption string|null
* @param $imapTimeout int|null
* @param $imapFolderSeparator string|null
*/
public function __construct(
$sourceEmail, $sourcePassword, $targetMailname, $targetPassword, $imapHost, $imapPort=null,
$ignoreSecurityWarnings=false,
$imapEncryption=null, $imapTimeout=null, $imapFolderSeparator=null
) {
$this->_sourceEmail = $sourceEmail;
$this->_sourcePassword = $sourcePassword;
$this->_targetMailname = $targetMailname;
$this->_targetPassword = $targetPassword;
$this->_imapHost = $imapHost;
$this->_imapPort = $imapPort;
$this->_ignoreSecurityWarnings = $ignoreSecurityWarnings;
$this->_imapEncryption = $imapEncryption;
$this->_imapTimeout = $imapTimeout;
$this->_imapFolderSeparator = $imapFolderSeparator;
}
/**
* @return string
*/
public function getSourceEmail()
{
return $this->_sourceEmail;
}
/**
* @return string
*/
public function getSourcePassword()
{
return $this->_sourcePassword;
}
/**
* @return string
*/
public function getTargetMailname()
{
return $this->_targetMailname;
}
/**
* @return string|null
*/
public function getTargetPassword()
{
return $this->_targetPassword;
}
/**
* @return string|null
*/
public function getImapHost()
{
return $this->_imapHost;
}
/**
* @return int|null
*/
public function getImapPort()
{
return $this->_imapPort;
}
/**
* @return bool
*/
public function getIgnoreSecurityWarnings()
{
return $this->_ignoreSecurityWarnings;
}
/**
* @return string|null
*/
public function getImapEncryption()
{
return $this->_imapEncryption;
}
/**
* @return int|null
*/
public function getImapTimeout()
{
return $this->_imapTimeout;
}
/**
* @return string|null
*/
public function getImapFolderSeparator()
{
return $this->_imapFolderSeparator;
}
}

View File

@@ -1,51 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Entity\Status;
/**
* Whole import status of a session - all mail address pairs ever migrated within the session.
*
* @package Plesk\MigrationLibV8\MailImport\Entity\Status
*/
class Import
{
/**
* @var \Plesk\MigrationLibV8\MailImport\Entity\Status\Import\MailAddressPair[]
*/
private $_mailAddressPairsStatus;
/**
* Import constructor.
*
* @param $mailAddressPairsStatus \Plesk\MigrationLibV8\MailImport\Entity\Status\Import\MailAddressPair[]
*/
public function __construct($mailAddressPairsStatus) {
$this->_mailAddressPairsStatus = $mailAddressPairsStatus;
}
/**
* @return \Plesk\MigrationLibV8\MailImport\Entity\Status\Import\MailAddressPair[]
*/
public function getMailAddressPairsStatus()
{
return $this->_mailAddressPairsStatus;
}
/**
* Get whole import status as array (useful for integration with JavaScript code).
*
* @return array
*/
public function asArray()
{
$mailAddressPairsStatus = [];
foreach ($this->getMailAddressPairsStatus() as $mailAddressPairStatus) {
$mailAddressPairsStatus[] = $mailAddressPairStatus->asArray();
}
return [
'mail_address_pairs' => $mailAddressPairsStatus,
];
}
}

View File

@@ -1,179 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Entity\Status\Import;
class MailAddressPair
{
/** @var string */
private $_sourceEmail;
/** @var string */
private $_targetMailname;
/** @var \Plesk\MigrationLibV8\MailImport\Entity\Status\Issue[] */
private $_issues;
/** @var string|null */
private $_status;
/** @var string|null */
private $_step;
/** @var string|null */
private $_errorId;
/** @var string|null */
private $_errorMessage;
/** @var int|null */
private $_restoredMessageNum;
/**
* MailAddressPair constructor.
*
* @param string $sourceEmail
* @param string $targetMailname
* @param \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[] $issues
* @param string|null $status
* @param string|null $step
* @param string|null $errorId
* @param string|null $errorMessage
* @param int|null $restoredMessageNum
*/
public function __construct(
$sourceEmail, $targetMailname, $issues,
$status=null, $step=null, $errorId=null, $errorMessage=null, $restoredMessageNum=null
) {
$this->_sourceEmail = $sourceEmail;
$this->_targetMailname = $targetMailname;
$this->_issues = $issues;
$this->_status = $status;
$this->_step = $step;
$this->_errorId = $errorId;
$this->_errorMessage = $errorMessage;
$this->_restoredMessageNum = $restoredMessageNum;
}
/**
* Get source e-mail (e.g. "john@example.com").
*
* @return string
*/
public function getSourceEmail()
{
return $this->_sourceEmail;
}
/**
* Get target mailname (a part of e-mail before "@", e.g. "john")
*
* @return string
*/
public function getTargetMailname()
{
return $this->_targetMailname;
}
/**
* Get list of issues happened during import.
*
* @return \Plesk\MigrationLibV8\MailImport\Entity\Status\Issue[]
*/
public function getIssues()
{
return $this->_issues;
}
/**
* Get import status of the mail address pair, as string (e.g. "success")
*
* @return string|null see constants from \Plesk\MigrationLibV8\MailImport\Entity\Status\Import\Statuses
*/
public function getStatus()
{
return $this->_status;
}
/**
* Get step on which migration is right now (if import is in progress).
*
* @return string|null
*/
public function getStep()
{
return $this->_step;
}
/**
* Get error identifier, as string.
*
* @return string|null
*/
public function getErrorId()
{
return $this->_errorId;
}
/**
* Get error message, as string.
*
* @return string|null
*/
public function getErrorMessage()
{
return $this->_errorMessage;
}
/**
* Get number of message which is restored by migrator backend right now.
*
* @return int|null
*/
public function getRestoredMessageNum()
{
return $this->_restoredMessageNum;
}
/**
* Return status information for imported mail address pairs as array (useful for integration with JavaScript code).
*
* Array has the following keys:
* 'source_email' - source e-mail address (e.g. "source@example.com")
* 'target_mailname' - target mailname - part of e-mail address
* before "@" (e.g. "target" for "target@example.com" e-mail)
* 'status' - import status of the mail address pair, as string (e.g. "success")
* 'step' - step on which import is running, if it is in progress, as string
* 'issues' - list of issues, as array, for example:
* [
* [
* 'severity' => 'error',
* 'execution_date' => 1520414386.50899,
* 'problem_text' => 'Failed to copy content',
* 'details_text' => 'Failed to execute command, non-zero exit code'
* ],
* [
* 'severity' => 'warning',
* 'execution_date' => 1520414234.31467,
* 'problem_text' => 'Password does not conform to Plesk rules, new password was generated',
* 'details_text' => null
* ],
* ]
* 'error_id' - error identifier, as string (use to perform special actions in case of specific error, e.g.
* highlight login/password fileds in case of authentication issue, and so on)
* 'error_message' - human readable error message
* 'restored_message_num' - number of a message which is restored by migrator backend right now (e.g. 42)
* @return array
*/
public function asArray()
{
$issues = [];
foreach ($this->getIssues() as $issue) {
$issues[] = $issue->asArray();
}
return [
'source_email' => $this->getSourceEmail(),
'target_mailname' => $this->getTargetMailname(),
'issues' => $issues,
'status' => $this->getStatus(),
'step' => $this->getStep(),
'error_id' => $this->getErrorId(),
'error_message' => $this->getErrorMessage(),
'restored_message_num' => $this->getRestoredMessageNum(),
];
}
}

View File

@@ -1,93 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Entity\Status;
class Issue
{
const SEVERITY_ERROR = 'error';
const SEVERITY_WARNING = 'warning';
const SEVERITY_INFO = 'info';
/** @var string */
private $_severity;
/** @var float */
private $_executionDate;
/** @var string */
private $_problemText;
/** @var string */
private $_detailsText;
/**
* Issue constructor.
*
* @param string $severity issue severity - see SEVERITY_* constants
* @param float $executionDate execution date as timestamp.
* @param string $problemText problem text - useful for end user of mail import.
* @param string $detailsText|null problem details - which could be useful for admin
* (e.g. executed CLI commands with their stdout/stderr).
*/
public function __construct($severity, $executionDate, $problemText, $detailsText)
{
$this->_severity = $severity;
$this->_executionDate = $executionDate;
$this->_problemText = $problemText;
$this->_detailsText = $detailsText;
}
/**
* Get issue severity - see SEVERITY_* constants.
*
* @return string
*/
public function getSeverity()
{
return $this->_severity;
}
/**
* Get execution date as timestamp.
*
* @return float
*/
public function getExecutionDate()
{
return $this->_executionDate;
}
/**
* Get problem text - useful for end user of mail import.
*
* @return string
*/
public function getProblemText()
{
return $this->_problemText;
}
/**
* Get problem details - which could be useful for admin (e.g. executed CLI commands with their stdout/stderr),
* stack traces, etc.
*
* @return string
*/
public function getDetailsText()
{
return $this->_detailsText;
}
/**
* Get issue information as array (useful for integration with JavaScript code).
*
* @return array
*/
public function asArray()
{
return [
'severity' => $this->getSeverity(),
'execution_date' => $this->getExecutionDate(),
'problem_text' => $this->getProblemText(),
'details_text' => $this->getDetailsText()
];
}
}

View File

@@ -1,109 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Entity\Status;
class Task
{
private $_status;
/** @var string|null */
private $_step;
/** @var string|null */
private $_errorId;
/** @var string|null */
private $_errorMessage;
/** @var string|null */
private $_errorDetails;
/**
* Task constructor.
*
* @param string|null $status
* @param string|null $step
* @param string|null $errorId
* @param string|null $errorMessage
* @param string|null $errorDetails
*/
public function __construct(
$status=null, $step=null, $errorId=null, $errorMessage=null, $errorDetails=null
) {
$this->_status = $status;
$this->_step = $step;
$this->_errorId = $errorId;
$this->_errorMessage = $errorMessage;
$this->_errorDetails = $errorDetails;
}
/**
* Get import status of the mail address pair, as string (e.g. "success")
*
* @return string|null see constants from \Plesk\MigrationLibV8\MailImport\Entity\Status\Import\Statuses
*/
public function getStatus()
{
return $this->_status;
}
/**
* Get step on which migration is right now (if import is in progress).
*
* @return string|null
*/
public function getStep()
{
return $this->_step;
}
/**
* Get error identifier, as string.
*
* @return string|null
*/
public function getErrorId()
{
return $this->_errorId;
}
/**
* Get error message, as string.
*
* @return string|null
*/
public function getErrorMessage()
{
return $this->_errorMessage;
}
/**
* Get error details, as string.
*
* @return string|null
*/
public function getErrorDetails()
{
return $this->_errorDetails;
}
/**
* Return status information for imported mail address pairs as array (useful for integration with JavaScript code).
*
* Array has the following keys:
* 'status' - import status of the mail address pair, as string (e.g. "success")
* 'step' - step on which import is running, if it is in progress, as string
* 'error_id' - error identifier, as string (use to perform special actions in case of specific error, e.g.
* highlight login/password fileds in case of authentication issue, and so on)
* 'error_message' - human readable error message
* 'error_details' - human readable error details
* @return array
*/
public function asArray()
{
return [
'status' => $this->getStatus(),
'step' => $this->getStep(),
'error_id' => $this->getErrorId(),
'error_message' => $this->getErrorMessage(),
'error_details' => $this->getErrorDetails(),
];
}
}

View File

@@ -1,15 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport\Entity;
class Statuses
{
const READY_TO_IMPORT = 'ready-to-import';
const IN_PROGRESS = 'in-progress';
const SUCCESS = 'success';
const WARNING = 'warning';
const FAILURE = 'failure';
const QUEUED = 'queued';
const CANCELLED = 'cancelled';
}

View File

@@ -1,257 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport;
use Plesk\MigrationLibV8\Common\SessionDirectory;
use Plesk\MigrationLibV8\MailImport\Backend\Files\MigrationList;
use Plesk\MigrationLibV8\MailImport\Backend\Tool;
use Plesk\MigrationLibV8\MailImport\Entity\Status\Import;
use Plesk\MigrationLibV8\MailImport\Entity\Status\Issue;
use Plesk\MigrationLibV8\MailImport\Entity\Status\Task;
use Plesk\MigrationLibV8\Utils\ArrayUtils;
/**
* A wrapper around backend of Plesk Migrator to perform mail import using IMAP protocol.
*/
class Manager
{
/**
* Prepare for mail import - configure session for specified site.
* Once session is configured, you should call "scheduleImport" to schedule import of specific mail addresses.
*
* This function is executed quickly: it just creates/modifies configuration files.
*
* To perform mail import, the following workflow is suggested:
*
* 1. Obtain a domain object for the target site, to which you want to import mail messages.
* For example, ask customer to select domain from a list of available domains,
* or use domain from the current context. The domain must be either subscription's main domain
* or addon domain. Mail import to subdomains is not supported as they can not have mailboxes.
*
* $domain = new \pm_Domain(123);
*
* 2. Obtain a session object. A session is a directory which contains configuration files,
* logs, reports and other temporary data for Plesk Migrator's backend. Each session has an unique string ID.
* It is recommended to use domain ID as a part of session ID.
*
* $session = \Plesk\MigrationLibV8\Common\SessionDirectory::getForCurrentExtension(
* 'mail-migration-' . $domain->getId()
* );
*
* 3. Create mail import manager:
*
* $manager = new \Plesk\MigrationLibV8\MailImport\Manager();
*
* 4. Configure session directory:
*
* $manager->configureSession($session, $domain);
*
* 5. Schedule import of a mailbox:
*
* $mailAddressPairs = [
* new MailAddressPair(
* 'john@example.com', '123qwe', 'tom', '456asd'
* ),
* new MailAddressPair(
* 'bob@example.com', '123qwe', 'bob', '456asd'
* ),
* ];
* $manager->scheduleImport($session, $mailAddressPairs);
*
* 6. Once you've scheduled import, start task runner which processes schedules import tasks:
*
* $manager->startTasksRunner($session);
*
* Task runner works in synchronous way on Windows and in asynchronous way on Linux. That is quite weird,
* the difference is caused by difficulties implementing asynchronous command execution on Windows.
*
* To improve stability, it is useful to start task runner periodically, for example once a minute.
* If another task runner is already running, the new one will exit immediately. In that case
* if server was rebooted, or task runner has stopped for any reason, import will continue to work.
*
* 7. Once task runner is started, poll import status of imported/scheduled mail address pairs:
*
* $status = $manager->getImportStatus($session);
*
* 8. Additionally, you have ability to cancel running mail import with "cancelImport" method.
*
* @param SessionDirectory $session
* @param \pm_Domain $site
*/
public function configureSession(SessionDirectory $session, \pm_Domain $site)
{
$session->initialize();
$sessionObjects = SessionObjects::getInstance($session);
$config = $sessionObjects->getConfig();
$config->initDefaultOptions();
$config->setSessionDirectory($session->getId());
$config->setTargetOS(\pm_ProductInfo::isUnix() ? 'unix' : 'windows');
$config->setSourceType('mail');
$config->setSourceTargetDomain($site->getName());
$config->save();
}
/**
* Schedule import of mail messages.
*
* Schedule import works fast (in most cases less than a second).
* Once import is scheduled, you should call "startTasksRunner" to actually start import.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\MailImport\Entity\ImportOperation\MailAddressPair[] $mailAddressPairs
* @param bool $isAsyncStatusReport use for different status reporting modes
* @return string task ID
*/
public function scheduleImport(
SessionDirectory $session,
$mailAddressPairs, $isAsyncStatusReport=false
) {
$sessionObjects = SessionObjects::getInstance($session);
$progress = $sessionObjects->getProgress();
$progress->cleanup();
$migrationList = $this->_createMigrationListWithRandomName($session, $mailAddressPairs);
$tool = new Tool();
$taskId = $tool->addMailMigrationTasks(
$sessionObjects->getConfig(), $migrationList->getFilePath(), $isAsyncStatusReport
);
return $taskId;
}
/**
* Get global import status and import issues for mail address pairs.
*
* Workflow of import is the following:
* - schedule import
* ("scheduleImport" method)
* - start task runner
* ("startTasksRunner" method)
* - periodically (e.g. once a second) poll import status with that function,
* display status/issues in user interface.
*
* @param SessionDirectory $session
* @return Import
*/
public function getGlobalStatus(SessionDirectory $session)
{
$sessionObjects = SessionObjects::getInstance($session);
$status = $sessionObjects->getMailMigrationStatus(null);
$statusData = $status->getStatusData();
$status = [];
$mailAddressPairStatusData = ArrayUtils::getElementDefaultArray($statusData, 'mail_address_pairs');
foreach ($mailAddressPairStatusData as $mailAddressPair) {
$status[] = new Import\MailAddressPair(
$mailAddressPair['source_email'], $mailAddressPair['target_mailname'],
$this->_convertIssuesToObject(
ArrayUtils::getElementDefaultArray($mailAddressPair, 'issues')
),
$mailAddressPair['status'] ?? null,
$mailAddressPair['step'] ?? null,
$mailAddressPair['error_id'] ?? null,
$mailAddressPair['error_message'] ?? null,
$mailAddressPair['restored_message_num'] ?? null
);
}
return new Import($status);
}
/**
* Get task status.
*
* @param SessionDirectory $session
* @param string $taskId
* @return Task
*/
public function getTaskStatus(
SessionDirectory $session, $taskId
) {
$sessionObjects = SessionObjects::getInstance($session);
$status = $sessionObjects->getMailMigrationStatus($taskId);
$statusData = $status->getStatusData();
return new Task(
$statusData['status'] ?? null,
$statusData['step'] ?? null,
$statusData['error_id'] ?? null,
$statusData['error_message'] ?? null,
$statusData['error_details'] ?? null
);
}
/**
* Cancel scheduled or running import of specified mail addresses.
*
* Operation is synchronous - function returns control once import is actually cancelled.
* Usually that is fast, but sometimes could take up to a minute, for example in case of hanged connection
* to the source server.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\MailImport\Entity\ImportOperation\MailAddressPair[] $mailAddressPairs
*/
public function cancelImport(
SessionDirectory $session,
$mailAddressPairs
) {
$sessionObjects = SessionObjects::getInstance($session);
$progress = $sessionObjects->getProgress();
$progress->cleanup();
$migrationList = $this->_createMigrationListWithRandomName($session, $mailAddressPairs);
$migratorTool = new Tool();
$migratorTool->cancelMailMigrationTasks($sessionObjects->getConfig(), $migrationList->getFilePath());
}
/**
* Start task runner, which runs import for previously scheduled imports of mail messages.
*
* On Unix this function returns once the task runner was started (asynchronously).
* On Windows this function returns only once the task runner was finished (synchronously).
* The difference is caused by difficulties implementing asynchronous command execution on Windows.
*
* @param SessionDirectory $session
*/
public function startTasksRunner(
SessionDirectory $session
) {
$sessionObjects = SessionObjects::getInstance($session);
$migratorTool = new Tool();
$migratorTool->runMailMigrationTasks($sessionObjects->getConfig());
}
/**
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\MailImport\Entity\ImportOperation\MailAddressPair[] $mailAddressPairs
* @return MigrationList
*/
private function _createMigrationListWithRandomName(
SessionDirectory $session, $mailAddressPairs
) {
$sessionObjects = SessionObjects::getInstance($session);
$migrationListSuffix = date('Y-m-d-H-i-s');
$migrationList = $sessionObjects->getMailMigrationList($migrationListSuffix);
$migrationList->write($mailAddressPairs);
return $migrationList;
}
private function _convertIssuesToObject($issuesArray)
{
$issues = [];
foreach ($issuesArray as $issue) {
$issues[] = new Issue(
$issue['severity'], $issue['execution_date'], $issue['problem_text'], $issue['details_text']
);
}
return $issues;
}
}

View File

@@ -1,57 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport;
class SessionFiles extends \Plesk\MigrationLibV8\Common\SessionFiles
{
/**
* Get full path to file with the mail migration status.
*
* The file contains status of migration (in progress, success, failure, etc) for each mail address pair,
* and list of import issues for each mail address pair.
*
* @param string|null $taskId get status file for specific mail import task;
* when not specified global status is returned
* @return string
* @throws \Exception when specified task ID is invalid
*/
public function getStatusFilePath($taskId=null)
{
if (is_null($taskId)) {
return $this->_session->getPath() . DIRECTORY_SEPARATOR . 'mail_migration_status.json';
} else {
$tasksDir = $this->_session->getPath() . DIRECTORY_SEPARATOR . 'tasks';
$allTasks = [];
foreach (new \DirectoryIterator($tasksDir) as $file) {
if ($file->isDir()) {
$allTasks[] = $file->getFilename();
}
}
if (!in_array($taskId, $allTasks)) {
throw new \Exception("Invalid task specified");
}
return $tasksDir . DIRECTORY_SEPARATOR . $taskId . DIRECTORY_SEPARATOR . 'task-status.json';
}
}
/**
* Get full path to file with the mail migration list.
*
* @param $suffix
* @return string
*/
public function getMailMigrationListPath($suffix)
{
if (!is_null($suffix)) {
$filename = "mail_migration_list_{$suffix}.json";
} else {
$filename = 'mail_migration_list.json';
}
return $this->_session->getPath() . DIRECTORY_SEPARATOR . $filename;
}
}

View File

@@ -1,117 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\MailImport;
use Plesk\MigrationLibV8\Common\Backend\Files\Progress;
use Plesk\MigrationLibV8\Common\SessionDirectory;
use Plesk\MigrationLibV8\MailImport\Backend\Files\Config;
use Plesk\MigrationLibV8\MailImport\Backend\Files\MigrationList;
use Plesk\MigrationLibV8\MailImport\Backend\Files\Status;
class SessionObjects
{
/** @var \Plesk\MigrationLibV8\MailImport\SessionObjects[] */
private static $_instances = [];
/** @var \Plesk\MigrationLibV8\Common\SessionDirectory */
protected $_session;
/** @var \Plesk\MigrationLibV8\MailImport\SessionFiles|null */
private $_sessionFiles = null;
/** @var \Plesk\MigrationLibV8\MailImport\Backend\Files\Config|null */
private $_config = null;
/** @var \Plesk\MigrationLibV8\Common\Backend\Files\Progress|null */
private $_progress = null;
/** @var \Plesk\MigrationLibV8\MailImport\Backend\Files\MigrationList[]|null */
private $_mailMigrationLists = [];
/** @var \Plesk\MigrationLibV8\MailImport\Backend\Files\Status|null */
private $_status = null;
/**
* SessionObjects constructor.
*
* @param SessionDirectory $session
*/
private function __construct(SessionDirectory $session)
{
$this->_session = $session;
}
/**
* @param \Plesk\MigrationLibV8\Common\SessionDirectory $session
* @return \Plesk\MigrationLibV8\MailImport\SessionObjects
*/
public static function getInstance(SessionDirectory $session)
{
if (!array_key_exists($session->getPath(), self::$_instances)) {
self::$_instances[$session->getPath()] = new self($session);
}
return self::$_instances[$session->getPath()];
}
/**
* @return \Plesk\MigrationLibV8\MailImport\Backend\Files\Config
*/
public function getConfig()
{
if (!$this->_config) {
$configPath = $this->getSessionFiles()->getConfigPath();
$this->_config = new Config($configPath);
$this->_config->setDefaultSourceSectionName('mail');
}
return $this->_config;
}
/**
* @return \Plesk\MigrationLibV8\Common\Backend\Files\Progress
*/
public function getProgress()
{
if (!$this->_progress) {
$this->_progress = new Progress(
$this->getSessionFiles()->getProgressPath()
);
}
return $this->_progress;
}
/**
* @return \Plesk\MigrationLibV8\MailImport\SessionFiles
*/
public function getSessionFiles()
{
if (!$this->_sessionFiles) {
$this->_sessionFiles = new SessionFiles($this->_session);
}
return $this->_sessionFiles;
}
/**
* @param string|null $suffix
* @return \Plesk\MigrationLibV8\MailImport\Backend\Files\MigrationList
*/
public function getMailMigrationList($suffix)
{
if (!array_key_exists($suffix, $this->_mailMigrationLists)) {
$this->_mailMigrationLists[$suffix] = new MigrationList(
$this->getSessionFiles()->getMailMigrationListPath($suffix)
);
}
return $this->_mailMigrationLists[$suffix];
}
/**
* @param string|null $taskId
* @return Status
*/
public function getMailMigrationStatus($taskId=null)
{
if (!$this->_status) {
$this->_status = new Status(
$this->getSessionFiles()->getStatusFilePath($taskId)
);
}
return $this->_status;
}
}

View File

@@ -1,14 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Plesk\PleskClasses;
/**
* Wrapper around Plesk dobule list selector class, used directly by extension, without using official extensions SDK.
*/
/** @noinspection PhpUndefinedClassInspection */
class DoubleListSelector extends \CommonPanel_Form_Element_DoubleListSelector
{
}

View File

@@ -1,47 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Plesk\PleskClasses;
/**
* Wrapper around Plesk form subsection, used directly by extension, without using official extensions SDK.
*/
/** @noinspection PhpUndefinedClassInspection */
class FormSection extends \CommonPanel_Form_Section
{
private $section;
public function __construct()
{
/** @noinspection PhpUndefinedClassInspection */
$this->section = new \CommonPanel_Form_Section();
}
public function setLegend($legend)
{
/** @noinspection PhpUndefinedMethodInspection */
$this->section->setLegend($legend);
}
public function addElement($element, $name = null, $options = null)
{
/** @noinspection PhpUndefinedMethodInspection */
$this->section->addElement($element, $name, $options);
}
public function getElement($name)
{
/** @noinspection PhpUndefinedMethodInspection */
return $this->section->getElement($name);
}
/**
* @return \Zend_Form_SubForm
*/
public function getZendFormSubForm()
{
/** @noinspection PhpIncompatibleReturnTypeInspection */
return $this->section;
}
}

View File

@@ -1,181 +0,0 @@
<?php
// Copyright 1999-2019. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Plesk;
use Plesk\MigrationLibV8\Utils\ArrayUtils;
use Plesk\MigrationLibV8\Utils\FileUtils;
/**
* Wrapper around Plesk function called directly by extension, without using official extensions SDK.
*/
class PleskFunctions
{
public static function encryptPassword($password)
{
/** @noinspection PhpUndefinedClassInspection */
return \Plesk_Base_Utils_String::encryptWithPrefix($password);
}
public static function decryptPassword($password)
{
/** @noinspection PhpUndefinedClassInspection */
return \Plesk_Base_Utils_String::decryptWithPrefix($password);
}
public static function utilExec($util, $params, $env, &$output)
{
/** @noinspection PhpIncludeInspection */
if (!@include_once('common_func.php')) {
/** @noinspection PhpIncludeInspection */
require_once('common_func.php3'); // for Plesk < 17.0
}
global $plesk_errormsg, $php_errormsg;
$execResponse = '';
/** @var \Db_Table_Broker_ServiceNodes $serviceNodesBroker */
$serviceNodesBroker = \Db_Table_Broker::get('ServiceNodes');
$serviceNode = $serviceNodesBroker->getManagementNode();
$utilPath = $serviceNode->env()->general()->getValue('PRODUCT_ROOT_D') .
DIRECTORY_SEPARATOR . 'admin' .
DIRECTORY_SEPARATOR . 'bin64' .
DIRECTORY_SEPARATOR . $util . '.exe';
$is64bit = FileUtils::fileExists($utilPath);
$response = $serviceNode->agent()->exec($util, $params, '', $env, $is64bit)
->saveResponse($execResponse)
->commit();
if ($error = $response->getError()) {
$plesk_errormsg = "util_io_exec() failed: " . $error->getMessage();
$stdError = $response->getStdErr();
if ("" != $stdError) {
$plesk_errormsg .= ' ' . $stdError;
}
return false;
}
$output = [];
$out_arr = explode("\n", rtrim($execResponse->stdout));
foreach ($out_arr as $out_str) {
$output[] = rtrim($out_str);
}
return true;
}
public static function sendFileDownloadHeaders($filename)
{
/** @noinspection PhpUndefinedFunctionInspection */
sendHeaders_Download($filename);
}
public static function getDefaultIPAddress()
{
/** @noinspection PhpUndefinedClassInspection */
$defaultIp = \Db_Table_Broker::get('IpAddresses')->getDefault();
return $defaultIp ? $defaultIp->ip_address : '';
}
public static function getIPAddresses()
{
$ipAddresses = [];
/** @noinspection PhpUndefinedClassInspection */
foreach (\Db_Table_Broker::get('IpAddresses')->fetchAll() as $ip) {
$ipAddresses[] = $ip->ip_address;
}
return $ipAddresses;
}
/**
* Get URLs to overview pages of each subscription in Plesk.
*
* @return string[] list of URLs
*/
public static function getSubscriptionOverviewUrls()
{
/** @noinspection PhpUndefinedClassInspection */
$data = \Db_Table_Broker::get('domains')->select()->setIntegrityCheck(false)
->from(['d' => 'domains'], ['name' => 'd.name', 'id' => 'd.id'])
->where('d.webspace_id = 0')
->query()->fetchAll();
foreach ($data as &$item) {
$item['url'] = '/admin/subscription/overview/id/' . $item['id'];
}
return ArrayUtils::groupValueById($data, 'name', 'url');
}
/**
* Get list of existing subscription names in Plesk.
*
* @return string[] list of existing subscription names
*/
public static function getSubscriptionNames()
{
$subscriptionNames = [];
/** @noinspection PhpUndefinedClassInspection */
$data = \Db_Table_Broker::get('domains')->select()->setIntegrityCheck(false)
->from(['d' => 'domains'], ['name' => 'd.name'])
->where('d.webspace_id = 0')
->query()->fetchAll();
foreach ($data as $item) {
$subscriptionNames[] = $item['name'];
}
return $subscriptionNames;
}
/**
* Check whether we are working on Plesk Multiserver.
*
* @return bool
*/
public static function isPleskMultiserver()
{
/** @noinspection PhpUndefinedClassInspection */
foreach (\DB_Table_Broker::get('Modules')->fetchAll() as $moduleInfo) {
if ($moduleInfo->name == 'plesk-multi-server') {
return true;
}
}
return false;
}
/**
* Check whether target Plesk server has remote SmarterMail as a mail server
*
* @return bool
*/
public static function hasRemoteSmarterMail()
{
/** @noinspection PhpUndefinedClassInspection */
$data = \Db_Table_Broker::get('ServiceNodeEnvironment')->select()
->where("section = 'mail' AND name = 'SMTP_Server_package'")
->query()->fetchAll();
return count($data) > 0 && $data[0]['value'] == 'smartermail_remote';
}
/**
* Get IP address of remote SmarterMail server.
*
* @return string
*/
public static function getRemoteSmarterMailIP()
{
/** @noinspection PhpUndefinedClassInspection */
$data = \Db_Table_Broker::get('misc')->select()
->where("param = 'smartermail_remote_host'")
->query()->fetchAll();
if (count($data) == 0) {
return '';
}
return gethostbyname($data[0]['val']);
}
public static function IDNToASCII($domainName)
{
/** @noinspection PhpUndefinedFunctionInspection */
return @idn_toascii($domainName);
}
}

View File

@@ -1,223 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Backend\Files;
use Plesk\MigrationLibV8\Plesk\PleskFunctions;
class Config extends \Plesk\MigrationLibV8\Common\Backend\Files\Config
{
const CONFIG_PASSWORD_TYPE_ENCRYPTED = 'encrypted';
/**
* Initialize default options, that do not depend on user's input and should be always presented
*/
public function initDefaultOptions() {
parent::initDefaultOptions();
$this->setAllowInsecureConnections(false);
}
/**
* Set host to transfer sites/applications from. Used for site migration scenario.
*
* @param $host string
*/
public function setSourceHost($host)
{
$this->setSourceValue('host', $host);
}
/**
* Get host to transfer sites/applications from. Used for site migration scenario.
*
* @return string
*/
public function getSourceHost()
{
$host = $this->getSourceValue('host');
if (is_null($host)) {
// for compatibility with existing sessions (parameter was renamed from "ftp-host" to "host")
$host = $this->getSourceValue('ftp-host');
}
return $host;
}
/**
* Set username for FTP/SSH host to transfer sites/applications from. Used for site migration scenario.
*
* @param $username string
*/
public function setSourceUsername($username)
{
$this->setSourceValue('username', $username);
}
/**
* Set password for FTP/SSH host to transfer sites/applications from. Used for site migration scenario.
*
* @param $password string
*/
public function setSourcePassword($password)
{
$passwordEncrypted = PleskFunctions::encryptPassword($password);
$this->setSourceValue(
'password', $passwordEncrypted
);
$this->setSourceValue(
'password-type', self::CONFIG_PASSWORD_TYPE_ENCRYPTED
);
}
/**
* Set encoding in which source FTP server returns directory listings.
*
* @param $ftpEncoding string
*/
public function setSourceFtpEncoding($ftpEncoding)
{
$this->setSourceValue('ftp-encoding', $ftpEncoding);
}
/**
* Set base URL of the site to transfer. Used for site migration scenario.
*
* @param $baseUrl string
*/
public function setSourceBaseUrl($baseUrl)
{
$this->setSourceValue('base-url', $baseUrl);
}
/**
* Set document root of migrated site related to FTP root or SSH home. Used for site migration scenario.
*
* @param $documentRoot string
*/
public function setSourceDocumentRoot($documentRoot)
{
$this->setSourceValue('document-root', $documentRoot);
}
/**
* Set files root of migrated site.
*
* Files root is a path to start scan for files, applications and document root,
* related to FTP/SSH root. When not set, default is used: when transport is FTP,
* then FTP root is used, when transport is SSH, then home directory of SSH user is used.
*
* @param $filesRoot string
*/
public function setSourceFilesRoot($filesRoot)
{
$this->setSourceValue('files-root', $filesRoot);
}
/**
* Set way to list files on the source server
*
* Possible ways: with file transport (FTP or SSH - see "file-transport" option), with Web RPC agent,
* with Web RPC agent with fallback to file transport.
*
* General considerations:
* - Listing with Web RPC agent works much more fast than listing with FTP, but it could be less reliable.
* - When FTP is used as file transport, listing with Web RPC agent with FTP fallback in
* case of unicode names and or any failure of RPC agent takes advantages of both ways:
* usually it works fast, but in case of any failure it works like FTP listing, so it is reliable.
* By default, migrator automatically selects the way which is optimal for most cases.
*
* Possible values: 'auto', 'file-transport', 'web-rpc-agent', 'hybrid'
*
* @param $listFilesMode string
*/
public function setListFilesMode($listFilesMode)
{
$this->setSourceValue('list-files-mode', $listFilesMode);
}
/**
* Set domain name to which site should be transferred.
*
* @param $domain string
*/
public function setSourceTargetDomain($domain)
{
$this->setSourceValue('target-domain', $domain);
}
/**
* Set whether to allow HTTP connections and HTTPS connections without valid SSL certificate
* When set to False only HTTPS connections with valid certificate
* and explicitly defined connections will be allowed.
* When set to True any connections will be allowed, SSL certificates validation will be skipped.
*
* @param $allowInsecureConnections bool
*/
public function setAllowInsecureConnections($allowInsecureConnections)
{
$this->setSourceValue(
'allow-insecure-connections',
$this->_encodeBooleanValue($allowInsecureConnections)
);
}
/**
* Set file transport - way to perform file operations on remote server.
*
* @param $fileTransport string
*/
public function setSourceFileTransport($fileTransport)
{
$this->setSourceValue('file-transport', $fileTransport);
}
/**
* Set way to transfer files from source site to target one.
*
* @param $transferFilesMode string
*/
public function setSourceTransferFilesMode($transferFilesMode)
{
$this->setSourceValue('transfer-files-mode', $transferFilesMode);
}
/**
* Set whether transfer of files with web streaming should be automatically selected when it makes sense.
*
* Web streaming makes sense in case when transfer files mode is 'auto' and actual file transport is FTP.
* Web streaming is a beta feature, and so it is not selected by default.
* @param $allowAutoWebStreaming bool
*/
public function setSourceAllowAutoWebStreaming($allowAutoWebStreaming)
{
$this->setSourceValue('allow-auto-web-streaming', $this->_encodeBooleanValue($allowAutoWebStreaming));
}
/**
* Set port to connect to the source website by SSH.
*
* @param $sshPort string
*/
public function setSourceSSHPort($sshPort)
{
$this->setSourceValue('ssh-port', $sshPort);
}
/**
* Set whether to ignore IP address returned by FTP server when opening data channel in passive mode.
* When is set to true, IP address returned by FTP server when opening data channel
* in passive mode is ignored. That option could be necessary because some misconfigured
* FTP servers return internal IPs, which could not be used to connect to the server.
* When the option is set, hostname specified for control connection to the FTP server
* will be used for data connections.
*
* @param $ignorePassiveModeServerIp bool
*/
public function setIgnorePassiveModeServerIp($ignorePassiveModeServerIp)
{
$this->setSourceValue(
'ignore-passive-mode-server-ip',
$this->_encodeBooleanValue($ignorePassiveModeServerIp)
);
}
}

View File

@@ -1,73 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Backend\Files;
use Plesk\MigrationLibV8\Utils\FileUtils;
class MigrationList
{
private $_migrationListFilePath;
public function __construct($migrationListFilePath)
{
$this->_migrationListFilePath = $migrationListFilePath;
}
/**
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application[] $applications
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Folder[] $folders
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Database[] $databases
* @param string $command
*/
public function write($applications, $folders, $databases, $command)
{
$siteMigrationListContents = [
'filter_applications' => [],
'include_files' => [],
'include_databases' => []
];
foreach ($applications as $application) {
$siteMigrationListContents['filter_applications'][] = [
'type' => $application->getType(),
'source_path' => $application->getSourcePath(),
'target_path' => $application->getTargetPath()
];
}
foreach ($folders as $folder) {
$siteMigrationListContents['include_files'][] = [
'source_path' => $folder->getSourcePath(),
'target_path' => $folder->getTargetPath()
];
}
foreach ($databases as $database) {
$siteMigrationListContents['include_databases'][] = [
'host' => $database->getHost(),
'port' => $database->getPort(),
'username' => $database->getUsername(),
'password' => $database->getPassword(),
'name' => $database->getName()
];
}
$siteMigrationListContents['task'] = $command;
FileUtils::putFileContents(
$this->getFilePath(),
\Zend_Json::prettyPrint(\Zend_Json::encode($siteMigrationListContents))
);
}
/**
* Get full path to file with the migration list.
*
* @return string
*/
public function getFilePath()
{
return $this->_migrationListFilePath;
}
}

View File

@@ -1,207 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Backend\Files;
use Plesk\MigrationLibV8\Utils\ArrayUtils;
use Plesk\MigrationLibV8\Utils\FileUtils;
class SiteInfo
{
const KEY_APPLICATIONS = 'applications';
const KEY_FILES = 'files';
const KEY_ROOT_PATH = 'root_path';
const KEY_FILESYSTEM_ROOT_PATH = 'filesystem_root_path';
const KEY_DOCUMENT_ROOT = 'document_root';
const KEY_SITE_NAME = 'site_name';
const KEY_TARGET_DOCUMENT_ROOT = 'target-document-root';
private $_siteName;
private $_siteInfoFilePath;
private $_data;
public function __construct($siteName, $siteInfoFilePath)
{
$this->_siteName = $siteName;
$this->_siteInfoFilePath = $siteInfoFilePath;
$this->_data = [];
if (FileUtils::fileExists($this->_siteInfoFilePath)) {
$allSitesData = json_decode(
FileUtils::fileGetContents($this->_siteInfoFilePath), true
);
if (!is_null($allSitesData) && array_key_exists($this->_siteName, $allSitesData)) {
$this->_data = $allSitesData[$this->_siteName];
}
}
}
public function getApplications()
{
$applications = [];
$siteInfoApplications = ArrayUtils::getElementDefaultArray(
$this->_data, self::KEY_APPLICATIONS
);
foreach ($siteInfoApplications as $applicationName => $paths) {
foreach ($paths as $path) {
$applications[] = [
'type' => $applicationName,
'source_path' => $path,
// 'target_path' contains path relative to target document root path
// Site info storage doesn't contain target path, consider it is the same as on source
'target_path' => $this->getSourceRelativePath($path)
];
}
}
return $applications;
}
public function getFiles()
{
return ArrayUtils::getElementDefaultArray(
$this->_data, self::KEY_FILES
);
}
public function getRootPath()
{
return ArrayUtils::getElementDefaultNull($this->_data, self::KEY_ROOT_PATH);
}
public function getFilesystemRootPath()
{
$filesystemRootPath = ArrayUtils::getElementDefaultNull($this->_data, self::KEY_FILESYSTEM_ROOT_PATH);
if ($filesystemRootPath === null) {
// for compatibility with old versions of migrator
$filesystemRootPath = $this->getRootPath();
}
return $filesystemRootPath;
}
public function getSourceDocumentRoot()
{
return ArrayUtils::getElementDefaultNull($this->_data, self::KEY_DOCUMENT_ROOT);
}
public function getTargetDocumentRoot()
{
return ArrayUtils::getElementDefaultNull($this->_data, self::KEY_TARGET_DOCUMENT_ROOT);
}
public function getSiteName()
{
return ArrayUtils::getElementDefaultNull($this->_data, self::KEY_SITE_NAME);
}
/**
* Whether site info file contains complete set of data, so migration could be started.
*
* @return bool
*/
public function isComplete()
{
foreach ($this->_getAllRequiredKeys() as $key) {
if (!array_key_exists($key, $this->_data)) {
return false;
}
}
return true;
}
/**
* Returns path relative to target document root
*
* Example:
* - path - /var/www/vhosts/site.com/httpdocs/subfolder
* - target document root - /var/www/vhosts/site.com/httpdocs
* - result subfolder
*
* @param string $path
* @return string
*/
public function getTargetRelativePath($path)
{
return $this->_getRelativePath($this->getTargetDocumentRoot(), $path);
}
/**
* Returns path relative to source document root
*
* Example:
* - path - /var/www/vhosts/site.com/httpdocs/subfolder
* - source document root - /var/www/vhosts/site.com/httpdocs
* - result subfolder
*
* @param string $path
* @return string
*/
public function getSourceRelativePath($path)
{
if ($this->_isWindowsAbsolutePath($path)) {
$fullSourceDocrootPath = (
trim($this->getFilesystemRootPath(), '\\') . '\\' . trim($this->getSourceDocumentRoot(), '/') . '\\'
);
} else {
$rootPathTrimmed = trim($this->getFilesystemRootPath(), '/');
if ($rootPathTrimmed == '') {
$rootPathNormalized = '/';
} else {
$rootPathNormalized = '/' . $rootPathTrimmed . '/' ;
}
$fullSourceDocrootPath = $rootPathNormalized . trim($this->getSourceDocumentRoot(), '/') . '/';
}
return $this->_getRelativePath($fullSourceDocrootPath, $path);
}
private function _getRelativePath($docrootPath, $path)
{
if ($this->_isWindowsAbsolutePath($path)) {
$docrootPath = rtrim($docrootPath, '\\') . '\\';
$path = trim($path, '\\') . '\\';
if (strpos($path, $docrootPath) === 0) {
return rtrim(
str_replace('\\', '/', substr($path, strlen($docrootPath))), '/'
);
}
} else {
$docrootPath = rtrim($docrootPath, '/') . '/';
$path = '/' . trim($path, '/') . '/';
if (strpos($path, $docrootPath) === 0) {
return rtrim(substr($path, strlen($docrootPath)), '/');
}
}
return '';
}
/**
* Whether provided path looks like a Windows path.
*
* @param string $path
* @return bool
*/
private function _isWindowsAbsolutePath($path)
{
// Path starts with something like "C:\"
return (bool)preg_match('/^[a-zA-Z]:\\\\/', $path);
}
/**
* Data keys in site info file which are required to start migration.
*
* @return array
*/
private function _getAllRequiredKeys()
{
return [
self::KEY_SITE_NAME,
self::KEY_ROOT_PATH,
self::KEY_DOCUMENT_ROOT,
self::KEY_APPLICATIONS,
self::KEY_FILES,
];
}
}

View File

@@ -1,210 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Backend\Files;
use Plesk\MigrationLibV8\Utils\ArrayUtils;
use Plesk\MigrationLibV8\Utils\FileUtils;
class Status
{
const OPERATION_CONNECT = 'connect';
const OPERATION_SCAN_CONTENT = 'scan-content';
const STATUS_NOT_STARTED = 'not-started';
const STATUS_SUCCESS = 'success';
const STATUS_FAILURE = 'failure';
/** @var string */
private $_statusFilePath;
/** @var string */
private $_siteName;
private $_siteData;
public function __construct($statusFilePath, $siteName)
{
$this->_statusFilePath = $statusFilePath;
$this->_siteName = $siteName;
$this->read();
}
public function isOperationFinished($operation)
{
return $this->getOperationStatus($operation) != self::STATUS_NOT_STARTED;
}
public function isOperationSuccessful($operation)
{
return $this->getOperationStatus($operation) == self::STATUS_SUCCESS;
}
public function getOperationStatus($operation)
{
if (isset($this->_siteData['operation'][$operation]['status'])) {
return $this->_siteData['operation'][$operation]['status'];
} else {
return self::STATUS_NOT_STARTED;
}
}
public function getErrorMessages()
{
$errorMessages = [];
foreach ([self::OPERATION_CONNECT, self::OPERATION_SCAN_CONTENT] as $operation) {
if (isset($this->_siteData['operation'][$operation]['message'])) {
$errorMessages[] = $this->_siteData['operation'][$operation]['message'];
}
}
return $errorMessages;
}
public function getIssueId()
{
foreach ([self::OPERATION_CONNECT, self::OPERATION_SCAN_CONTENT] as $operation) {
if (isset($this->_siteData['operation'][$operation]['issue_id'])) {
return $this->_siteData['operation'][$operation]['issue_id'];
}
}
return null;
}
/**
* Get whole set of site status data as array.
*
* @return array
*/
public function getSiteData()
{
return $this->_siteData;
}
public function resetOperationsStatus()
{
if (FileUtils::fileExists($this->getFilePath())) {
$data = json_decode(FileUtils::fileGetContents($this->getFilePath()), true);
if (isset($data[$this->_siteName]['operation'])) {
unset($data[$this->_siteName]['operation']);
// fix for JSON serialization: avoid empty lists where backend expects empty dictionaries
if (count($data[$this->_siteName]) == 0) {
unset($data[$this->_siteName]);
}
if (count($data) == 0) {
$data = new \stdClass();
}
FileUtils::putFileContents(
$this->getFilePath(), \Zend_Json::prettyPrint(\Zend_Json::encode($data))
);
// re-read contents of status file
$this->read();
}
}
}
/**
* Set backend error for the last unfinished operation, if it was not already set by backend itself.
*
* @param $message
*/
public function setBackendFailure($message)
{
if (FileUtils::fileExists($this->getFilePath())) {
$data = json_decode(FileUtils::fileGetContents($this->getFilePath()), true);
} else {
$data = [];
}
// find the last unfinished operation, and set failure for it
$lastOperation = null;
foreach ([self::OPERATION_CONNECT, self::OPERATION_SCAN_CONTENT] as $operation) {
$lastOperation = $operation;
if (isset($data[$this->_siteName]['operation'][$operation]['status'])) {
$status = $data[$this->_siteName]['operation'][$operation]['status'];
if ($status == self::STATUS_FAILURE) {
// failure is already set in the status file by backend; consider backend has better
// message, so don't change anything in the status file
return;
} else if ($status != self::STATUS_FAILURE && $status != self::STATUS_SUCCESS) {
// found operation, for which we have unfinished status - it is the last unfinished operation
break;
}
} else {
// found operation which has no status set - it is the last unfinished operation
break;
}
}
if (!isset($data[$this->_siteName])) {
$data[$this->_siteName] = [];
}
if (!isset($data[$this->_siteName]['operation'])) {
$data[$this->_siteName]['operation'] = [];
}
$data[$this->_siteName]['operation'][$lastOperation] = [
'status' => self::STATUS_FAILURE,
'message' => $message
];
FileUtils::putFileContents(
$this->getFilePath(), \Zend_Json::prettyPrint(\Zend_Json::encode($data))
);
}
/**
* Get full path to file with the site info.
*
* @return string
*/
private function getFilePath()
{
return $this->_statusFilePath;
}
public function read()
{
if (FileUtils::fileExists($this->getFilePath())) {
$data = json_decode(FileUtils::fileGetContents($this->getFilePath()), true);
} else {
$data = [];
}
$data = ArrayUtils::getElementDefaultArray($data, $this->_siteName);
// Leave issue details only for administrator:
// - for better security (details could accidentally contain sensitive data)
// - for better user experience (in most cases user won't understood the details, and there is no sense
// to show that useless info).
// So, only administrator could see logs, stack traces, etc.
if (!\pm_Session::getClient()->isAdmin()) {
$data = $this->_filterOutDetails($data);
}
$this->_siteData = $data;
}
/**
* Remove issue details from migration status data structure
*
* @param mixed $data
* @return mixed
*/
private function _filterOutDetails($data)
{
if (is_array($data)) {
$result = [];
foreach ($data as $key => $value) {
if ($key !== 'details_text') {
$result[$key] = $this->_filterOutDetails($value);
}
}
return $result;
} else {
return $data;
}
}
}

View File

@@ -1,143 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Backend;
use Plesk\MigrationLibV8\Common\Backend\ToolUtils;
use Plesk\MigrationLibV8\Common\Exception\NonZeroExitCode;
use Plesk\MigrationLibV8\SiteImport\Backend\Files\Config;
/**
* Wrapper around "plesk-migrator" utility (which is backend entry point) for site import.
*/
class Tool
{
/**
* Site migration: run get information about site on the source server by FTP/SSH.
*
* @param Config $config
* @param bool $reloadSourceData whether to use cached data, or reload all data from source site again
* @param bool $async whether to wait for execution results, or run the command in background
*/
public function getSiteInfo(
Config $config, $reloadSourceData=true, $async=false
) {
$command = 'get-site-info';
$args = [];
if ($reloadSourceData) {
$args[] = '--reload-source-data';
}
if ($async) {
$args[] = '--async';
}
$this->_exec($command, $args, $config);
}
/**
* Site migration: schedule site migration tasks.
* Once the tasks are scheduled, start them with 'runSiteMigrationTasks' function.
*
* @param Config $config
* @param string $migrationListFile full path to file with migration list
*/
public function addSiteMigrationTasks(
Config $config, $migrationListFile
) {
$command = 'add-tasks';
$args = [
"--site-migration-list=$migrationListFile",
];
$this->_exec($command, $args, $config);
}
/**
* Site migration: cancel site migration tasks related to apps/folders/databases specified by migration list.
*
* @param Files\Config $config
* @param string $migrationListFile full path to file with migration list
*/
public function cancelSiteMigrationTasks(
Config $config, $migrationListFile
) {
$command = 'cancel-tasks';
$args = [
"--site-migration-list=$migrationListFile",
];
$this->_exec($command, $args, $config);
}
/**
* Site migration: run previously scheduled site migration tasks.
* Schedule site migration tasks with 'addSiteMigrationTasks' function.
*
* On Unix this function returns once the task runner was started (asynchronously).
* On Windows this function returns only once the task runner was finished (synchronously).
* The difference is caused by difficulties implementing asynchronous command execution on Windows.
*
* @param Config $config
*/
public function runSiteMigrationTasks(Config $config)
{
// Start task queue runner for site migration.
// If it is already running, this call will simply do nothing - "run-tasks" will exit immediately.
$this->_exec('run-tasks', ['--async'], $config);
}
/**
* Get migration statistics, as JSON string
*
* @return string
*/
public function getStatistics()
{
return $this->_exec('summarize-statistics', ['--quiet']);
}
/**
* Execute backend action for site migration.
*
* Backend for site migration runs under superuser (root on Linux, SYSTEM on Windows)
* with Plesk 17.0 SDK features, which are not available on Plesk 12.5. No Administrator password is
* required on Windows comparing to regular migration, so site migration could be launched by customer,
* not only by server administrator.
*
* Backend lowers privileges to system user of subscription when necessary, for example when transferring files
* by FTP/SSH.
*
* @param string $action
* @param string[] $args
* @param Config $config
* @return mixed
* @throws \Exception
*/
private function _exec($action, $args, ?Config $config=null)
{
// Execute the backend under superuser
$env = ToolUtils::getEnvVarsByConfig($config);
$params = [$action];
if (!is_null($config)) {
$params[] = $config->getPath();
}
$params = array_merge($params, $args);
if (\pm_ProductInfo::isWindows()) {
$sbinExecutable = 'plesk-migrator.bat';
} else {
$sbinExecutable = 'plesk-migrator';
}
$result = \pm_ApiCli::callSbin($sbinExecutable, $params, \pm_ApiCli::RESULT_FULL, $env);
if ($result['code'] !== 0) {
$commandParts = ['plesk-migrator'];
$commandParts = array_merge($commandParts, $params);
foreach ($commandParts as &$commandPart) {
$commandPart = escapeshellarg($commandPart);
}
throw new NonZeroExitCode(
implode(" ", $commandParts), $result['code'], $result['stdout'], $result['stderr']
);
}
return $result['stdout'];
}
}

View File

@@ -1,13 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity;
class ApplicationTypes
{
const WORDPRESS = 'WordPress';
const DRUPAL = 'Drupal';
const JOOMLA = 'Joomla!';
const MAGENTO = 'Magento';
const PRESTASHOP = 'PrestaShop';
}

View File

@@ -1,16 +0,0 @@
<?php
// Copyright 1999-2018. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity;
class CheckStatuses
{
const NOT_IMPORTED = 'not-imported';
const READY_TO_CHECK = 'ready-to-check';
const IN_PROGRESS = 'in-progress';
const SUCCESS = 'success';
const WARNING = 'warning';
const FAILURE = 'failure';
const QUEUED = 'queued';
const CANCELLED = 'cancelled';
}

View File

@@ -1,11 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity;
class FileTransports
{
const AUTO = 'auto';
const FTP = 'ftp';
const SSH = 'ssh';
}

View File

@@ -1,114 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All Rights Reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity;
class FtpServerEncodings
{
private static $utf8Encoding = ['id' => 'utf-8', 'title' => 'UTF-8'];
public static function getCodepagesList()
{
return [
// List of codepages as accepted by backend (Python 2.7) - see
// https://docs.python.org/2.7/library/codecs.html#standard-encodings
// for details
self::$utf8Encoding,
['id' => 'big5', 'title' => 'big5 (Traditional Chinese)'],
['id' => 'big5hkscs', 'title' => 'big5hkscs (Traditional Chinese)'],
['id' => 'cp037', 'title' => 'cp037 (English)'],
['id' => 'cp424', 'title' => 'cp424 (Hebrew)'],
['id' => 'cp437', 'title' => 'cp437 (English)'],
['id' => 'cp500', 'title' => 'cp500 (Western Europe)'],
['id' => 'cp720', 'title' => 'cp720 (Arabic)'],
['id' => 'cp737', 'title' => 'cp737 (Greek)'],
['id' => 'cp775', 'title' => 'cp775 (Baltic languages)'],
['id' => 'cp850', 'title' => 'cp850 (Western Europe)'],
['id' => 'cp852', 'title' => 'cp852 (Central and Eastern Europe)'],
['id' => 'cp855', 'title' => 'cp855 (Bulgarian, Byelorussian, Macedonian, Russian, Serbian)'],
['id' => 'cp856', 'title' => 'cp856 (Hebrew)'],
['id' => 'cp857', 'title' => 'cp857 (Turkish)'],
['id' => 'cp858', 'title' => 'cp858 (Western Europe)'],
['id' => 'cp860', 'title' => 'cp860 (Portuguese)'],
['id' => 'cp861', 'title' => 'cp861 (Icelandic)'],
['id' => 'cp862', 'title' => 'cp862 (Hebrew)'],
['id' => 'cp863', 'title' => 'cp863 (Canadian)'],
['id' => 'cp864', 'title' => 'cp864 (Arabic)'],
['id' => 'cp865', 'title' => 'cp865 (Danish, Norwegian)'],
['id' => 'cp866', 'title' => 'cp866 (Russian)'],
['id' => 'cp869', 'title' => 'cp869 (Greek)'],
['id' => 'cp874', 'title' => 'cp874 (Thai)'],
['id' => 'cp875', 'title' => 'cp875 (Greek)'],
['id' => 'cp932', 'title' => 'cp932 (Japanese)'],
['id' => 'cp949', 'title' => 'cp949 (Korean)'],
['id' => 'cp950', 'title' => 'cp950 (Traditional Chinese)'],
['id' => 'cp1006', 'title' => 'cp1006 (Urdu)'],
['id' => 'cp1026', 'title' => 'cp1026 (Turkish)'],
['id' => 'cp1140', 'title' => 'cp1140 (Western Europe)'],
['id' => 'cp1250', 'title' => 'cp1250 (Central and Eastern Europe)'],
['id' => 'cp1251', 'title' => 'cp1251 (Bulgarian, Byelorussian, Macedonian, Russian, Serbian)'],
['id' => 'cp1252', 'title' => 'cp1252 (Western Europe)'],
['id' => 'cp1253', 'title' => 'cp1253 (Greek)'],
['id' => 'cp1254', 'title' => 'cp1254 (Turkish)'],
['id' => 'cp1255', 'title' => 'cp1255 (Hebrew)'],
['id' => 'cp1256', 'title' => 'cp1256 (Arabic)'],
['id' => 'cp1257', 'title' => 'cp1257 (Baltic languages)'],
['id' => 'cp1258', 'title' => 'cp1258 (Vietnamese)'],
['id' => 'euc_jp', 'title' => 'euc_jp (Japanese)'],
['id' => 'euc_jis_2004', 'title' => 'euc_jis_2004 (Japanese)'],
['id' => 'euc_jisx0213', 'title' => 'euc_jisx0213 (Japanese)'],
['id' => 'euc_kr', 'title' => 'euc_kr (Korean)'],
['id' => 'gb2312', 'title' => 'gb2312 (Simplified Chinese)'],
['id' => 'gbk', 'title' => 'gbk (Unified Chinese)'],
['id' => 'gb18030', 'title' => 'gb18030 (Unified Chinese)'],
['id' => 'hz', 'title' => 'hz (Simplified Chinese)'],
['id' => 'iso2022_jp', 'title' => 'iso2022_jp (Japanese)'],
['id' => 'iso2022_jp_1', 'title' => 'iso2022_jp_1 (Japanese)'],
['id' => 'iso2022_jp_2', 'title' => 'iso2022_jp_2 (Japanese, Korean, Simplified Chinese, Western Europe, Greek)'],
['id' => 'iso2022_jp_2004', 'title' => 'iso2022_jp_2004 (Japanese)'],
['id' => 'iso2022_jp_3', 'title' => 'iso2022_jp_3 (Japanese)'],
['id' => 'iso2022_jp_ext', 'title' => 'iso2022_jp_ext (Japanese)'],
['id' => 'iso2022_kr', 'title' => 'iso2022_kr (Korean)'],
['id' => 'latin_1', 'title' => 'latin_1 (West Europe)'],
['id' => 'iso8859_2', 'title' => 'iso8859_2 (Central and Eastern Europe)'],
['id' => 'iso8859_3', 'title' => 'iso8859_3 (Esperanto, Maltese)'],
['id' => 'iso8859_4', 'title' => 'iso8859_4 (Baltic languages)'],
['id' => 'iso8859_5', 'title' => 'iso8859_5 (Bulgarian, Byelorussian, Macedonian, Russian, Serbian)'],
['id' => 'iso8859_6', 'title' => 'iso8859_6 (Arabic)'],
['id' => 'iso8859_7', 'title' => 'iso8859_7 (Greek)'],
['id' => 'iso8859_8', 'title' => 'iso8859_8 (Hebrew)'],
['id' => 'iso8859_9', 'title' => 'iso8859_9 (Turkish)'],
['id' => 'iso8859_10', 'title' => 'iso8859_10 (Nordic languages)'],
['id' => 'iso8859_11', 'title' => 'iso8859_11 (Thai languages)'],
['id' => 'iso8859_13', 'title' => 'iso8859_13 (Baltic languages)'],
['id' => 'iso8859_14', 'title' => 'iso8859_14 (Celtic languages)'],
['id' => 'iso8859_15', 'title' => 'iso8859_15 (Western Europe)'],
['id' => 'iso8859_16', 'title' => 'iso8859_16 (South-Eastern Europe)'],
['id' => 'johab', 'title' => 'johab (Korean)'],
['id' => 'koi8_r', 'title' => 'koi8_r (Russian)'],
['id' => 'koi8_u', 'title' => 'koi8_u (Ukrainian)'],
['id' => 'mac_cyrillic', 'title' => 'mac_cyrillic (Bulgarian, Byelorussian, Macedonian, Russian, Serbian)'],
['id' => 'mac_greek', 'title' => 'mac_greek (Greek)'],
['id' => 'mac_iceland', 'title' => 'mac_iceland (Icelandic)'],
['id' => 'mac_latin2', 'title' => 'mac_latin2 (Central and Eastern Europe)'],
['id' => 'mac_roman', 'title' => 'mac_roman (Western Europe)'],
['id' => 'mac_turkish', 'title' => 'mac_turkish (Turkish)'],
['id' => 'ptcp154', 'title' => 'ptcp154 (Kazakh)'],
['id' => 'shift_jis', 'title' => 'shift_jis (Japanese)'],
['id' => 'shift_jis_2004', 'title' => 'shift_jis_2004 (Japanese)'],
['id' => 'shift_jisx0213', 'title' => 'shift_jisx0213 (Japanese)'],
['id' => 'utf_32', 'title' => 'UTF-32'],
['id' => 'utf_32_be', 'title' => 'UTF-32BE'],
['id' => 'utf_32_le', 'title' => 'UTF-32LE'],
['id' => 'utf_16', 'title' => 'UTF-16'],
['id' => 'utf_16be', 'title' => 'UTF-16BE'],
['id' => 'utf_16le', 'title' => 'UTF-16LE'],
['id' => 'utf_7', 'title' => 'UTF-7'],
];
}
public static function getDefaultCodepage()
{
return self::$utf8Encoding;
}
}

View File

@@ -1,52 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation;
class Application
{
/** @var string */
private $_type;
/** @var string */
private $_sourcePath;
/** @var string */
private $_targetPath;
/**
* Application constructor.
*
* @param $type string
* @param $sourcePath string
* @param $targetPath string
*/
public function __construct($type, $sourcePath, $targetPath)
{
$this->_type = $type;
$this->_sourcePath = $sourcePath;
$this->_targetPath = $targetPath;
}
/**
* @return string
*/
public function getType()
{
return $this->_type;
}
/**
* @return string
*/
public function getSourcePath()
{
return $this->_sourcePath;
}
/**
* @return string
*/
public function getTargetPath()
{
return $this->_targetPath;
}
}

View File

@@ -1,76 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation;
class Database
{
/** @var string */
private $_name;
/** @var string */
private $_host;
/** @var string */
private $_port;
/** @var string */
private $_username;
/** @var string */
private $_password;
/**
* Database constructor.
*
* @param $name string
* @param $host string
* @param $port string
* @param $username string
* @param $password string
*/
public function __construct($name, $host, $port, $username, $password)
{
$this->_name = $name;
$this->_host = $host;
$this->_port = $port;
$this->_username = $username;
$this->_password = $password;
}
/**
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* @return string
*/
public function getHost()
{
return $this->_host;
}
/**
* @return string
*/
public function getPort()
{
return $this->_port;
}
/**
* @return string
*/
public function getUsername()
{
return $this->_username;
}
/**
* @return string
*/
public function getPassword()
{
return $this->_password;
}
}

View File

@@ -1,40 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation;
class Folder
{
/** @var string */
private $_sourcePath;
/** @var string */
private $_targetPath;
/**
* Folder constructor.
*
* @param $sourcePath string
* @param $targetPath string
*/
public function __construct($sourcePath, $targetPath)
{
$this->_sourcePath = $sourcePath;
$this->_targetPath = $targetPath;
}
/**
* @return string
*/
public function getSourcePath()
{
return $this->_sourcePath;
}
/**
* @return string
*/
public function getTargetPath()
{
return $this->_targetPath;
}
}

View File

@@ -1,52 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo;
class Application
{
/** @var string */
private $_type;
/** @var string */
private $_sourcePath;
/** @var string */
private $_targetPath;
/**
* Application constructor.
*
* @param $type string
* @param $sourcePath string
* @param $targetPath string
*/
public function __construct($type, $sourcePath, $targetPath)
{
$this->_type = $type;
$this->_sourcePath = $sourcePath;
$this->_targetPath = $targetPath;
}
/**
* @return string see \Plesk\MigrationLibV8\SiteImport\Entity\ApplicationTypes constants
*/
public function getType()
{
return $this->_type;
}
/**
* @return string
*/
public function getSourcePath()
{
return $this->_sourcePath;
}
/**
* @return string
*/
public function getTargetPath()
{
return $this->_targetPath;
}
}

View File

@@ -1,30 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo;
class File
{
/**
* @var string
*/
private $_name;
/**
* File constructor.
*
* @param $name string
*/
public function __construct($name)
{
$this->_name = $name;
}
/**
* @return string
*/
public function getName()
{
return $this->_name;
}
}

View File

@@ -1,52 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo;
class Folder
{
/** @var string */
private $_name;
/** @var \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\File[] */
private $_files;
/** @var \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Folder[] */
private $_folders;
/**
* Folder constructor.
*
* @param $name string
* @param $files \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\File[]
* @param $folders \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Folder[]
*/
public function __construct($name, $files, $folders)
{
$this->_name = $name;
$this->_files = $files;
$this->_folders = $folders;
}
/**
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\File[]
*/
public function getFiles()
{
return $this->_files;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Folder[]
*/
public function getFolders()
{
return $this->_folders;
}
}

View File

@@ -1,76 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo;
class SiteInfo
{
/** @var \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Application[] */
private $_applications;
/** @var \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Folder */
private $_rootFolder;
/** @var string */
private $_rootPath;
/** @var string */
private $_documentRoot;
/** @var string */
private $_siteName;
/**
* SiteInfo constructor.
*
* @param $applications \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Application[]
* @param $rootFolder \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Folder
* @param $rootPath string
* @param $documentRoot string
* @param $siteName string
*/
public function __construct($applications, $rootFolder, $rootPath, $documentRoot, $siteName)
{
$this->_applications = $applications;
$this->_rootFolder = $rootFolder;
$this->_rootPath = $rootPath;
$this->_documentRoot = $documentRoot;
$this->_siteName = $siteName;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Application[]
*/
public function getApplications()
{
return $this->_applications;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Folder
*/
public function getRootFolder()
{
return $this->_rootFolder;
}
/**
* @return string
*/
public function getRootPath()
{
return $this->_rootPath;
}
/**
* @return string
*/
public function getDocumentRoot()
{
return $this->_documentRoot;
}
/**
* @return string
*/
public function getSiteName()
{
return $this->_siteName;
}
}

View File

@@ -1,242 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity;
class SourceServerAccess
{
/** @var string */
private $_host;
/** @var string */
private $_username;
/** @var string */
private $_password;
/** @var string|null */
private $_siteUrl;
/** @var string|null */
private $_siteDocumentRoot;
/** @var string|null */
private $_ftpEncoding;
/** @var bool */
private $_fileTransport;
/** @var string|null */
private $_transferFilesMode;
/** @var bool|null */
private $_allowAutoWebStreaming;
/** @var string|null */
private $_filesRoot;
/** @var string|null */
private $_sshPort;
/** @var bool|null */
private $_ignorePassiveModeServerIp;
/** @var string|null */
private $_listFilesMode;
/**
* SourceServerAccess constructor.
*
* @param $host string domain name of source server (must be resolvable to the source server)
* @param $username string FTP/SSH username
* @param $password string FTP/SSH password
* @param $siteUrl string|null full URL of the site (use when FTP root or SSH home is in a
* folder inside document root), e.g. http://example.com/blog/ is a FTP root ("/");
* in most cases don't specify that parameter
* @param $siteDocumentRoot string|null document root of the site relative to FTP root (SSH home); in most cases,
* automatic detection of document root works well, but when it does not (e.g. when there are rewrite rules)
* then you could specify document root manually.
* @param $ftpEncoding string|null encoding in which FTP server returns directory listings
* @param $fileTransport string|null File transport used for deployment of Web RPC agent
* and file operations on remote server (like upload file, create directory, etc).
* See constants from \Plesk\MigrationLibV8\SiteImport\Entity\FileTransports.
* @param $transferFilesMode string|null Way to transfer application files and folders from the source server.
* See constants from \Plesk\MigrationLibV8\SiteImport\Entity\TransferFileModes.
* @param $allowAutoWebStreaming bool|null Whether transfer of files with web streaming should
* be automatically selected when it makes sense. Web streaming makes sense in case
* when 'transfer-files-mode' is 'auto' and actual file transport is FTP. Web streaming is a beta feature,
* and so it is not selected by default.
* @param $filesRoot string|null Path to start scan for files, applications and document root,
* related to FTP/SSH root. When not specified, default is used: when transport is FTP,
* then FTP root is used, when transport is SSH, then home directory of SSH user is used.
* @param $sshPort string|null port to connect to the source website by SSH
* @param $ignorePassiveModeServerIp bool|null Whether to ignore IP address returned by FTP server
* when opening data channel in passive mode.
* When is set to true, IP address returned by FTP server when opening data channel
* in passive mode is ignored. That option could be necessary because some misconfigured
* FTP servers return internal IPs, which could not be used to connect to the server.
* When the option is set, hostname specified for control connection to the FTP server
* will be used for data connections.
* @param $listFilesMode string|null Way to list files on the source server
* Possible ways: with file transport (FTP or SSH - see "file-transport" option), with Web RPC agent,
* with Web RPC agent with fallback to file transport.
* General considerations:
* - Listing with Web RPC agent works much more fast than listing with FTP, but it could be less reliable.
* - When FTP is used as file transport, listing with Web RPC agent with FTP fallback in
* case of unicode names and or any failure of RPC agent takes advantages of both ways:
* usually it works fast, but in case of any failure it works like FTP listing, so it is reliable.
* By default, migrator automatically selects the way which is optimal for most cases.
* Possible values: 'auto', 'file-transport', 'web-rpc-agent', 'hybrid'
*/
public function __construct(
$host, $username, $password, $siteUrl=null, $siteDocumentRoot=null, $ftpEncoding=null,
$fileTransport=null, $transferFilesMode=null, $allowAutoWebStreaming=null,
$filesRoot=null, $sshPort=null, $ignorePassiveModeServerIp=null, $listFilesMode=null
) {
$this->_host = $host;
$this->_username = $username;
$this->_password = $password;
$this->_siteUrl = $siteUrl;
$this->_siteDocumentRoot = $siteDocumentRoot;
$this->_ftpEncoding = $ftpEncoding;
$this->_fileTransport = $fileTransport;
$this->_transferFilesMode = $transferFilesMode;
$this->_allowAutoWebStreaming = $allowAutoWebStreaming;
$this->_filesRoot = $filesRoot;
$this->_sshPort = $sshPort;
$this->_ignorePassiveModeServerIp = $ignorePassiveModeServerIp;
$this->_listFilesMode = $listFilesMode;
}
/**
* Get domain name of source server (must be resolvable to the source server).
*
* @return string
*/
public function getHost()
{
return $this->_host;
}
/**
* Get FTP/SSH username.
*
* @return string
*/
public function getUsername()
{
return $this->_username;
}
/**
* Get FTP/SSH password.
*
* @return string
*/
public function getPassword()
{
return $this->_password;
}
/**
* Get full URL of the site, if it was specified.
*
* @return string|null
*/
public function getSiteUrl()
{
return $this->_siteUrl;
}
/**
* Get site document root, if it was specified.
*
* @return string|null
*/
public function getSiteDocumentRoot()
{
return $this->_siteDocumentRoot;
}
/**
* Get encoding in which FTP server returns directory listings.
*
* @return null|string
*/
public function getFtpEncoding()
{
return $this->_ftpEncoding;
}
/**
* @return null|string
*/
public function getFileTransport()
{
return $this->_fileTransport;
}
/**
* @return null|string
*/
public function getTransferFilesMode()
{
return $this->_transferFilesMode;
}
/**
* @return bool|null
*/
public function getAllowAutoWebStreaming()
{
return $this->_allowAutoWebStreaming;
}
/**
* Get path to start scan for files, applications and document root, related to FTP/SSH root.
* When not specified, default is used: when transport is FTP,
* then FTP root is used, when transport is SSH, then home directory of SSH user is used.
*
* @return string|null
*/
public function getFilesRoot()
{
return $this->_filesRoot;
}
/**
* Get port to connect to the source website by SSH.
*
* @return string|null
*/
public function getSSHPort()
{
return $this->_sshPort;
}
/**
* Whether to ignore IP address returned by FTP server when opening data channel in passive mode.
*
* When is set to true, IP address returned by FTP server when opening data channel
* in passive mode is ignored. That option could be necessary because some misconfigured
* FTP servers return internal IPs, which could not be used to connect to the server.
* When the option is set, hostname specified for control connection to the FTP server
* will be used for data connections.
*
* @return bool|null
*/
public function getIgnorePassiveModeServerIp()
{
return $this->_ignorePassiveModeServerIp;
}
/**
* Way to list files on the source server
*
* Possible ways: with file transport (FTP or SSH - see "file-transport" option), with Web RPC agent,
* with Web RPC agent with fallback to file transport.
*
* General considerations:
* - Listing with Web RPC agent works much more fast than listing with FTP, but it could be less reliable.
* - When FTP is used as file transport, listing with Web RPC agent with FTP fallback in
* case of unicode names and or any failure of RPC agent takes advantages of both ways:
* usually it works fast, but in case of any failure it works like FTP listing, so it is reliable.
* By default, migrator automatically selects the way which is optimal for most cases.
*
* Possible values: 'auto', 'file-transport', 'web-rpc-agent', 'hybrid'
*
* @return string|null
*/
public function getListFilesMode()
{
return $this->_listFilesMode;
}
}

View File

@@ -1,91 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\Status;
/**
* Whole import status of a session - all applications, folders and databases ever migrated within the session.
*
* @package Plesk\MigrationLibV8\SiteImport\Entity\Status
*/
class Import
{
/**
* @var \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Application[]
*/
private $_applicationsStatus;
/**
* @var \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Folder[]
*/
private $_foldersStatus;
/**
* @var \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Database[]
*/
private $_databasesStatus;
/**
* Import constructor.
*
* @param $applicationsStatus \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Application[]
* @param $foldersStatus \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Folder[]
* @param $databasesStatus \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Database[]
*/
public function __construct($applicationsStatus, $foldersStatus, $databasesStatus) {
$this->_applicationsStatus = $applicationsStatus;
$this->_foldersStatus = $foldersStatus;
$this->_databasesStatus = $databasesStatus;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Application[]
*/
public function getApplicationsStatus()
{
return $this->_applicationsStatus;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Folder[]
*/
public function getFoldersStatus()
{
return $this->_foldersStatus;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Database[]
*/
public function getDatabasesStatus()
{
return $this->_databasesStatus;
}
/**
* Get whole import status as array (useful for integration with JavaScript code).
*
* @return array
*/
public function asArray()
{
$applicationsStatus = [];
foreach ($this->getApplicationsStatus() as $applicationStatus) {
$applicationsStatus[] = $applicationStatus->asArray();
}
$foldersStatus = [];
foreach ($this->getFoldersStatus() as $folderStatus) {
$foldersStatus[] = $folderStatus->asArray();
}
$databasesStatus = [];
foreach ($this->getDatabasesStatus() as $databaseStatus) {
$databasesStatus[] = $databaseStatus->asArray();
}
return [
'applications' => $applicationsStatus,
'folders' => $foldersStatus,
'databases' => $databasesStatus
];
}
}

View File

@@ -1,157 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\Status\Import;
use Plesk\MigrationLibV8\SiteImport\Entity\CheckStatuses;
class Application
{
/** @var string */
private $_type;
/** @var string */
private $_sourcePath;
/** @var string */
private $_targetPath;
/** @var \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[] */
private $_issues;
/** @var string */
private $_status;
/** @var \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[] */
private $_checkIssues;
/** @var string */
private $_checkStatus;
/**
* Application constructor.
*
* @param string $type
* @param string $sourcePath
* @param string $targetPath
* @param \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[] $issues
* @param string $status
* @param \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[] $checkIssues
* @param string $checkStatus
*/
public function __construct($type, $sourcePath, $targetPath, $issues, $status, $checkIssues, $checkStatus)
{
$this->_type = $type;
$this->_sourcePath = $sourcePath;
$this->_targetPath = $targetPath;
$this->_issues = $issues;
$this->_status = $status;
$this->_checkIssues = $checkIssues;
$this->_checkStatus = $checkStatus;
}
/**
* Get application type (e.g. "WordPress", see see \Plesk\MigrationLibV8\SiteImport\Entity\ApplicationTypes constants).
*
* @return string see \Plesk\MigrationLibV8\SiteImport\Entity\ApplicationTypes constants
*/
public function getType()
{
return $this->_type;
}
/**
* Get location of the application on the source server.
* Example: "/var/www/vhosts/source.example.com/httpdocs/wordpress".
*
* @return string
*/
public function getSourcePath()
{
return $this->_sourcePath;
}
/**
* Get location of the application on the target server.
* Example: "/var/www/vhosts/target.example.com/httpdocs/wordpress".
*
* @return string
*/
public function getTargetPath()
{
return $this->_targetPath;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[]
*/
public function getIssues()
{
return $this->_issues;
}
/**
* Get import status of the application, as string (e.g. "success")
*
* @return string string see constants from \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Statuses
*/
public function getStatus()
{
return $this->_status;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[]
*/
public function getCheckIssues()
{
return $this->_checkIssues;
}
/**
* Get check status of the application, as string (e.g. "success")
*
* @return string string see constants from \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Statuses
*/
public function getCheckStatus()
{
if ($this->_checkStatus == null) {
$importFinishedStatues = array(
CheckStatuses::SUCCESS, CheckStatuses::WARNING, CheckStatuses::FAILURE
);
if (in_array($this->_status, $importFinishedStatues)) {
return CheckStatuses::READY_TO_CHECK;
}
return CheckStatuses::NOT_IMPORTED;
}
return $this->_checkStatus;
}
/**
* Return status information for imported application as array (useful for integration with JavaScript code).
*
* Array has the following keys:
* 'type' - application type (e.g. "WordPress")
* 'source_path' - location of the application on the source server
* (e.g. "/var/www/vhosts/source.example.com/httpdocs/wordpress")
* 'target_path - location of the application on the target server
* (e.g. "/var/www/vhosts/target.example.com/httpdocs/wordpress")
* 'status' - import status of the application, as string (e.g. "success")
* @return array
*/
public function asArray()
{
$issues = [];
foreach ($this->getIssues() as $issue) {
$issues[] = $issue->asArray();
}
$check_issues = [];
foreach ($this->getCheckIssues() as $check_issue) {
$check_issues[] = $check_issue->asArray();
}
return [
'type' => $this->getType(),
'source_path' => $this->getSourcePath(),
'target_path' => $this->getTargetPath(),
'issues' => $issues,
'status' => $this->getStatus(),
'check_issues' => $check_issues,
'check_status' => $this->getCheckStatus()
];
}
}

View File

@@ -1,123 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\Status\Import;
class Database
{
/** @var string */
private $_name;
/** @var string */
private $_host;
/** @var string */
private $_port;
/** @var string */
private $_username;
/** @var string */
private $_password;
/** @var \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[] */
private $_issues;
/** @var string */
private $_status;
/**
* Database constructor.
*
* @param $name string
* @param $host string
* @param $port string
* @param $username string
* @param $password string
* @param $issues \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[]
* @param $status string
*/
public function __construct($name, $host, $port, $username, $password, $issues, $status)
{
$this->_name = $name;
$this->_host = $host;
$this->_port = $port;
$this->_username = $username;
$this->_password = $password;
$this->_issues = $issues;
$this->_status = $status;
}
/**
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* @return string
*/
public function getHost()
{
return $this->_host;
}
/**
* @return string
*/
public function getPort()
{
return $this->_port;
}
/**
* @return string
*/
public function getUsername()
{
return $this->_username;
}
/**
* @return string
*/
public function getPassword()
{
return $this->_password;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[]
*/
public function getIssues()
{
return $this->_issues;
}
/**
* @return string string see constants from \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Statuses
*/
public function getStatus()
{
return $this->_status;
}
/**
* Return status information for imported database as array (useful for integration with JavaScript code).
*
* @return array
*/
public function asArray()
{
$issues = [];
foreach ($this->getIssues() as $issue) {
$issues[] = $issue->asArray();
}
return [
'name' => $this->getName(),
'host' => $this->getHost(),
'port' => $this->getPort(),
'username' => $this->getUsername(),
'password' => $this->getPassword(),
'issues' => $issues,
'status' => $this->getStatus()
];
}
}

View File

@@ -1,84 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\Status\Import;
class Folder
{
/** @var string */
private $_sourcePath;
/** @var string */
private $_targetPath;
/** @var \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[] */
private $_issues;
/** @var string */
private $_status;
/**
* Folder constructor.
*
* @param $sourcePath string
* @param $targetPath string
* @param $issues \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[]
* @param $status string
*/
public function __construct($sourcePath, $targetPath, $issues, $status)
{
$this->_sourcePath = $sourcePath;
$this->_targetPath = $targetPath;
$this->_issues = $issues;
$this->_status = $status;
}
/**
* @return string
*/
public function getSourcePath()
{
return $this->_sourcePath;
}
/**
* @return string
*/
public function getTargetPath()
{
return $this->_targetPath;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue[]
*/
public function getIssues()
{
return $this->_issues;
}
/**
* @return string string see constants from \Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Statuses
*/
public function getStatus()
{
return $this->_status;
}
/**
* Return status information for imported database as array (useful for integration with JavaScript code).
*
* @return array
*/
public function asArray()
{
$issues = [];
foreach ($this->getIssues() as $issue) {
$issues[] = $issue->asArray();
}
return [
'source_path' => $this->getSourcePath(),
'target_path' => $this->getTargetPath(),
'issues' => $issues,
'status' => $this->getStatus()
];
}
}

View File

@@ -1,93 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\Status;
class Issue
{
const SEVERITY_ERROR = 'error';
const SEVERITY_WARNING = 'warning';
const SEVERITY_INFO = 'info';
/** @var string */
private $_severity;
/** @var float */
private $_executionDate;
/** @var string */
private $_problemText;
/** @var string */
private $_detailsText;
/**
* Issue constructor.
*
* @param string $severity issue severity - see SEVERITY_* constants
* @param float $executionDate execution date as timestamp.
* @param string $problemText problem text - useful for end user of site import.
* @param string $detailsText|null problem details - which could be useful for admin
* (e.g. executed CLI commands with their stdout/stderr).
*/
public function __construct($severity, $executionDate, $problemText, $detailsText)
{
$this->_severity = $severity;
$this->_executionDate = $executionDate;
$this->_problemText = $problemText;
$this->_detailsText = $detailsText;
}
/**
* Get issue severity - see SEVERITY_* constants.
*
* @return string
*/
public function getSeverity()
{
return $this->_severity;
}
/**
* Get execution date as timestamp.
*
* @return float
*/
public function getExecutionDate()
{
return $this->_executionDate;
}
/**
* Get problem text - useful for end user of site import.
*
* @return string
*/
public function getProblemText()
{
return $this->_problemText;
}
/**
* Get problem details - which could be useful for admin (e.g. executed CLI commands with their stdout/stderr),
* stack traces, etc.
*
* @return string
*/
public function getDetailsText()
{
return $this->_detailsText;
}
/**
* Get issue information as array (useful for integration with JavaScript code).
*
* @return array
*/
public function asArray()
{
return [
'severity' => $this->getSeverity(),
'execution_date' => $this->getExecutionDate(),
'problem_text' => $this->getProblemText(),
'details_text' => $this->getDetailsText()
];
}
}

View File

@@ -1,105 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity\Status;
class RetrieveSiteInfo
{
const OPERATION_CONNECT = 'connect';
const OPERATION_SCAN_CONTENT = 'scan-content';
const STATUS_NOT_STARTED = 'not-started';
const STATUS_SUCCESS = 'success';
const STATUS_FAILURE = 'failure';
/** @var \string[] */
private $_statuses;
/** @var string|null */
private $_errorMessage;
/** @var string|null */
private $_issueId;
/**
* RetrieveSiteInfo constructor.
*
* @param $statuses string[]
* @param $errorMessage string|null
* @param $issueId string|null
*/
public function __construct($statuses, $errorMessage, $issueId)
{
$this->_statuses = $statuses;
$this->_errorMessage = $errorMessage;
$this->_issueId = $issueId;
}
/**
* Get operation status - see STATUS_* constants.
*
* @param $operation string operation ID - see OPERATION_* constants
* @return string see STATUS_* constants
*/
public function getOperationStatus($operation)
{
return $this->_statuses[$operation];
}
/**
* Whether specified operation was finished.
*
* @param $operation string operation ID - see OPERATION_* constants
* @return bool
*/
public function isOperationFinished($operation)
{
return $this->getOperationStatus($operation) != self::STATUS_NOT_STARTED;
}
/**
* Whether specified operation was successful.
*
* @param $operation string operation ID - see OPERATION_* constants
* @return bool
*/
public function isOperationSuccessful($operation)
{
return $this->getOperationStatus($operation) == self::STATUS_SUCCESS;
}
/**
* Get error message string if any of operations failed.
*
* @return string|null
*/
public function getErrorMessage()
{
return $this->_errorMessage;
}
/**
* Get backend issue ID if any of operations failed.
*
* @return string|null
*/
public function getIssueId()
{
return $this->_issueId;
}
/**
* Get retrieve site info status as array (useful for integration with JavaScript code).
*
* @return array
*/
public function asArray()
{
return [
'operations' => [
self::OPERATION_CONNECT => $this->getOperationStatus(self::OPERATION_CONNECT),
self::OPERATION_SCAN_CONTENT => $this->getOperationStatus(self::OPERATION_SCAN_CONTENT)
],
'errorMessage' => $this->getErrorMessage(),
'issueId' => $this->getIssueId()
];
}
}

View File

@@ -1,15 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity;
class Statuses
{
const READY_TO_IMPORT = 'ready-to-import';
const IN_PROGRESS = 'in-progress';
const SUCCESS = 'success';
const WARNING = 'warning';
const FAILURE = 'failure';
const QUEUED = 'queued';
const CANCELLED = 'cancelled';
}

View File

@@ -1,13 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport\Entity;
class TransferFileModes
{
const AUTO = 'auto';
const FTP = 'ftp';
const SSH_RSYNC = 'ssh-rsync';
const SSH_SCP = 'ssh-scp';
const WEB_STREAMING = 'web-streaming';
}

View File

@@ -1,752 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport;
use Plesk\MigrationLibV8\Common\SessionDirectory;
use Plesk\MigrationLibV8\SiteImport\Backend\Files\MigrationList;
use Plesk\MigrationLibV8\SiteImport\Backend\Tool;
use Plesk\MigrationLibV8\SiteImport\Entity\FileTransports;
use Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\Application;
use Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\File;
use Plesk\MigrationLibV8\SiteImport\Entity\SiteInfo\SiteInfo;
use Plesk\MigrationLibV8\SiteImport\Entity\SourceServerAccess;
use Plesk\MigrationLibV8\SiteImport\Entity\Status\Import;
use Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Database;
use Plesk\MigrationLibV8\SiteImport\Entity\Status\Import\Folder;
use Plesk\MigrationLibV8\SiteImport\Entity\Status\Issue;
use Plesk\MigrationLibV8\SiteImport\Entity\Status\RetrieveSiteInfo;
use Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation;
use Plesk\MigrationLibV8\Utils\ArrayUtils;
use Plesk\MigrationLibV8\Utils\FileUtils;
/**
* A wrapper around backend of Plesk Migrator to perform site import.
* Site import allows you to import applications, folders and databases from source site using FTP/SSH.
*
* The key object of site import is a session directory - a directory which stores state of import
* and temporary files necessary for import.
* Before running any site import operation, you must obtain a session directory object.
*
* To perform an application/folder/database import, the following workflow is suggested:
*
* 1. Obtain a domain object for the target site, to which you want to import applications, folders and databases.
* For example, ask customer to select domain from a list of available domains,
* or use domain from the current context. The domain must have physical hosting enabled. Import to domain
* without hosting or with forwarding type of hosting is not supported.
*
* $domain = new \pm_Domain(123);
*
* 2. Obtain a session object. A session is a directory which contains configuration files,
* logs, reports and other temporary data for Plesk Migrator's backend. Each session has an unique string ID.
* It is recommended to use domain ID as a part of session ID.
*
* $session = \Plesk\MigrationLibV8\Common\SessionDirectory::getForCurrentExtension('site-migration-' . $domain->getId());
*
* 3. Obtain credentials to access the source server (source domain name, FTP/SSH login, FTP/SSH password, and so on).
* For example, ask customer to provide this information. Create an object:
*
* $sourceServerParameters = new \Plesk\MigrationLibV8\SiteImport\Entity\SourceServerAccess('example.com', 'john', '123qwe');
*
* 4. Create site import manager:
*
* $manager = new \Plesk\MigrationLibV8\SiteImport\Manager();
*
* 5. Request Plesk Migrator to get information about the source site:
*
* $manager->retrieveSiteInfo($session, $domain, $sourceServerParameters);
*
* The function is executed in synchronous way. Sometimes it could be useful to split configuration
* and retrieve site info into 2 separate operations - "configure", which is fast,
* and "run" which could take a lot of time:
*
* $manager->configureRetrieveSiteInfo($session, $domain, $sourceServerParameters);
* $manager->runRetrieveSiteInfo($session, $domain, $sourceServerParameters);
*
* It is reasonable to execute "retrieveSiteInfo"/"runRetrieveSiteInfo" withing a long task.
*
* 6. Poll information about retrieve site info progress from another process/thread:
*
* $retrieveStatus = $manager->getRetrieveSiteInfoStatus($session);
*
* Retrieve site information has 2 separate operations: connect to the source site and scan content.
* You could get their status separately. To get status:
*
* $connectStatus = $retrieveStatus->getOperationStatus(
* \Plesk\MigrationLibV8\SiteImport\Entity\Status\RetrieveSiteInfo::OPERATION_CONNECT
* );
* $retrieveStatus->getOperationStatus(
* \Plesk\MigrationLibV8\SiteImport\Entity\Status\RetrieveSiteInfo::OPERATION_SCAN_CONTENT
* );
*
* Compare status with constants:
* - \Plesk\MigrationLibV8\SiteImport\Entity\Status\RetrieveSiteInfo::STATUS_NOT_STARTED
* - \Plesk\MigrationLibV8\SiteImport\Entity\Status\RetrieveSiteInfo::STATUS_SUCCESS
* - \Plesk\MigrationLibV8\SiteImport\Entity\Status\RetrieveSiteInfo::STATUS_FAILURE
*
* Also there are auxiliary methods "isOperationFinished" and "isOperationSuccessful".
*
* In case when any of operations has failed, you could get error message, which could be displayed to customer:
*
* $errorMessage = $retrieveStatus->getErrorMessage();
*
* 7. Once Plesk Migrator finished retrieving information about the source site, you could get it with:
*
* $siteInfo = $manager->getSiteInfo($session);
*
* You could read list of detected applications:
*
* $applications = $siteInfo->getApplications();
*
* Also, you could iterate over tree of files on the source server:
*
* $rootFolder = $siteInfo->getRootFolder();
* $rootFiles = $rootFolder->getFiles();
*
* 8. According to the information about the source site, select applications/folders/databases and schedule import.
*
* To schedule import of an application:
*
* $application = new \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application(
* \Plesk\MigrationLibV8\SiteImport\Entity\ApplicationTypes::WORDPRESS, '/source/path', '/target/path'
* );
* $manager->scheduleApplicationImport($session, $application);
*
* To schedule import of a folder:
*
* $folder = new \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Folder('/source/path', '/target/path');
* $manager->scheduleFolderImport($session, $folder);
*
* To schedule import of a database:
*
* $database = new \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Database(
* 'databaseName', 'localhost', '3306', 'login', '123qwe'
* );
* $manager->scheduleDatabaseImport($session, $database);
*
* Scheduling import is fast operation (in most cases should take less than 1 second).
*
* 9. Once you've scheduled import, start task runner which processes schedules import tasks:
*
* $manager->startTasksRunner($session);
*
* Task runner works in synchronous way on Windows and in asynchronous way on Linux. That is quite weird,
* the difference is caused by difficulties implementing asynchronous command execution on Windows.
*
* To improve stability, it is useful to start task runner periodically, for example once a minute.
* If another task runner is already running, the new one will exit immediately. In that case
* if server was rebooted, or task runner has stopped for any reason, import will continue to work.
*
* 10. Once task runner is started, poll import status of imported/schedules applications/folders/databases:
*
* $importStatus = $manager->getImportStatus($session);
*
* $applicationsStatus = $importStatus->getApplicationsStatus();
* $foldersStatus = $importStatus->getFoldersStatus();
* $databasesStatus = $importStatus->getDatabasesStatus();
*
* To get status and issues of applications, you could use the following code snippet:
*
* foreach ($applicationsStatus as $applicationStatus) {
* $type = $applicationStatus->getType();
* $sourcePath = $applicationStatus->getSourcePath();
* $targetPath = $applicationStatus->getTargetPath();
* $status = $applicationStatus->getStatus();
* $issues = $applicationStatus->getIssues();
*
* foreach ($issue as $issue) {
* $severity = $issue->getSeverity();
* $problemText = $issue->getProblemText();
* $detailsText = $issue->getDetailsText();
* }
* }
*
* 11. Additionally, you have the following abilities:
*
* - Cancel migration of scheduled/importing applications/folders/databases with
* "cancelApplicationImport", "cancelFolderImport", "cancelDatabaseImport" and "cancelImport" methods.
* - Check whether session is configured: "isSessionConfigured" method.
* - Check whether site information was retrieved: "isSiteInfoRetrieved" method.
*/
class Manager
{
/**
* Commands which can be put in migration list for task runner.
*/
const IMPORT_COMMAND = 'import';
const CHECK_APPLICATIONS_COMMAND = 'check';
const CANCEL_COMMAND = 'cancel';
/**
* Request Plesk Migrator to get information about source site: list files and detect applications.
*
* Method is executed in synchronous way: the function will return control only once Plesk Migrator
* retrieved all information from the source site or failed.
* Operation could take a lot of time (up to several minutes), so run it within a long task.
*
* @param SessionDirectory $session session directory to save migration state and temporary data
* @param \pm_Domain $site Plesk SDK object for target domain
* @param SourceServerAccess $sourceServerAccess source server access: hostname, FTP/SSH login and password
*/
public function retrieveSiteInfo(
SessionDirectory $session, \pm_Domain $site,
SourceServerAccess $sourceServerAccess
) {
$this->configureRetrieveSiteInfo($session, $site, $sourceServerAccess);
$this->runRetrieveSiteInfo($session);
}
/**
* Prepare to get information about source site (list files and detect applications).
*
* This function is executed quickly: it just creates/modifies configuration files.
*
* @param SessionDirectory $session session directory to save migration state and temporary data
* @param \pm_Domain $site Plesk SDK object for target domain
* @param SourceServerAccess $sourceServerAccess source server access: hostname, FTP/SSH login and password
*/
public function configureRetrieveSiteInfo(
SessionDirectory $session, \pm_Domain $site,
SourceServerAccess $sourceServerAccess
)
{
$session->initialize();
$sessionObjects = SessionObjects::getInstance($session);
$config = $sessionObjects->getConfig();
$config->initDefaultOptions();
$config->setSessionDirectory($session->getId());
$config->setTargetOS(\pm_ProductInfo::isUnix() ? 'unix' : 'windows');
$config->setSourceType('web');
$config->setSourceHost($sourceServerAccess->getHost());
$config->setSourceUsername($sourceServerAccess->getUsername());
$config->setSourcePassword($sourceServerAccess->getPassword());
if ($sourceServerAccess->getFtpEncoding()) {
$config->setSourceFtpEncoding($sourceServerAccess->getFtpEncoding());
}
if ($sourceServerAccess->getFileTransport() !== null) {
$config->setSourceFileTransport($sourceServerAccess->getFileTransport());
}
if ($sourceServerAccess->getTransferFilesMode() !== null) {
$config->setSourceTransferFilesMode($sourceServerAccess->getTransferFilesMode());
}
if ($sourceServerAccess->getAllowAutoWebStreaming() !== null) {
$config->setSourceAllowAutoWebStreaming($sourceServerAccess->getAllowAutoWebStreaming());
}
if ($sourceServerAccess->getSSHPort() !== null) {
$config->setSourceSSHPort($sourceServerAccess->getSSHPort());
}
if ($sourceServerAccess->getIgnorePassiveModeServerIp() !== null) {
$config->setIgnorePassiveModeServerIp($sourceServerAccess->getIgnorePassiveModeServerIp());
}
$config->setSourceBaseUrl($sourceServerAccess->getSiteUrl());
$config->setSourceDocumentRoot($sourceServerAccess->getSiteDocumentRoot());
if ($sourceServerAccess->getFilesRoot() !== null) {
$config->setSourceFilesRoot($sourceServerAccess->getFilesRoot());
}
if ($sourceServerAccess->getListFilesMode() !== null) {
$config->setListFilesMode($sourceServerAccess->getListFilesMode());
}
$config->setSourceTargetDomain($site->getName());
$config->save();
$this->resetStatus($session);
}
/**
* Reset migration status to be ready to the new migration attempt.
*/
public function resetStatus($session) {
$sessionObjects = SessionObjects::getInstance($session);
$status = $sessionObjects->getSiteMigrationStatus();
$status->resetOperationsStatus();
$progress = $sessionObjects->getProgress();
$progress->cleanup();
}
/**
* Save configuration
*/
public function saveConfig($session) {
$sessionObjects = SessionObjects::getInstance($session);
$config = $sessionObjects->getConfig();
$config->save();
}
/**
* Allow insecure connections by setting option in session`s config.
*/
public function allowInsecureConnections($session) {
$sessionObjects = SessionObjects::getInstance($session);
$config = $sessionObjects->getConfig();
$config->setAllowInsecureConnections(true);
}
/**
* Set FTP as file transport.
*/
public function setFileTransportFtp($session) {
$sessionObjects = SessionObjects::getInstance($session);
$config = $sessionObjects->getConfig();
$config->setSourceFileTransport(FileTransports::FTP);
}
/**
* Request Plesk Migrator to get information about source site for pre-configured session:
* list files and detect applications.
*
* Session directory must be pre-configured with "configureRetrieveSiteInfo" method.
*
* Method is executed in synchronous way: the function will return control only once Plesk Migrator
* retrieved all information from the source site or failed.
* Operation could take a lot of time (up to several minutes), so run it within a long task.
*
* @param SessionDirectory $session pre-configured session directory to save migration state and temporary data
*/
public function runRetrieveSiteInfo(SessionDirectory $session)
{
$sessionObjects = SessionObjects::getInstance($session);
$config = $sessionObjects->getConfig();
try {
$migratorTool = new Tool();
$migratorTool->getSiteInfo($config, true, false);
} catch (\Exception $e) {
// In case of any error - store the error to the status file
$status = $sessionObjects->getSiteMigrationStatus();
$status->setBackendFailure($e->getMessage());
}
}
/**
* Check whether session directory is pre-configured and could be used for migration.
*
* If session is not configured - you could configure it with "configureRetrieveSiteInfo" method.
* If session is configured - you could retrieve information about source site with "runRetrieveSiteInfo".
*
* @param SessionDirectory $session | null session directory object to check
* @return bool
*/
public function isSessionConfigured(?SessionDirectory $session=null)
{
try {
if (
is_null($session) ||
!FileUtils::fileExists($session->getPath())
) {
return false;
}
$sessionObjects = SessionObjects::getInstance($session);
return (
$sessionObjects->getConfig()->getSourceType() &&
$sessionObjects->getConfig()->getSourceHost()
);
} catch(\Exception $e) {
\pm_Log::err(
"Failed to check if session is configured, it will be considered as not configured: " .
$e->getMessage()
);
}
return false;
}
/**
* Get status of retrieve source site info operation,
* started by "runRetrieveSiteInfo" or "retrieveSiteInfo" methods.
*
* @param SessionDirectory $session session directory on which retrieve site info operation was started
* @return RetrieveSiteInfo object with status and progress of operation
*/
public function getRetrieveSiteInfoStatus(
SessionDirectory $session
) {
$sessionObjects = SessionObjects::getInstance($session);
$status = $sessionObjects->getSiteMigrationStatus();
$status->read();
return new RetrieveSiteInfo(
[
$status::OPERATION_CONNECT => $status->getOperationStatus($status::OPERATION_CONNECT),
$status::OPERATION_SCAN_CONTENT => $status->getOperationStatus($status::OPERATION_SCAN_CONTENT)
],
implode("\n", $status->getErrorMessages()),
$status->getIssueId()
);
}
/**
* Check whether source site info (list of applications and files) was retrieved.
*
* @param SessionDirectory $session session directory object
* @return bool
*/
public function isSiteInfoRetrieved(
SessionDirectory $session
) {
$sessionObjects = SessionObjects::getInstance($session);
$siteInfoFile = $sessionObjects->getSiteInfo();
return $siteInfoFile->isComplete();
}
/**
* Get information about source site, retrieved in advance by "runRetrieveSiteInfo" or "retrieveSiteInfo" methods.
*
* @param SessionDirectory $session session directory for which retrieve site info was finished.
* @return SiteInfo information about source site: list of applications and files
*/
public function getSiteInfo(
SessionDirectory $session
) {
$sessionObjects = SessionObjects::getInstance($session);
$siteInfoFile = $sessionObjects->getSiteInfo();
$importStatus = $this->getImportStatus($session);
$applications = [];
foreach ($siteInfoFile->getApplications() as $application) {
$applicationTargetPath = $application['target_path'];
foreach ($importStatus->getApplicationsStatus() as $applicationStatus) {
if (
$application['type'] == $applicationStatus->getType()
&& $application['source_path'] == $applicationStatus->getSourcePath()
) {
$applicationTargetPath = $siteInfoFile->getTargetRelativePath($applicationStatus->getTargetPath());
}
}
$applications[] = new Application(
$application['type'], $application['source_path'], $applicationTargetPath
);
}
$rootFolder = $this->_convertFolder('', $siteInfoFile->getFiles());
return new SiteInfo(
$applications, $rootFolder,
$siteInfoFile->getRootPath(), $siteInfoFile->getSourceDocumentRoot(), $siteInfoFile->getSiteName()
);
}
/**
* Schedule import of an application.
*
* Schedule import works fast (in most cases less than a second).
* Once import is scheduled, you should call "startTasksRunner" to actually start import.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application $application
*/
public function scheduleApplicationImport(SessionDirectory $session, ImportOperation\Application $application)
{
$this->scheduleImport($session, [$application], [], []);
}
/**
* Schedule import of a folder.
*
* Schedule import works fast (in most cases less than a second).
* Once import is scheduled, you should call "startTasksRunner" to actually start import.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Folder $folder
*/
public function scheduleFolderImport(SessionDirectory $session, ImportOperation\Folder $folder)
{
$this->scheduleImport($session, [], [$folder], []);
}
/**
* Schedule import of a database.
*
* Schedule import works fast (in most cases less than a second).
* Once import is scheduled, you should call "startTasksRunner" to actually start import.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Database $database
*/
public function scheduleDatabaseImport(SessionDirectory $session, ImportOperation\Database $database)
{
$this->scheduleImport($session, [], [], [$database]);
}
/**
* Schedule import of applications, folders and databases.
*
* Use this function if you need to schedule import of several applications, folders, databases.
* If you need to schedule import of a single application, folder or database then
* use "scheduleApplicationImport", "scheduleFolderImport" or "scheduleDatabaseImport" respectively,
* which are more simple to call.
*
* Schedule import works fast (in most cases less than a second).
* Once import is scheduled, you should call "startTasksRunner" to actually start import.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application[] $applications
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Folder[] $folders
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Database[] $databases
*/
public function scheduleImport(
SessionDirectory $session,
$applications, $folders, $databases
) {
$this->_scheduleTask($session, $applications, $folders, $databases, self::IMPORT_COMMAND);
}
/**
* Schedule check of applications.
*
* Use this function if you need to schedule check of several applications.
*
* Schedule check works fast (in most cases less than a second).
* Once check is scheduled, you should call "startTasksRunner" to actually start check.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application[] $applications
*/
public function scheduleCheckApplications(
SessionDirectory $session, $applications
) {
$this->_scheduleTask($session, $applications, [], [], self::CHECK_APPLICATIONS_COMMAND);
}
/**
* Start task runner, which runs import for previously scheduled imports for applications, folders and databases.
*
* On Unix this function returns once the task runner was started (asynchronously).
* On Windows this function returns only once the task runner was finished (synchronously).
* The difference is caused by difficulties implementing asynchronous command execution on Windows.
*
* @param SessionDirectory $session
*/
public function startTasksRunner(
SessionDirectory $session
) {
$sessionObjects = SessionObjects::getInstance($session);
$migratorTool = new Tool();
$migratorTool->runSiteMigrationTasks($sessionObjects->getConfig());
}
/**
* Get import status and import issues for applications, databases and folders.
*
* Workflow of import is the following:
* - schedule import
* ("scheduleApplicationImport", "scheduleFolderImport" , "scheduleDatabaseImport", "scheduleImport" methods)
* - start task runner
* ("startTasksRunner" method)
* - periodically (e.g. once a second) poll import status with that function,
* display status/issues in user interface.
*
* @param SessionDirectory $session
* @return Import
*/
public function getImportStatus(
SessionDirectory $session
) {
$sessionObjects = SessionObjects::getInstance($session);
$status = $sessionObjects->getSiteMigrationStatus();
$siteData = $status->getSiteData();
$siteDataApplications = ArrayUtils::getElementDefaultArray($siteData, 'applications');
$siteDataDatabases = ArrayUtils::getElementDefaultArray($siteData, 'databases');
$siteDataFolders = ArrayUtils::getElementDefaultArray($siteData, 'files');
$applicationsStatus = [];
foreach ($siteDataApplications as $application) {
$applicationsStatus[] = new Entity\Status\Import\Application(
$application['type'], $application['source_path'], $application['target_path'],
$this->_convertIssuesToObject(
ArrayUtils::getElementDefaultArray($application, 'issues')
),
$application['status'],
$this->_convertIssuesToObject(
ArrayUtils::getElementDefaultArray($application, 'check-issues')
),
$application['check-status'] ?? null
);
}
$foldersStatus = [];
foreach ($siteDataFolders as $folder) {
$foldersStatus[] = new Folder(
$folder['source_path'], $folder['target_path'],
$this->_convertIssuesToObject(
ArrayUtils::getElementDefaultArray($folder, 'issues')
),
$folder['status']
);
}
$databasesStatus = [];
foreach ($siteDataDatabases as $database) {
$databasesStatus[] = new Database(
$database['name'], $database['host'], $database['port'],
$database['username'], $database['password'],
$this->_convertIssuesToObject(
ArrayUtils::getElementDefaultArray($database, 'issues')
),
$database['status']
);
}
return new Import(
$applicationsStatus, $foldersStatus, $databasesStatus
);
}
/**
* Cancel scheduled or running import or specified application.
*
* Operation is synchronous - function returns control once import is actually cancelled.
* Usually that is fast, but sometimes could take up to a minute, for example in case of hanged connection
* to the source server.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application $application
*/
public function cancelApplicationImport(SessionDirectory $session, ImportOperation\Application $application)
{
$this->cancelImport($session, [$application], [], []);
}
/**
* Cancel scheduled or running import or specified folder.
*
* Operation is synchronous - function returns control once import is actually cancelled.
* Usually that is fast, but sometimes could take up to a minute, for example in case of hanged connection
* to the source server.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Folder $folder
*/
public function cancelFolderImport(SessionDirectory $session, ImportOperation\Folder $folder)
{
$this->cancelImport($session, [], [$folder], []);
}
/**
* Cancel scheduled or running import or specified database.
*
* Operation is synchronous - function returns control once import is actually cancelled.
* Usually that is fast, but sometimes could take up to a minute, for example in case of hanged connection
* to the source server.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Database $database
*/
public function cancelDatabaseImport(SessionDirectory $session, ImportOperation\Database $database)
{
$this->cancelImport($session, [], [], [$database]);
}
/**
* Cancel scheduled or running import or specified applications, folders and databases.
*
* Operation is synchronous - function returns control once import is actually cancelled.
* Usually that is fast, but sometimes could take up to a minute, for example in case of hanged connection
* to the source server.
*
* Use this function if you need to cancel import of several applications, folders, databases.
* If you need to cancel import of a single application, folder or database then
* use "cancelApplicationImport", "cancelFolderImport" or "cancelDatabaseImport" respectively,
* which are more simple to call.
*
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application[] $applications
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Folder[] $folders
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Database[] $databases
*/
public function cancelImport(
SessionDirectory $session,
$applications, $folders, $databases
) {
$sessionObjects = SessionObjects::getInstance($session);
$progress = $sessionObjects->getProgress();
$progress->cleanup();
$migrationList = $this->_createMigrationListWithRandomName(
$session, $applications, $folders, $databases, self::CANCEL_COMMAND
);
$migratorTool = new Tool();
$migratorTool->cancelSiteMigrationTasks($sessionObjects->getConfig(), $migrationList->getFilePath());
}
private function _convertFolder($name, $folderData)
{
$folders = [];
$files = [];
foreach ($folderData as $item) {
if (is_array($item)) {
foreach ($item as $key => $subfolder) {
$folders[] = $this->_convertFolder($key, $subfolder);
}
} else {
$files[] = new File($item);
}
}
return new Entity\SiteInfo\Folder($name, $files, $folders);
}
private function _convertIssuesToObject($issuesArray)
{
$issues = [];
foreach ($issuesArray as $issue) {
$issues[] = new Issue(
$issue['severity'] ?? '',
$issue['execution_date'] ?? '',
$issue['problem_text'] ?? '',
$issue['details_text'] ?? ''
);
}
return $issues;
}
/**
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application[] $applications
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Folder[] $folders
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Database[] $databases
* @param string $command
* @return MigrationList
*/
private function _createMigrationListWithRandomName(
SessionDirectory $session, $applications, $folders, $databases, $command
) {
$sessionObjects = SessionObjects::getInstance($session);
$migrationListSuffix = date('Y-m-d-H-i-s');
$migrationList = $sessionObjects->getSiteMigrationList($migrationListSuffix);
$migrationList->write(
$applications, $folders, $databases, $command
);
return $migrationList;
}
/**
* @param SessionDirectory $session
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Application[] $applications
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Folder[] $folders
* @param \Plesk\MigrationLibV8\SiteImport\Entity\ImportOperation\Database[] $databases
* @param string $command
*/
private function _scheduleTask(
SessionDirectory $session,
$applications, $folders, $databases, $command
) {
$sessionObjects = SessionObjects::getInstance($session);
$progress = $sessionObjects->getProgress();
$progress->cleanup();
$migrationList = $this->_createMigrationListWithRandomName(
$session, $applications, $folders, $databases, $command
);
$tool = new Tool();
$tool->addSiteMigrationTasks($sessionObjects->getConfig(), $migrationList->getFilePath());
}
}

View File

@@ -1,41 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport;
class SessionFiles extends \Plesk\MigrationLibV8\Common\SessionFiles
{
/**
* @return string
*/
public function getStatusFilePath()
{
return $this->_session->getPath() . DIRECTORY_SEPARATOR . 'site_migration_status.json';
}
/**
* Get full path to file with the migration list.
*
* @param $suffix
* @return string
*/
public function getSiteMigrationListPath($suffix)
{
if (!is_null($suffix)) {
$filename = "site_migration_list_{$suffix}.json";
} else {
$filename = 'site_migration_list.json';
}
return $this->_session->getPath() . DIRECTORY_SEPARATOR . $filename;
}
/**
* Get full path to file with the site info.
*
* @return string
*/
public function getSiteInfoFilePath()
{
return $this->_session->getPath() . DIRECTORY_SEPARATOR . 'site_info.json';
}
}

View File

@@ -1,132 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\SiteImport;
use Plesk\MigrationLibV8\Common\Backend\Files\Progress;
use Plesk\MigrationLibV8\Common\SessionDirectory;
use Plesk\MigrationLibV8\SiteImport\Backend\Files\Config;
use Plesk\MigrationLibV8\SiteImport\Backend\Files\MigrationList;
use Plesk\MigrationLibV8\SiteImport\Backend\Files\SiteInfo;
use Plesk\MigrationLibV8\SiteImport\Backend\Files\Status;
class SessionObjects
{
/** @var \Plesk\MigrationLibV8\SiteImport\SessionObjects[] */
private static $_instances = [];
/** @var \Plesk\MigrationLibV8\SiteImport\Backend\Files\Status|null */
private $_status = null;
/** @var \Plesk\MigrationLibV8\SiteImport\Backend\Files\Config|null */
private $_config = null;
/** @var \Plesk\MigrationLibV8\SiteImport\SessionFiles|null */
private $_sessionFiles = null;
/** @var \Plesk\MigrationLibV8\SiteImport\Backend\Files\MigrationList[]|null */
private $_siteMigrationLists = [];
/** @var \Plesk\MigrationLibV8\SiteImport\Backend\Files\SiteInfo|null */
private $_siteInfo = null;
/** @var \Plesk\MigrationLibV8\Common\Backend\Files\Progress|null */
private $_progress = null;
/** @var SessionDirectory|null */
protected $_session = null;
/**
* SessionObjects constructor.
*
* @param SessionDirectory $session
*/
private function __construct(SessionDirectory $session)
{
$this->_session = $session;
}
/**
* @param \Plesk\MigrationLibV8\Common\SessionDirectory $session
* @return \Plesk\MigrationLibV8\SiteImport\SessionObjects
*/
public static function getInstance(SessionDirectory $session)
{
if (!array_key_exists($session->getPath(), self::$_instances)) {
self::$_instances[$session->getPath()] = new self($session);
}
return self::$_instances[$session->getPath()];
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Backend\Files\Config
*/
public function getConfig()
{
if (!$this->_config) {
$configPath = $this->getSessionFiles()->getConfigPath();
$this->_config = new Config($configPath);
$this->_config->setDefaultSourceSectionName('web');
}
return $this->_config;
}
/**
* @return \Plesk\MigrationLibV8\Common\Backend\Files\Progress
*/
public function getProgress()
{
if (!$this->_progress) {
$this->_progress = new Progress(
$this->getSessionFiles()->getProgressPath()
);
}
return $this->_progress;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\SessionFiles
*/
public function getSessionFiles()
{
if (!$this->_sessionFiles) {
$this->_sessionFiles = new SessionFiles($this->_session);
}
return $this->_sessionFiles;
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Backend\Files\Status
*/
public function getSiteMigrationStatus()
{
if (!$this->_status) {
$this->_status = new Status(
$this->getSessionFiles()->getStatusFilePath(), $this->getConfig()->getSourceHost()
);
}
return $this->_status;
}
/**
* @param string|null $suffix
* @return \Plesk\MigrationLibV8\SiteImport\Backend\Files\MigrationList
*/
public function getSiteMigrationList($suffix)
{
if (!array_key_exists($suffix, $this->_siteMigrationLists)) {
$this->_siteMigrationLists[$suffix] = new MigrationList(
$this->getSessionFiles()->getSiteMigrationListPath($suffix)
);
}
return $this->_siteMigrationLists[$suffix];
}
/**
* @return \Plesk\MigrationLibV8\SiteImport\Backend\Files\SiteInfo
*/
public function getSiteInfo()
{
if (!$this->_siteInfo) {
$this->_siteInfo = new SiteInfo(
$this->getConfig()->getSourceHost(), $this->getSessionFiles()->getSiteInfoFilePath()
);
}
return $this->_siteInfo;
}
}

View File

@@ -1,167 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Utils;
/**
* Collection of methods useful to work with PHP arrays
*/
class ArrayUtils
{
/**
* Get array value by key that is supposed to be array. If key does not exist in the array - return empty array.
*
* @param $array array
* @param $key string
* @return array
*/
public static function getElementDefaultArray($array, $key)
{
if (is_array($array) && array_key_exists($key, $array)) {
return $array[$key];
} else {
return [];
}
}
/**
* Get array value by key. If key does not exists in the array - return null.
*
* @param $array array
* @param $key string
* @return mixed|null
*/
public static function getElementDefaultNull($array, $key)
{
if (is_array($array) && array_key_exists($key, $array)) {
return $array[$key];
} else {
return null;
}
}
/**
* Get array value by key. If key does not exists in the array - return default value.
*
* @param $array array
* @param $key string
* @param $default mixed default value
* @return mixed|null
*/
public static function getElement($array, $key, $default)
{
if (is_array($array) && array_key_exists($key, $array)) {
return $array[$key];
} else {
return $default;
}
}
/**
* Remove specified keys from array
*
* For example, if array was [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'], and function was called with
* [1, 2] as keys, it returns [0 => 'a', 3 => 'd']
*
* @param $array array
* @param $keys string[]
* @return array
*/
public static function removeKeys($array, $keys)
{
foreach ($keys as $keyToRemove) {
unset($array[$keyToRemove]);
}
return $array;
}
/**
* Remove specified keys from array and compress keys, so they are correct sequence
*
* For example, if array was [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'], and function was called with
* [1, 2] as keys, it returns [0 => 'a', 1 => 'd']
*
* @param $array array
* @param $keys string[]
* @return array
*/
public static function removeKeysAndCompress($array, $keys)
{
foreach ($keys as $keyToRemove) {
unset($array[$keyToRemove]);
}
return array_values($array);
}
/**
* Remove specified key from array if value is an empty sequence.
*
* @param $array array
* @param $key string
* @return array|void
*/
public static function removeKeyIfEmptyArray($array, $key)
{
if (!is_array($array) || !array_key_exists($key, $array)) {
return $array;
}
if (count($array[$key]) > 0) {
return $array;
}
unset($array[$key]);
return $array;
}
/**
* Remove keys from array except for specified ones.
*
* @param $array array
* @param $exceptKeys string[]
* @return array
*/
public static function removeExceptKeys($array, $exceptKeys)
{
$keysToRemove = array_diff(array_keys($array), $exceptKeys);
foreach ($keysToRemove as $key) {
unset($array[$key]);
}
return $array;
}
/**
* Returns array which does not contain null elements.
*
* @param $array array
* @return array
*/
public static function filterNullValues($array)
{
$filteredArray = [];
foreach ($array as $key => $value) {
if (!is_null($value)) {
$filteredArray[$key] = $value;
}
}
return $filteredArray;
}
/**
* Group value by id for array of arrays.
*
* For example, function call on array [['id' => 10, 'name' => 'test1.tld'], ['id' => 20, 'name' => 'test2.tld']]
* with id key 'id' and value key 'name' will result in [10 => 'test1.tld', 20 => 'test2.tld']
*
* @param $array array array which consists of item-arrays
* @param $idKey string key to use to get identifier of each item
* @param $valueKey string key to use to get value of each item
* @return array
*/
public static function groupValueById($array, $idKey, $valueKey)
{
$grouped = [];
foreach ($array as $item) {
$grouped[$item[$idKey]] = $item[$valueKey];
}
return $grouped;
}
}

View File

@@ -1,52 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Utils;
/**
* Collection of methods useful to work with files.
*
* Always use functions from this class instead of built-in ones and Plesk SDK functions.
* Functions from this class respect security considerations and allow correct integration with backend.
*/
class FileUtils
{
public static function createDirectory($path)
{
// Plesk Migrator frontend is running under "psaadm" user and "psaadm" group.
// New directory will have the following permissions:
// rwxrwx--- psaadm psaadm
// So, nobody except for "psaadm" and superuser could work with the directory.
mkdir($path, 0770);
}
public static function putFileContents($filepath, $contents)
{
// Plesk Migrator frontend is running under "psaadm" user and "psaadm" group.
// New file will have the following permissions:
// rw-rw---- psaadm psaadm
// So, nobody except for "psaadm" and superuser could work with the file.
$oldUmask = umask(0007);
try {
file_put_contents($filepath, $contents);
} finally {
umask($oldUmask);
}
}
public static function fileExists($filepath)
{
return file_exists($filepath);
}
public static function fileGetContents($filename)
{
return file_get_contents($filename);
}
public static function removeDirectory($directory)
{
$fileManager = new \pm_ServerFileManager();
$fileManager->removeDirectory($directory);
}
}

View File

@@ -1,53 +0,0 @@
<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.
namespace Plesk\MigrationLibV8\Utils;
use Plesk\MigrationLibV8\Plesk\PleskFunctions;
/**
* Collection of methods useful to work with PHP strings
*/
class StringUtils
{
/**
* Normalize domain name for comparison - convert to lowercase punycode form.
*
* @param string $domainName original domain name
* @return string normalized domain name
*/
public static function normalizeDomainName($domainName)
{
return strtolower(PleskFunctions::IDNToASCII($domainName));
}
/**
* Normalize domain names for comparison - convert to lowercase punycode form.
*
* @param string[] $domainNames array of original domain names
* @return array array of normalized domain names
*/
public static function normalizeDomainNames($domainNames)
{
$normalized = [];
foreach ($domainNames as $domainName) {
$normalized[] = self::normalizeDomainName($domainName);
}
return $normalized;
}
/**
* Normalize domain names for comparison, which are used as array keys - convert to lowercase punycode form.
*
* @param string[] $dataArray array, where each key is a domain name
* @return array array where each key is normalized domain name, value is the same as in original array
*/
public static function normalizeDomainNameKeys($dataArray)
{
$normalized = [];
foreach ($dataArray as $domainName => $data) {
$normalized[self::normalizeDomainName($domainName)] = $data;
}
return $normalized;
}
}