HEX
Server: Apache
System: Linux info 3.0 #1337 SMP Tue Jan 01 00:00:00 CEST 2000 all GNU/Linux
User: u112718762 (3890930)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: //homepages/oneclick/WordPress/6.9/601/scripts/wrappers/wordpress.php
<?php

namespace Wrappers;

use \Core\WPConfigReader;
use \Factory\Wrapper;
use \Exceptions\DbTableNotFoundException;
use \Core\File;
use \Core\Util;
use \Exception;

class WordPress extends Wrapper
{
    protected $wpTablePrefix;

    protected $wpContentFolders = array(
        "plugins",
        "mu-plugins",
        "themes",
        "uploads",
        "upgrade",
        "languages",
        "ngg",
        "gallery"
    );

    protected $oldWpOptions = array(
        'oneandone_assistant_completed'     => 'ionos_assistant_completed',
        'oneandone_assistant_sitetype'      => 'ionos_assistant_sitetype',
        'assistant_gmarket_panel_dismissed' => 'ionos_assistant_gmarket_panel_dismissed',
        'assistant_editor_panel_dismissed'  => 'ionos_assistant_editor_panel_dismissed',
        'ionos_assistant_market'            => 'ionos_market'
    );

    protected $oldWpCrons = array(
        'oneandone_cron_update_meta_cache',
        'oneandone_cron_cleanup_expired_transients',
        'oneandone_cron_update_deactivated_plugins'
    );

    /**
     * Installation
     */
    public function install()
    {
        $this->ensureWpContentStructure();
        $this->addFavicon();
        $this->createConfig();
        $this->coreInstall();
        $this->setBlogDescription();
        $this->setLanguage();
        $this->setOptions();
        $this->installCustomPlugins();
        $this->activateCustomPlugins();
        $this->rewriteStructure();
        $this->updateInstalledThemes();
        $this->deleteAuxiliaryFiles();
        $this->configureHtaccess();
        $this->generateCodeguardBlacklist();
    }

    /**
     * Domain switch OR
     * Managed -> Standard switch
     */
    public function configure()
    {
        $this->ensureWpContentStructure();
        $this->prepareWPTablePrefix();
        $this->configureCustomPlugins();
        $this->moveOldOptions();
        $this->cleanUpCronJobs();
        $this->removeLogFiles();
        $this->createNewConfigure();
        $this->setLanguage();
        $this->setOptions();
        $this->configureForSSL();
        $this->changeDomain();
        $this->updateAdmin();
        $this->changeWebsiteName();
        $this->configureHtaccess();
        $this->generateCodeguardBlacklist();
    }

    /**
     * WP update (Managed only)
     */
    public function upgrade($from, $to)
    {
        $this->replaceDbConfigurationInWpConfig();
        $this->prepareWPTablePrefix();
        $this->ensureWpContentStructure();
        $this->removeMuPlugins();
        $this->updateCustomPlugins();
        $this->moveOldOptions();
        $this->cleanUpCronJobs();
        $this->removeLogFiles();
        $this->restoreConfig();
        $this->setOptions();
        $this->configureForSSL();
        $this->deleteAuxiliaryFiles();
        $this->doUpgrade();
        $this->generateCodeguardBlacklist();
    }

    /**
     * SSL configuration
     */
    public function ssl()
    {
        $this->prepareWPTablePrefix();
        $this->restoreConfig();
        $this->setOptions();
        $this->configureForSSL();
        $this->searchReplaceSSL();
        $this->configureHtaccess();
    }

    /**
     * Configure .htaccess for SSL
     *
     * @throws Exception
     */
    protected function configureHtaccess()
    {
        if ('https' === $this->baseUrlScheme()) {
            File::writeFile(
                $this->webspace() . '/.htaccess',
                Util::replace(
                    '#BASE_URL_PATH#', $this->baseUrlPath(),
                    File::readFile($this->package() . '/.htaccess_SSL')
                )
            );
        } else if ('http' === $this->baseUrlScheme()) {
            $this->htaccess();
        } else {
            throw new Exception('An unexpected error occurred.');
        }
    }

    /**
     * Copies the CodeGuard blacklist file to the root of the WordPress installation
     */
    protected function generateCodeguardBlacklist()
    {
        if (is_file($this->webspace() . '/.codeguard_blacklist')) {
            unlink($this->webspace() . '/.codeguard_blacklist');
        }
        if ($this->managedMode()) {
            copy(
                $this->package() . '/.codeguard_blacklist',
                $this->webspace() . '/.codeguard_blacklist'
            );
        }
    }

