<?php
    /**
     * File: install
     * Creates the SQL tables and builds the site configuration.
     */

    header("Content-Type: text/html; charset=UTF-8");

    define('DEBUG',                         true);
    define('CHYRP_VERSION',                 "2024.02");
    define('CHYRP_CODENAME',                "Miombo");
    define('CHYRP_IDENTITY',                "Chyrp/".CHYRP_VERSION." (".CHYRP_CODENAME.")");
    define('MAIN',                          false);
    define('ADMIN',                         false);
    define('AJAX',                          false);
    define('UPGRADING',                     false);
    define('INSTALLING',                    true);
    define('COOKIE_LIFETIME',               2592000);
    define('PASSWORD_RESET_TOKEN_LIFETIME', 3600);
    define('MAX_TIME_LIMIT',                600);
    define('MAX_MEMORY_LIMIT',              "100M");
    define('SQL_DATETIME_ZERO',             "1000-01-01 00:00:00");
    define('SQL_DATETIME_ZERO_VARIANTS',
                                            array(
                                                "0000-00-00 00:00:00",
                                                "0001-01-01 00:00:00",
                                                "1000-01-01 00:00:00"
                                            )
    );
    define('BOT_UA',                        false);
    define('DIR',                           DIRECTORY_SEPARATOR);
    define('MAIN_DIR',                      dirname(__FILE__));
    define('INCLUDES_DIR',                  MAIN_DIR.DIR."includes");
    define('CACHES_DIR',                    INCLUDES_DIR.DIR."caches");
    define('MODULES_DIR',                   MAIN_DIR.DIR."modules");
    define('FEATHERS_DIR',                  MAIN_DIR.DIR."feathers");
    define('THEMES_DIR',                    MAIN_DIR.DIR."themes");
    define('UPDATE_XML',                    null);
    define('UPDATE_INTERVAL',               null);
    define('UPDATE_PAGE',                   null);
    define('SESSION_DENY_BOT',              true);
    define('GET_REMOTE_UNSAFE',             false);
    define('USE_GETTEXT_SHIM',              stripos(PHP_OS, "Win") === 0);
    define('USE_OB',                        true);
    define('HTTP_ACCEPT_DEFLATE',           false);
    define('HTTP_ACCEPT_GZIP',              false);
    define('CAN_USE_ZLIB',                  false);
    define('USE_ZLIB',                      false);
    define('PREVIEWING',                    false);
    define('THEME_DIR',                     null);
    define('THEME_URL',                     null);

    ob_start();
    define('OB_BASE_LEVEL', ob_get_level());

    if (version_compare(PHP_VERSION, "8.0", "<"))
        exit("Chyrp Lite requires PHP 8.0 or greater. Installation cannot continue.");

    # File: error
    # Functions for handling and reporting errors.
    require_once INCLUDES_DIR.DIR."error.php";

    # File: helpers
    # Various functions used throughout the codebase.
    require_once INCLUDES_DIR.DIR."helpers.php";

    # File: Config
    # See Also:
    #     <Config>
    require_once INCLUDES_DIR.DIR."class".DIR."Config.php";

    # File: SQL
    # See Also:
    #     <SQL>
    require INCLUDES_DIR.DIR."class".DIR."SQL.php";

    # File: Model
    # See Also:
    #     <Model>
    require_once INCLUDES_DIR.DIR."class".DIR."Model.php";

    # File: User
    # See Also:
    #     <User>
    require_once INCLUDES_DIR.DIR."model".DIR."User.php";

    # File: Translation
    # See Also:
    #     <Translation>
    require_once INCLUDES_DIR.DIR."class".DIR."Translation.php";

    # Register our autoloader.
    spl_autoload_register("autoload");

    # Boolean: $installed
    # Has Chyrp Lite been installed?
    $installed = false;

    # Prepare the Config interface.
    $config = Config::current();

    # Get the timezone.
    $timezone = get_timezone();

    # Get the locale.
    $locale = get_locale();

    # List of discovered drivers.
    $drivers = array();

    # Currently selected adapter.
    $adapter = isset($_POST['adapter']) ? $_POST['adapter'] : "mysql" ;

    # Where are we?
    $url = preg_replace("/\/install\.php.*$/i", "", guess_url());

    # Set the timezone.
    set_timezone($timezone);

    # Set the locale.
    set_locale($locale);

    # Try to load an appropriate translation.
    load_translator("chyrp", INCLUDES_DIR.DIR."locale");

    # Already installed?
    if (file_exists(INCLUDES_DIR.DIR."config.json.php"))
        redirect($config->url);

    if (class_exists("PDO")) {
        $pdo_available_drivers = PDO::getAvailableDrivers();

        if (in_array("sqlite", $pdo_available_drivers))
            $drivers[] = "sqlite";

        if (in_array("mysql", $pdo_available_drivers))
            $drivers[] = "mysql";

        if (in_array("pgsql", $pdo_available_drivers))
            $drivers[] = "pgsql";
    }

    # Test for basic database access requirements.
    if (empty($drivers))
        alert(
            __("PDO is required for database access."));

    # Test if we can write to MAIN_DIR (needed for the .htaccess file).
    if (!is_writable(MAIN_DIR))
        alert(
            __("Please CHMOD or CHOWN the installation directory to make it writable.")
        );

    # Test if we can write to INCLUDES_DIR (needed for config.json.php).
    if (!is_writable(INCLUDES_DIR))
        alert(
            __("Please CHMOD or CHOWN the <em>includes</em> directory to make it writable.")
        );

    # Test if we can write to CACHES_DIR (needed by some extensions).
    if (!is_writable(CACHES_DIR))
        alert(
            __("Please CHMOD or CHOWN the <em>caches</em> directory to make it writable.")
        );

    # Test if we can write to twig cache.
    if (!is_writable(CACHES_DIR.DIR."twig"))
        alert(
            __("Please CHMOD or CHOWN the <em>twig</em> directory to make it writable.")
        );

    # Test if we can write to thumbs cache.
    if (!is_writable(CACHES_DIR.DIR."thumbs"))
        alert(
            __("Please CHMOD or CHOWN the <em>thumbs</em> directory to make it writable.")
        );

    /**
     * Function: alert
     * Logs an alert message and returns the log to date.
     */
    function alert($message = null): ?array {
        static $log = array();

        if (isset($message))
            $log[] = (string) $message;

        return empty($log) ? null : $log ;
    }

    /**
     * Function: guess_url
     * Returns a best guess of the current URL.
     */
    function guess_url(): string {
        $scheme = (!empty($_SERVER['HTTPS']) and $_SERVER['HTTPS'] !== "off") ?
            "https" :
            "http" ;

        $host = isset($_SERVER['HTTP_HOST']) ?
            $_SERVER['HTTP_HOST'] :
            $_SERVER['SERVER_NAME'] ;

        return $scheme."://".$host.$_SERVER['REQUEST_URI'];
    }

    /**
     * Function: posted
     * Echoes a $_POST value if set, otherwise echoes the fallback value.
     *
     * Parameters:
     *     $key - The key to test in the $_POST array.
     *     $fallback - The value to echo if the $_POST value is not set.
     */
    function posted($key, $fallback = ""): void {
        echo fix(
            isset($_POST[$key]) ? $_POST[$key] : $fallback, true
        );
    }

    /**
     * Function: selected
     * Echoes " selected" HTML attribute if the supplied values are equal.
     *
     * Parameters:
     *     $val1 - Compare this value...
     *     $val2 - ... with this value.
     */
    function selected($val1, $val2): void {
        if ($val1 == $val2)
            echo " selected";
    }

    #---------------------------------------------
    # Output Starts
    #---------------------------------------------
