This commit is contained in:
Flatlogic Bot 2026-05-17 16:07:02 +00:00
parent 5905eaa8ce
commit 88752efa83
7 changed files with 377 additions and 209 deletions

View File

@ -1,8 +1,14 @@
<?php
declare(strict_types=1);
const DB_MANUAL_CONFIG_FILE = __DIR__ . '/database.php';
const DB_INSTALLER_CONFIG_FILE = __DIR__ . '/installer-config.php';
function db_manual_config_relative_path(): string
{
return 'db/database.php';
}
function db_normalize_settings(array $settings): array
{
$host = trim((string)($settings['DB_HOST'] ?? ''));
@ -20,6 +26,76 @@ function db_normalize_settings(array $settings): array
];
}
function db_export_settings_file(array $settings): string
{
$settings = db_normalize_settings($settings);
$payload = "<?php
";
$payload .= "declare(strict_types=1);
";
$payload .= "/**
";
$payload .= " * Konfigurasi database manual.
";
$payload .= " * Isi file ini langsung saat upload ke cPanel/shared hosting.
";
$payload .= " * Untuk cPanel, DB_NAME dan DB_USER biasanya memakai prefix akun.
";
$payload .= " */
";
$payload .= 'return ' . var_export([
'DB_HOST' => $settings['DB_HOST'],
'DB_PORT' => $settings['DB_PORT'],
'DB_NAME' => $settings['DB_NAME'],
'DB_USER' => $settings['DB_USER'],
'DB_PASS' => $settings['DB_PASS'],
], true) . ";
";
return $payload;
}
function db_read_settings_file(string $path): array
{
static $cache = [];
if (array_key_exists($path, $cache)) {
return $cache[$path];
}
$result = [
'settings' => db_normalize_settings([]),
'error' => null,
];
if (!is_file($path)) {
$cache[$path] = $result;
return $result;
}
try {
$loaded = include $path;
} catch (Throwable $exception) {
$result['error'] = $exception->getMessage();
$cache[$path] = $result;
return $result;
}
if (!is_array($loaded)) {
$result['error'] = 'Format file konfigurasi harus return array.';
$cache[$path] = $result;
return $result;
}
$result['settings'] = db_normalize_settings($loaded);
$cache[$path] = $result;
return $result;
}
function db_env_settings(): array
{
$settings = [];
@ -34,23 +110,24 @@ function db_env_settings(): array
return db_normalize_settings($settings);
}
function db_local_settings(): array
function db_manual_settings(): array
{
static $settings = null;
return db_read_settings_file(DB_MANUAL_CONFIG_FILE)['settings'];
}
if (is_array($settings)) {
return $settings;
}
function db_manual_settings_error(): ?string
{
return db_read_settings_file(DB_MANUAL_CONFIG_FILE)['error'];
}
if (!is_file(DB_INSTALLER_CONFIG_FILE)) {
$settings = db_normalize_settings([]);
return $settings;
}
function db_legacy_installer_settings(): array
{
return db_read_settings_file(DB_INSTALLER_CONFIG_FILE)['settings'];
}
$loaded = include DB_INSTALLER_CONFIG_FILE;
$settings = is_array($loaded) ? db_normalize_settings($loaded) : db_normalize_settings([]);
return $settings;
function db_legacy_installer_settings_error(): ?string
{
return db_read_settings_file(DB_INSTALLER_CONFIG_FILE)['error'];
}
function db_settings_complete(array $settings): bool
@ -68,33 +145,24 @@ function db_resolved_settings(): array
return $settings;
}
$env = db_env_settings();
$local = db_local_settings();
$envComplete = db_settings_complete($env);
$localComplete = db_settings_complete($local);
if ($envComplete && $localComplete) {
$error = null;
if (db_test_connection($env, true, $error)) {
$env['__source'] = 'env';
$settings = $env;
return $settings;
}
$local['__source'] = 'file';
$settings = $local;
$manual = db_manual_settings();
if (db_settings_complete($manual)) {
$manual['__source'] = 'manual_file';
$settings = $manual;
return $settings;
}
if ($envComplete) {
$env = db_env_settings();
if (db_settings_complete($env)) {
$env['__source'] = 'env';
$settings = $env;
return $settings;
}
if ($localComplete) {
$local['__source'] = 'file';
$settings = $local;
$legacy = db_legacy_installer_settings();
if (db_settings_complete($legacy)) {
$legacy['__source'] = 'legacy_installer_file';
$settings = $legacy;
return $settings;
}
@ -117,6 +185,21 @@ function db_config_source(): string
return db_resolved_settings()['__source'] ?? 'missing';
}
function db_configuration_problem(): ?string
{
$manualError = db_manual_settings_error();
if ($manualError !== null) {
return 'Ada error di file ' . db_manual_config_relative_path() . ': ' . $manualError;
}
$legacyError = db_legacy_installer_settings_error();
if ($legacyError !== null) {
return 'Ada error di file lama db/installer-config.php: ' . $legacyError;
}
return null;
}
function db_has_required_config(): bool
{
return db_settings_complete(db_resolved_settings());
@ -185,7 +268,7 @@ function db(): PDO
}
if (!db_has_required_config()) {
throw new RuntimeException('Database belum dikonfigurasi.');
throw new RuntimeException('Database belum dikonfigurasi. Isi file ' . db_manual_config_relative_path() . '.');
}
$pdo = db_create_pdo(db_resolved_settings(), true);
@ -226,21 +309,9 @@ function db_create_database_if_missing(array $settings): void
function db_save_local_settings(array $settings): void
{
$settings = db_normalize_settings($settings);
$payload = "<?php
";
$payload .= "declare(strict_types=1);
$payload = db_export_settings_file($settings);
";
$payload .= 'return ' . var_export([
'DB_HOST' => $settings['DB_HOST'],
'DB_PORT' => $settings['DB_PORT'],
'DB_NAME' => $settings['DB_NAME'],
'DB_USER' => $settings['DB_USER'],
'DB_PASS' => $settings['DB_PASS'],
], true) . ";
";
$bytes = file_put_contents(DB_INSTALLER_CONFIG_FILE, $payload, LOCK_EX);
$bytes = file_put_contents(DB_MANUAL_CONFIG_FILE, $payload, LOCK_EX);
if ($bytes === false) {
throw new RuntimeException('Gagal menyimpan file konfigurasi database. Pastikan folder db bisa ditulis.');
}

16
db/database.php Normal file
View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
/**
* Konfigurasi database manual.
* Isi file ini langsung saat upload ke cPanel/shared hosting.
* Untuk cPanel, DB_NAME dan DB_USER biasanya memakai prefix akun.
*/
return [
'DB_HOST' => 'localhost',
'DB_PORT' => '3306',
'DB_NAME' => '',
'DB_USER' => '',
'DB_PASS' => '',
];

View File

@ -13,7 +13,10 @@ if (empty($status['ready'])) {
'php_version' => PHP_VERSION,
'time_utc' => gmdate('c'),
'db' => 'setup_required',
'source' => $status['source'] ?? 'missing',
'config_path' => db_manual_config_relative_path(),
'message' => $status['message'],
'details' => $status['details'],
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
exit;
}
@ -29,6 +32,7 @@ try {
'time_utc' => gmdate('c'),
'posts' => $count,
'db' => 'ok',
'source' => $status['source'] ?? 'unknown',
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
} catch (Throwable $exception) {
http_response_code(503);

View File

@ -156,7 +156,7 @@ function site_installation_status(): array
if (!db_has_required_config()) {
$status['message'] = 'Koneksi database belum diatur.';
$status['details'] = 'Masukkan host, port, nama database, username, dan password di installer.';
$status['details'] = db_configuration_problem() ?: ('Isi host, port, nama database, username, dan password di file ' . db_manual_config_relative_path() . '.');
return $status;
}
@ -173,6 +173,169 @@ function site_installation_status(): array
return $status;
}
function render_manual_database_setup_screen(array $status): void
{
$configPath = db_manual_config_relative_path();
$exampleConfig = db_export_settings_file([
'DB_HOST' => 'localhost',
'DB_PORT' => '3306',
'DB_NAME' => 'usernamecpanel_namadb',
'DB_USER' => 'usernamecpanel_userdb',
'DB_PASS' => 'password_database',
]);
http_response_code(503);
header('Content-Type: text/html; charset=utf-8');
?>
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= e(project_name()) ?> - Setup Database Manual</title>
<meta name="description" content="Isi file <?= e($configPath) ?> secara manual untuk menghubungkan aplikasi ke MySQL atau MariaDB.">
<meta name="robots" content="noindex,nofollow">
<style>
:root {
color-scheme: light;
--bg: #f5f7fb;
--card: #ffffff;
--text: #0f172a;
--muted: #475569;
--border: #dbe3ef;
--accent: #0f172a;
--accent-soft: #e2e8f0;
--warning: #fff7ed;
--warning-border: #fdba74;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: Inter, Arial, sans-serif;
background: radial-gradient(circle at top, #ffffff 0%, var(--bg) 55%);
color: var(--text);
line-height: 1.6;
}
.setup-wrap {
min-height: 100vh;
padding: 32px 16px;
display: flex;
align-items: center;
justify-content: center;
}
.setup-card {
width: min(960px, 100%);
background: rgba(255, 255, 255, 0.96);
border: 1px solid var(--border);
border-radius: 28px;
box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
padding: 28px;
}
.setup-eyebrow {
display: inline-flex;
padding: 8px 12px;
border-radius: 999px;
background: var(--accent-soft);
color: var(--accent);
font-size: 13px;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
}
h1 { margin: 16px 0 12px; font-size: clamp(28px, 4vw, 42px); line-height: 1.1; }
h2 { margin: 0 0 12px; font-size: 20px; }
p { margin: 0 0 14px; color: var(--muted); }
.notice {
margin: 20px 0;
padding: 16px 18px;
border-radius: 18px;
border: 1px solid var(--warning-border);
background: var(--warning);
color: var(--text);
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 18px;
margin-top: 22px;
}
.panel {
border: 1px solid var(--border);
border-radius: 22px;
background: var(--card);
padding: 20px;
}
ol, ul { margin: 0; padding-left: 20px; color: var(--muted); }
li + li { margin-top: 10px; }
pre {
margin: 0;
padding: 16px;
overflow: auto;
border-radius: 18px;
background: #0f172a;
color: #e2e8f0;
font-size: 13px;
line-height: 1.5;
white-space: pre-wrap;
word-break: break-word;
}
code {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
background: #eef2ff;
padding: 2px 6px;
border-radius: 8px;
color: #1e293b;
}
.footer-note {
margin-top: 22px;
padding-top: 18px;
border-top: 1px solid var(--border);
font-size: 14px;
color: var(--muted);
}
</style>
</head>
<body>
<main class="setup-wrap">
<section class="setup-card">
<span class="setup-eyebrow">Setup manual</span>
<h1>Isi file <code><?= e($configPath) ?></code> dulu.</h1>
<p>Installer form sudah tidak dipakai. Sekarang koneksi database diisi manual lewat file PHP supaya lebih aman dan lebih cocok untuk cPanel/shared hosting.</p>
<div class="notice">
<strong><?= e((string)$status['message']) ?></strong>
<?php if (!empty($status['details'])): ?>
<div style="margin-top:8px;"><?= e((string)$status['details']) ?></div>
<?php endif; ?>
</div>
<div class="grid">
<section class="panel">
<h2>Langkah cepat</h2>
<ol>
<li>Buka file <code><?= e($configPath) ?></code> di hosting atau editor.</li>
<li>Isi <code>DB_HOST</code>, <code>DB_PORT</code>, <code>DB_NAME</code>, <code>DB_USER</code>, dan <code>DB_PASS</code>.</li>
<li>Kalau database belum ada, buat dulu di cPanel lalu import <code>db/database.sql</code>.</li>
<li>Reload halaman ini setelah file disimpan.</li>
</ol>
</section>
<section class="panel">
<h2>Contoh isi file</h2>
<pre><?= e($exampleConfig) ?></pre>
</section>
</div>
<div class="footer-note">
Tip cPanel: nama database dan username sering memakai prefix akun, misalnya <code>akunpanel_namadb</code> dan <code>akunpanel_userdb</code>. Host biasanya <code>localhost</code> dan port default <code>3306</code>.
</div>
</section>
</main>
</body>
</html>
<?php
exit;
}
function ensure_site_installed(): void
{
if (current_script_name() === 'install.php') {
@ -184,9 +347,7 @@ function ensure_site_installed(): void
return;
}
$nextPath = safe_install_next_path((string)($_SERVER['REQUEST_URI'] ?? '/'));
header('Location: install.php?next=' . rawurlencode($nextPath));
exit;
render_manual_database_setup_screen($status);
}
function post_url(array $post): string

View File

@ -4,99 +4,37 @@ declare(strict_types=1);
require_once __DIR__ . '/includes/site.php';
require_once __DIR__ . '/includes/layout.php';
function installer_source_label(string $source): string
function manual_source_label(string $source): string
{
return match ($source) {
'env' => 'environment server',
'file' => 'file installer lokal',
default => 'belum ada',
};
switch ($source) {
case 'manual_file':
return 'file manual db/database.php';
case 'env':
return 'environment server';
case 'legacy_installer_file':
return 'file legacy db/installer-config.php';
default:
return 'belum ada';
}
}
$status = site_installation_status();
$nextPath = safe_install_next_path((string)($_REQUEST['next'] ?? '/'));
$formData = [
'db_host' => DB_HOST !== '' ? DB_HOST : 'localhost',
'db_port' => DB_PORT !== '' ? DB_PORT : '3306',
'db_name' => DB_NAME,
'db_user' => DB_USER,
'db_pass' => DB_PASS,
];
$errors = [];
$flash = null;
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
$formData = [
'db_host' => trim((string)($_POST['db_host'] ?? 'localhost')),
'db_port' => trim((string)($_POST['db_port'] ?? '3306')),
'db_name' => trim((string)($_POST['db_name'] ?? '')),
'db_user' => trim((string)($_POST['db_user'] ?? '')),
'db_pass' => (string)($_POST['db_pass'] ?? ''),
];
$nextPath = safe_install_next_path((string)($_POST['next'] ?? '/'));
if ($formData['db_host'] === '') {
$formData['db_host'] = 'localhost';
}
if ($formData['db_port'] === '') {
$formData['db_port'] = '3306';
}
if ($formData['db_name'] === '') {
$errors['db_name'] = 'Nama database wajib diisi.';
}
if ($formData['db_user'] === '') {
$errors['db_user'] = 'Username database wajib diisi.';
}
if (!ctype_digit($formData['db_port']) || (int)$formData['db_port'] < 1 || (int)$formData['db_port'] > 65535) {
$errors['db_port'] = 'Port harus berupa angka 1 sampai 65535.';
}
if ($errors === []) {
$settings = [
'DB_HOST' => $formData['db_host'],
'DB_PORT' => $formData['db_port'],
'DB_NAME' => $formData['db_name'],
'DB_USER' => $formData['db_user'],
'DB_PASS' => $formData['db_pass'],
];
try {
$connectionError = db_connection_error($settings);
if ($connectionError !== null && db_error_is_missing_database($connectionError)) {
db_create_database_if_missing($settings);
$connectionError = db_connection_error($settings);
}
if ($connectionError !== null) {
throw new RuntimeException($connectionError);
}
db_save_local_settings($settings);
header('Location: ' . $nextPath);
exit;
} catch (Throwable $exception) {
$flash = [
'type' => 'danger',
'title' => 'Koneksi database gagal.',
'message' => $exception->getMessage(),
];
}
} else {
$flash = [
'type' => 'warning',
'title' => 'Form belum lengkap.',
'message' => 'Periksa lagi field yang diberi tanda merah.',
];
}
}
$nextPath = safe_install_next_path((string)($_GET['next'] ?? '/'));
$configPath = db_manual_config_relative_path();
$configTemplate = db_export_settings_file([
'DB_HOST' => 'localhost',
'DB_PORT' => '3306',
'DB_NAME' => 'usernamecpanel_namadb',
'DB_USER' => 'usernamecpanel_userdb',
'DB_PASS' => 'password_database',
]);
render_page_start([
'title' => 'Installer Database',
'description' => 'Form instalasi cepat untuk menghubungkan aplikasi ke database MySQL.',
'title' => 'Konfigurasi Database Manual',
'description' => 'Panduan isi file db/database.php untuk koneksi MySQL atau MariaDB.',
'canonical' => canonical_for('install.php'),
'robots' => 'noindex,nofollow',
'keywords' => 'installer database, setup mysql, setup php app',
'keywords' => 'konfigurasi database manual, mysql cpanel, database php',
'body_class' => 'install-page',
]);
?>
@ -105,20 +43,19 @@ render_page_start([
<section class="hero-panel mb-4">
<div class="row g-4 align-items-center">
<div class="col-lg-7">
<span class="eyebrow">Auto installer</span>
<h1 class="hero-title mt-3 mb-3">Pindah hosting? Tinggal isi data database, lalu website jalan lagi.</h1>
<p class="hero-copy mb-0">Kalau script ini dipindah ke server baru, halaman ini akan muncul otomatis saat koneksi database belum siap. Anda hanya perlu memasukkan host, port, nama database, username, dan password MySQL.</p>
<span class="eyebrow">Setup manual</span>
<h1 class="hero-title mt-3 mb-3">Installer form dinonaktifkan. Isi database lewat file PHP saja.</h1>
<p class="hero-copy mb-0">Sekarang koneksi MySQL/MariaDB memakai file <code><?= e($configPath) ?></code>. Jadi saat pindah ke cPanel/shared hosting, Anda cukup edit satu file lalu reload website.</p>
</div>
<div class="col-lg-5">
<div class="panel-card h-100">
<div class="card-label">Yang perlu disiapkan</div>
<ul class="mb-0 ps-3 small">
<li>Host database, seringnya <code>localhost</code>.</li>
<li>Host database, biasanya <code>localhost</code>.</li>
<li>Port MySQL, default <code>3306</code>.</li>
<li>Nama database dari hosting/cPanel.</li>
<li>Nama database dari cPanel atau hosting.</li>
<li>Username dan password database.</li>
</ul>
<div class="alert alert-info mt-3 mb-0 small">Jika database yang Anda tulis belum ada, installer akan mencoba membuatnya otomatis jika akun database punya izin.</div>
</div>
</div>
</div>
@ -130,8 +67,8 @@ render_page_start([
<div class="card-label">Status saat ini</div>
<?php if (!empty($status['ready'])): ?>
<div class="alert alert-success mb-3">Aplikasi sudah terhubung ke database.</div>
<p class="section-copy mb-2">Sumber konfigurasi aktif: <strong><?= e(installer_source_label((string)$status['source'])) ?></strong>.</p>
<p class="section-copy mb-0">Kalau Anda hanya ingin memakai website, tidak perlu mengisi ulang form di kanan.</p>
<p class="section-copy mb-2">Sumber konfigurasi aktif: <strong><?= e(manual_source_label((string)$status['source'])) ?></strong>.</p>
<p class="section-copy mb-0">Kalau website sudah normal, file <code><?= e($configPath) ?></code> tidak perlu diubah lagi.</p>
<?php else: ?>
<div class="alert alert-warning mb-3">
<strong><?= e((string)$status['message']) ?></strong>
@ -139,72 +76,51 @@ render_page_start([
<div class="small mt-2"><?= e((string)$status['details']) ?></div>
<?php endif; ?>
</div>
<p class="section-copy mb-0">Begitu data database benar, aplikasi akan membuat tabel blog otomatis saat Anda masuk ke halaman utama.</p>
<p class="section-copy mb-0">Setelah file manual terisi benar, website akan membuat tabel blog otomatis saat halaman utama dibuka.</p>
<?php endif; ?>
</section>
</div>
<div class="col-lg-8">
<section class="panel-card">
<div class="d-flex flex-column flex-md-row justify-content-between align-items-start gap-3 mb-4">
<div>
<span class="section-kicker">Form koneksi</span>
<h2 class="section-title mb-1">Isi data MySQL / MariaDB</h2>
<p class="section-copy mb-0">Data ini biasanya ada di menu Database pada panel hosting atau PHPMyAdmin.</p>
</div>
<a class="btn btn-outline-dark btn-sm" href="https://www.phpmyadmin.net/" target="_blank" rel="noopener noreferrer">Apa itu PHPMyAdmin?</a>
<div class="section-heading mb-4">
<span class="section-kicker">File yang diedit</span>
<h2 class="section-title mb-2">Buka <code><?= e($configPath) ?></code> lalu isi seperti ini</h2>
<p class="section-copy mb-0">Anda tidak perlu submit form. Cukup simpan file, lalu refresh browser.</p>
</div>
<?php if ($flash !== null): ?>
<div class="alert alert-<?= e((string)$flash['type']) ?>">
<strong><?= e((string)$flash['title']) ?></strong>
<div class="small mt-1"><?= e((string)$flash['message']) ?></div>
</div>
<?php endif; ?>
<pre class="mb-4"><code><?= e($configTemplate) ?></code></pre>
<?php if (!empty($status['ready'])): ?>
<div class="d-flex flex-wrap gap-2">
<a class="btn btn-dark" href="<?= e($nextPath) ?>">Masuk ke website</a>
<a class="btn btn-outline-dark" href="index.php">Ke beranda</a>
<div class="alert alert-secondary small mb-4">
Untuk cPanel, nama database dan username sering wajib memakai prefix akun. Contoh: jika akun cPanel <code>kawaii</code>, maka bisa menjadi <code>kawaii_appdb</code> dan <code>kawaii_appuser</code>.
</div>
<div class="row g-3">
<div class="col-md-6">
<div class="panel-card h-100 bg-light border-0">
<div class="card-label">Urutan setup</div>
<ol class="mb-0 ps-3 small">
<li>Buat database MySQL di cPanel.</li>
<li>Import <code>db/database.sql</code> lewat phpMyAdmin.</li>
<li>Edit file <code><?= e($configPath) ?></code>.</li>
<li>Buka ulang halaman website.</li>
</ol>
</div>
</div>
<?php else: ?>
<form method="post" novalidate>
<input type="hidden" name="next" value="<?= e($nextPath) ?>">
<div class="row g-3">
<div class="col-md-8">
<label class="form-label" for="db_host">Host database</label>
<input class="form-control <?= isset($errors['db_host']) ? 'is-invalid' : '' ?>" type="text" id="db_host" name="db_host" value="<?= e($formData['db_host']) ?>" placeholder="localhost" autocomplete="off">
<?php if (isset($errors['db_host'])): ?><div class="invalid-feedback"><?= e($errors['db_host']) ?></div><?php endif; ?>
</div>
<div class="col-md-4">
<label class="form-label" for="db_port">Port</label>
<input class="form-control <?= isset($errors['db_port']) ? 'is-invalid' : '' ?>" type="text" id="db_port" name="db_port" value="<?= e($formData['db_port']) ?>" placeholder="3306" inputmode="numeric" autocomplete="off">
<?php if (isset($errors['db_port'])): ?><div class="invalid-feedback"><?= e($errors['db_port']) ?></div><?php endif; ?>
</div>
<div class="col-md-6">
<label class="form-label" for="db_name">Nama database</label>
<input class="form-control <?= isset($errors['db_name']) ? 'is-invalid' : '' ?>" type="text" id="db_name" name="db_name" value="<?= e($formData['db_name']) ?>" placeholder="nama_database" autocomplete="off">
<?php if (isset($errors['db_name'])): ?><div class="invalid-feedback"><?= e($errors['db_name']) ?></div><?php endif; ?>
</div>
<div class="col-md-6">
<label class="form-label" for="db_user">Username database</label>
<input class="form-control <?= isset($errors['db_user']) ? 'is-invalid' : '' ?>" type="text" id="db_user" name="db_user" value="<?= e($formData['db_user']) ?>" placeholder="username_db" autocomplete="off">
<?php if (isset($errors['db_user'])): ?><div class="invalid-feedback"><?= e($errors['db_user']) ?></div><?php endif; ?>
</div>
<div class="col-12">
<label class="form-label" for="db_pass">Password database</label>
<input class="form-control" type="password" id="db_pass" name="db_pass" value="<?= e($formData['db_pass']) ?>" placeholder="Kosongkan jika memang tidak ada password" autocomplete="new-password">
<div class="col-md-6">
<div class="panel-card h-100 bg-light border-0">
<div class="card-label">Langkah berikutnya</div>
<div class="d-flex flex-wrap gap-2">
<?php if (!empty($status['ready'])): ?>
<a class="btn btn-dark" href="<?= e($nextPath) ?>">Masuk ke website</a>
<?php else: ?>
<a class="btn btn-dark" href="index.php">Coba reload beranda</a>
<?php endif; ?>
<a class="btn btn-outline-dark" href="healthz.php">Cek health</a>
</div>
</div>
<div class="alert alert-secondary mt-4 mb-0 small">Setelah berhasil disimpan, website akan memakai file konfigurasi lokal di folder <code>db/</code>. Jadi kalau script dipindah ke server lain, cukup buka web dan isi form ini lagi bila koneksi lama tidak cocok.</div>
<div class="d-flex flex-wrap gap-2 mt-4">
<button class="btn btn-dark btn-cta" type="submit">Simpan &amp; masuk ke website</button>
<a class="btn btn-outline-dark btn-cta" href="/">Kembali</a>
</div>
</form>
<?php endif; ?>
</div>
</div>
</section>
</div>
</div>

View File

@ -1,4 +1,4 @@
User-agent: *
Allow: /
Disallow: /admin.php
Sitemap: https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/sitemap.xml
Sitemap: http://127.0.0.1/sitemap.xml

View File

@ -1,49 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/</loc>
<lastmod>2026-05-17T14:40:34+00:00</lastmod>
<loc>http://127.0.0.1/</loc>
<lastmod>2026-05-17T16:04:30+00:00</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/blog.php</loc>
<lastmod>2026-05-17T14:40:34+00:00</lastmod>
<loc>http://127.0.0.1/blog.php</loc>
<lastmod>2026-05-17T16:04:30+00:00</lastmod>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/post.php?slug=checklist-link-seo-ke-apknusa-com</loc>
<loc>http://127.0.0.1/post.php?slug=checklist-link-seo-ke-apknusa-com</loc>
<lastmod>2026-05-17T13:29:20+00:00</lastmod>
<changefreq>weekly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/post.php?slug=perbedaan-apk-xapk-dan-file-instalasi-lain-yang-perlu-dipahami</loc>
<loc>http://127.0.0.1/post.php?slug=perbedaan-apk-xapk-dan-file-instalasi-lain-yang-perlu-dipahami</loc>
<lastmod>2026-05-17T13:29:11+00:00</lastmod>
<changefreq>weekly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/post.php?slug=tips-menyimpan-file-apk-supaya-mudah-dicari-lagi</loc>
<loc>http://127.0.0.1/post.php?slug=tips-menyimpan-file-apk-supaya-mudah-dicari-lagi</loc>
<lastmod>2026-05-17T13:29:11+00:00</lastmod>
<changefreq>weekly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/post.php?slug=kenapa-review-aplikasi-penting-sebelum-download</loc>
<loc>http://127.0.0.1/post.php?slug=kenapa-review-aplikasi-penting-sebelum-download</loc>
<lastmod>2026-05-17T13:29:11+00:00</lastmod>
<changefreq>weekly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/post.php?slug=panduan-update-aplikasi-android-tanpa-kehilangan-data</loc>
<loc>http://127.0.0.1/post.php?slug=panduan-update-aplikasi-android-tanpa-kehilangan-data</loc>
<lastmod>2026-05-17T13:29:11+00:00</lastmod>
<changefreq>weekly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://baclink-apknusa-microsite-ad42.dev.flatlogic.app/post.php?slug=cara-memilih-sumber-apk-yang-aman-sebelum-instal</loc>
<loc>http://127.0.0.1/post.php?slug=cara-memilih-sumber-apk-yang-aman-sebelum-instal</loc>
<lastmod>2026-05-17T13:29:11+00:00</lastmod>
<changefreq>weekly</changefreq>
<priority>0.7</priority>