    /**
     * Prepares table prefix to be used in commands
     *
     *
     * order of prefixes:
     *
     * 1. the one from settings: DB_main_PREFIX
     * 2. the one from settings with other keyword: dbPrefix
     * 3. the old prefix from settings: OLD_DB_main_PREFIX
     * 4. the wp-config DB_PREFIX constant
     *
     * @throws DbTableNotFoundException in case all prefix fetching steps fail
     * @throws \Exceptions\ConfigurationException
     */
    protected function prepareWPTablePrefix()
    {
        $optionsTableNames = $this->db->selectOptionsTableNames();

        $this->optionsTableExistsInArray($optionsTableNames);

        $mainDbPrefix = $this->dbPrefix();
        if ($this->isValidPrefix($mainDbPrefix, $optionsTableNames)) {
            $this->wpTablePrefix = $mainDbPrefix;
            return;
        }

        $fallbackDbPrefix = $this->dbPrefixFromFallbackParam();
        if ($this->isValidPrefix($fallbackDbPrefix, $optionsTableNames)) {
            $this->wpTablePrefix = $fallbackDbPrefix;
            return;
        }

        $oldDbPrefix = $this->dbOldPrefix();
        if ($this->isValidPrefix($oldDbPrefix, $optionsTableNames)) {
            $this->wpTablePrefix = $oldDbPrefix;
            return;
        }

        $wpConfigPrefix = $this->getWPConfigPrefix();
        if ($this->isValidPrefix($wpConfigPrefix, $optionsTableNames)) {
            $this->wpTablePrefix = $wpConfigPrefix;
            return;
        }

        $prefixFromOptionTableNames = $this->getPrefixFromOptionsTableNames($optionsTableNames);
        if ($this->isValidPrefix($prefixFromOptionTableNames, $optionsTableNames)) {
            $this->wpTablePrefix = $prefixFromOptionTableNames;
            return;
        }

        throw new DbTableNotFoundException(
            sprintf(
                'could not resolve wp table prefix from [%s => %s, %s => %s, %s => %s, %s=> %s, %s=> %s]',
                'DB_main_PREFIX',
                $mainDbPrefix,
                'dbPrefix',
                $fallbackDbPrefix,
                'OLD_DB_main_PREFIX',
                $oldDbPrefix,
                'WP Config File Prefix',
                $wpConfigPrefix,
                'WP Prefix from option table names',
                $prefixFromOptionTableNames
            )
        );
    }

    /**
     * Insert/update the contract's market value (DE, US, ES, etc.) as option in WP
     * (N.B. given that this value can change over time we call this function
     * every time we do an action on the WP installation)
     */
    protected function setOptions()
    {
        try {
            $this->wpCli('wp option update ionos_market ' . $this->market());

            $installModeOption = $this->managedMode() ? 'managed' : 'standard';
            $this->wpCli('wp option update ionos_install_mode ' . $installModeOption);

        } catch (Exception $e) {
            print('Assistant Market option could not be set');
        }
    }

    /**
     * Checks if given options table name list contains only one value
     *
     * A log warning will be raised in case more than one value is found
     *
     * @param array $optionsTableNames
     *
     * @throws DbTableNotFoundException if given options table name list is empty
     */
    protected function optionsTableExistsInArray(array $optionsTableNames)
    {
        if (empty($optionsTableNames)) {
            throw new DbTableNotFoundException('no options table found in database ' . $this->dbName());
        }
    }

    /**
     * Checks if given prefix is valid by searching it given list of known table names
     *
     * @param string $prefix
     * @param array $tableNames
     *
     * @return bool
     */
    protected function isValidPrefix($prefix, array $tableNames)
    {
        $expectedTableName = $prefix . 'options';
        $isValidPrefix = in_array($expectedTableName, $tableNames);

        return $isValidPrefix;
    }

