spotweb/spotweb

View on GitHub
lib/SpotInstall.php

Summary

Maintainability
F
3 days
Test Coverage
<?php

/**
 * Created by PhpStorm.
 * User: root
 * Date: 11/6/16
 * Time: 3:07 PM.
 */
class SpotInstall
{
    public static function showTemplate($tplname, $vars)
    {
        /**
         * Make the variables availbale to the local context.
         */
        extract($vars, EXTR_REFS);

        require_once __DIR__.'/../templates/installer/includes/header.inc.php';
        require_once __DIR__.'/../templates/installer/'.$tplname;
    }

    public static function performAndPrintTests()
    {
        global $settings;
        global $_testInstall_Ok;

        /**
         * Load all the SSL signing code, we need it to create a private key.
         */
        $spotSigning = Services_Signing_Base::factory();
        $privKey = $spotSigning->createPrivateKey($settings['openssl_cnf_path']);

        // We need either one of those 3 extensions, so set the error flag manually.
        if ((!extension_loaded('openssl')) && (!extension_loaded('gmp')) && (!extension_loaded('bcmath'))) {
            $_testInstall_Ok = false;
        }

        /**
         * Try to create the cache directory.
         */
        if (!file_exists(__DIR__.'/../cache')) {
            mkdir(__DIR__.'/../cache', 0777);
        }

        /**
         * Load the template.
         */
        static::showTemplate('step-001.inc.php', ['privKey' => $privKey]);
    }

    public static function askDbSettings()
    {
        global $settings;

        if (!isset($settings['mydb'])) {
            $form = [
                'engine'  => 'pdo_mysql',
                'rootpwd' => '',
                'host'    => 'localhost',
                'port'    => '3306',
                'dbname'  => 'spotweb',
                'schema'  => 'public',
                'user'    => 'spotweb',
                'pass'    => 'spotweb',
                'submit'  => '',
            ];
        } else {
            $form = $settings['mydb'];
            unset($settings['mydb']);
        }

        if (isset($_POST['dbform'])) {
            $form = array_merge($form, $_POST['dbform']);
        }

        /**
         * Did the user press submit? If so, try to
         * connect to the database.
         */
        $databaseCreated = false;
        if ($form['submit'] === 'Verify database') {
            if (($form['engine'] == 'pdo_mysql') and (empty($form['port']))) {
                $form['port'] = '3306';
            }

            if (($form['engine'] == 'pdo_pgsql') and (empty($form['port']))) {
                $form['port'] = '5432';
            }

            try {
                $dbCon = dbeng_abs::getDbFactory($form['engine']);

                if (($form['engine'] == 'pdo_mysql' or $form['engine'] == 'pdo_pgsql') and (!empty($form['rootpwd']))) {
                    $dbCon->connectRoot($form['host'], $form['rootpwd'], $form['port']);
                    $dbCon->createDb($form['dbname'], $form['user'], $form['pass']);
                }

                $dbCon->connect(
                    $form['host'],
                    $form['user'],
                    $form['pass'],
                    $form['dbname'],
                    $form['port'],
                    $form['schema']
                );

                $databaseCreated = true;

                /**
                 * Store the given database settings in the
                 * SESSION object, we need it later to generate
                 * a 'dbsettings.inc.php' file.
                 */
                $_SESSION['spotsettings']['db'] = $form;

                // Call the next stage in the setup.
                static::gotoPage(3);
            } catch (Exception $x) {
                static::showTemplate('fatalerror.inc.php', ['x' => $x]);
            }
        }

        if (!$databaseCreated) {
            static::showTemplate('step-002.inc.php', ['form' => $form]);
        }
    }

