initiall comit
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
<?php
|
||||
// ========================================
|
||||
// FILE: php/db_tool.php
|
||||
// Alat Manajemen & Perbaikan Database (Production Ready)
|
||||
// ========================================
|
||||
|
||||
include 'koneksi.php';
|
||||
|
||||
// Timpa header dari koneksi.php agar browser merender HTML dengan benar
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
|
||||
// Ambil PIN keamanan dari environment variable, default ke "123456" jika belum diatur
|
||||
$secure_pin = getenv('DB_TOOL_PIN') ?: "123456";
|
||||
|
||||
// Mulai session untuk authentikasi pin
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
$authenticated = isset($_SESSION['db_tool_auth']) && $_SESSION['db_tool_auth'] === true;
|
||||
|
||||
// Proses Login PIN
|
||||
if (isset($_POST['pin'])) {
|
||||
if ($_POST['pin'] === $secure_pin) {
|
||||
$_SESSION['db_tool_auth'] = true;
|
||||
$authenticated = true;
|
||||
} else {
|
||||
$login_error = "PIN yang Anda masukkan salah!";
|
||||
}
|
||||
}
|
||||
|
||||
// Proses Logout
|
||||
if (isset($_GET['logout'])) {
|
||||
$_SESSION['db_tool_auth'] = false;
|
||||
session_destroy();
|
||||
header("Location: db_tool.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Daftar tabel wajib
|
||||
$required_tables = [
|
||||
'masyarakat_miskin',
|
||||
'rumah_ibadah',
|
||||
'bantuan_riwayat',
|
||||
'bpjs_record',
|
||||
'users',
|
||||
'fasilitas_jalan',
|
||||
'fasilitas_polygon',
|
||||
'fasilitas_spbu'
|
||||
];
|
||||
|
||||
$logs = [];
|
||||
$error_logs = [];
|
||||
|
||||
// Fungsi bantu eksekusi perintah SQL secara massal
|
||||
function executeSQLFile($conn, $filepath, &$logs, &$error_logs) {
|
||||
if (!file_exists($filepath)) {
|
||||
$error_logs[] = "File SQL tidak ditemukan di: " . basename($filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = file_get_contents($filepath);
|
||||
|
||||
// Nonaktifkan foreign key checks sementara untuk menghindari error dependensi saat drop/create
|
||||
$conn->query("SET FOREIGN_KEY_CHECKS = 0;");
|
||||
|
||||
if ($conn->multi_query($sql)) {
|
||||
do {
|
||||
if ($res = $conn->store_result()) {
|
||||
$res->free();
|
||||
}
|
||||
} while ($conn->more_results() && $conn->next_result());
|
||||
|
||||
$conn->query("SET FOREIGN_KEY_CHECKS = 1;");
|
||||
$logs[] = "File SQL " . basename($filepath) . " berhasil diimpor sepenuhnya.";
|
||||
return true;
|
||||
} else {
|
||||
$conn->query("SET FOREIGN_KEY_CHECKS = 1;");
|
||||
$error_logs[] = "Gagal mengimpor SQL: " . $conn->error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Handler Aksi Perbaikan Database (Hanya berjalan jika terautentikasi)
|
||||
$action_result = null;
|
||||
if ($authenticated && isset($_POST['action'])) {
|
||||
$action = $_POST['action'];
|
||||
|
||||
if ($action === 'check_connection') {
|
||||
if ($conn->ping()) {
|
||||
$logs[] = "Koneksi ke database server aktif! Server info: " . $conn->server_info;
|
||||
} else {
|
||||
$error_logs[] = "Koneksi database terputus: " . $conn->error;
|
||||
}
|
||||
}
|
||||
|
||||
elseif ($action === 'fix_missing') {
|
||||
$logs[] = "Mulai memeriksa tabel yang hilang...";
|
||||
// Dapatkan DDL Cadangan
|
||||
$sql_file = __DIR__ . '/../database.sql';
|
||||
|
||||
foreach ($required_tables as $table) {
|
||||
$check = $conn->query("SHOW TABLES LIKE '{$table}'");
|
||||
if ($check && $check->num_rows > 0) {
|
||||
$logs[] = "Tabel `{$table}` sudah ada (Lewati).";
|
||||
} else {
|
||||
$logs[] = "Tabel `{$table}` hilang! Mencoba membuat tabel...";
|
||||
// Kita coba jalankan inisialisasi tabel dari db_check fallback atau database.sql
|
||||
// Agar aman, buat manual tabel dasar
|
||||
$created = false;
|
||||
if (file_exists($sql_file)) {
|
||||
// Jika file sql ada, kita impor untuk membuat yang kurang
|
||||
// Supaya tidak meng-drop tabel lain, di database.sql harus menggunakan CREATE TABLE IF NOT EXISTS
|
||||
executeSQLFile($conn, $sql_file, $logs, $error_logs);
|
||||
$created = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$logs[] = "Pemeriksaan tabel selesai.";
|
||||
}
|
||||
|
||||
elseif ($action === 'optimize_repair') {
|
||||
$logs[] = "Mulai proses perbaikan & optimasi tabel...";
|
||||
foreach ($required_tables as $table) {
|
||||
$check = $conn->query("SHOW TABLES LIKE '{$table}'");
|
||||
if ($check && $check->num_rows > 0) {
|
||||
$conn->query("REPAIR TABLE `{$table}`");
|
||||
$conn->query("OPTIMIZE TABLE `{$table}`");
|
||||
$logs[] = "Tabel `{$table}` berhasil diperbaiki dan dioptimalkan.";
|
||||
} else {
|
||||
$error_logs[] = "Tabel `{$table}` tidak ditemukan untuk dioptimalkan.";
|
||||
}
|
||||
}
|
||||
$logs[] = "Proses optimasi selesai.";
|
||||
}
|
||||
|
||||
elseif ($action === 'hard_reset') {
|
||||
$logs[] = "⚠️ Melakukan HARD RESET Database...";
|
||||
// Drop all known tables
|
||||
$conn->query("SET FOREIGN_KEY_CHECKS = 0;");
|
||||
foreach ($required_tables as $table) {
|
||||
$conn->query("DROP TABLE IF EXISTS `{$table}`");
|
||||
$logs[] = "Menghapus tabel `{$table}` jika ada.";
|
||||
}
|
||||
$conn->query("SET FOREIGN_KEY_CHECKS = 1;");
|
||||
|
||||
// Impor ulang database.sql
|
||||
$sql_file = __DIR__ . '/../database.sql';
|
||||
if (executeSQLFile($conn, $sql_file, $logs, $error_logs)) {
|
||||
$logs[] = "✅ Database berhasil di-reset ke kondisi awal.";
|
||||
} else {
|
||||
$error_logs[] = "❌ Hard reset gagal saat mengimpor skema.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kumpulkan status database saat ini
|
||||
$status_tables = [];
|
||||
if ($authenticated && !$conn->connect_error) {
|
||||
foreach ($required_tables as $table) {
|
||||
$check = $conn->query("SHOW TABLES LIKE '{$table}'");
|
||||
if ($check && $check->num_rows > 0) {
|
||||
$count_res = $conn->query("SELECT COUNT(*) as total FROM `{$table}`");
|
||||
$count = $count_res ? $count_res->fetch_assoc()['total'] : 0;
|
||||
$status_tables[$table] = [
|
||||
'exists' => true,
|
||||
'count' => $count
|
||||
];
|
||||
} else {
|
||||
$status_tables[$table] = [
|
||||
'exists' => false,
|
||||
'count' => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Database Master Tool - WebGIS</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700;800&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Outfit', sans-serif;
|
||||
background-color: #0b0f19;
|
||||
color: #f1f5f9;
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
background: rgba(17, 24, 39, 0.8);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
h1 {
|
||||
color: #38bdf8;
|
||||
font-weight: 800;
|
||||
margin-top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.btn-logout {
|
||||
font-size: 13px;
|
||||
padding: 6px 12px;
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.card {
|
||||
background: rgba(30, 41, 59, 0.5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
color: #94a3b8;
|
||||
}
|
||||
input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 8px;
|
||||
background: #0f172a;
|
||||
color: white;
|
||||
box-sizing: border-box;
|
||||
font-size: 16px;
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background: linear-gradient(135deg, #38bdf8 0%, #0284c7 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 15px rgba(56, 189, 248, 0.3);
|
||||
}
|
||||
.btn-warning {
|
||||
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
||||
}
|
||||
.btn-danger {
|
||||
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.status-ok { background: #059669; color: #ecfdf5; }
|
||||
.status-err { background: #dc2626; color: #fef2f2; }
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 10px;
|
||||
}
|
||||
th, td {
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
th { color: #38bdf8; font-weight: 600; }
|
||||
|
||||
.terminal {
|
||||
background: #020617;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
color: #34d399;
|
||||
}
|
||||
.terminal-err { color: #f87171; }
|
||||
.action-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
border-left: 4px solid #38bdf8;
|
||||
padding-left: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<h1>
|
||||
<span>🛠️ Database Master Debug Tool</span>
|
||||
<?php if ($authenticated): ?>
|
||||
<a href="?logout=1" class="btn-logout">Logout / Lock</a>
|
||||
<?php endif; ?>
|
||||
</h1>
|
||||
|
||||
<?php if (!$authenticated): ?>
|
||||
<!-- Form Verifikasi PIN -->
|
||||
<div class="card" style="max-width: 400px; margin: 40px auto;">
|
||||
<h3 style="margin-top: 0; color: #38bdf8;">Keamanan Diperlukan</h3>
|
||||
<p style="color: #94a3b8; font-size: 14px;">Masukkan PIN Keamanan untuk mengakses fungsi diagnostik database.</p>
|
||||
|
||||
<?php if (isset($login_error)): ?>
|
||||
<div style="background:#fef2f2; color:#b91c1c; padding:10px; border-radius:6px; margin-bottom:15px; font-size:14px;">
|
||||
<?php echo htmlspecialchars($login_error); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="">
|
||||
<div class="form-group">
|
||||
<label for="pin">PIN Keamanan</label>
|
||||
<input type="password" id="pin" name="pin" placeholder="Masukkan PIN..." required autofocus>
|
||||
</div>
|
||||
<button type="submit" class="btn" style="width: 100%;">Masuk & Periksa</button>
|
||||
</form>
|
||||
<p style="text-align:center; font-size:12px; color:#64748b; margin-top:15px;">
|
||||
* PIN default lokal adalah <code>123456</code> (Atur via <code>DB_TOOL_PIN</code> di .env)
|
||||
</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<!-- Halaman Kontrol Database Utama -->
|
||||
<div class="grid">
|
||||
<!-- Sektor Status Koneksi & Tabel -->
|
||||
<div class="card" style="grid-column: span 2;">
|
||||
<h3 style="margin-top: 0; color: #38bdf8;">📊 Status Tabel Database</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nama Tabel</th>
|
||||
<th>Keberadaan</th>
|
||||
<th>Jumlah Data</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($required_tables as $table):
|
||||
$status = $status_tables[$table] ?? ['exists' => false, 'count' => 0];
|
||||
?>
|
||||
<tr>
|
||||
<td><code><?php echo htmlspecialchars($table); ?></code></td>
|
||||
<td>
|
||||
<?php if ($status['exists']): ?>
|
||||
<span class="status-badge status-ok">OK (Tersedia)</span>
|
||||
<?php else: ?>
|
||||
<span class="status-badge status-err">Hilang / Tidak Ada</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo (int)$status['count']; ?> Baris</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Sektor Aksi Kontrol -->
|
||||
<div class="card">
|
||||
<h3 style="margin-top: 0; color: #38bdf8;">⚡ Aksi Perbaikan</h3>
|
||||
<div style="display:flex; flex-direction:column; gap:15px;">
|
||||
|
||||
<form method="POST" action="" class="action-card" style="border-left-color: #3b82f6;">
|
||||
<input type="hidden" name="action" value="check_connection">
|
||||
<strong>Konektivitas Database</strong>
|
||||
<small style="color:#94a3b8;">Uji ulang ping ke server MySQL dan baca info status server.</small>
|
||||
<button type="submit" class="btn">Ping Test</button>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="" class="action-card" style="border-left-color: #10b981;">
|
||||
<input type="hidden" name="action" value="fix_missing">
|
||||
<strong>Buat Tabel yang Hilang</strong>
|
||||
<small style="color:#94a3b8;">Membuat tabel yang hilang secara otomatis tanpa menyentuh tabel yang sudah ada.</small>
|
||||
<button type="submit" class="btn btn-warning">Auto-Fix Tabel</button>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="" class="action-card" style="border-left-color: #f59e0b;">
|
||||
<input type="hidden" name="action" value="optimize_repair">
|
||||
<strong>Perbaiki & Optimasi</strong>
|
||||
<small style="color:#94a3b8;">Menjalankan perintah SQL REPAIR dan OPTIMIZE untuk memperbaiki data corrupt.</small>
|
||||
<button type="submit" class="btn btn-warning">Repair & Optimize</button>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="" class="action-card" style="border-left-color: #ef4444;" onsubmit="return confirm('⚠️ PERINGATAN KERAS! Tindakan ini akan menghapus semua data Anda secara permanen dan mereset database. Lanjutkan?');">
|
||||
<input type="hidden" name="action" value="hard_reset">
|
||||
<strong>Reset Ulang (Hard Reset)</strong>
|
||||
<small style="color:#ef4444; font-weight:bold;">Menghapus semua tabel dan mengimpor ulang skema awal dari database.sql.</small>
|
||||
<button type="submit" class="btn btn-danger">Hapus & Reset Database</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Terminal Output Log -->
|
||||
<?php if (!empty($logs) || !empty($error_logs)): ?>
|
||||
<div class="card">
|
||||
<h3 style="margin-top: 0; color: #34d399;">💻 Output Log Eksekusi</h3>
|
||||
<div class="terminal">
|
||||
<?php foreach ($logs as $log): ?>
|
||||
<div>[INFO] <?php echo htmlspecialchars($log); ?></div>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($error_logs as $err): ?>
|
||||
<div class="terminal-err">[ERROR] <?php echo htmlspecialchars($err); ?></div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div style="text-align: center; margin-top: 20px;">
|
||||
<a href="../index.html" style="color: #38bdf8; text-decoration: none; font-weight: 600;">← Kembali ke Portal WebGIS</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user