    /**
     * Copy custom files in a new WP directory structure
     * for WP installation
     *
     * @throws Exception
     */
    protected function installCustomPlugins()
    {
        if ($this->managedMode()) {

            File::copyDirectory(
                $this->package() . '/wp-content/mu-plugins',
                $this->webspace() . '/wp-content/mu-plugins'
            );

            File::copyDirectory(
                $this->package() . '/wp-content/plugins',
                $this->webspace() . '/wp-content/plugins'
            );

            File::copyDirectory(
                $this->package() . '/wp-content/themes',
                $this->webspace() . '/wp-content/themes'
            );

        } else {
            if (!is_dir($this->webspace() . '/wp-content/mu-plugins')) {
                if (false === mkdir($this->webspace() . '/wp-content/mu-plugins', 0777, true)) {
                    throw new Exception('Permission denied.');
                }
            }

            File::copyDirectory(
                $this->package() . '/wp-content/plugins/ionos-performance',
                $this->webspace() . '/wp-content/plugins/ionos-performance'
            );

            copy(
                $this->package() . '/wp-content/mu-plugins/1and1-subdomain.php',
                $this->webspace() . '/wp-content/mu-plugins/1and1-subdomain.php'
            );
        }
    }

    /**
     * Copy custom files in an existing WP directory structure
     * for WP configuration
     */
    protected function configureCustomPlugins()
    {
        if (!$this->managedMode()) {
            $this->removeMuPlugins();

            if (is_dir($this->webspace() . '/wp-content/mu-plugins/ionos-marketplace')) {
                File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/ionos-marketplace');
            }

            if (is_file($this->webspace() . '/wp-content/mu-plugins/ionos-marketplace.php')) {
                unlink($this->webspace() . '/wp-content/mu-plugins/ionos-marketplace.php');
            }

            $plugins = [
                'ionos-navigation',
                'ionos-help-center',
                'ionos-sso'
            ];
            foreach ($plugins as $plugin) {
                if (is_dir($this->webspace() . '/wp-content/plugins/' . $plugin)) {
                    File::removeDirectory($this->webspace() . '/wp-content/plugins/' . $plugin);
                }
            }

            File::copyDirectory(
                $this->package() . '/wp-content/plugins/ionos-assistant',
                $this->webspace() . '/wp-content/plugins/ionos-assistant'
            );
            $this->activatePlugin('ionos-assistant');

            // Remove other Plugins from /mu-plugins/
            if (is_file($this->webspace() . '/wp-content/mu-plugins/1and1-email.php')) {
                unlink($this->webspace() . '/wp-content/mu-plugins/1and1-email.php');
            }
            if (is_dir($this->webspace() . '/wp-content/mu-plugins/tumblr-importer')) {
                File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/tumblr-importer');
            }
            if (is_dir($this->webspace() . '/wp-content/mu-plugins/wordpress-importer')) {
                File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/wordpress-importer');
            }
            if (is_dir($this->webspace() . '/wp-content/mu-plugins/blogger-importer')) {
                File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/blogger-importer');
            }
            if (is_dir($this->webspace() . '/wp-content/mu-plugins/movabletype-importer')) {
                File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/movabletype-importer');
            }
            if (is_dir($this->webspace() . '/wp-content/mu-plugins/rss-importer')) {
                File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/rss-importer');
            }
            if (is_file($this->webspace() . '/wp-content/mu-plugins/1and1-importer-dispatch.php')) {
                unlink($this->webspace() . '/wp-content/mu-plugins/1and1-importer-dispatch.php');
            }
        }

        $this->moveCosyPlugin();
        $this->removeOldPlugins();
    }