    public static function askNntpSettings()
    {
        global $settings;

        // Loading the file directly seems to sometimes result in a weird error. GH issue #1861
        $serverList = simplexml_load_string(file_get_contents(__DIR__.'/../usenetservers.xml'));
        if (!isset($settings['mynntp'])) {
            $form = [
                'name'   => 'custom',
                'host'   => '',
                'user'   => '',
                'pass'   => '',
                'port'   => 119,
                'enc'    => false,
                'submit' => '', 'ssl' => '', 'namefield' => 'custom', 'verifyname'=> 'on',
            ];
        } else {
            $form = $settings['mynntp'];
            unset($settings['mynntp']);
        }

        if (isset($_POST['nntpform'])) {
            //unset($form['verifyname']);
            //$form = array_merge($form, $_POST['nntpform']);
            $form = $_POST['nntpform'];
        }

        /**
         * Did the user press submit? If so, try to
         * connect to the database.
         */
        $nntpVerified = false;
        if (($form['submit'] === 'Verify usenet server') ||
            ($form['submit'] === 'Skip validation')
        ) {
            try {
                /**
                 * Convert the selected NNTP name to an actual
                 * server record.
                 */
                if ($form['name'] == 'custom') {
                    $form['buggy'] = false;
                    $form['hdr'] = $form;
                    $form['nzb'] = $form;
                    $form['post'] = $form;
                    $form['nzb']['port'] = '';
                    $form['nzb']['enc'] = false;
                } else {
                    foreach ($serverList->usenetservers->server as $provider) {
                        if (extension_loaded('openssl') && isset($provider->ssl)) {
                            $server = $provider->ssl;
                        } else {
                            $server = $provider->plain;
                        }

                        if ((string) $provider['name'] == $form['name']) {
                            // Header usenet server
                            $form['hdr']['host'] = (string) $server->header;
                            $form['hdr']['user'] = $form['user'];
                            $form['hdr']['pass'] = $form['pass'];
                            if ((string) $server->header['ssl'] == 'yes') {
                                $form['hdr']['enc'] = 'ssl';
                            } else {
                                $form['hdr']['enc'] = false;
                            }
                            $form['hdr']['port'] = (int) $server->header['port'];
                            $form['hdr']['buggy'] = (bool) $server['buggy'];
                            $form['hdr']['verifyname'] = isset($form['verifyname']);

                            // NZB usenet server
                            $form['nzb']['host'] = (string) $server->nzb;
                            $form['nzb']['user'] = $form['user'];
                            $form['nzb']['pass'] = $form['pass'];
                            if ((string) $server->nzb['ssl'] == 'yes') {
                                $form['nzb']['enc'] = 'ssl';
                            } else {
                                $form['nzb']['enc'] = false;
                            }
                            $form['nzb']['port'] = (int) $server->nzb['port'];
                            $form['nzb']['buggy'] = (bool) $server['buggy'];
                            $form['nzb']['verifyname'] = isset($form['verifyname']);

                            // Posting usenet server
                            $form['post']['host'] = (string) $server->post;
                            $form['post']['user'] = $form['user'];
                            $form['post']['pass'] = $form['pass'];
                            if ((string) $server->post['ssl'] == 'yes') {
                                $form['post']['enc'] = 'ssl';
                            } else {
                                $form['post']['enc'] = false;
                            }
                            $form['post']['port'] = (int) $server->post['port'];
                            $form['post']['buggy'] = (bool) $server['buggy'];
                            $form['post']['verifyname'] = isset($form['verifyname']);
                        }
                    }
                }

                // Try to connect to the usenet server.
                if ($form['submit'] === 'Verify usenet server') {
                    $nntp = new Services_Nntp_Engine($form['hdr']);
                    $nntp->validateServer();
                }

                $nntpVerified = true;
                /**
                 * Store the given NNTP settings in the
                 * SESSION object, we need it later to update
                 * the settings in the database.
                 */
                $_SESSION['spotsettings']['nntp'] = $form;

                /**
                 * Call the next stage in the setup.
                 */
                static::gotoPage(4);
            } catch (Exception $x) {
                static::showTemplate('fatalerror.inc.php', ['x' => $x]);
            }
        }

        if (!$nntpVerified) {
            static::showTemplate('step-003.inc.php', [
                'form'       => $form,
                'nntpVerified' > $nntpVerified,
                'serverList' => $serverList,
            ]);
        }
    }

    public static function askSpotwebSettings()
    {
        global $settings;

        if (!isset($settings['myadminuser'])) {
            $form = [
                'systemtype'   => 'public',
                'username'     => '',
                'newpassword1' => '',
                'newpassword2' => '',
                'firstname'    => '',
                'lastname'     => '',
                'mail'         => '',
                'userid'       => -1,
            ];
        } else {
            $form = $settings['myadminuser'];
            unset($settings['myadminuser']);
        }

        if (isset($_POST['settingsform'])) {
            $form = array_merge($form, $_POST['settingsform']);
        }

        /**
         * Did the user press submit? If so, try to
         * connect to the database.
         */
        if ((isset($form['submit'])) && ($form['submit'] === 'Create system')) {
            try {
                /**
                 * Store the given user settings in the
                 * SESSION object, we need it later to update
                 * the settings in the database.
                 */
                $_SESSION['spotsettings']['adminuser'] = $form;

                /**
                 * Get the schema version and other constants.
                 */
                $bootstrap = new Bootstrap();

                /**
                 * And initiate the user system, this allows us to use
                 * validateUserRecord().
                 */
                $dbsettings = $_SESSION['spotsettings']['db'];
                $dbCon = dbeng_abs::getDbFactory($dbsettings['engine']);
                $dbCon->connect(
                    $dbsettings['host'],
                    $dbsettings['user'],
                    $dbsettings['pass'],
                    $dbsettings['dbname'],
                    $dbsettings['port'],
                    $dbsettings['schema']
                );
                $daoFactory = Dao_Factory::getDAOFactory($dbsettings['engine']);
                $daoFactory->setConnection($dbCon);
                $svcUserRecord = new ServicesValidateUserRecord(
                    $daoFactory,
                    $bootstrap->getSettings($daoFactory, false)
                );
                $errorList = $svcUserRecord->validateUserRecord($form, false)->getErrors();

                if (!empty($errorList)) {
                    throw new Exception($errorList[0]);
                }

                /**
                 * Call the next stage in the setup.
                 */
                static::gotoPage(99);
            } catch (Exception $x) {
                static::showTemplate('fatalerror.inc.php', ['x' => $x]);
            }
        }

        static::showTemplate('step-004.inc.php', [
            'form'         => $form,
        ]);
    }