?>
<!DOCTYPE html>
<html dir="auto">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=640">
        <title><?php echo __("Chyrp Lite Installer"); ?></title>
        <style type="text/css">
            @font-face {
                font-family: 'Open Sans webfont';
                src: url('./fonts/OpenSans-Regular.woff') format('woff');
                font-weight: normal;
                font-style: normal;
            }
            @font-face {
                font-family: 'Open Sans webfont';
                src: url('./fonts/OpenSans-SemiBold.woff') format('woff');
                font-weight: 600;
                font-style: normal;
            }
            @font-face {
                font-family: 'Open Sans webfont';
                src: url('./fonts/OpenSans-Bold.woff') format('woff');
                font-weight: bold;
                font-style: normal;
            }
            @font-face {
                font-family: 'Open Sans webfont';
                src: url('./fonts/OpenSans-Italic.woff') format('woff');
                font-weight: normal;
                font-style: italic;
            }
            @font-face {
                font-family: 'Open Sans webfont';
                src: url('./fonts/OpenSans-SemiBoldItalic.woff') format('woff');
                font-weight: 600;
                font-style: italic;
            }
            @font-face {
                font-family: 'Open Sans webfont';
                src: url('./fonts/OpenSans-BoldItalic.woff') format('woff');
                font-weight: bold;
                font-style: italic;
            }
            @font-face {
                font-family: 'Cousine webfont';
                src: url('./fonts/Cousine-Regular.woff') format('woff');
                font-weight: normal;
                font-style: normal;
            }
            @font-face {
                font-family: 'Cousine webfont';
                src: url('./fonts/Cousine-Bold.woff') format('woff');
                font-weight: bold;
                font-style: normal;
            }
            @font-face {
                font-family: 'Cousine webfont';
                src: url('./fonts/Cousine-Italic.woff') format('woff');
                font-weight: normal;
                font-style: italic;
            }
            @font-face {
                font-family: 'Cousine webfont';
                src: url('./fonts/Cousine-BoldItalic.woff') format('woff');
                font-weight: bold;
                font-style: italic;
            }
            :root {
                color-scheme: light dark;
            }
            *::selection {
                color: #ffffff;
                background-color: #ff7f00;
            }
            html, body, div, dl, dt, dd, ul, ol, li, p,
            h1, h2, h3, h4, h5, h6, img, pre, code,
            form, fieldset, input, select, textarea,
            table, tbody, tr, th, td, legend, caption,
            blockquote, aside, figure, figcaption {
                margin: 0em;
                padding: 0em;
                border: 0em;
            }
            html {
                font-size: 16px;
            }
            body {
                font-size: 1rem;
                font-family: "Open Sans webfont", sans-serif;
                line-height: 1.5;
                color: #1f1f23;
                tab-size: 4;
                background: #efefef;
                margin: 2rem;
            }
            h1 {
                font-size: 2em;
                font-weight: bold;
                margin: 1rem 0rem;
                text-align: center;
            }
            h2 {
                font-size: 1.5em;
                text-align: center;
                font-weight: bold;
                margin: 1rem 0rem;
            }
            h3 {
                font-size: 1em;
                font-weight: 600;
                margin: 1rem 0rem;
                border-bottom: 1px solid #cfcfcf;
            }
            p {
                margin-bottom: 1rem;
            }
            strong {
                font: inherit;
                font-weight: bold;
                color: #c11600;
            }
            em, dfn, cite, var {
                font: inherit;
                font-style: italic;
            }
            ul, ol {
                margin-bottom: 1rem;
                margin-inline-start: 2rem;
                list-style-position: outside;
            }
            label {
                display: block;
                font-weight: 600;
            }
            textarea {
                display: block;
                resize: vertical;
            }
            input, select {
                display: inline-block;
            }
            input[type="text"],
            input[type="email"],
            input[type="url"],
            input[type="number"],
            input[type="password"],
            select,
            textarea {
                box-sizing: border-box;
                width: 100%;
                margin: 0rem;
                color: #1f1f23;
                font: inherit;
                font-size: 1.25em;
                padding: 0.5rem;
                border-radius: 0em;
                border: 1px solid #cfcfcf;
                background-color: #ffffff;
            }
            select {
                appearance: none;
                padding-right: 1em;
                background-image: url(admin/images/icons/select.svg);
                background-position: center right 0.1em;
                background-repeat: no-repeat;
            }
            input:invalid,
            textarea:invalid {
                border-color: #ff7f00;
            }
            input[type="text"]:focus,
            input[type="email"]:focus,
            input[type="url"]:focus,
            input[type="number"]:focus,
            input[type="password"]:focus,
            select:focus,
            textarea:focus {
                border-color: #1e57ba;
                outline: #1e57ba solid 2px;
                outline-offset: -2px;
            }
            input[type="text"].error,
            input[type="email"].error,
            input[type="url"].error,
            input[type="number"].error,
            input[type="password"].error,
            textarea.error {
                background-color: #faebe4;
            }
            input[type="text"].error:focus,
            input[type="email"].error:focus,
            input[type="url"].error:focus,
            input[type="number"].error:focus,
            input[type="password"].error:focus,
            textarea.error:focus {
                border: 1px solid #c11600;
                outline-color: #c11600;
            }
            input[type="password"].strong {
                background-color: #ebfae4;
            }
            input[type="password"].strong:focus {
                border: 1px solid #108600;
                outline-color: #108600;
            }
            form:has(#adapter > option[value="sqlite"]:checked) *.not-sqlite {
                display: none;
            }
            form:has(#adapter > option[value="mysql"]:checked) *.not-mysql {
                display: none;
            }
            form:has(#adapter > option[value="pgsql"]:checked) *.not-pgsql {
                display: none;
            }
            pre {
                font-family: "Cousine webfont", monospace;
                font-size: 0.85em;
                background-color: #efefef;
                margin: 1rem 0rem;
                padding: 1rem;
                overflow-x: auto;
                white-space: pre;
            }
            code {
                font-family: "Cousine webfont", monospace;
                font-size: 0.85em;
                background-color: #efefef;
                padding: 0px 2px;
                border: 1px solid #cfcfcf;
                vertical-align: bottom;
                white-space: break-spaces;
            }
            pre > code {
                font-size: 0.85rem;
                display: block;
                border: none;
                padding: 0px;
                white-space: inherit;
            }
            pre.pane {
                height: 15rem;
                overflow: auto;
            }
            pre.pane:empty {
                display: none;
            }
            pre.pane:empty + h1 {
                margin-top: 0rem;
            }
            a:link,
            a:visited {
                color: #1f1f23;
                text-decoration: underline;
                text-underline-offset: 0.125em;
            }
            a:focus {
                outline: #ff7f00 dashed 2px;
                outline-offset: 1px;
            }
            a:hover,
            a:focus,
            a:active {
                color: #1e57ba;
                text-decoration: underline;
                text-underline-offset: 0.125em;
            }
            a.big,
            button {
                box-sizing: border-box;
                display: block;
                clear: both;
                font: inherit;
                font-size: 1.25em;
                text-align: center;
                color: #1f1f23;
                text-decoration: none;
                margin: 1rem 0rem;
                padding: 0.5rem;
                background-color: #f2fbff;
                border: 2px solid #b8cdd9;
                border-radius: 0.25em;
                cursor: pointer;
            }
            button {
                width: 100%;
            }
            a.big:hover,
            button:hover,
            a.big:focus,
            button:focus,
            a.big:active,
            button:active {
                border-color: #1e57ba;
                outline: none;
            }
            hr {
                border: none;
                clear: both;
                border-top: 1px solid #cfcfcf;
                margin: 2rem 0rem;
            }
            aside {
                margin-bottom: 1rem;
                padding: 0.5rem 1rem;
                border: 1px solid #e5d7a1;
                border-radius: 0.25em;
                background-color: #fffde6;
            }
            .window {
                width: 30rem;
                background: #ffffff;
                padding: 2rem;
                margin: 0rem auto 0rem auto;
                border-radius: 2rem;
            }
            .window > *:first-child,
            form > *:first-child {
                margin-top: 0rem;
            }
            .window > *:last-child,
            form > *:last-child {
                margin-bottom: 0rem;
            }
            @media (prefers-color-scheme: dark) {
                body {
                    color: #ffffff;
                    background-color: #1f1f23;
                }
                .window {
                    color: #1f1f23;
                    background-color: #efefef;
                }
                hr {
                    border-color: #afafaf;
                }
                aside {
                    border-color: #afafaf;
                }
                pre {
                    background-color: #dfdfdf;
                }
                code {
                    background-color: #dfdfdf;
                    border-color: #afafaf;
                }
                select,
                textarea,
                input[type="text"],
                input[type="email"],
                input[type="url"],
                input[type="number"],
                input[type="password"] {
                    background-color: #dfdfdf;
                    border-color: #afafaf;
                }
                input:invalid {
                    border-color: #ff7f00;
                }
            }
        </style>
        <script src="includes/common.js" type="text/javascript" charset="UTF-8"></script>
        <script type="text/javascript">
            'use strict';

            $(function() {
                $("#password1").keyup(function(e) {
                    var password = $(this).val();

                    if (passwordStrength(password) > 99)
                        $(this).addClass("strong");
                    else
                        $(this).removeClass("strong");
                });

                $("#password1, #password2").keyup(function(e) {
                    var password1 = $("#password1").val();
                    var password2 = $("#password2").val();

                    if (password1 != "" && password1 != password2)
                        $("#password2").addClass("error");
                    else
                        $("#password2").removeClass("error");
                });

                $("#installer").on("submit", function(e) {
                    var password1 = $("#password1").val();
                    var password2 = $("#password2").val();

                    if (password1 != password2) {
                        e.preventDefault();
                        alert('<?php echo __("Passwords do not match."); ?>');
                    }
                });

                $("#url").keyup(function(e) {
                    var text = $(this).val();

                    if (text != "" && !isURL(text))
                        $(this).addClass("error");
                    else
                        $(this).removeClass("error");
                });

                $("#url").on("change", function(e) {
                    var text = $(this).val();

                    if (isURL(text))
                        $(this).val(addScheme(text));
                });

                $("#email").keyup(function(e) {
                    var text = $(this).val();

                    if (text != "" && !isEmail(text))
                        $(this).addClass("error");
                    else
                        $(this).removeClass("error");
                });

                $("#locale").change(function(e) {
                    $("#installer").submit();
                });
            });
        </script>
    </head>
    <body>
        <div class="window">
            <pre class="pane"><?php

    #---------------------------------------------
    # Installation Starts
    #---------------------------------------------

    if (isset($_POST['install']) and $_POST['install'] == "yes") {
        if (empty($_POST['database']))
            alert(__("Database cannot be blank."));

        if (empty($_POST['url']))
            alert(__("Chyrp URL cannot be blank."));
        elseif (!is_url($_POST['url']))
            alert(__("Invalid Chyrp URL."));

        if (empty($_POST['name']))
            alert(__("Please enter a name for your website."));

        if (empty($_POST['timezone']))
            alert(__("Time zone cannot be blank."));

        if (empty($_POST['locale']))
            alert(__("Language cannot be blank."));

        if (empty($_POST['login']))
            alert(__("Please enter a username for your account."));

        if (empty($_POST['password1']) or empty($_POST['password2']))
            alert(__("Passwords cannot be blank."));
        elseif ($_POST['password1'] != $_POST['password2'])
            alert(__("Passwords do not match."));

        if (empty($_POST['email']))
            alert(__("Email address cannot be blank."));
        elseif (!is_email($_POST['email']))
            alert(__("Invalid email address."));

        if (!alert() and $_POST['adapter'] == "sqlite") {
            $realpath = realpath(dirname($_POST['database']));

            if ($realpath === false)
                alert(__("Could not determine the absolute path to the database."));
            else
                $_POST['database'] = $realpath.DIR.basename($_POST['database']);
        }

        if (!alert() and $_POST['adapter'] == "sqlite")
            if (!is_writable(dirname($_POST['database'])))
                alert(__("Please make the database writable by the server."));

        if (!alert() and $_POST['adapter'] != "sqlite")
            if (empty($_POST['username']) or empty($_POST['password']))
                alert(__("Please enter a username and password for the database."));

        if (!alert()) {
            # Build the SQL settings based on user input.
            $settings = ($_POST['adapter'] == "sqlite") ?
                array(
                    "host"     => "",
                    "port"     => "",
                    "username" => "",
                    "password" => "",
                    "database" => $_POST['database'],
                    "prefix"   => "",
                    "adapter"  => $_POST['adapter']
                )
                :
                array(
                    "host"     => $_POST['host'],
                    "port"     => $_POST['port'],
                    "username" => $_POST['username'],
                    "password" => $_POST['password'],
                    "database" => $_POST['database'],
                    "prefix"   => $_POST['prefix'],
                    "adapter"  => $_POST['adapter']
                )
                ;

            # Configure the SQL interface.
            $sql = SQL::current($settings);

            # Test the database connection.
            if (!$sql->connect(true))
                alert(_f("Database error: %s", fix($sql->error, false, true)));
        }

        if (!alert()) {
            # Reconnect to the database.
            $sql->connect();

            # Posts table.
            $sql->create(
                table:"posts",
                cols:array(
                    "id INTEGER PRIMARY KEY AUTO_INCREMENT",
                    "feather VARCHAR(32) DEFAULT ''",
                    "clean VARCHAR(128) DEFAULT ''",
                    "url VARCHAR(128) DEFAULT ''",
                    "pinned BOOLEAN DEFAULT FALSE",
                    "status VARCHAR(32) DEFAULT 'public'",
                    "user_id INTEGER DEFAULT 0",
                    "created_at DATETIME DEFAULT NULL",
                    "updated_at DATETIME DEFAULT NULL"
                )
            );

            # Post attributes table.
            $sql->create(
                table:"post_attributes",
                cols:array(
                    "post_id INTEGER NOT NULL",
                    "name VARCHAR(100) DEFAULT ''",
                    "value LONGTEXT",
                    "PRIMARY KEY (post_id, name)"
                )
            );

            # Pages table.
            $sql->create(
                table:"pages",
                cols:array(
                    "id INTEGER PRIMARY KEY AUTO_INCREMENT",
                    "title VARCHAR(250) DEFAULT ''",
                    "body LONGTEXT",
                    "public BOOLEAN DEFAULT '1'",
                    "show_in_list BOOLEAN DEFAULT '1'",
                    "list_order INTEGER DEFAULT 0",
                    "clean VARCHAR(128) DEFAULT ''",
                    "url VARCHAR(128) DEFAULT ''",
                    "user_id INTEGER DEFAULT 0",
                    "parent_id INTEGER DEFAULT 0",
                    "created_at DATETIME DEFAULT NULL",
                    "updated_at DATETIME DEFAULT NULL"
                )
            );

            # Users table.
            $sql->create(
                table:"users",
                cols:array(
                    "id INTEGER PRIMARY KEY AUTO_INCREMENT",
                    "login VARCHAR(64) DEFAULT ''",
                    "password VARCHAR(128) DEFAULT ''",
                    "full_name VARCHAR(250) DEFAULT ''",
                    "email VARCHAR(128) DEFAULT ''",
                    "website VARCHAR(128) DEFAULT ''",
                    "group_id INTEGER DEFAULT 0",
                    "approved BOOLEAN DEFAULT '1'",
                    "joined_at DATETIME DEFAULT NULL",
                    "UNIQUE (login)"
                )
            );

            # Groups table.
            $sql->create(
                table:"groups",
                cols:array(
                    "id INTEGER PRIMARY KEY AUTO_INCREMENT",
                    "name VARCHAR(100) DEFAULT ''",
                    "UNIQUE (name)"
                )
            );

            # Permissions table.
            $sql->create(
                table:"permissions",
                cols:array(
                    "id VARCHAR(100) DEFAULT ''",
                    "name VARCHAR(100) DEFAULT ''",
                    "group_id INTEGER DEFAULT 0",
                    "PRIMARY KEY (id, group_id)"
                )
            );

            # Sessions table.
            $sql->create(
                table:"sessions",
                cols:array(
                    "id VARCHAR(40) DEFAULT ''",
                    "data LONGTEXT",
                    "user_id INTEGER DEFAULT 0",
                    "created_at DATETIME DEFAULT NULL",
                    "updated_at DATETIME DEFAULT NULL",
                    "PRIMARY KEY (id)"
                )
            );

            # Define and insert the default permissions.
            $names = array(
                "change_settings" => "Change Settings",
                "toggle_extensions" => "Toggle Extensions",
                "view_site" => "View Site",
                "view_private" => "View Private Posts",
                "view_scheduled" => "View Scheduled Posts",
                "view_draft" => "View Drafts",
                "view_own_draft" => "View Own Drafts",
                "add_post" => "Add Posts",
                "add_draft" => "Add Drafts",
                "edit_post" => "Edit Posts",
                "edit_draft" => "Edit Drafts",
                "edit_own_post" => "Edit Own Posts",
                "edit_own_draft" => "Edit Own Drafts",
                "delete_post" => "Delete Posts",
                "delete_draft" => "Delete Drafts",
                "delete_own_post" => "Delete Own Posts",
                "delete_own_draft" => "Delete Own Drafts",
                "view_page" => "View Pages",
                "add_page" => "Add Pages",
                "edit_page" => "Edit Pages",
                "delete_page" => "Delete Pages",
                "add_user" => "Add Users",
                "edit_user" => "Edit Users",
                "delete_user" => "Delete Users",
                "add_group" => "Add Groups",
                "edit_group" => "Edit Groups",
                "delete_group" => "Delete Groups",
                "import_content" => "Import Content",
                "export_content" => "Export Content"
            );

            # Delete all existing permissions.
            $sql->delete(
                table:"permissions",
                conds:false
            );

            # Insert the new default permissions.
            foreach ($names as $id => $name)
                $sql->insert(
                    table:"permissions",
                    data:array(
                        "id" => $id,
                        "name" => $name,
                        "group_id" => 0
                    )
                );

            # Define and insert the default groups.
            $groups = array(
                "Admin"  => array_keys($names),
                "Member" => array("view_site"),
                "Friend" => array(
                    "view_site",
                    "view_private",
                    "view_scheduled"
                ),
                "Banned" => array(),
                "Guest"  => array("view_site")
            );

            $group_id = array();

            foreach ($groups as $name => $permissions) {
                # Insert the group if it does not exist.
                if (
                    !$sql->count(
                        tables:"groups",
                        conds:array("name" => $name)
                    )
                )
                    $sql->insert(
                        table:"groups",
                        data:array("name" => $name)
                    );

                # Fetch the group's ID for permission creation.
                $group_id[$name] = $sql->select(
                    tables:"groups",
                    fields:"id",
                    conds:array("name" => $name),
                )->fetchColumn();

                # Insert the new permissions for this group.
                foreach ($permissions as $permission)
                    $sql->insert(
                        table:"permissions",
                        data:array(
                            "id" => $permission,
                            "name" => $names[$permission],
                            "group_id" => $group_id[$name]
                        )
                    );
            }

            # Add the admin user account if it does not exist.
            if (
                !$sql->count(
                    tables:"users",
                    conds:array("login" => $_POST['login'])
                )
            )
                $sql->insert(
                    table:"users",
                    data:array(
                        "login" => $_POST['login'],
                        "password" => User::hash_password($_POST['password1']),
                        "email" => $_POST['email'],
                        "group_id" => $group_id["Admin"],
                        "approved" => true,
                        "joined_at" => datetime()
                    )
                );

            # Normalize the Chyrp URL.
            $chyrp_url = rtrim(add_scheme($_POST['url']), "/");

            # Build the configuration file.
            $set = array(
                $config->set("sql", $settings),
                $config->set("name", strip_tags($_POST['name'])),
                $config->set("description", strip_tags($_POST['description'])),
                $config->set("url", $chyrp_url),
                $config->set("chyrp_url", $chyrp_url),
                $config->set("email", $_POST['email']),
                $config->set("timezone", $_POST['timezone']),
                $config->set("locale", $_POST['locale']),
                $config->set("monospace_font", false),
                $config->set("check_updates", true),
                $config->set("check_updates_last", 0),
                $config->set("theme", "blossom"),
                $config->set("posts_per_page", 5),
                $config->set("admin_per_page", 25),
                $config->set("feed_format", "AtomFeed"),
                $config->set("feed_items", 20),
                $config->set("uploads_path", DIR."uploads".DIR),
                $config->set("uploads_limit", 10),
                $config->set("search_pages", false),
                $config->set("send_pingbacks", false),
                $config->set("enable_emoji", true),
                $config->set("enable_markdown", true),
                $config->set("can_register", false),
                $config->set("email_activation", false),
                $config->set("email_correspondence", true),
                $config->set("default_group", $group_id["Member"]),
                $config->set("guest_group", $group_id["Guest"]),
                $config->set("clean_urls", false),
                $config->set("enable_homepage", false),
                $config->set("post_url", "(year)/(month)/(day)/(url)/"),
                $config->set("enabled_modules", array()),
                $config->set("enabled_feathers", array("text")),
                $config->set("routes", array()),
                $config->set("secure_hashkey", random(32))
            );

            if (in_array(false, $set, true))
                error(
                    __("Error"),
                    __("Could not write the configuration file.")
                );

            @unlink(INCLUDES_DIR.DIR."upgrading.lock");
            $installed = true;
        }
    }

    #---------------------------------------------
    # Installation Ends
    #---------------------------------------------

    foreach ((array) alert() as $message)
        echo '<span role="alert">'.sanitize_html($message).'</span>'."\n";

          ?></pre>
