= 1024 && $i < count($units) - 1) { $n /= 1024; $i++; } return ($i === 0 ? $n : round($n, 1)) . ' ' . $units[$i]; } // -------------------------------------------------------------------------- // Environment pre-flight checks. Each entry: label, ok, detail, fatal. // -------------------------------------------------------------------------- function preflight_checks($configPath, $schemaPath, $uploadsDir) { $checks = array(); $phpOk = version_compare(PHP_VERSION, '7.4.0', '>='); $checks[] = array( 'label' => 'PHP version 7.4 or newer', 'ok' => $phpOk, 'detail' => $phpOk ? 'Running PHP ' . PHP_VERSION . '.' : 'You are on PHP ' . PHP_VERSION . '. Ask your host to switch the PHP ' . 'version (in cPanel this is "Select PHP Version" / "MultiPHP Manager"), ' . 'or update your local MAMP/XAMPP.', 'fatal' => true, ); $pdo = extension_loaded('pdo_mysql'); $checks[] = array( 'label' => 'PDO MySQL database driver', 'ok' => $pdo, 'detail' => $pdo ? 'The pdo_mysql extension is enabled.' : 'The pdo_mysql extension is missing. Enable it in your PHP settings ' . '(cPanel: "Select PHP Version" → tick "pdo_mysql"; MAMP usually has it on).', 'fatal' => true, ); $canWriteConfig = file_exists($configPath) ? is_writable($configPath) : is_writable(dirname($configPath)); $checks[] = array( 'label' => 'config.php can be written', 'ok' => $canWriteConfig, 'detail' => $canWriteConfig ? (file_exists($configPath) ? 'config.php exists and is writable.' : 'The folder is writable, so config.php can be created.') : 'The web server cannot write to this folder. Set the folder\'s permissions to ' . '755 (and config.php to 644) via your host\'s File Manager or FTP client.', 'fatal' => true, ); $uploadsOk = is_dir($uploadsDir) ? is_writable($uploadsDir) : is_writable(dirname($uploadsDir)); $checks[] = array( 'label' => 'uploads/ folder is writable', 'ok' => $uploadsOk, 'detail' => $uploadsOk ? (is_dir($uploadsDir) ? 'uploads/ exists and is writable.' : 'uploads/ will be created during install.') : 'The uploads/ folder is not writable. Create a folder named "uploads" next to ' . 'this file and set its permissions to 755.', 'fatal' => false, ); $schemaOk = is_file($schemaPath) && is_readable($schemaPath); $checks[] = array( 'label' => 'schema.sql is present', 'ok' => $schemaOk, 'detail' => $schemaOk ? 'Found schema.sql (the database table definitions).' : 'schema.sql is missing. Re-upload it from the project files — the installer ' . 'needs it to create the database tables.', 'fatal' => false, ); $zip = class_exists('ZipArchive'); $checks[] = array( 'label' => 'Zip extension (optional)', 'ok' => $zip, 'detail' => $zip ? 'Zip uploads will work.' : 'The zip extension is off. Everything works except "Upload a zip"; you can ' . 'still upload files and folders. Enable php-zip later if you want it.', 'fatal' => false, ); return $checks; } /** Build the contents of config.php from validated values. */ function build_config_php($v) { $x = function ($s) { return var_export($s, true); }; $lines = array(); $lines[] = 'getMessage(); $code = $e->getCode(); if (stripos($msg, 'Access denied') !== false) { return 'The database refused the username or password. Double-check DB_USER and ' . 'DB_PASS. On cPanel the username is usually your account name plus an ' . 'underscore, like "myacct_code".'; } if (stripos($msg, 'Unknown database') !== false) { return 'The database name was not found. Create the database first (cPanel → ' . '"MySQL Databases"), or tick "Create the database if it does not exist" below ' . 'if your user is allowed to create databases.'; } if (stripos($msg, 'Connection refused') !== false || stripos($msg, "Can't connect") !== false || $code === 2002) { return 'Could not reach the database server at that host. Try "localhost" (most ' . 'shared hosts and MAMP). If MAMP uses a custom port, use "127.0.0.1:8889".'; } if (stripos($msg, 'getaddrinfo') !== false || stripos($msg, 'php_network_getaddresses') !== false) { return 'The database host name could not be resolved. Check DB_HOST for typos; it ' . 'is usually "localhost".'; } return 'Database error: ' . $msg; } // -------------------------------------------------------------------------- // Handle the install submission. // -------------------------------------------------------------------------- $errors = array(); $warnings = array(); $success = false; $results = array(); // Sticky form values (also used to prefill on first load). $f = array( 'db_host' => 'localhost', 'db_name' => '', 'db_user' => '', 'db_pass' => '', 'admin_user' => '', 'base_path' => detect_base_path(), 'max_file' => 25, 'max_zip' => 200, ); if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['do_install'])) { foreach (array('db_host','db_name','db_user','db_pass','admin_user','base_path') as $k) { if (isset($_POST[$k])) { $f[$k] = trim($_POST[$k]); } } $f['max_file'] = isset($_POST['max_file']) ? max(1, (int) $_POST['max_file']) : 25; $f['max_zip'] = isset($_POST['max_zip']) ? max(1, (int) $_POST['max_zip']) : 200; $adminPass = isset($_POST['admin_pass']) ? (string) $_POST['admin_pass'] : ''; $adminPass2 = isset($_POST['admin_pass2']) ? (string) $_POST['admin_pass2'] : ''; $createDb = !empty($_POST['create_db']); $importSchema = !empty($_POST['import_schema']); // Normalise base path: ensure a single leading slash, no trailing slash, or ''. $bp = str_replace('\\', '/', $f['base_path']); $bp = '/' . trim($bp, '/'); $f['base_path'] = ($bp === '/') ? '' : $bp; // ---- Field validation ------------------------------------------------- if ($f['db_name'] === '') { $errors[] = 'Database name is required.'; } if ($f['db_user'] === '') { $errors[] = 'Database username is required.'; } if ($f['admin_user'] === '') { $errors[] = 'Admin username is required.'; } if (strlen($adminPass) < 8) { $errors[] = 'Admin password must be at least 8 characters. Pick something long and hard to guess.'; } elseif ($adminPass !== $adminPass2) { $errors[] = 'The two admin passwords do not match. Re-type them carefully.'; } // ---- Database connection & optional creation -------------------------- $pdo = null; if (!$errors) { try { if ($createDb) { // Connect without a database, create it, then select it. $dsn = 'mysql:host=' . $f['db_host'] . ';charset=utf8mb4'; $pdo = new PDO($dsn, $f['db_user'], $f['db_pass'], array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); $safe = str_replace('`', '', $f['db_name']); $pdo->exec('CREATE DATABASE IF NOT EXISTS `' . $safe . '` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'); $pdo->exec('USE `' . $safe . '`'); $results[] = 'Database "' . h($f['db_name']) . '" is ready.'; } else { $dsn = 'mysql:host=' . $f['db_host'] . ';dbname=' . $f['db_name'] . ';charset=utf8mb4'; $pdo = new PDO($dsn, $f['db_user'], $f['db_pass'], array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); $results[] = 'Connected to the database successfully.'; } } catch (PDOException $e) { $errors[] = friendly_db_error($e); } } // ---- Import the schema ------------------------------------------------ if (!$errors && $pdo && $importSchema) { if (!is_file($SCHEMA_PATH)) { $errors[] = 'schema.sql is missing, so the tables could not be created. Re-upload it and try again.'; } else { try { $sql = file_get_contents($SCHEMA_PATH); $sql = preg_replace('/^\s*--.*$/m', '', $sql); // strip comment lines $parts = array_filter(array_map('trim', explode(';', $sql))); foreach ($parts as $stmt) { $pdo->exec($stmt); } $results[] = 'Database tables created (repositories, files, folders).'; } catch (PDOException $e) { $errors[] = 'Could not create the tables: ' . h($e->getMessage()) . ' — you can also import schema.sql manually via phpMyAdmin.'; } } } // ---- Write config.php ------------------------------------------------- if (!$errors) { $vals = array( 'db_host' => $f['db_host'], 'db_name' => $f['db_name'], 'db_user' => $f['db_user'], 'db_pass' => $f['db_pass'], 'admin_user' => $f['admin_user'], 'admin_hash' => password_hash($adminPass, PASSWORD_DEFAULT), 'base_path' => $f['base_path'], 'site_url' => detect_site_url(), 'max_file' => $f['max_file'], 'max_zip' => $f['max_zip'], ); $written = @file_put_contents($CONFIG_PATH, build_config_php($vals)); if ($written === false) { $errors[] = 'Could not write config.php. Check the folder is writable (permissions 755) ' . 'and try again. Nothing else was changed.'; } else { @chmod($CONFIG_PATH, 0644); $results[] = 'config.php written with your settings.'; } } // ---- Make sure uploads/ exists --------------------------------------- if (!$errors) { if (!is_dir($UPLOADS_DIR)) { if (@mkdir($UPLOADS_DIR, 0755, true)) { $results[] = 'Created the uploads/ folder.'; } else { $warnings[] = 'Could not create the uploads/ folder automatically. Create a folder ' . 'named "uploads" next to install.php (permissions 755) before uploading files.'; } } } // ---- Best-effort: match .htaccess RewriteBase to BASE_PATH ------------ if (!$errors && is_file($HTACCESS) && is_writable($HTACCESS)) { $ht = file_get_contents($HTACCESS); $rewriteBase = ($f['base_path'] === '') ? '/' : $f['base_path'] . '/'; $newHt = preg_replace('/^(\s*RewriteBase\s+).*$/m', '${1}' . $rewriteBase, $ht, 1, $count); if ($count > 0 && $newHt !== null && $newHt !== $ht) { if (@file_put_contents($HTACCESS, $newHt) !== false) { $results[] = 'Updated .htaccess RewriteBase to "' . h($rewriteBase) . '".'; } else { $warnings[] = 'Could not update .htaccess. If pretty URLs 404, set "RewriteBase ' . h($rewriteBase) . '" in .htaccess by hand.'; } } } elseif (!$errors && is_file($HTACCESS)) { $rewriteBase = ($f['base_path'] === '') ? '/' : $f['base_path'] . '/'; $warnings[] = '.htaccess is not writable, so its RewriteBase was left as-is. If pretty URLs ' . '404, set "RewriteBase ' . h($rewriteBase) . '" in .htaccess by hand.'; } if (!$errors) { $success = true; } } // Public login / home URLs for the success screen. $base = $f['base_path']; $loginUrl = ($base === '' ? '' : $base) . '/admin/login.php'; $homeUrl = ($base === '' ? '/' : $base . '/'); $checks = preflight_checks($CONFIG_PATH, $SCHEMA_PATH, $UPLOADS_DIR); $fatalBlock = false; foreach ($checks as $c) { if ($c['fatal'] && !$c['ok']) { $fatalBlock = true; } } $alreadyInstalled = is_file($CONFIG_PATH) && !$success; ?> Install NestEggCode