    /**
     * Copy custom files in an existing WP directory structure
     * for a WP update
     */
    protected function updateCustomPlugins()
    {
        $performanceInstalled = is_dir($this->webspace() . '/wp-content/plugins/ionos-performance');
        $journeyInstalled = is_dir($this->webspace() . '/wp-content/plugins/ionos-journey');
        $securityInstalled = is_dir($this->webspace() . '/wp-content/plugins/ionos-security');
        $installMuPluginInstalled = is_file($this->webspace() . '/wp-content/mu-plugins/1and1-install.php');

        if ($installMuPluginInstalled) {
            unlink($this->webspace() . '/wp-content/mu-plugins/1and1-install.php');
        }

        if ($this->managedMode()) {
            File::copyDirectory(
                $this->package() . '/wp-content/mu-plugins',
                $this->webspace() . '/wp-content/mu-plugins'
            );

            File::copyDirectory(
                $this->package() . '/wp-content/plugins',
                $this->webspace() . '/wp-content/plugins'
            );

            File::copyDirectory(
                $this->package() . '/wp-content/themes',
                $this->webspace() . '/wp-content/themes'
            );

            if (!$performanceInstalled) {
                File::removeDirectory($this->webspace() . '/wp-content/plugins/ionos-performance');
            }

            if ($performanceInstalled) {
                // Maybe we need to activate the plugin because it was installed for BK with
                // the 6.0.3 update but not activated.
                $this->maybeActivatePerformance();
            }

            if (!$journeyInstalled) {
                File::removeDirectory($this->webspace() . '/wp-content/plugins/ionos-journey');
            }

            if (!$securityInstalled) {
                File::removeDirectory($this->webspace() . '/wp-content/plugins/ionos-security');
            }

            if (is_file($this->webspace() . '/wp-content/plugins/1and1-subdomain.php')) {
                unlink($this->webspace() . '/wp-content/plugins/1and1-subdomain.php');
            }

            if (is_file($this->webspace() . '/wp-content/plugins/1and1-email.php')) {
                unlink($this->webspace() . '/wp-content/plugins/1and1-email.php');
            }

            if (is_file($this->webspace() . '/wp-content/plugins/1and1-importer-dispatch.php')) {
                unlink($this->webspace() . '/wp-content/plugins/1and1-importer-dispatch.php');
            }

            if (is_file($this->webspace() . '/wp-content/plugins/1and1-install.php')) {
                unlink($this->webspace() . '/wp-content/plugins/1and1-install.php');
            }

            $this->moveCosyPlugin();
            $this->removeOldPlugins();
        }
    }

    protected function maybeActivatePerformance()
    {
        $pluginActive = (string) $this->wpCli("wp plugin get ionos-performance --field=status", false);
        if (trim($pluginActive) !== 'inactive') {
            return;
        }

        $activationNoticeOption = (string) $this->wpCli("wp option get ionos_performance_show_activation_admin_notice", false);
        if (trim($activationNoticeOption) !== '1') {
            return;
        }

        $guidedComponentOption = (string) $this->wpCli("wp option get ionos_performance_show_guided_component_activation", false);
        if (trim($guidedComponentOption) !== '1') {
            return;
        }

        $ionosPerformanceOption = json_decode($this->wpCli("wp option get ionos-performance --json", false), true);
        if (!is_array($ionosPerformanceOption)) {
            return;
        }

        if ($ionosPerformanceOption !== array('caching_enabled' => 0)) {
            return;
        }

        $this->wpCli("wp plugin activate ionos-performance");
    }

    /**
     * Remove legacy log files in existing Safe/Managed WP installations
     * (logging was only active in Safe & Managed modes)
     */
    protected function removeLogFiles()
    {
        if (is_dir($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-assistant/log')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-assistant/log');
        }
    }

    /**
     * Move CoSy Plugin to the "normal" plugins folder if installed
     */
    protected function moveCosyPlugin()
    {
        if (is_dir($this->webspace() . '/wp-content/mu-plugins/cosy-address-book')) {
            if (is_file($this->webspace() . '/wp-content/mu-plugins/cosy-address-book.php')) {
                unlink($this->webspace() . '/wp-content/mu-plugins/cosy-address-book.php');
            }

            File::moveDirectory(
                $this->webspace() . '/wp-content/mu-plugins/cosy-address-book',
                $this->webspace() . '/wp-content/plugins/cosy-address-book'
            );

            $this->activatePlugin('cosy-address-book');
        }
    }