<?php if (!$installed): ?>
            <form action="install.php" method="post" accept-charset="UTF-8" id="installer">
                <h1><?php echo __("Database Setup"); ?></h1>
                <p id="adapter_field">
                    <label for="adapter"><?php echo __("Adapter"); ?></label>
                    <select name="adapter" id="adapter">
                        <?php if (in_array("sqlite", $drivers)): ?>
                        <option value="sqlite"<?php selected("sqlite", $adapter); ?>>SQLite</option>
                        <?php endif; ?>
                        <?php if (in_array("mysql", $drivers)): ?>
                        <option value="mysql"<?php selected("mysql", $adapter); ?>>MySQL</option>
                        <?php endif; ?>
                        <?php if (in_array("pgsql", $drivers)): ?>
                        <option value="pgsql"<?php selected("pgsql", $adapter); ?>>PostgreSQL</option>
                        <?php endif; ?>
                    </select>
                </p>
                <p id="host_field" class="not-sqlite">
                    <label for="host"><?php echo __("Host"); ?></label>
                    <input type="text" name="host" value="<?php posted("host", (isset($_ENV['DATABASE_SERVER']) ? $_ENV['DATABASE_SERVER'] : "localhost")); ?>" id="host">
                </p>
                <p id="port_field" class="not-sqlite">
                    <label for="port"><?php echo __("Port"); ?> <span class="sub"><?php echo __("(optional)"); ?></span></label>
                    <input type="text" name="port" value="<?php posted("port"); ?>" id="port">
                </p>
                <p id="username_field" class="not-sqlite">
                    <label for="username"><?php echo __("Username"); ?></label>
                    <input type="text" name="username" value="<?php posted("username"); ?>" id="username">
                </p>
                <p id="password_field" class="not-sqlite">
                    <label for="password"><?php echo __("Password"); ?></label>
                    <input type="password" name="password" value="<?php posted("password"); ?>" id="password">
                </p>
                <p id="database_field">
                    <label for="database"><?php echo __("Database"); ?>
                        <span id="database_sub" class="sub not-mysql not-pgsql">
                            <?php echo __("(absolute or relative path)"); ?>
                        </span>
                    </label>
                    <input type="text" name="database" value="<?php posted("database"); ?>" id="database">
                </p>
                <aside id="db_aside_pgsql" class="not-sqlite not-mysql">
                    <?php echo __("Make sure your PostgreSQL database uses UTF-8 encoding."); ?>
                </aside>
                <aside id="db_aside_mysql" class="not-sqlite not-pgsql">
                    <?php echo __("The collation <code>utf8mb4_general_ci</code> is recommended for your MySQL database."); ?>
                </aside>
                <aside id="db_aside_sqlite" class="not-mysql not-pgsql">
                    <?php echo __("Be sure to put your SQLite database outside the document root directory, otherwise visitors will be able to download it."); ?>
                </aside>
                <p id="prefix_field">
                    <label for="prefix"><?php echo __("Table Prefix"); ?> <span class="sub"><?php echo __("(optional)"); ?></span></label>
                    <input type="text" name="prefix" value="<?php posted("prefix"); ?>" id="prefix">
                </p>
                <h1><?php echo __("Website Setup"); ?></h1>
                <p id="url_field">
                    <label for="url"><?php echo __("Chyrp URL"); ?></label>
                    <input type="url" name="url" value="<?php posted("url", $url); ?>" id="url">
                </p>
                <p id="name_field">
                    <label for="name"><?php echo __("Site Name"); ?></label>
                    <input type="text" name="name" value="<?php posted("name", __("My Awesome Site")); ?>" id="name">
                </p>
                <p id="description_field">
                    <label for="description"><?php echo __("Description"); ?></label>
                    <input type="text" name="description" value="<?php posted("description"); ?>" id="description">
                </p>
                <p id="timezone_field">
                    <label for="timezone"><?php echo __("Time Zone"); ?></label>
                    <select name="timezone" id="timezone">
                    <?php foreach (timezones() as $timezones): ?>
                        <option value="<?php echo $timezones['code']; ?>"<?php selected($timezones['code'], $timezone); ?>>
                            <?php echo $timezones['name']; ?>
                        </option>
                    <?php endforeach; ?>
                    </select>
                </p>
                <p id="locale_field">
                    <label for="locale"><?php echo __("Language"); ?></label>
                    <select name="locale" id="locale">
                        <?php foreach (locales() as $locales): ?>
                            <option value="<?php echo $locales['code']; ?>"<?php selected($locales['code'], $locale); ?>>
                                <?php echo $locales['name']; ?>
                            </option>
                        <?php endforeach; ?>
                    </select>
                </p>
                <h1><?php echo __("Admin Account"); ?></h1>
                <p id="login_field">
                    <label for="login"><?php echo __("Username"); ?></label>
                    <input type="text" name="login" value="<?php posted("login", "Admin"); ?>" id="login" maxlength="64">
                </p>
                <p id="password1_field">
                    <label for="password1"><?php echo __("Password"); ?></label>
                    <input type="password" name="password1" value="<?php posted("password1"); ?>" id="password1" maxlength="128">
                </p>
                <p id="password2_field">
                    <label for="password2"><?php echo __("Password"); ?> <span class="sub"><?php echo __("(again)"); ?></span></label>
                    <input type="password" name="password2" value="<?php posted("password2"); ?>" id="password2" maxlength="128">
                </p>
                <p id="email_field">
                    <label for="email"><?php echo __("Email Address"); ?></label>
                    <input type="email" name="email" value="<?php posted("email"); ?>" id="email" maxlength="128">
                </p>
                <button type="submit" name="install" value="yes"><?php echo __("Install me!"); ?></button>
            </form>
<?php else: ?>
            <h1><?php echo __("Installation Complete"); ?></h1>
            <h2><?php echo __("What now?"); ?></h2>
            <ol>
                <li><?php echo __("Delete <em>install.php</em>, you won't need it anymore."); ?></li>
                <li><?php echo __("Log in to your site and configure things to your liking."); ?></a></li>
            </ol>
            <hr>
            <a class="big" href="<?php echo $config->url.'/'; ?>"><?php echo __("Take me to my site!"); ?></a>
<?php endif; ?>
        </div>
    </body>
</html>