🎉 Installation complete

NestEggCode is set up. Here is what the installer did:

Go to the admin login →   View the public site →

✅ Post-launch checklist

Run through this to confirm everything works. Once it all checks out, delete install.php (the dashboard will offer to do this for you).

  1. Log in. Open the admin login and sign in with the username and password you just chose.
  2. Create a repository. On the dashboard, add one (e.g. slug demo, name Demo). It should appear in the list.
  3. Upload a file. Click Upload, drop in a small text or code file, and confirm it saves without an error.
  4. Browse it publicly. Visit the home page, open your repo, and click the file — it should show with line numbers and highlighting.
  5. Check a README renders. Upload a README.md; it should render as formatted text on the repo's front page (headings, code blocks, links).
  6. Try Raw & Download. On a file page, both buttons should work.
  7. Confirm secrets are protected. Visit /config.php directly — you should get a "Forbidden" error, not the file contents.
  8. Delete this installer. Return to the dashboard and use the "Remove installer" prompt, or delete install.php via FTP/File Manager.

Tip: also add config.php, uploads/ and *.zip to a .gitignore before pushing this project anywhere public.

Install NestEggCode

This sets up your self-hosted code browser. Have your database name, username and password ready (create the database in your host's control panel first if you can).

Server checks

Database

On shared hosting, create the database and a user in your control panel (cPanel → "MySQL Databases"), then paste those exact values here.

Admin account

The single login for managing repositories. The password is stored as a secure bcrypt hash — never in plain text.

Site settings

Your server also caps uploads via PHP settings (upload_max_filesize is currently , post_max_size ). Raise those in .user.ini or php.ini if you need bigger uploads.

Resolve the failed server checks above to enable this button.

NestEggCode installer · delete install.php when you're done.