diff --git a/bin/froxlor-cli b/bin/froxlor-cli new file mode 100755 index 00000000..df75b0b0 --- /dev/null +++ b/bin/froxlor-cli @@ -0,0 +1,18 @@ +#!/usr/bin/env php +add(new ConfigServices()); +$application->add(new PhpSessionclean()); +$application->add(new SwitchServerIp()); +$application->run(); diff --git a/composer.json b/composer.json index 9aa5c221..aba7f797 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,8 @@ "froxlor/idna-convert-legacy": "^2.1", "voku/anti-xss": "^4.1", "twig/twig": "^3.3", - "erusev/parsedown": "^1.7" + "erusev/parsedown": "^1.7", + "symfony/console": "^6.0" }, "require-dev": { "phpunit/phpunit": "^9", diff --git a/composer.lock b/composer.lock index ef01a54a..67408b97 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "51513cb9d850aec753c740ee37871430", + "content-hash": "1744b69cc6cb1d92362c44860a6baeac", "packages": [ { "name": "erusev/parsedown", @@ -276,6 +276,54 @@ ], "time": "2021-11-25T16:34:11+00:00" }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, { "name": "psr/log", "version": "1.1.4", @@ -396,6 +444,168 @@ ], "time": "2021-10-20T12:19:55+00:00" }, + { + "name": "symfony/console", + "version": "v6.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e", + "reference": "70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.4|^6.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/lock": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-31T17:18:25+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-07-12T14:48:14+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.24.0", @@ -885,6 +1095,174 @@ ], "time": "2021-05-27T09:17:38+00:00" }, + { + "name": "symfony/service-contracts", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-11-04T16:48:04+00:00" + }, + { + "name": "symfony/string", + "version": "v6.0.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/522144f0c4c004c80d56fa47e40e17028e2eefc2", + "reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.0" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/translation-contracts": "^2.0|^3.0", + "symfony/var-exporter": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v6.0.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:55:41+00:00" + }, { "name": "twig/twig", "version": "v3.3.8", @@ -2561,54 +2939,6 @@ ], "time": "2022-01-24T07:33:35+00:00" }, - { - "name": "psr/container", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" - }, - "time": "2021-11-05T16:50:12+00:00" - }, { "name": "sebastian/cli-parser", "version": "1.0.1", @@ -3858,73 +4188,6 @@ ], "time": "2022-01-26T16:28:35+00:00" }, - { - "name": "symfony/deprecation-contracts", - "version": "v2.5.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-07-12T14:48:14+00:00" - }, { "name": "symfony/filesystem", "version": "v5.4.3", @@ -4151,89 +4414,6 @@ ], "time": "2021-09-13T13:58:11+00:00" }, - { - "name": "symfony/service-contracts", - "version": "v2.5.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", - "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "suggest": { - "symfony/service-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-11-04T16:48:04+00:00" - }, { "name": "theseer/tokenizer", "version": "1.2.1", @@ -4367,5 +4547,5 @@ "platform-dev": { "ext-pcntl": "*" }, - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.2.0" } diff --git a/install/scripts/config-services.php b/install/scripts/config-services.php deleted file mode 100755 index 9ba08d08..00000000 --- a/install/scripts/config-services.php +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/php - (2018-) - * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt - * @package Cron - * - */ - -// Check if we're in the CLI -if (@php_sapi_name() !== 'cli') { - die('This script will only work in the shell.'); -} - -require dirname(dirname(__DIR__)) . '/vendor/autoload.php'; - -// give control to command line handler -try { - \Froxlor\Cli\ConfigServicesCmd::processParameters($argc, $argv); -} catch (Exception $e) { - \Froxlor\Cli\ConfigServicesCmd::printerr($e->getMessage()); - exit(1); -} diff --git a/install/scripts/index.html b/install/scripts/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/install/scripts/switch-server-ip.php b/install/scripts/switch-server-ip.php deleted file mode 100755 index b76e5b3c..00000000 --- a/install/scripts/switch-server-ip.php +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/php - (2016-) - * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt - * @package Cron - * - */ - -// Check if we're in the CLI -if (@php_sapi_name() !== 'cli') { - die('This script will only work in the shell.'); -} - -require dirname(dirname(__DIR__)) . '/vendor/autoload.php'; - -// give control to command line handler -try { - \Froxlor\Cli\SwitchServerIpCmd::processParameters($argc, $argv); -} catch (Exception $e) { - \Froxlor\Cli\SwitchServerIpCmd::printerr($e->getMessage()); - exit(1); -} diff --git a/lib/Froxlor/Cli/Action.php b/lib/Froxlor/Cli/Action.php deleted file mode 100644 index 3f079d48..00000000 --- a/lib/Froxlor/Cli/Action.php +++ /dev/null @@ -1,18 +0,0 @@ -_args = $args; - } - - public function getActionName() - { - return get_called_class(); - } - - abstract public function run(); -} diff --git a/lib/Froxlor/Cli/Action/ConfigServicesAction.php b/lib/Froxlor/Cli/Action/ConfigServicesAction.php deleted file mode 100644 index 1cd6a5d1..00000000 --- a/lib/Froxlor/Cli/Action/ConfigServicesAction.php +++ /dev/null @@ -1,456 +0,0 @@ -validate(); - } - - /** - * validates the parsed command line parameters - * - * @throws \Exception - */ - private function validate() - { - global $lng; - - $this->checkConfigParam(true); - $this->parseConfig(); - - require FROXLOR_INSTALL_DIR . '/lib/tables.inc.php'; - - include_once FROXLOR_INSTALL_DIR . '/lng/english.lng.php'; - include_once FROXLOR_INSTALL_DIR . '/lng/lng_references.php'; - - if (array_key_exists("import-settings", $this->_args)) { - $this->importSettings(); - } - - if (array_key_exists("create", $this->_args)) { - $this->createConfig(); - } elseif (array_key_exists("apply", $this->_args)) { - $this->applyConfig(); - } elseif (array_key_exists("list-daemons", $this->_args) || array_key_exists("daemon", $this->_args)) { - ConfigServicesCmd::printwarn("--list-daemons and --daemon only work together with --apply"); - } - } - - private function importSettings() - { - if (strtoupper(substr($this->_args["import-settings"], 0, 4)) == 'HTTP') { - echo "Settings file seems to be an URL, trying to download" . PHP_EOL; - $target = "/tmp/froxlor-import-settings-" . time() . ".json"; - if (@file_exists($target)) { - @unlink($target); - } - $this->downloadFile($this->_args["import-settings"], $target); - $this->_args["import-settings"] = $target; - } - if (! is_file($this->_args["import-settings"])) { - throw new \Exception("Given settings file is not a file"); - } elseif (! file_exists($this->_args["import-settings"])) { - throw new \Exception("Given settings file cannot be found ('" . $this->_args["import-settings"] . "')"); - } elseif (! is_readable($this->_args["import-settings"])) { - throw new \Exception("Given settings file cannot be read ('" . $this->_args["import-settings"] . "')"); - } - $imp_content = file_get_contents($this->_args["import-settings"]); - SImExporter::import($imp_content); - ConfigServicesCmd::printsucc("Successfully imported settings from '" . $this->_args["import-settings"] . "'"); - } - - private function createConfig() - { - $_daemons_config = array( - 'distro' => "" - ); - - $config_dir = FROXLOR_INSTALL_DIR . '/lib/configfiles/'; - // show list of available distro's - $distros = glob($config_dir . '*.xml'); - // tmp array - $distributions_select_data = array(); - - //set default os. - $os_dist = array('ID' => 'bullseye'); - $os_version = array('0' => '11'); - $os_default = $os_dist['ID']; - - //read os-release - if(file_exists('/etc/os-release')) { - $os_dist = parse_ini_file('/etc/os-release', false); - if(is_array($os_dist) && array_key_exists('ID', $os_dist) && array_key_exists('VERSION_ID', $os_dist)) { - $os_version = explode('.',$os_dist['VERSION_ID'])[0]; - } - } - - // read in all the distros - foreach ($distros as $_distribution) { - // get configparser object - $dist = new \Froxlor\Config\ConfigParser($_distribution); - // get distro-info - $dist_display = $this->getCompleteDistroName($dist); - // store in tmp array - $distributions_select_data[$dist_display] = str_replace(".xml", "", strtolower(basename($_distribution))); - - //guess if this is the current distro. - $ver = explode('.', $dist->distributionVersion)[0]; - if (strtolower($os_dist['ID']) == strtolower($dist->distributionName) && $os_version == $ver) { - $os_default = str_replace(".xml", "", strtolower(basename($_distribution))); - } - } - - // sort by distribution name - ksort($distributions_select_data); - - // list all distributions - $mask = "|%-50.50s |%-50.50s |\n"; - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - printf($mask, 'dist', 'name'); - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - foreach ($distributions_select_data as $name => $filename) { - printf($mask, $filename, $name); - } - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - echo PHP_EOL; - - while (! in_array($_daemons_config['distro'], $distributions_select_data)) { - $_daemons_config['distro'] = ConfigServicesCmd::getInput("choose distribution", $os_default); - } - - // go through all services and let user check whether to include it or not - $configfiles = new \Froxlor\Config\ConfigParser($config_dir . '/' . $_daemons_config['distro'] . ".xml"); - $services = $configfiles->getServices(); - - foreach ($services as $si => $service) { - echo PHP_EOL . "--- " . strtoupper($si) . " ---" . PHP_EOL . PHP_EOL; - $_daemons_config[$si] = ""; - - $daemons = $service->getDaemons(); - $mask = "|%-50.50s |%-50.50s |\n"; - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - printf($mask, 'value', 'name'); - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - $default_daemon = ""; - foreach ($daemons as $di => $dd) { - $title = $dd->title; - if ($dd->default) { - $default_daemon = $di; - $title = $title . " (default)"; - } - printf($mask, $di, $title); - } - printf($mask, "x", "No " . $si); - $daemons['x'] = 'x'; - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - echo PHP_EOL; - if ($si == 'system') { - $_daemons_config[$si] = array(); - // for the system/other services we need a multiple choice possibility - ConfigServicesCmd::println("Select every service you need. Enter empty value when done"); - $sysservice = ""; - do { - $sysservice = ConfigServicesCmd::getInput("choose service"); - if (! empty($sysservice)) { - $_daemons_config[$si][] = $sysservice; - } - } while (! empty($sysservice)); - // add 'cron' as fixed part (doesn't hurt if it exists) - if (! in_array('cron', $_daemons_config[$si])) { - $_daemons_config[$si][] = 'cron'; - } - } else { - // for all others -> only one value - while (! array_key_exists($_daemons_config[$si], $daemons)) { - $_daemons_config[$si] = ConfigServicesCmd::getInput("choose service", $default_daemon); - } - } - } - - echo PHP_EOL . PHP_EOL; - $daemons_config = json_encode($_daemons_config); - $output = ConfigServicesCmd::getInput("choose output-filename", "/tmp/froxlor-config-" . date('Ymd') . ".json"); - file_put_contents($output, $daemons_config); - ConfigServicesCmd::printsucc("Successfully generated service-configfile '" . $output . "'"); - echo PHP_EOL; - ConfigServicesCmd::printsucc("You can now apply this config running:" . PHP_EOL . "php " . FROXLOR_INSTALL_DIR . "install/scripts/config-services.php --apply=" . $output); - echo PHP_EOL; - $proceed = ConfigServicesCmd::getYesNo("Do you want to apply the config now? [y/N]", 0); - if ($proceed) { - passthru("php " . FROXLOR_INSTALL_DIR . "install/scripts/config-services.php --apply=" . $output); - } - } - - private function getCompleteDistroName($cparser) - { - // get distro-info - $dist_display = $cparser->distributionName; - if ($cparser->distributionCodename != '') { - $dist_display .= " " . $cparser->distributionCodename; - } - if ($cparser->distributionVersion != '') { - $dist_display .= " (" . $cparser->distributionVersion . ")"; - } - if ($cparser->deprecated) { - $dist_display .= " [deprecated]"; - } - return $dist_display; - } - - private function applyConfig() - { - if (strtoupper(substr($this->_args["apply"], 0, 4)) == 'HTTP') { - echo "Config file seems to be an URL, trying to download" . PHP_EOL; - $target = "/tmp/froxlor-config-" . time() . ".json"; - if (@file_exists($target)) { - @unlink($target); - } - $this->downloadFile($this->_args["apply"], $target); - $this->_args["apply"] = $target; - } - if (! is_file($this->_args["apply"])) { - throw new \Exception("Given config file is not a file"); - } elseif (! file_exists($this->_args["apply"])) { - throw new \Exception("Given config file cannot be found ('" . $this->_args["apply"] . "')"); - } elseif (! is_readable($this->_args["apply"])) { - throw new \Exception("Given config file cannot be read ('" . $this->_args["apply"] . "')"); - } - - $config = file_get_contents($this->_args["apply"]); - $decoded_config = json_decode($config, true); - - if (array_key_exists("list-daemons", $this->_args)) { - $mask = "|%-50.50s |%-50.50s |\n"; - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - printf($mask, 'service', 'daemon'); - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - foreach ($decoded_config as $service => $daemon) { - if (is_array($daemon) && count($daemon) > 0) { - foreach ($daemon as $sysdaemon) { - printf($mask, $service, $sysdaemon); - } - } else { - if ($daemon == 'x') { - $daemon = '--- skipped ---'; - } - printf($mask, $service, $daemon); - } - } - printf($mask, str_repeat("-", 50), str_repeat("-", 50)); - echo PHP_EOL; - exit(); - } - - $only_daemon = null; - if (array_key_exists("daemon", $this->_args)) { - $only_daemon = $this->_args['daemon']; - } - - if (! empty($decoded_config)) { - $config_dir = FROXLOR_INSTALL_DIR . '/lib/configfiles/'; - $configfiles = new \Froxlor\Config\ConfigParser($config_dir . '/' . $decoded_config['distro'] . ".xml"); - $services = $configfiles->getServices(); - $replace_arr = $this->getReplacerArray(); - - foreach ($services as $si => $service) { - echo PHP_EOL . "--- Configuring: " . strtoupper($si) . " ---" . PHP_EOL . PHP_EOL; - if (! isset($decoded_config[$si]) || $decoded_config[$si] == 'x') { - ConfigServicesCmd::printwarn("Skipping " . strtoupper($si) . " configuration as desired"); - continue; - } - $daemons = $service->getDaemons(); - foreach ($daemons as $di => $dd) { - // check for desired service - if (($si != 'system' && $decoded_config[$si] != $di) || (is_array($decoded_config[$si]) && ! in_array($di, $decoded_config[$si]))) { - continue; - } - ConfigServicesCmd::println("Configuring '" . $di . "'"); - - if (! empty($only_daemon) && $only_daemon != $di) { - ConfigServicesCmd::printwarn("Skipping " . $di . " configuration as desired"); - continue; - } - // run all cmds - $confarr = $dd->getConfig(); - foreach ($confarr as $action) { - switch ($action['type']) { - case "install": - ConfigServicesCmd::println("Installing required packages"); - $result = null; - passthru(strtr($action['content'], $replace_arr), $result); - if (strlen($result) > 1) { - echo $result; - } - break; - case "command": - exec(strtr($action['content'], $replace_arr)); - break; - case "file": - if (array_key_exists('content', $action)) { - ConfigServicesCmd::printwarn("Creating file '" . $action['name'] . "'"); - file_put_contents($action['name'], trim(strtr($action['content'], $replace_arr))); - } elseif (array_key_exists('subcommands', $action)) { - foreach ($action['subcommands'] as $fileaction) { - if (array_key_exists('execute', $fileaction) && $fileaction['execute'] == "pre") { - exec(strtr($fileaction['content'], $replace_arr)); - } elseif (array_key_exists('execute', $fileaction) && $fileaction['execute'] == "post") { - exec(strtr($fileaction['content'], $replace_arr)); - } elseif ($fileaction['type'] == 'file') { - ConfigServicesCmd::printwarn("Creating file '" . $fileaction['name'] . "'"); - file_put_contents($fileaction['name'], trim(strtr($fileaction['content'], $replace_arr))); - } - } - } - break; - } - } - } - } - // set is_configured flag - Settings::Set('panel.is_configured', '1', true); - // run cronjob at the end to ensure configs are all up to date - exec('php ' . FROXLOR_INSTALL_DIR . '/scripts/froxlor_master_cronjob.php --force'); - // and done - ConfigServicesCmd::printsucc("All services have been configured"); - } else { - ConfigServicesCmd::printerr("Unable to decode given JSON file"); - } - } - - private function getReplacerArray() - { - $customer_tmpdir = '/tmp/'; - if (Settings::Get('system.mod_fcgid') == '1' && Settings::Get('system.mod_fcgid_tmpdir') != '') { - $customer_tmpdir = Settings::Get('system.mod_fcgid_tmpdir'); - } elseif (Settings::Get('phpfpm.enabled') == '1' && Settings::Get('phpfpm.tmpdir') != '') { - $customer_tmpdir = Settings::Get('phpfpm.tmpdir'); - } - - // try to convert namserver hosts to ip's - $ns_ips = ""; - $known_ns_ips = []; - if (Settings::Get('system.nameservers') != '') { - $nameservers = explode(',', Settings::Get('system.nameservers')); - foreach ($nameservers as $nameserver) { - $nameserver = trim($nameserver); - // DNS servers might be multi homed; allow transfer from all ip - // addresses of the DNS server - $nameserver_ips = \Froxlor\PhpHelper::gethostbynamel6($nameserver); - // append dot to hostname - if (substr($nameserver, - 1, 1) != '.') { - $nameserver .= '.'; - } - // ignore invalid responses - if (! is_array($nameserver_ips)) { - // act like \Froxlor\PhpHelper::gethostbynamel6() and return unmodified hostname on error - $nameserver_ips = array( - $nameserver - ); - } else { - $known_ns_ips = array_merge($known_ns_ips, $nameserver_ips); - } - if (!empty($ns_ips)) { - $ns_ips .= ','; - } - $ns_ips .= implode(",", $nameserver_ips); - } - } - - // AXFR server - if (Settings::Get('system.axfrservers') != '') { - $axfrservers = explode(',', Settings::Get('system.axfrservers')); - foreach ($axfrservers as $axfrserver) { - if (!in_array(trim($axfrserver), $known_ns_ips)) { - if (!empty($ns_ips)) { - $ns_ips .= ','; - } - $ns_ips .= trim($axfrserver); - } - } - } - - Database::needSqlData(); - $sql = Database::getSqlData(); - - $replace_arr = array( - '' => $sql['user'], - '' => $sql['passwd'], - '' => $sql['db'], - '' => $sql['host'], - '' => isset($sql['socket']) ? $sql['socket'] : null, - '' => Settings::Get('system.hostname'), - '' => Settings::Get('system.ipaddress'), - '' => Settings::Get('system.nameservers'), - '' => $ns_ips, - '' => Settings::Get('system.vmail_homedir'), - '' => Settings::Get('system.vmail_uid'), - '' => Settings::Get('system.vmail_gid'), - '' => (Settings::Get('system.use_ssl') == '1') ? 'imaps pop3s' : '', - '' => \Froxlor\FileDir::makeCorrectDir($customer_tmpdir), - '' => \Froxlor\FileDir::makeCorrectDir(FROXLOR_INSTALL_DIR), - '' => \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.bindconf_directory')), - '' => Settings::Get('system.apachereload_command'), - '' => \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')), - '' => \Froxlor\FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir')), - '' => Settings::Get('system.httpgroup') - ); - return $replace_arr; - } - - private function parseConfig() - { - define('FROXLOR_INSTALL_DIR', $this->_args['froxlor-dir']); - if (! class_exists('\\Froxlor\\Database\\Database')) { - throw new \Exception("Could not find froxlor's Database class. Is froxlor really installed to '" . FROXLOR_INSTALL_DIR . "'?"); - } - if (! file_exists(FROXLOR_INSTALL_DIR . '/lib/userdata.inc.php')) { - throw new \Exception("Could not find froxlor's userdata.inc.php file. You should use this script only with a fully installed and setup froxlor system."); - } - } - - private function checkConfigParam($needed = false) - { - if ($needed) { - if (! isset($this->_args["froxlor-dir"])) { - $this->_args["froxlor-dir"] = \Froxlor\Froxlor::getInstallDir(); - } elseif (! is_dir($this->_args["froxlor-dir"])) { - throw new \Exception("Given --froxlor-dir parameter is not a directory"); - } elseif (! file_exists($this->_args["froxlor-dir"])) { - throw new \Exception("Given froxlor directory cannot be found ('" . $this->_args["froxlor-dir"] . "')"); - } elseif (! is_readable($this->_args["froxlor-dir"])) { - throw new \Exception("Given froxlor directory cannot be read ('" . $this->_args["froxlor-dir"] . "')"); - } - } - } - - private function downloadFile($src, $dest) - { - set_time_limit(0); - // This is the file where we save the information - $fp = fopen($dest, 'w+'); - // Here is the file we are downloading, replace spaces with %20 - $ch = curl_init(str_replace(" ", "%20", $src)); - curl_setopt($ch, CURLOPT_TIMEOUT, 50); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - // write curl response to file - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - // get curl response - curl_exec($ch); - curl_close($ch); - fclose($fp); - } -} diff --git a/lib/Froxlor/Cli/Action/PhpSessioncleanAction.php b/lib/Froxlor/Cli/Action/PhpSessioncleanAction.php deleted file mode 100644 index ee93883b..00000000 --- a/lib/Froxlor/Cli/Action/PhpSessioncleanAction.php +++ /dev/null @@ -1,99 +0,0 @@ -validate(); - - if ((int) Settings::Get('phpfpm.enabled') == 1) { - if (isset($this->_args["max-lifetime"]) && is_numeric($this->_args["max-lifetime"]) && $this->_args["max-lifetime"] > 0) { - $this->cleanSessionfiles((int)$this->_args["max-lifetime"]); - } else { - // use default max-lifetime value - $this->cleanSessionfiles(); - } - } - } - - /** - * validates the parsed command line parameters - * - * @throws \Exception - */ - private function validate() - { - global $lng; - - $this->checkConfigParam(true); - $this->parseConfig(); - - require FROXLOR_INSTALL_DIR . '/lib/tables.inc.php'; - } - - private function cleanSessionfiles(int $maxlifetime = 1440) - { - // store paths to clean up - $paths_to_clean = []; - // get all pool-config directories configured - $sel_stmt = Database::prepare("SELECT DISTINCT `config_dir` FROM `" . TABLE_PANEL_FPMDAEMONS . "`"); - Database::pexecute($sel_stmt); - while ($fpmd = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) { - $poolfiles = glob(\Froxlor\FileDir::makeCorrectFile($fpmd['config_dir'] . '/*.conf')); - foreach ($poolfiles as $cf) { - $contents = file_get_contents($cf); - $pattern = preg_quote('session.save_path', '/'); - $pattern = "/" . $pattern . ".+?\=(.*)/"; - if (preg_match_all($pattern, $contents, $matches)) { - $paths_to_clean[] = \Froxlor\FileDir::makeCorrectDir(trim($matches[1][0])); - } - } - } - - // every path is just needed once - $paths_to_clean = array_unique($paths_to_clean); - - if (count($paths_to_clean) > 0) { - foreach ($paths_to_clean as $ptc) { - // find all files older then maxlifetime and delete them - \Froxlor\FileDir::safe_exec("find -O3 \"" . $ptc . "\" -ignore_readdir_race -depth -mindepth 1 -name 'sess_*' -type f -cmin \"+" . $maxlifetime . "\" -delete"); - } - } - } - private function parseConfig() - { - define('FROXLOR_INSTALL_DIR', $this->_args['froxlor-dir']); - if (!class_exists('\\Froxlor\\Database\\Database')) { - throw new \Exception("Could not find froxlor's Database class. Is froxlor really installed to '" . FROXLOR_INSTALL_DIR . "'?"); - } - if (!file_exists(FROXLOR_INSTALL_DIR . '/lib/userdata.inc.php')) { - throw new \Exception("Could not find froxlor's userdata.inc.php file. You should use this script only with a fully installed and setup froxlor system."); - } - } - - private function checkConfigParam($needed = false) - { - if ($needed) { - if (!isset($this->_args["froxlor-dir"])) { - $this->_args["froxlor-dir"] = \Froxlor\Froxlor::getInstallDir(); - } elseif (!is_dir($this->_args["froxlor-dir"])) { - throw new \Exception("Given --froxlor-dir parameter is not a directory"); - } elseif (!file_exists($this->_args["froxlor-dir"])) { - throw new \Exception("Given froxlor directory cannot be found ('" . $this->_args["froxlor-dir"] . "')"); - } elseif (!is_readable($this->_args["froxlor-dir"])) { - throw new \Exception("Given froxlor directory cannot be read ('" . $this->_args["froxlor-dir"] . "')"); - } - } - } -} diff --git a/lib/Froxlor/Cli/Action/SwitchServerIpAction.php b/lib/Froxlor/Cli/Action/SwitchServerIpAction.php deleted file mode 100644 index fe6719a5..00000000 --- a/lib/Froxlor/Cli/Action/SwitchServerIpAction.php +++ /dev/null @@ -1,186 +0,0 @@ -validate(); - } - - /** - * validates the parsed command line parameters - * - * @throws \Exception - */ - private function validate() - { - $need_config = false; - if (array_key_exists("list", $this->_args) || array_key_exists("switch", $this->_args)) { - $need_config = true; - } - - $this->checkConfigParam($need_config); - - $this->parseConfig(); - - if (array_key_exists("list", $this->_args)) { - $this->listIPs(); - } - if (array_key_exists("switch", $this->_args)) { - $this->switchIPs(); - } - } - - private function listIPs() - { - $sel_stmt = Database::prepare("SELECT * FROM panel_ipsandports ORDER BY ip ASC, port ASC"); - Database::pexecute($sel_stmt); - $ips = $sel_stmt->fetchAll(\PDO::FETCH_ASSOC); - $mask = "|%-10.10s |%-50.50s | %10.10s |\n"; - printf($mask, str_repeat("-", 10), str_repeat("-", 50), str_repeat("-", 10)); - printf($mask, 'id', 'IP address', 'port'); - printf($mask, str_repeat("-", 10), str_repeat("-", 50), str_repeat("-", 10)); - foreach ($ips as $ipdata) { - printf($mask, $ipdata['id'], $ipdata['ip'], $ipdata['port']); - } - printf($mask, str_repeat("-", 10), str_repeat("-", 50), str_repeat("-", 10)); - echo PHP_EOL . PHP_EOL; - } - - private function switchIPs() - { - $ip_list = $this->_args['switch']; - - if (empty($ip_list) || is_bool($ip_list)) { - throw new \Exception("No parameters given for --switch action."); - } - - $ips_to_switch = array(); - $ip_list = explode(" ", $ip_list); - foreach ($ip_list as $ips_combo) { - $ip_pair = explode(",", $ips_combo); - if (count($ip_pair) != 2) { - throw new \Exception("Invalid parameter given for --switch"); - } else { - if (filter_var($ip_pair[0], FILTER_VALIDATE_IP) == false) { - throw new \Exception("Invalid source ip address: " . $ip_pair[0]); - } - if (filter_var($ip_pair[1], FILTER_VALIDATE_IP) == false) { - throw new \Exception("Invalid target ip address: " . $ip_pair[1]); - } - if ($ip_pair[0] == $ip_pair[1]) { - throw new \Exception("Source and target ip address are equal"); - } - } - $ips_to_switch[] = $ip_pair; - } - - if (count($ips_to_switch) > 0) { - $check_stmt = Database::prepare("SELECT `id` FROM panel_ipsandports WHERE `ip` = :newip"); - $upd_stmt = Database::prepare("UPDATE panel_ipsandports SET `ip` = :newip WHERE `ip` = :oldip"); - - // system.ipaddress - $check_sysip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'ipaddress'"); - $check_sysip = Database::pexecute_first($check_sysip_stmt); - - // system.mysql_access_host - $check_mysqlip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'mysql_access_host'"); - $check_mysqlip = Database::pexecute_first($check_mysqlip_stmt); - - // system.axfrservers - $check_axfrip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'axfrservers'"); - $check_axfrip = Database::pexecute_first($check_axfrip_stmt); - - foreach ($ips_to_switch as $ip_pair) { - echo "Switching IP \033[1m" . $ip_pair[0] . "\033[0m to IP \033[1m" . $ip_pair[1] . "\033[0m" . PHP_EOL; - - $ip_check = Database::pexecute_first($check_stmt, array( - 'newip' => $ip_pair[1] - )); - if ($ip_check) { - SwitchServerIpCmd::printwarn("Note: " . $ip_pair[0] . " not updated to " . $ip_pair[1] . " - IP already exists in froxlor's database"); - continue; - } - - Database::pexecute($upd_stmt, array( - 'newip' => $ip_pair[1], - 'oldip' => $ip_pair[0] - )); - $rows_updated = $upd_stmt->rowCount(); - - if ($rows_updated == 0) { - SwitchServerIpCmd::printwarn("Note: " . $ip_pair[0] . " not updated to " . $ip_pair[1] . " (possibly no entry found in froxlor database. Use --list to see what IP addresses are added in froxlor"); - } - - // check whether the system.ipaddress needs updating - if ($check_sysip['value'] == $ip_pair[0]) { - $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newip WHERE `settinggroup` = 'system' and `varname` = 'ipaddress'"); - Database::pexecute($upd2_stmt, array( - 'newip' => $ip_pair[1] - )); - SwitchServerIpCmd::printsucc("Updated system-ipaddress from '" . $ip_pair[0] . "' to '" . $ip_pair[1] . "'"); - } - - // check whether the system.mysql_access_host needs updating - if (strstr($check_mysqlip['value'], $ip_pair[0]) !== false) { - $new_mysqlip = str_replace($ip_pair[0], $ip_pair[1], $check_mysqlip['value']); - $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newmysql WHERE `settinggroup` = 'system' and `varname` = 'mysql_access_host'"); - Database::pexecute($upd2_stmt, array( - 'newmysql' => $new_mysqlip - )); - SwitchServerIpCmd::printsucc("Updated mysql_access_host from '" . $check_mysqlip['value'] . "' to '" . $new_mysqlip . "'"); - } - - // check whether the system.axfrservers needs updating - if (strstr($check_axfrip['value'], $ip_pair[0]) !== false) { - $new_axfrip = str_replace($ip_pair[0], $ip_pair[1], $check_axfrip['value']); - $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newaxfr WHERE `settinggroup` = 'system' and `varname` = 'axfrservers'"); - Database::pexecute($upd2_stmt, array( - 'newaxfr' => $new_axfrip - )); - SwitchServerIpCmd::printsucc("Updated axfrservers from '" . $check_axfrip['value'] . "' to '" . $new_axfrip . "'"); - } - } - } - - echo PHP_EOL; - SwitchServerIpCmd::printwarn("*** ATTENTION *** Remember to replace IP addresses in configuration files if used anywhere."); - SwitchServerIpCmd::printsucc("IP addresses updated"); - } - - private function parseConfig() - { - define('FROXLOR_INSTALL_DIR', $this->_args['froxlor-dir']); - if (! class_exists('\\Froxlor\\Database\\Database')) { - throw new \Exception("Could not find froxlor's Database class. Is froxlor really installed to '" . FROXLOR_INSTALL_DIR . "'?"); - } - if (! file_exists(FROXLOR_INSTALL_DIR . '/lib/userdata.inc.php')) { - throw new \Exception("Could not find froxlor's userdata.inc.php file. You should use this script only with a fully installed and setup froxlor system."); - } - } - - private function checkConfigParam($needed = false) - { - if ($needed) { - if (! isset($this->_args["froxlor-dir"])) { - $this->_args["froxlor-dir"] = \Froxlor\Froxlor::getInstallDir(); - } elseif (! is_dir($this->_args["froxlor-dir"])) { - throw new \Exception("Given --froxlor-dir parameter is not a directory"); - } elseif (! file_exists($this->_args["froxlor-dir"])) { - throw new \Exception("Given froxlor directory cannot be found ('" . $this->_args["froxlor-dir"] . "')"); - } elseif (! is_readable($this->_args["froxlor-dir"])) { - throw new \Exception("Given froxlor directory cannot be read ('" . $this->_args["froxlor-dir"] . "')"); - } - } - } -} diff --git a/lib/Froxlor/Cli/Action/index.html b/lib/Froxlor/Cli/Action/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/Froxlor/Cli/CmdLineHandler.php b/lib/Froxlor/Cli/CmdLineHandler.php deleted file mode 100644 index 1cb3fe46..00000000 --- a/lib/Froxlor/Cli/CmdLineHandler.php +++ /dev/null @@ -1,216 +0,0 @@ - (2018-) - * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt - * @package Cron - * - */ -abstract class CmdLineHandler -{ - - /** - * internal variable for passed arguments - * - * @var array - */ - private static $args = null; - - /** - * Action object read from commandline/config - * - * @var \Froxlor\Cli\Action - */ - private $action = null; - - /** - * Returns a CmdLineHandler object with given - * arguments from command line - * - * @param int $argc - * @param array $argv - * - * @return CmdLineHandler - */ - public static function processParameters($argc, $argv) - { - $me = get_called_class(); - return new $me($argc, $argv); - } - - /** - * class constructor, validates the command line parameters - * and sets the Action-object if valid - * - * @param int $argc - * @param string[] $argv - * - * @return null - * @throws \Exception - */ - private function __construct($argc, $argv) - { - self::$args = $this->parseArgs($argv); - $this->action = $this->createAction(); - $this->action->run(); - } - - /** - * Parses the arguments given via the command line; - * three types are supported: - * 1. - * --parm1 or --parm2=value - * 2. -xyz (multiple switches in one) or -a=value - * 3. parm1 parm2 - * - * The 1. will be mapped as - * ["parm1"] => true, ["parm2"] => "value" - * The 2. as - * ["x"] => true, ["y"] => true, ["z"] => true, ["a"] => "value" - * And the 3. as - * [0] => "parm1", [1] => "parm2" - * - * @param array $argv - * - * @return array - */ - private function parseArgs($argv) - { - array_shift($argv); - $o = array(); - foreach ($argv as $a) { - if (substr($a, 0, 2) == '--') { - $eq = strpos($a, '='); - if ($eq !== false) { - $o[substr($a, 2, $eq - 2)] = substr($a, $eq + 1); - } else { - $k = substr($a, 2); - if (! isset($o[$k])) { - $o[$k] = true; - } - } - } elseif (substr($a, 0, 1) == '-') { - if (substr($a, 2, 1) == '=') { - $o[substr($a, 1, 1)] = substr($a, 3); - } else { - foreach (str_split(substr($a, 1)) as $k) { - if (! isset($o[$k])) { - $o[$k] = true; - } - } - } - } else { - $o[] = $a; - } - } - return $o; - } - - /** - * Creates an Action-Object for the Action-Handler - * - * @return \Froxlor\Cli\Action - * @throws \Exception - */ - private function createAction() - { - - // Test for help-switch - if (empty(self::$args) || array_key_exists("help", self::$args) || array_key_exists("h", self::$args)) { - static::printHelp(); - // end of execution - } - // check if no unknown parameters are present - foreach (self::$args as $arg => $value) { - - if (is_numeric($arg)) { - throw new \Exception("Unknown parameter '" . $value . "' in argument list"); - } elseif (! in_array($arg, static::$params) && ! in_array($arg, static::$switches)) { - throw new \Exception("Unknown parameter '" . $arg . "' in argument list"); - } - } - - // set debugger switch - if (isset(self::$args["d"]) && self::$args["d"] == true) { - // Debugger::getInstance()->setEnabled(true); - // Debugger::getInstance()->debug("debug output enabled"); - } - - return new static::$action_class(self::$args); - } - - public static function getInput($prompt = "#", $default = "") - { - if (! empty($default)) { - $prompt .= " [" . $default . "]"; - } - $result = readline($prompt . ":"); - if (empty($result) && ! empty($default)) { - $result = $default; - } - return mb_strtolower($result); - } - - public static function getYesNo($prompt = "#", $default = null) - { - $value = null; - $_v = null; - - while (true) { - $_v = self::getInput($prompt); - - if (strtolower($_v) == 'y' || strtolower($_v) == 'yes') { - $value = 1; - break; - } elseif (strtolower($_v) == 'n' || strtolower($_v) == 'no') { - $value = 0; - break; - } else { - if ($_v == '' && $default != null) { - $value = $default; - break; - } else { - echo "Sorry, response " . $_v . " not understood. Please enter 'yes' or 'no'\n"; - $value = null; - continue; - } - } - } - - return $value; - } - - public static function println($msg = "") - { - print $msg . PHP_EOL; - } - - private static function printcolor($msg = "", $color = "0") - { - print "\033[" . $color . "m" . $msg . "\033[0m" . PHP_EOL; - } - - public static function printerr($msg = "") - { - self::printcolor($msg, "31"); - } - - public static function printsucc($msg = "") - { - self::printcolor($msg, "32"); - } - - public static function printwarn($msg = "") - { - self::printcolor($msg, "33"); - } -} diff --git a/lib/Froxlor/Cli/ConfigServices.php b/lib/Froxlor/Cli/ConfigServices.php new file mode 100644 index 00000000..16977eb9 --- /dev/null +++ b/lib/Froxlor/Cli/ConfigServices.php @@ -0,0 +1,475 @@ + (2018-) + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Cron + * + */ +final class ConfigServices extends Command +{ + + protected function configure() + { + $this->setName('froxlor:config-services'); + $this->setDescription('Configure system services'); + $this->addOption('create', 'c', InputOption::VALUE_NONE, 'Create a services list configuration for the --apply option.') + ->addOption('apply', 'a', InputOption::VALUE_REQUIRED, 'Configure your services by given configuration file. To create one run the command with the --create option.') + ->addOption('list', 'l', InputOption::VALUE_NONE, 'Output the services that are going to be configured using a given config file (--apply option). No services will be configured.') + ->addOption('daemon', 'd', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'When used with --apply you can specify one or multiple daemons. These will be the only services that get configured.') + ->addOption('import-settings', 'i', InputOption::VALUE_REQUIRED, 'Import settings from another froxlor installation. This can be done standalone or in addition to --apply.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + global $lng; + + if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) { + $output->writeln("Could not find froxlor's userdata.inc.php file. You should use this script only with an installed froxlor system."); + return self::INVALID; + } + + include_once Froxlor::getInstallDir() . 'lng/english.lng.php'; + include_once Froxlor::getInstallDir() . 'lng/lng_references.php'; + + $result = self::SUCCESS; + + // import settings if given + if ($input->getOption('import-settings')) { + $result = $this->importSettings($input, $output); + } + + if ($result == self::SUCCESS) { + $io = new SymfonyStyle($input, $output); + if ($input->getOption('create')) { + $result = $this->createConfig($input, $output, $io); + } elseif ($input->getOption('apply')) { + $result = $this->applyConfig($input, $output, $io); + } elseif ($input->getOption('list') || $input->getOption('daemon')) { + $output->writeln('Options --list and --daemon only work together with --apply.'); + $result = self::INVALID; + } + } + + return $result; + } + + private function createConfig(InputInterface $input, OutputInterface $output, SymfonyStyle $io) + { + $_daemons_config = array( + 'distro' => "" + ); + + $config_dir = Froxlor::getInstallDir() . '/lib/configfiles/'; + // show list of available distro's + $distros = glob($config_dir . '*.xml'); + // tmp array + $distributions_select_data = array(); + + //set default os. + $os_dist = array('ID' => 'bullseye'); + $os_version = array('0' => '11'); + $os_default = $os_dist['ID']; + + //read os-release + if (file_exists('/etc/os-release')) { + $os_dist = parse_ini_file('/etc/os-release', false); + if (is_array($os_dist) && array_key_exists('ID', $os_dist) && array_key_exists('VERSION_ID', $os_dist)) { + $os_version = explode('.', $os_dist['VERSION_ID'])[0]; + } + } + + // read in all the distros + foreach ($distros as $_distribution) { + // get configparser object + $dist = new \Froxlor\Config\ConfigParser($_distribution); + // get distro-info + $dist_display = $this->getCompleteDistroName($dist); + // store in tmp array + $distributions_select_data[$dist_display] = str_replace(".xml", "", strtolower(basename($_distribution))); + + //guess if this is the current distro. + $ver = explode('.', $dist->distributionVersion)[0]; + if (strtolower($os_dist['ID']) == strtolower($dist->distributionName) && $os_version == $ver) { + $os_default = str_replace(".xml", "", strtolower(basename($_distribution))); + } + } + + // sort by distribution name + ksort($distributions_select_data); + + // list all distributions + $table_rows = []; + $valid_dists = []; + foreach ($distributions_select_data as $name => $filename) { + $table_rows[] = [$filename, $name]; + $valid_dists[] = $filename; + } + $io->table( + ['ID', 'Distribution'], + $table_rows + ); + + $_daemons_config['distro'] = $io->choice('Choose distribution', $valid_dists, $os_default); + + // go through all services and let user check whether to include it or not + $configfiles = new ConfigParser($config_dir . '/' . $_daemons_config['distro'] . ".xml"); + $services = $configfiles->getServices(); + + foreach ($services as $si => $service) { + $output->writeln("--- " . strtoupper($si) . " ---"); + $_daemons_config[$si] = ""; + + $daemons = $service->getDaemons(); + $default_daemon = ""; + $table_rows = []; + $valid_options = []; + foreach ($daemons as $di => $dd) { + $title = $dd->title; + if ($dd->default) { + $default_daemon = $di; + $title = $title . " (default)"; + } + $table_rows[] = [$di, $title]; + $valid_options[] = $di; + } + if ($si != 'system') { + $table_rows[] = ['x', 'No']; + $valid_options[] = 'x'; + } + $io->table( + ['Value', 'Name'], + $table_rows + ); + + $daemons['x'] = 'x'; + if ($si == 'system') { + $_daemons_config[$si] = array(); + // for the system/other services we need a multiple choice possibility + $output->writeln("Select every service you need. Enter empty value when done"); + $sysservice = ""; + do { + $sysservice = $io->ask('Choose service'); + if (!empty($sysservice)) { + $_daemons_config[$si][] = $sysservice; + } + } while (!empty($sysservice)); + // add 'cron' as fixed part (doesn't hurt if it exists) + if (!in_array('cron', $_daemons_config[$si])) { + $_daemons_config[$si][] = 'cron'; + } + } else { + // for all others -> only one value + $_daemons_config[$si] = $io->choice('Choose service', $valid_options, $default_daemon); + } + } + + $daemons_config = json_encode($_daemons_config); + $output_file = $io->ask("Choose output-filename", "/tmp/froxlor-config-" . date('Ymd') . ".json"); + file_put_contents($output_file, $daemons_config); + $output->writeln("Successfully generated service-configfile '" . $output_file . "'"); + $output->writeln([ + "", + "You can now apply this config running:", + "php " . Froxlor::getInstallDir() . "bin/froxlor-cli froxlor:config-services --apply=" . $output_file, + "" + ]); + $proceed = $io->confirm("Do you want to apply the config now?", false); + if ($proceed) { + passthru("php " . Froxlor::getInstallDir() . "bin/froxlor-cli froxlor:config-services --apply=" . $output_file); + } + return self::SUCCESS; + } + + private function applyConfig(InputInterface $input, OutputInterface $output, SymfonyStyle $io) + { + $applyFile = $input->getOption('apply'); + + if (strtoupper(substr($applyFile, 0, 4)) == 'HTTP') { + $output->writeln("Config file seems to be an URL, trying to download"); + $target = "/tmp/froxlor-config-" . time() . ".json"; + if (@file_exists($target)) { + @unlink($target); + } + $this->downloadFile($applyFile, $target); + $applyFile = $target; + } + if (!is_file($applyFile)) { + $output->writeln('Given config file is not a file'); + return self::INVALID; + } elseif (!file_exists($applyFile)) { + $output->writeln('Given config file cannot be found (' . $applyFile . ')'); + return self::INVALID; + } elseif (!is_readable($applyFile)) { + $output->writeln('Given config file cannot be read (' . $applyFile . ')'); + return self::INVALID; + } + + $config = file_get_contents($applyFile); + $decoded_config = json_decode($config, true); + + if ($input->getOption('list') != false) { + $table_rows = []; + foreach ($decoded_config as $service => $daemon) { + if (is_array($daemon) && count($daemon) > 0) { + foreach ($daemon as $sysdaemon) { + $table_rows[] = [$service, $sysdaemon]; + } + } else { + if ($daemon == 'x') { + $daemon = '--- skipped ---'; + } + $table_rows[] = [$service, $daemon]; + } + } + + $io->table( + ['Service', 'Selected daemon'], + $table_rows + ); + return self::SUCCESS; + } + + $only_daemon = []; + if ($input->getOption('daemon') != false) { + $only_daemon = $input->getOption('daemon'); + } + + if (!empty($decoded_config)) { + $config_dir = Froxlor::getInstallDir() . 'lib/configfiles/'; + $configfiles = new ConfigParser($config_dir . '/' . $decoded_config['distro'] . ".xml"); + $services = $configfiles->getServices(); + $replace_arr = $this->getReplacerArray(); + + foreach ($services as $si => $service) { + $output->writeln("--- Configuring: " . strtoupper($si) . " ---"); + if (!isset($decoded_config[$si]) || $decoded_config[$si] == 'x') { + $output->writeln('Skipping ' . strtoupper($si) . ' configuration as desired'); + continue; + } + $daemons = $service->getDaemons(); + foreach ($daemons as $di => $dd) { + // check for desired service + if (($si != 'system' && $decoded_config[$si] != $di) || (is_array($decoded_config[$si]) && !in_array($di, $decoded_config[$si]))) { + continue; + } + $output->writeln("Configuring '" . $di . "'"); + + if (!empty($only_daemon) && !in_array($di, $only_daemon)) { + $output->writeln('Skipping ' . $di . ' configuration as desired'); + continue; + } + // run all cmds + $confarr = $dd->getConfig(); + foreach ($confarr as $action) { + switch ($action['type']) { + case "install": + $output->writeln("Installing required packages"); + $result = null; + passthru(strtr($action['content'], $replace_arr), $result); + if (strlen($result) > 1) { + echo $result; + } + break; + case "command": + exec(strtr($action['content'], $replace_arr)); + break; + case "file": + if (array_key_exists('content', $action)) { + $output->writeln('Creating file "' . $action['name'] . '"'); + file_put_contents($action['name'], trim(strtr($action['content'], $replace_arr))); + } elseif (array_key_exists('subcommands', $action)) { + foreach ($action['subcommands'] as $fileaction) { + if (array_key_exists('execute', $fileaction) && $fileaction['execute'] == "pre") { + exec(strtr($fileaction['content'], $replace_arr)); + } elseif (array_key_exists('execute', $fileaction) && $fileaction['execute'] == "post") { + exec(strtr($fileaction['content'], $replace_arr)); + } elseif ($fileaction['type'] == 'file') { + $output->writeln('Creating file "' . $fileaction['name'] . '"'); + file_put_contents($fileaction['name'], trim(strtr($fileaction['content'], $replace_arr))); + } + } + } + break; + } + } + } + } + // set is_configured flag + Settings::Set('panel.is_configured', '1', true); + // run cronjob at the end to ensure configs are all up to date + exec('php ' . Froxlor::getInstallDir() . 'scripts/froxlor_master_cronjob.php --force'); + // and done + $output->writeln('All services have been configured'); + return self::SUCCESS; + } else { + $output->writeln('Unable to decode given JSON file'); + return self::INVALID; + } + } + + private function getReplacerArray() + { + $customer_tmpdir = '/tmp/'; + if (Settings::Get('system.mod_fcgid') == '1' && Settings::Get('system.mod_fcgid_tmpdir') != '') { + $customer_tmpdir = Settings::Get('system.mod_fcgid_tmpdir'); + } elseif (Settings::Get('phpfpm.enabled') == '1' && Settings::Get('phpfpm.tmpdir') != '') { + $customer_tmpdir = Settings::Get('phpfpm.tmpdir'); + } + + // try to convert namserver hosts to ip's + $ns_ips = ""; + $known_ns_ips = []; + if (Settings::Get('system.nameservers') != '') { + $nameservers = explode(',', Settings::Get('system.nameservers')); + foreach ($nameservers as $nameserver) { + $nameserver = trim($nameserver); + // DNS servers might be multi homed; allow transfer from all ip + // addresses of the DNS server + $nameserver_ips = \Froxlor\PhpHelper::gethostbynamel6($nameserver); + // append dot to hostname + if (substr($nameserver, -1, 1) != '.') { + $nameserver .= '.'; + } + // ignore invalid responses + if (!is_array($nameserver_ips)) { + // act like \Froxlor\PhpHelper::gethostbynamel6() and return unmodified hostname on error + $nameserver_ips = array( + $nameserver + ); + } else { + $known_ns_ips = array_merge($known_ns_ips, $nameserver_ips); + } + if (!empty($ns_ips)) { + $ns_ips .= ','; + } + $ns_ips .= implode(",", $nameserver_ips); + } + } + + // AXFR server + if (Settings::Get('system.axfrservers') != '') { + $axfrservers = explode(',', Settings::Get('system.axfrservers')); + foreach ($axfrservers as $axfrserver) { + if (!in_array(trim($axfrserver), $known_ns_ips)) { + if (!empty($ns_ips)) { + $ns_ips .= ','; + } + $ns_ips .= trim($axfrserver); + } + } + } + + Database::needSqlData(); + $sql = Database::getSqlData(); + + $replace_arr = array( + '' => $sql['user'], + '' => $sql['passwd'], + '' => $sql['db'], + '' => $sql['host'], + '' => isset($sql['socket']) ? $sql['socket'] : null, + '' => Settings::Get('system.hostname'), + '' => Settings::Get('system.ipaddress'), + '' => Settings::Get('system.nameservers'), + '' => $ns_ips, + '' => Settings::Get('system.vmail_homedir'), + '' => Settings::Get('system.vmail_uid'), + '' => Settings::Get('system.vmail_gid'), + '' => (Settings::Get('system.use_ssl') == '1') ? 'imaps pop3s' : '', + '' => FileDir::makeCorrectDir($customer_tmpdir), + '' => Froxlor::getInstallDir(), + '' => FileDir::makeCorrectDir(Settings::Get('system.bindconf_directory')), + '' => Settings::Get('system.apachereload_command'), + '' => FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')), + '' => FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir')), + '' => Settings::Get('system.httpgroup') + ); + return $replace_arr; + } + + private function getCompleteDistroName($cparser) + { + // get distro-info + $dist_display = $cparser->distributionName; + if ($cparser->distributionCodename != '') { + $dist_display .= " " . $cparser->distributionCodename; + } + if ($cparser->distributionVersion != '') { + $dist_display .= " (" . $cparser->distributionVersion . ")"; + } + if ($cparser->deprecated) { + $dist_display .= " [deprecated]"; + } + return $dist_display; + } + + private function importSettings(InputInterface $input, OutputInterface $output) + { + $importFile = $input->getOption('import-settings'); + + if (strtoupper(substr($importFile, 0, 4)) == 'HTTP') { + $output->writeln("Settings file seems to be an URL, trying to download"); + $target = "/tmp/froxlor-import-settings-" . time() . ".json"; + if (@file_exists($target)) { + @unlink($target); + } + $this->downloadFile($importFile, $target); + $importFile = $target; + } + if (!is_file($importFile)) { + $output->writeln('Given settings file is not a file'); + return self::INVALID; + } elseif (!file_exists($importFile)) { + $output->writeln('Given settings file cannot be found (' . $importFile . ')'); + return self::INVALID; + } elseif (!is_readable($importFile)) { + $output->writeln('Given settings file cannot be read (' . $importFile . ')'); + return self::INVALID; + } + $imp_content = file_get_contents($importFile); + SImExporter::import($imp_content); + $output->writeln("Successfully imported settings from '" . $input->getOption('import-settings') . "'"); + return self::SUCCESS; + } + + private function downloadFile($src, $dest) + { + set_time_limit(0); + // This is the file where we save the information + $fp = fopen($dest, 'w+'); + // Here is the file we are downloading, replace spaces with %20 + $ch = curl_init(str_replace(" ", "%20", $src)); + curl_setopt($ch, CURLOPT_TIMEOUT, 50); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + // write curl response to file + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + // get curl response + curl_exec($ch); + curl_close($ch); + fclose($fp); + } +} diff --git a/lib/Froxlor/Cli/ConfigServicesCmd.php b/lib/Froxlor/Cli/ConfigServicesCmd.php deleted file mode 100644 index aec0e7f9..00000000 --- a/lib/Froxlor/Cli/ConfigServicesCmd.php +++ /dev/null @@ -1,79 +0,0 @@ - (2018-) - * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt - * @package Cron - * - */ -class ConfigServicesCmd extends CmdLineHandler -{ - - /** - * list of valid switches - * - * @var array - */ - public static $switches = array( - 'h' - ); - - /** - * list of valid parameters - * - * @var array - */ - public static $params = array( - 'create', - 'apply', - 'import-settings', - 'daemon', - 'list-daemons', - 'froxlor-dir', - 'help' - ); - - public static $action_class = '\\Froxlor\\Cli\\Action\\ConfigServicesAction'; - - public static function printHelp() - { - self::println(""); - self::println("Help / command line parameters:"); - self::println(""); - // commands - self::println("--create\t\tlets you create a services list configuration for the 'apply' command"); - self::println(""); - self::println("--apply\t\t\tconfigure your services by given configuration file. To create one run the --create command"); - self::println("\t\t\tExample: --apply=/path/to/my-config.json or --apply=http://domain.tld/my-config.json"); - self::println(""); - self::println("--list-daemons\t\tOutput the services that are going to be configured using a given config file. No services will be configured."); - self::println("\t\t\tExample: --apply=/path/to/my-config.json --list-daemons"); - self::println(""); - self::println("--daemon\t\tWhen running --apply you can specify a daemon. This will be the only service that gets configured"); - self::println("\t\t\tExample: --apply=/path/to/my-config.json --daemon=apache24"); - self::println(""); - self::println("--import-settings\tImport settings from another froxlor installation. This should be done prior to running --apply or alternatively in the same command together."); - self::println("\t\t\tExample: --import-settings=/path/to/Froxlor_settings-[version]-[dbversion]-[date].json or --import-settings=http://domain.tld/Froxlor_settings-[version]-[dbversion]-[date].json"); - self::println(""); - self::println("--froxlor-dir\t\tpath to froxlor installation"); - self::println("\t\t\tExample: --froxlor-dir=/var/www/froxlor/"); - self::println(""); - self::println("--help\t\t\tshow help screen (this)"); - self::println(""); - // switches - // self::println("-d\t\t\tenable debug output"); - self::println("-h\t\t\tsame as --help"); - self::println(""); - - die(); // end of execution - } -} diff --git a/lib/Froxlor/Cli/PhpSessionclean.php b/lib/Froxlor/Cli/PhpSessionclean.php new file mode 100644 index 00000000..4af9a1dd --- /dev/null +++ b/lib/Froxlor/Cli/PhpSessionclean.php @@ -0,0 +1,88 @@ + (2018-) + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Cron + * + */ +final class PhpSessionclean extends Command +{ + + protected function configure() + { + $this->setName('froxlor:php-sessionclean'); + $this->setDescription('Cleans old php-session files from tmp folder'); + $this->addArgument('max-lifetime', InputArgument::OPTIONAL, 'The number of seconds after which data will be seen as "garbage" and potentially cleaned up. Defaults to "1440"'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) { + $output->writeln("Could not find froxlor's userdata.inc.php file. You should use this script only with an installed froxlor system."); + return self::INVALID; + } + + if ((int) Settings::Get('phpfpm.enabled') == 1) { + if ($input->hasArgument('max-lifetime') && is_numeric($input->getArgument('max-lifetime')) && $input->getArgument('max-lifetime') > 0) { + $this->cleanSessionfiles((int)$input->getArgument('max-lifetime')); + } else { + // use default max-lifetime value + $this->cleanSessionfiles(); + } + return self::SUCCESS; + } + // php-fpm not enabled + $output->writeln('PHP-FPM not enabled for this installation.'); + return self::INVALID; + } + + private function cleanSessionfiles(int $maxlifetime = 1440) + { + // store paths to clean up + $paths_to_clean = []; + // get all pool-config directories configured + $sel_stmt = Database::prepare("SELECT DISTINCT `config_dir` FROM `" . TABLE_PANEL_FPMDAEMONS . "`"); + Database::pexecute($sel_stmt); + while ($fpmd = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) { + $poolfiles = glob(FileDir::makeCorrectFile($fpmd['config_dir'] . '/*.conf')); + foreach ($poolfiles as $cf) { + $contents = file_get_contents($cf); + $pattern = preg_quote('session.save_path', '/'); + $pattern = "/" . $pattern . ".+?\=(.*)/"; + if (preg_match_all($pattern, $contents, $matches)) { + $paths_to_clean[] = FileDir::makeCorrectDir(trim($matches[1][0])); + } + } + } + + // every path is just needed once + $paths_to_clean = array_unique($paths_to_clean); + + if (count($paths_to_clean) > 0) { + foreach ($paths_to_clean as $ptc) { + // find all files older then maxlifetime and delete them + FileDir::safe_exec("find -O3 \"" . $ptc . "\" -ignore_readdir_race -depth -mindepth 1 -name 'sess_*' -type f -cmin \"+" . $maxlifetime . "\" -delete"); + } + } + } +} diff --git a/lib/Froxlor/Cli/PhpSessioncleanCmd.php b/lib/Froxlor/Cli/PhpSessioncleanCmd.php deleted file mode 100644 index 4d83e7c3..00000000 --- a/lib/Froxlor/Cli/PhpSessioncleanCmd.php +++ /dev/null @@ -1,64 +0,0 @@ - (2018-) - * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt - * @package Cron - * - */ -class PhpSessioncleanCmd extends CmdLineHandler -{ - - /** - * list of valid switches - * - * @var array - */ - public static $switches = array( - 'h' - ); - - /** - * list of valid parameters - * - * @var array - */ - public static $params = array( - 'froxlor-dir', - 'max-lifetime', - 'help' - ); - - public static $action_class = '\\Froxlor\\Cli\\Action\\PhpSessioncleanAction'; - - public static function printHelp() - { - self::println(""); - self::println("Help / command line parameters:"); - self::println(""); - // commands - self::println("--froxlor-dir\t\tpath to froxlor installation"); - self::println("\t\t\tExample: --froxlor-dir=/var/www/froxlor/"); - self::println(""); - self::println("--max-lifetime\t\tThe number of seconds after which data will be seen as 'garbage' and potentially cleaned up. Defaults to '1440'"); - self::println("\t\t\tExample: --max-lifetime=2000"); - self::println(""); - self::println("--help\t\t\tshow help screen (this)"); - self::println(""); - // switches - self::println("-h\t\t\tsame as --help"); - self::println(""); - - die(); // end of execution - } -} diff --git a/lib/Froxlor/Cli/SwitchServerIp.php b/lib/Froxlor/Cli/SwitchServerIp.php new file mode 100644 index 00000000..9956f39b --- /dev/null +++ b/lib/Froxlor/Cli/SwitchServerIp.php @@ -0,0 +1,181 @@ + (2018-) + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Cron + * + */ +final class SwitchServerIp extends Command +{ + + protected function configure() + { + $this->setName('froxlor:switch-server-ip'); + $this->setDescription('Easily switch IP addresses e.g. after server migration'); + $this->addOption('switch', 's', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Switch IP-address pair. A pair is separated by comma. For example: --switch=A,B') + ->addOption('list', 'l', InputOption::VALUE_NONE, 'List all IP addresses currently added for this server in froxlor'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) { + $output->writeln("Could not find froxlor's userdata.inc.php file. You should use this script only with an installed froxlor system."); + return self::INVALID; + } + + if ($input->getOption('list') == false && $input->getOption('switch') == false) { + $output->writeln('Either --list or --switch option must be provided. Nothing to do, exiting.'); + return self::INVALID; + } + + $io = new SymfonyStyle($input, $output); + + $result = self::SUCCESS; + + if ($input->getOption('list')) { + + $sel_stmt = Database::prepare("SELECT * FROM panel_ipsandports ORDER BY ip ASC, port ASC"); + Database::pexecute($sel_stmt); + $ips = $sel_stmt->fetchAll(\PDO::FETCH_ASSOC); + $table_rows = []; + foreach ($ips as $ipdata) { + $table_rows[] = [$ipdata['id'], $ipdata['ip'], $ipdata['port']]; + } + + $io->table( + ['#', 'IP address', 'Port'], + $table_rows + ); + } + + if ($input->getOption('switch')) { + $result = $this->switchIPs($input, $output); + } + + return $result; + } + + private function switchIPs(InputInterface $input, OutputInterface $output): int + { + $ip_list = $input->getOption('switch'); + + $has_error = false; + foreach ($ip_list as $ips_combo) { + $ip_pair = explode(",", $ips_combo); + if (count($ip_pair) != 2) { + $output->writeln('Invalid option parameter, not a valid IP address pair.'); + $has_error = true; + } else { + if (filter_var($ip_pair[0], FILTER_VALIDATE_IP) == false) { + $output->writeln('Invalid source ip address: ' . $ip_pair[0] . ''); + $has_error = true; + } + if (filter_var($ip_pair[1], FILTER_VALIDATE_IP) == false) { + $output->writeln('Invalid target ip address: ' . $ip_pair[1] . ''); + $has_error = true; + } + if ($ip_pair[0] == $ip_pair[1] && !$has_error) { + $output->writeln('Source and target ip address are equal'); + $has_error = true; + } + } + $ips_to_switch[] = $ip_pair; + } + if ($has_error) { + return self::FAILURE; + } + + if (count($ips_to_switch) > 0) { + $check_stmt = Database::prepare("SELECT `id` FROM panel_ipsandports WHERE `ip` = :newip"); + $upd_stmt = Database::prepare("UPDATE panel_ipsandports SET `ip` = :newip WHERE `ip` = :oldip"); + + // system.ipaddress + $check_sysip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'ipaddress'"); + $check_sysip = Database::pexecute_first($check_sysip_stmt); + + // system.mysql_access_host + $check_mysqlip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'mysql_access_host'"); + $check_mysqlip = Database::pexecute_first($check_mysqlip_stmt); + + // system.axfrservers + $check_axfrip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'axfrservers'"); + $check_axfrip = Database::pexecute_first($check_axfrip_stmt); + + foreach ($ips_to_switch as $ip_pair) { + $output->writeln('Switching IP ' . $ip_pair[0] . ' to IP ' . $ip_pair[1] . ''); + + $ip_check = Database::pexecute_first($check_stmt, array( + 'newip' => $ip_pair[1] + )); + if ($ip_check) { + $output->writeln('Note: ' . $ip_pair[0] . ' not updated to ' . $ip_pair[1] . ' - IP already exists in froxlor\'s database'); + continue; + } + + Database::pexecute($upd_stmt, array( + 'newip' => $ip_pair[1], + 'oldip' => $ip_pair[0] + )); + $rows_updated = $upd_stmt->rowCount(); + + if ($rows_updated == 0) { + $output->writeln('Note: ' . $ip_pair[0] . ' not updated to ' . $ip_pair[1] . ' (possibly no entry found in froxlor database. Use --list to see what IP addresses are added in froxlor'); + continue; + } + + // check whether the system.ipaddress needs updating + if ($check_sysip['value'] == $ip_pair[0]) { + $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newip WHERE `settinggroup` = 'system' and `varname` = 'ipaddress'"); + Database::pexecute($upd2_stmt, array( + 'newip' => $ip_pair[1] + )); + $output->writeln('Updated system-ipaddress from ' . $ip_pair[0] . ' to ' . $ip_pair[1] . ''); + } + + // check whether the system.mysql_access_host needs updating + if (strstr($check_mysqlip['value'], $ip_pair[0]) !== false) { + $new_mysqlip = str_replace($ip_pair[0], $ip_pair[1], $check_mysqlip['value']); + $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newmysql WHERE `settinggroup` = 'system' and `varname` = 'mysql_access_host'"); + Database::pexecute($upd2_stmt, array( + 'newmysql' => $new_mysqlip + )); + $output->writeln('Updated mysql_access_host from ' . $check_mysqlip['value'] . ' to ' . $new_mysqlip . ''); + } + + // check whether the system.axfrservers needs updating + if (strstr($check_axfrip['value'], $ip_pair[0]) !== false) { + $new_axfrip = str_replace($ip_pair[0], $ip_pair[1], $check_axfrip['value']); + $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newaxfr WHERE `settinggroup` = 'system' and `varname` = 'axfrservers'"); + Database::pexecute($upd2_stmt, array( + 'newaxfr' => $new_axfrip + )); + $output->writeln('Updated axfr-servers from ' . $check_axfrip['value'] . ' to ' . $new_axfrip . ''); + } + } + } + + $output->writeln(""); + $output->writeln("*** ATTENTION *** Remember to replace IP addresses in configuration files if used anywhere."); + $output->writeln("IP addresses updated"); + return self::SUCCESS; + } +} diff --git a/lib/Froxlor/Cli/SwitchServerIpCmd.php b/lib/Froxlor/Cli/SwitchServerIpCmd.php deleted file mode 100644 index 6839b765..00000000 --- a/lib/Froxlor/Cli/SwitchServerIpCmd.php +++ /dev/null @@ -1,68 +0,0 @@ - (2018-) - * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt - * @package Cron - * - */ -class SwitchServerIpCmd extends CmdLineHandler -{ - - /** - * list of valid switches - * - * @var array - */ - public static $switches = array( - 'h' - ); - - /** - * list of valid parameters - * - * @var array - */ - public static $params = array( - 'switch', - 'list', - 'froxlor-dir', - 'help' - ); - - public static $action_class = '\\Froxlor\\Cli\\Action\\SwitchServerIpAction'; - - public static function printHelp() - { - self::println(""); - self::println("Help / command line parameters:"); - self::println(""); - // commands - self::println("--switch\t\tlets you switch ip-address A with ip-address B"); - self::println("\t\t\tExample: --switch=A,B"); - self::println("\t\t\tExample: --switch=\"A1,B1 A2,B2 A3,B3 ...\""); - self::println(""); - self::println("--list\t\t\tshow all currently used ip-addresses in froxlor"); - self::println(""); - self::println("--froxlor-dir\t\tpath to froxlor installation"); - self::println("\t\t\tExample: --froxlor-dir=/var/www/froxlor/"); - self::println(""); - self::println("--help\t\t\tshow help screen (this)"); - self::println(""); - // switches - // self::println("-d\t\t\tenable debug output"); - self::println("-h\t\t\tsame as --help"); - self::println(""); - - die(); // end of execution - } -} diff --git a/lib/Froxlor/Cron/CronConfig.php b/lib/Froxlor/Cron/CronConfig.php index 5233c708..259c869e 100644 --- a/lib/Froxlor/Cron/CronConfig.php +++ b/lib/Froxlor/Cron/CronConfig.php @@ -111,7 +111,7 @@ class CronConfig // php sessionclean if enabled if ((int) Settings::Get('phpfpm.enabled') == 1) { $cronfile .= "# Look for and purge old sessions every 30 minutes" . PHP_EOL; - $cronfile .= "09,39 * * * * root " . $binpath . " " . \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . "/scripts/php-sessionclean.php") . " --froxlor-dir=" . escapeshellarg(\Froxlor\Froxlor::getInstallDir()) . " 1> /dev/null" . PHP_EOL; + $cronfile .= "09,39 * * * * root " . $binpath . " " . \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . "/bin/froxlor-cli") . " froxlor:php-sessionclean 1> /dev/null" . PHP_EOL; } if (\Froxlor\FileDir::isFreeBSD()) { diff --git a/scripts/php-sessionclean.php b/scripts/php-sessionclean.php deleted file mode 100755 index b63100b5..00000000 --- a/scripts/php-sessionclean.php +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/php - (2018-) - * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt - * @package Cron - * - */ - -// Check if we're in the CLI -if (@php_sapi_name() !== 'cli') { - die('This script will only work in the shell.'); -} - -require dirname(__DIR__) . '/vendor/autoload.php'; - -// give control to command line handler -try { - \Froxlor\Cli\PhpSessioncleanCmd::processParameters($argc, $argv); -} catch (Exception $e) { - \Froxlor\Cli\PhpSessioncleanCmd::printerr($e->getMessage()); - exit(1); -} diff --git a/templates/Froxlor/settings/configuration-final.html.twig b/templates/Froxlor/settings/configuration-final.html.twig index f8689f14..7be58716 100644 --- a/templates/Froxlor/settings/configuration-final.html.twig +++ b/templates/Froxlor/settings/configuration-final.html.twig @@ -6,7 +6,7 @@
-
{% endblock %}