.
 *
 * @category Installation
 * @package  Installation
 *
 * @author   Adrian Lang %s', $req));
                $pass = false;
            }
        }
        // Make sure we have at least one database module available
        $missingExtensions = array();
        foreach (self::$dbModules as $type => $info) {
            if (!$this->checkExtension($info['check_module'])) {
                $missingExtensions[] = $info['check_module'];
            }
        }
        if (count($missingExtensions) == count(self::$dbModules)) {
            $req = implode(', ', $missingExtensions);
            $this->warning(sprintf('Cannot find a database extension. You need at least one of %s.', $req));
            $pass = false;
        }
        // @fixme this check seems to be insufficient with Windows ACLs
        if (!$this->skipConfig && !is_writable(INSTALLDIR)) {
            $this->warning(sprintf('Cannot write config file to: %s
chmod a+w %s', INSTALLDIR));
            $pass = false;
        }
        // Check the subdirs used for file uploads
        // TODO get another flag for this --skipFileSubdirCreation
        if (!$this->skipConfig) {
            $fileSubdirs = array($this->avatarDir, $this->fileDir);
        foreach ($fileSubdirs as $fileSubdir) {
            $fileFullPath = INSTALLDIR."/$fileSubdir";
            if (!file_exists($fileFullPath)) {
                $pass = $pass && mkdir($fileFullPath);
            } elseif (!is_dir($fileFullPath)) {
                $this->warning(sprintf('GNU social expected a directory but found something else on this path: %s', $fileFullPath),
                               'Either make sure it goes to a directory or remove it and a directory will be created.');
                $pass = false;
            } elseif (!is_writable($fileFullPath)) {
                $this->warning(sprintf('Cannot write to %s directory: %s', $fileSubdir, $fileFullPath),
                               sprintf('On your server, try this command: chmod a+w %s', $fileFullPath));
                $pass = false;
            }
        }
        }
        return $pass;
    }
    /**
     * Checks if a php extension is both installed and loaded
     *
     * @param string $name of extension to check
     *
     * @return boolean whether extension is installed and loaded
     */
    function checkExtension($name)
    {
        if (extension_loaded($name)) {
            return true;
        } elseif (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode')) {
            // dl will throw a fatal error if it's disabled or we're in safe mode.
            // More fun, it may not even exist under some SAPIs in 5.3.0 or later...
            $soname = $name . '.' . PHP_SHLIB_SUFFIX;
            if (PHP_SHLIB_SUFFIX == 'dll') {
                $soname = "php_" . $soname;
            }
            return @dl($soname);
        } else {
            return false;
        }
    }
    /**
     * Basic validation on the database paramters
     * Side effects: error output if not valid
     *
     * @return boolean success
     */
    function validateDb()
    {
        $fail = false;
        if (empty($this->host)) {
            $this->updateStatus("No hostname specified.", true);
            $fail = true;
        }
        if (empty($this->database)) {
            $this->updateStatus("No database specified.", true);
            $fail = true;
        }
        if (empty($this->username)) {
            $this->updateStatus("No username specified.", true);
            $fail = true;
        }
        if (empty($this->sitename)) {
            $this->updateStatus("No sitename specified.", true);
            $fail = true;
        }
        return !$fail;
    }
    /**
     * Basic validation on the administrator user paramters
     * Side effects: error output if not valid
     *
     * @return boolean success
     */
    function validateAdmin()
    {
        $fail = false;
        if (empty($this->adminNick)) {
            $this->updateStatus("No initial user nickname specified.", true);
            $fail = true;
        }
        if ($this->adminNick && !preg_match('/^[0-9a-z]{1,64}$/', $this->adminNick)) {
            $this->updateStatus('The user nickname "' . htmlspecialchars($this->adminNick) .
                         '" is invalid; should be plain letters and numbers no longer than 64 characters.', true);
            $fail = true;
        }
        // @fixme hardcoded list; should use Nickname::isValid()
        // if/when it's safe to have loaded the infrastructure here
        $blacklist = array('main', 'panel', 'twitter', 'settings', 'rsd.xml', 'favorited', 'featured', 'favoritedrss', 'featuredrss', 'rss', 'getfile', 'api', 'groups', 'group', 'peopletag', 'tag', 'user', 'message', 'conversation', 'notice', 'attachment', 'search', 'index.php', 'doc', 'opensearch', 'robots.txt', 'xd_receiver.html', 'facebook', 'activity');
        if (in_array($this->adminNick, $blacklist)) {
            $this->updateStatus('The user nickname "' . htmlspecialchars($this->adminNick) .
                         '" is reserved.', true);
            $fail = true;
        }
        if (empty($this->adminPass)) {
            $this->updateStatus("No initial user password specified.", true);
            $fail = true;
        }
        return !$fail;
    }
    /**
     * Make sure a site profile was selected
     *
     * @return type boolean success
     */
    function validateSiteProfile()
    {
        if (empty($this->siteProfile))  {
            $this->updateStatus("No site profile selected.", true);
            return false;
        }
        return true;
    }
    /**
     * Set up the database with the appropriate function for the selected type...
     * Saves database info into $this->db.
     *
     * @fixme escape things in the connection string in case we have a funny pass etc
     * @return mixed array of database connection params on success, false on failure
     */
    function setupDatabase()
    {
        if ($this->db) {
            throw new Exception("Bad order of operations: DB already set up.");
        }
        $this->updateStatus("Starting installation...");
        if (empty($this->password)) {
            $auth = '';
        } else {
            $auth = ":$this->password";
        }
        $scheme = self::$dbModules[$this->dbtype]['scheme'];
        $dsn = "{$scheme}://{$this->username}{$auth}@{$this->host}/{$this->database}";
        $this->updateStatus("Checking database...");
        $conn = $this->connectDatabase($dsn);
        if (!$conn instanceof DB_common) {
            // Is not the right instance
            throw new Exception('Cannot connect to database: ' . $conn->getMessage());
        }
        // ensure database encoding is UTF8
        if ($this->dbtype == 'mysql') {
            // @fixme utf8m4 support for mysql 5.5?
            // Force the comms charset to utf8 for sanity
            // This doesn't currently work. :P
            //$conn->executes('set names utf8');
        } else if ($this->dbtype == 'pgsql') {
            $record = $conn->getRow('SHOW server_encoding');
            if ($record->server_encoding != 'UTF8') {
                $this->updateStatus("GNU social requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
                return false;
            }
        }
        $res = $this->updateStatus("Creating database tables...");
        if (!$this->createCoreTables($conn)) {
            $this->updateStatus("Error creating tables.", true);
            return false;
        }
        foreach (array('sms_carrier' => 'SMS carrier',
                    'notice_source' => 'notice source',
                    'foreign_services' => 'foreign service')
              as $scr => $name) {
            $this->updateStatus(sprintf("Adding %s data to database...", $name));
            $res = $this->runDbScript($scr.'.sql', $conn);
            if ($res === false) {
                $this->updateStatus(sprintf("Can't run %s script.", $name), true);
                return false;
            }
        }
        $db = array('type' => $this->dbtype, 'database' => $dsn);
        return $db;
    }
    /**
     * Open a connection to the database.
     *
     * @param