    public static function createSystem()
    {
        try {
            /**
             * The settings system is used to create a lot of output,
             * we swallow it all.
             */
            ob_start();

            /**
             * Get the schema version and other constants.
             */
            $bootstrap = new Bootstrap();
            $schema = 'public';

            /**
             * Now create the database.
             */
            $dbsettings = $_SESSION['spotsettings']['db'];
            $dbCon = dbeng_abs::getDbFactory($dbsettings['engine']);
            $dbCon->connect(
                $dbsettings['host'],
                $dbsettings['user'],
                $dbsettings['pass'],
                $dbsettings['dbname'],
                $dbsettings['port'],
                $dbsettings['schema']
            );

            $daoFactory = Dao_Factory::getDAOFactory($dbsettings['engine']);
            $daoFactory->setConnection($dbCon);

            /**
             * The database must exist before we can get the Service_Settings_Base instance.
             */
            $dbStruct = SpotStruct_abs::factory($dbsettings['engine'], $daoFactory->getConnection());
            $dbStruct->updateSchema();

            $spotSettings = $bootstrap->getSettings($daoFactory, false);
            $svcUpgradeBase = new Services_Upgrade_Base($daoFactory, $spotSettings, $dbsettings['engine']);

            /**
             * Create all the different settings (only the default) ones.
             */
            $svcUpgradeBase->settings();

            /**
             * Create the users.
             */
            $svcUpgradeBase->users();

            /**
             * print all the output as HTML comment for debugging.
             */
            $dbCreateOutput = ob_get_contents();
            ob_end_clean();

            /**
             * Now it is time to do something with
             * the information the user has given to us.
             */

            /**
             * Update the NNTP settings in the databas.
             */
            $spotSettings->set('nntp_nzb', $_SESSION['spotsettings']['nntp']['nzb']);
            $spotSettings->set('nntp_hdr', $_SESSION['spotsettings']['nntp']['hdr']);
            $spotSettings->set('nntp_post', $_SESSION['spotsettings']['nntp']['post']);

            /**
             * Create the given user.
             */
            $svcUserRecord = new Services_User_Record($daoFactory, $spotSettings);
            $spotUser = $_SESSION['spotsettings']['adminuser'];

            /**
             * and actually add the user.
             */
            $spotUser['userid'] = $svcUserRecord->createUserRecord($spotUser)->getData('userid');

            /**
             * When the new user was created a random password was assigned,
             * so now have to set the supplied password.
             */
            $svcUserRecord->setUserPassword($spotUser);

            // Change the administrators' account password to that of this created user.
            $adminUser = $svcUserRecord->getUser(SPOTWEB_ADMIN_USERID);
            $adminUser['newpassword1'] = $spotUser['newpassword1'];
            $svcUserRecord->setUserPassword($adminUser);

            // Update the settings with our system type and our admin id.
            $spotSettings->set('custom_admin_userid', $spotUser['userid']);
            $spotSettings->set('systemtype', $spotUser['systemtype']);

            // Set the system type.
            $svcUpgradeBase->resetSystemType($spotUser['systemtype']);

            /**
             * Create the necessary database connection information (dbsettings.inc.php).
             */
            $dbConnectionString = '';
            switch ($_SESSION['spotsettings']['db']['engine']) {
                case 'pdo_mysql':
                    $dbConnectionString = static::createDbSettingsFile('pdo_mysql');
                    break;
                case 'pdo_pgsql':
                    $dbConnectionString = static::createDbSettingsFile('pdo_pgsql');
                    break;
                case 'pdo_sqlite':
                    $dbConnectionString = static::createDbSettingsFile('pdo_sqlite');
                    break;
            }

            static::showTemplate(
                'step-final.inc.php',
                [
                    'createdDbSettings'  => file_exists(__DIR__.'/../dbsettings.inc.php'),
                    'dbCreateOutput'     => $dbCreateOutput,
                    'dbConnectionString' => $dbConnectionString,
                ]
            );
        } catch (Exception $x) {
            static::showTemplate('fatalerror.inc.php', ['x' => $x]);
        }
    }