    /**
     * Remove legacy plugins which were automatically installed in the old versions
     */
    protected function removeOldPlugins()
    {
        if (is_dir($this->webspace() . '/wp-content/plugins/1and1-wordpress-wizard')) {
            File::removeDirectory($this->webspace() . '/wp-content/plugins/1and1-wordpress-wizard');
        }

        if (is_dir($this->webspace() . '/wp-content/plugins/1and1-wordpress-assistant')) {
            File::removeDirectory($this->webspace() . '/wp-content/plugins/1and1-wordpress-assistant');
        }

        if (is_dir($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-wizard')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-wizard');
        }
        if (is_file($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-wizard.php')) {
            unlink($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-wizard.php');
        }

        if (is_dir($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-assistant')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-assistant');
        }
        if (is_file($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-assistant.php')) {
            unlink($this->webspace() . '/wp-content/mu-plugins/1and1-wordpress-assistant.php');
        }

        if (is_dir($this->webspace() . '/wp-content/mu-plugins/limit-login-attempts')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/limit-login-attempts');
        }
        if (is_file($this->webspace() . '/wp-content/mu-plugins/limit-login-attempts.php')) {
            unlink($this->webspace() . '/wp-content/mu-plugins/limit-login-attempts.php');
        }

        if (is_file($this->webspace() . '/wp-content/mu-plugins/product-domain.php')) {
            unlink($this->webspace() . '/wp-content/mu-plugins/product-domain.php');
        }

        if (is_file($this->webspace() . '/wp-content/mu-plugins/safe-mode.php')) {
            unlink($this->webspace() . '/wp-content/mu-plugins/safe-mode.php');
        }

        if (is_dir($this->webspace() . '/wp-content/mu-plugins/blogger-importer')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/blogger-importer');
        }

        if (is_dir($this->webspace() . '/wp-content/mu-plugins/movabletype-importer')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/movabletype-importer');
        }

        if (is_dir($this->webspace() . '/wp-content/mu-plugins/rss-importer')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/rss-importer');
        }

        if (is_dir($this->webspace() . '/wp-content/mu-plugins/tumblr-importer')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/tumblr-importer');
        }

        if (is_dir($this->webspace() . '/wp-content/mu-plugins/wordpress-importer')) {
            File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/wordpress-importer');
        }

        if (is_file($this->webspace() . '/wp-content/mu-plugins/1and1-importer-dispatch.php')) {
            unlink($this->webspace() . '/wp-content/mu-plugins/1and1-importer-dispatch.php');
        }
    }

    /**
     * Migrate old options
     */
    protected function moveOldOptions()
    {
        foreach ($this->oldWpOptions as $oldOptionName => $newOptionName) {
            try {
                $optionValue = $this->wpCli("wp option get $oldOptionName");
                $this->wpCli("wp option set $newOptionName $optionValue");
                $this->wpCli("wp option delete $oldOptionName");

            } catch (Exception $exception) {
                // If the old option doesn't exist the commands will fail and end up here
                // --> then we just catch the error and do nothing, no migration is needed
            }
        }
    }

    /**
     * Remove schedule from old WP cron jobs
     * since we introduced new one in Assistant 6.0.0
     */
    protected function cleanUpCronJobs()
    {
        foreach ($this->oldWpCrons as $cron) {
            try {
                $this->wpCli("wp cron event delete $cron");
            } catch (Exception $exception) {
                // If the cron job doesn't exist the "delete" command will fail and end up here
                // --> then we just catch the error and do nothing, no cleanup is needed
            }
        }
    }

    /**
     * (Re)Creates the `wp-content` folder structure
     *
     * @return void
     * @see $this->wpContentFolders for required folders
     *
     */
    protected function ensureWpContentStructure()
    {
        foreach ($this->wpContentFolders as $contentFolder) {
            $folder = $this->webspace() . '/wp-content/' . $contentFolder;

            if (!is_dir($folder)) {
                mkdir($folder, 0777, true);
            }
        }
    }

    /**
     * Create a 0x0 favicon file to avoid WordPress redirect to the WP favicon, which costs a lot of runtime
     *
     * @throws Exception
     */
    protected function addFavicon()
    {
        File::writeFile(
            $this->webspace() . '/favicon.ico',
            File::readFile($this->package() . '/favicon.ico')
        );
    }

    /**
     * Generate WP configuration file (wp-config.php)
     * Using our predefined DB credentials
     *
     * @throws Exception
     */
    protected function createConfig()
    {
        $command = "wp core config";

        $args = array(
            'dbname' => $this->dbName(),
            'dbuser' => $this->dbUsername(),
            'dbpass' => $this->dbPasswd(),
            'dbhost' => $this->dbHost(),
            // in creation mode we use the one from ENV
            'dbprefix' => $this->dbPrefix()
        );

        foreach ($args as $argName => $argValue) {
            $command .= " --$argName='$argValue'";
        }

        $this->wpCli($command, true, true, false, true);
        $this->configureForSSL();
    }

    /**
     * Update base & DB data in wp-config.php
     */
    protected function createNewConfigure()
    {
        $this->restoreConfig();
        $this->replaceDbConfigurationInWpConfig();
    }

    /**
     * Add SSL/HTTPS configuration in wp-config.php
     *
     * @throws Exception
     */
    protected function configureForSSL()
    {
        $configure = File::readFile($this->webspace() . '/wp-config.php');

        if ($this->managedMode()) {
            if ('https' === $this->baseUrlScheme()) {

                $configure = Util::replace('<?php',
                    "<?php\n\n" .
                    "define('FS_METHOD', 'direct');\n" .
                    "define('DISALLOW_FILE_EDIT', true);\n" .
                    "define('WP_HOME', 'https://{$this->absoluteUrl()}');\n" .
                    "define('WP_SITEURL', 'https://{$this->absoluteUrl()}');\n" .
                    "define('FORCE_SSL_ADMIN', true);",

                    $configure);

            } else if ('http' === $this->baseUrlScheme()) {

                $configure = Util::replace('<?php',
                    "<?php\n\n" .
                    "define('FS_METHOD', 'direct');\n" .
                    "define('DISALLOW_FILE_EDIT', true);\n" .
                    "define('WP_HOME', 'http://{$this->absoluteUrl()}');\n" .
                    "define('WP_SITEURL', 'http://{$this->absoluteUrl()}');\n",

                    $configure);

            } else {
                throw new Exception('An unexpected error occurred.');
            }
        } else {
            if ('https' === $this->baseUrlScheme()) {
                $configure = Util::replace('<?php',

                    "<?php\n\n" .
                    "define('FS_METHOD', 'direct');\n" .
                    "define('FORCE_SSL_ADMIN', true);",

                    $configure);
            } else if ('http' === $this->baseUrlScheme()) {
                $configure = Util::replace('<?php',

                    "<?php\n\n" .
                    "define('FS_METHOD', 'direct');\n",

                    $configure);
            } else {
                throw new Exception('An unexpected error occurred.');
            }
        }

        File::writeFile($this->webspace() . '/wp-config.php', $configure);
    }

    /**
     * Update base data in wp-config.php
     *
     * @throws Exception
     */
    protected function restoreConfig()
    {
        $wpconfig = File::readFile($this->webspace() . '/wp-config.php');

        $wpconfig = preg_replace($this->regexDeleteLine('WP_HOME'), '', $wpconfig);
        $wpconfig = preg_replace($this->regexDeleteLine('WP_SITEURL'), '', $wpconfig);
        $wpconfig = preg_replace($this->regexDeleteLine('FS_METHOD'), '', $wpconfig);
        $wpconfig = preg_replace($this->regexDeleteLine('DISALLOW_FILE_EDIT'), '', $wpconfig);
        $wpconfig = preg_replace($this->regexDeleteLine('FORCE_SSL_ADMIN'), '', $wpconfig);

        File::writeFile($this->webspace() . '/wp-config.php', $wpconfig);
    }

    /**
     * changes DB_* parameters to new ones from environment in wp-config.php
     *
     * @throws Exception
     */
    protected function replaceDbConfigurationInWpConfig()
    {
        $wpconfig = File::readFile($this->webspace() . '/wp-config.php');

        //define( 'DB_NAME', 'db698661496' );
        $wpconfig = preg_replace($this->getRegexForDefineSearch('DB_NAME'), "define( 'DB_NAME', '" . $this->dbName() . "' );", $wpconfig);
        $wpconfig = preg_replace($this->getRegexForDefineSearch('DB_USER'), "define( 'DB_USER', '" . $this->dbUsername() . "' );", $wpconfig);
        $wpconfig = preg_replace($this->getRegexForDefineSearch('DB_PASSWORD'), "define( 'DB_PASSWORD', '" . $this->dbPasswd() . "' );", $wpconfig);
        $wpconfig = preg_replace($this->getRegexForDefineSearch('DB_HOST'), "define( 'DB_HOST', '" . $this->dbHost() . "' );", $wpconfig);

        File::writeFile($this->webspace() . '/wp-config.php', $wpconfig);
    }

    /**
     * Install WordPress
     */
    protected function coreInstall()
    {
        $command = "wp core install";

        $args = array(
            'url' => $this->escapeShell($this->absoluteUrl()),
            'title' => $this->escapeShell($this->websiteName()),
            'admin_name' => $this->escapeShell($this->username()),
            'admin_password' => $this->escapeShell($this->password()),
            'admin_email' => $this->escapeShell($this->email())
        );

        foreach ($args as $argName => $argValue) {
            $command .= " --$argName=$argValue";
        }

        $this->wpCli($command, true, true, false, true);
    }

    /**
     * Update WP Website/Blog description in the header
     */
    protected function setBlogDescription()
    {
        if ($this->managedMode()) {
            $blogDescription = 'Your story, beautifully told - Created with WordPress managed by IONOS';
            // we use dbPrefix from ENV here because we are triggered from installation
            $query = "UPDATE `{$this->dbPrefix()}options` SET `option_value`='$blogDescription' WHERE `option_name`='blogdescription'";

            $this->db->querySql($query);
        }
    }

    /**
     * Update language
     */
    protected function setLanguage()
    {
        switch ($this->locale()) {
            case 'en_US':
                break;
            case ($this->locale() !== $this->locale('OLD_')):
                try {
                    $this->wpCli("wp core language install '{$this->locale()}' --activate");
                } catch (Exception $language) {
                    print('Language could have not been installed.');
                }
                break;
            case ($this->locale() === $this->locale('OLD_')):
                break;
            default:
                break;
        }

        try {
            $this->wpCli("wp core language update");
        } catch (Exception $language) {
            print('Language could have not been updated.');
        }
    }

    /**
     * Add custom rewrite rule in .htaccess for posts
     * to have a better semantic in the URI
     */
    protected function rewriteStructure()
    {
        $this->wpCli("wp rewrite structure '/%postname%'");
    }

    /**
     * Update themes originally installed with WP, in case
     * they aren't at the last version (ex. twentytwentyone)
     */
    protected function updateInstalledThemes()
    {
        try {
            $this->wpCli("wp theme update --all");
        } catch (Exception $content) {
            print('Some theme could not be updated');
        }
    }

    /**
     * Delete installation wizard after install
     */
    protected function deleteAuxiliaryFiles()
    {
        unlink($this->webspace() . '/wp-content/mu-plugins/1and1-install.php');
    }

    /**
     * Activate an installed plugin
     *
     * @param string $plugin Plugin Slug
     */
    protected function activatePlugin($plugin)
    {
        if (is_dir($this->webspace() . '/wp-content/plugins/' . $plugin)) {
            $this->wpCli("wp plugin activate '$plugin'");
        }
    }

    /**
     * Deactivate an installed plugin
     *
     * @param string $plugin Plugin Slug
     */
    protected function deactivatePlugin($plugin)
    {
        $this->wpCli("wp plugin deactivate '$plugin'");
    }

    /**
     * Activate multiple installed plugins
     *
     * @param string[] $plugins
     */
    protected function activatePlugins(array $plugins)
    {
        foreach ($plugins as $plugin) {
            $this->activatePlugin($plugin);
        }
    }

    /**
     * Deactivate multiple installed plugins
     *
     * @param string[] $plugins
     */
    protected function deactivatePlugins(array $plugins)
    {
        foreach ($plugins as $plugin) {
            $this->deactivatePlugin($plugin);
        }
    }

    /**
     * Automatically activate the Assistant plugin in Standard mode
     * (the plugin is still possible to deactivate/uninstall by the user)
     */
    protected function activateCustomPlugins()
    {
        $this->activatePlugin('ionos-assistant');
        $this->activatePlugin('ionos-journey');
        $this->activatePlugin('ionos-performance');

        if ($this->managedMode()) {
            $this->activatePlugin('ionos-navigation');
            $this->activatePlugin('ionos-sso');
            $this->activatePlugin('ionos-security');
            $this->activatePlugin('ionos-help-center');
        }
    }

    /**
     * Regex to delete a wp-config.php line
     *
     * @param string $key
     *
     * @return string
     */
    protected function regexDeleteLine($key)
    {
        return "/^.*(?:$key).*$(?:\r\n|\n)?/m";
    }

    /**
     * Return a match for a define() line which contains the given key
     * on preg_match() $result[1] should contain value if matching
     *
     * @param $defineKey
     * @return string
     */
    protected function getRegexForDefineSearch($defineKey)
    {
        return "#^define\(.+$defineKey.+,[ ]*'(.+)'[ ]*\);#m";
    }

    /**
     * Update WordPress with a new domain URL
     */
    protected function changeDomain()
    {
        $this->deleteTransients();
        $this->searchReplace($this->domain('OLD_'), $this->domain());
        $this->deleteTransients();
        $this->rewrite();
    }

    /**
     * Update all URLs stored in the WP database with HTTPS
     *
     * @throws Exception
     */
    protected function searchReplaceSSL()
    {
        if ('https' === $this->baseUrlScheme()) {
            $this->searchReplace('http://' . $this->domain(), 'https://' . $this->domain());
            $this->searchReplace('http://www.' . $this->domain(), 'https://www.' . $this->domain());
        } else if ('http' === $this->baseUrlScheme()) {
            $this->searchReplace('https://' . $this->domain(), 'http://' . $this->domain());
            $this->searchReplace('https://www.' . $this->domain(), 'http://www.' . $this->domain());
        } else {
            throw new Exception('An unexpected error occurred.');
        }
    }

    /**
     * Search and replace a string in the WP database
     *
     * @param string $search
     * @param string $replace
     */
    protected function searchReplace($search, $replace)
    {
        $this->wpCli(
            "wp search-replace '$search' '$replace' " .
            "--skip-columns=guid " .
            "--recurse-objects",
            true,
            true,
            false,
            true            
        );
    }

    /**
     * Clean up all transients in the WP database
     */
    protected function deleteTransients()
    {
        $this->wpCli("wp transient delete-all");
    }

    /**
     * Clear cache for rewrite rules
     */
    protected function rewrite()
    {
        $this->wpCli("wp rewrite flush");
    }

    /**
     * Migrate DB
     *
     * @throws Exception
     */
    protected function updateAdmin()
    {
        $sql = File::readFile($this->package() . '/admin.sql');
        $sql = Util::replaces(array(
            '#PREFIX#' => $this->getWpTablePrefix(),
            '#USERNAME#' => $this->username(),
            '#PASSWORD#' => $this->getHash(),
            '#EMAIL#' => $this->email()
        ), $sql);

        $this->db->import($sql);
    }

    /**
     * retrieve the prefix out of first options table name
     *
     * @param array $optionsTableNames
     *
     * @return string
     *
     * @throws DbTableNotFoundException
     */
    protected function getPrefixFromOptionsTableNames(array $optionsTableNames)
    {
        if (count($optionsTableNames) > 1) {
            $error = sprintf(
                '%s no matching prefix and more than one options table found in database %s',
                date('Y/m/d H:i:s'),
                $this->dbName()
            );
            throw new DbTableNotFoundException($error);
        }
        $prefix = str_replace('options', '', reset($optionsTableNames));

        return $prefix;
    }

    /**
     * @return mixed
     */
    protected function getWpTablePrefix()
    {
        return $this->wpTablePrefix;
    }

    /**
     * @return mixed
     */
    protected function getHash()
    {
        require_once $this->webspace() . '/wp-includes/class-phpass.php';

        $hash = new \PasswordHash(8, true);

        return $hash->HashPassword(trim($this->password()));
    }

    /**
     * @return string
     * @throws \Exceptions\ConfigurationException
     */
    protected function getWPConfigPrefix()
    {
        $reader = new WPConfigReader($this->webspace());
        return $reader->getVariableValue('table_prefix');
    }

    /**
     * Update WP Website/Blog name in the header
     */
    protected function changeWebsiteName()
    {
        $this->wpCli("wp option update blogname '{$this->websiteName()}'", true, true, false, true);
    }

    /**
     * Run WP database update after code update
     */
    protected function doUpgrade()
    {
        $this->wpCli("wp core update-db");
    }

    /**
     * Remove plugins that shouldn't reside in mu-plugins anymore
     *
     * @return void
     * @throws Exception
     */
    protected function removeMuPlugins()
    {
        $plugins = array(
            'ionos-assistant',
            'ionos-sso',
            'ionos-navigation',
            'ionos-journey',
            'ionos-performance',
            'ionos-help-center',
        );

        foreach ($plugins as $plugin) {
            if (is_dir($this->webspace() . '/wp-content/mu-plugins/' . $plugin)) {
                File::removeDirectory($this->webspace() . '/wp-content/mu-plugins/' . $plugin);
            }

            if (is_file($this->webspace() . '/wp-content/mu-plugins/' . $plugin . '.php')) {
                unlink($this->webspace() . '/wp-content/mu-plugins/' . $plugin . '.php');
            }
        }
    }
}