<?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>