    /**
     * Gets the database connection string.
     *
     * @param string $engine
     *
     * @return string
     */
    public static function createDbSettingsFile($engine)
    {
        $dbSettings = $_SESSION['spotsettings']['db'];
        switch ($_SESSION['spotsettings']['db']['engine']) {
            case 'pdo_pgsql':
                $settings = sprintf(
                    '<?php%1$s%1$s'
                    .'$dbsettings[\'engine\'] = \'%2$s\';%1$s'
                    .'$dbsettings[\'host\'] = \'%3$s\';%1$s'
                    .'$dbsettings[\'dbname\'] = \'%4$s\';%1$s'
                    .'$dbsettings[\'user\'] = \'%5$s\';%1$s'
                    .'$dbsettings[\'pass\'] = \'%6$s\';%1$s'
                    .'$dbsettings[\'port\'] = \'%7$s\';%1$s'
                    .'$dbsettings[\'schema\'] = \'%8$s\';%1$s',
                    PHP_EOL,
                    $engine,
                    $dbSettings['host'],
                    $dbSettings['dbname'],
                    $dbSettings['user'],
                    $dbSettings['pass'],
                    $dbSettings['port'],
                    $dbSettings['schema']
                );
                break;
            case 'pdo_mysql':
            case 'pdo_sqlite':
                $settings = sprintf(
                    '<?php%1$s%1$s'
            .'$dbsettings[\'engine\'] = \'%2$s\';%1$s'
            .'$dbsettings[\'host\'] = \'%3$s\';%1$s'
            .'$dbsettings[\'dbname\'] = \'%4$s\';%1$s'
            .'$dbsettings[\'user\'] = \'%5$s\';%1$s'
            .'$dbsettings[\'pass\'] = \'%6$s\';%1$s'
            .'$dbsettings[\'port\'] = \'%7$s\';%1$s'
            .'$dbsettings[\'schema\'] = \'\';',
                    PHP_EOL,
                    $engine,
                    $dbSettings['host'],
                    $dbSettings['dbname'],
                    $dbSettings['user'],
                    $dbSettings['pass'],
                    $dbSettings['port']
                );
                break;
        }

        if (is_writable(__DIR__.'/../')) {
            file_put_contents(
                __DIR__.'/../dbsettings.inc.php',
                $settings
            );
        }

        return $settings;
    }

    public static function returnBytes($val)
    {
        $val = trim($val);
        $last = strtolower($val[strlen($val) - 1]);
        $val = filter_var($val, FILTER_SANITIZE_NUMBER_INT);
        switch ($last) {
            // The 'G' modifier is available since PHP 5.1.0
            case 'g':
                $val *= 1024 * 1024 * 1024;
                break;
            case 'm':
                $val *= 1024 * 1024;
                break;
            case 'k':
                $val *= 1024;
                break;
        }

        return $val;
    }

    public static function showResult($b, $isRequired, $okMsg = '', $nokMsg = '')
    {
        global $_testInstall_Ok;

        if ($b) {
            echo 'OK';
            if (!empty($okMsg)) {
                echo ' ('.$okMsg.')';
            }
        } else {
            echo 'NOT OK';
            if (!empty($nokMsg)) {
                echo ' ('.$nokMsg.')';
            }

            if ($isRequired) {
                $_testInstall_Ok = true;
            }
        }

        return null;
    }

    /**
     * Callback for set_error_handler.
     *
     * @param int    $number
     * @param string $message
     * @param string $file
     * @param string $line
     * @param array  $context
     *
     * @return bool False, when the default error handler should take over and true when we handled it ourself.
     */
    public static function ownWarning($number, $message, $file, $line, array $context = [])
    {
        // don't show errors if they are being suppressed by silent (@) operator.
        if (error_reporting() === 0) {
            return false;
        }

        $GLOBALS['iserror'] = true;
        error_log($message);
        echo $message;

        return true;
    }

    public static function testInclude($filename)
    {
        if (!file_exists($filename)) {
            return false;
        }

        require_once $filename;

        return dirname(realpath($filename));
    }

    /**
     * Goes to the one of the installation pages.
     *
     * @param int $number
     */
    public static function gotoPage($number)
    {
        header(
            sprintf(
                'Location: %s?page=%u',
                $_SERVER['SCRIPT_NAME'],
                $number
            )
        );
    }
}