Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bb883473e4 | |||
| d7dd18ddba | |||
| 4949c84feb | |||
| 9f8eee401a | |||
| d4afc16e02 | |||
| 4703557dbe | |||
| aad7e80246 | |||
| f98e707faf | |||
| 3da59f80da |
@@ -0,0 +1,17 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
QUICK_START.md
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.vscode
|
||||
.idea
|
||||
docker-compose.yml
|
||||
docker-compose.local.yml
|
||||
.dockerignore
|
||||
.env.local
|
||||
.env.*.local
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
# Coolify Local Debugger config
|
||||
.env
|
||||
.coolify-local.json
|
||||
Dockerfile.coolify
|
||||
@@ -0,0 +1,15 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
QUICK_START.md
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.vscode
|
||||
.idea
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
@@ -15,3 +15,8 @@ access_log
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Coolify Local Debugger config
|
||||
.env
|
||||
.coolify-local.json
|
||||
Dockerfile.coolify
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Use official PHP image with Apache
|
||||
FROM php:8.1-apache
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && (apt-get install -y mysql-client || apt-get install -y default-mysql-client) && apt-get install -y \
|
||||
git \
|
||||
curl \
|
||||
zip \
|
||||
unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Enable Apache modules
|
||||
RUN a2enmod rewrite \
|
||||
&& a2enmod headers
|
||||
|
||||
# Install PHP extensions
|
||||
RUN docker-php-ext-install \
|
||||
mysqli \
|
||||
pdo \
|
||||
pdo_mysql
|
||||
|
||||
# Set PHP configuration
|
||||
RUN echo "display_errors = On" >> /usr/local/etc/php/conf.d/php.ini \
|
||||
&& echo "error_reporting = E_ALL" >> /usr/local/etc/php/conf.d/php.ini \
|
||||
&& echo "date.timezone = Asia/Jakarta" >> /usr/local/etc/php/conf.d/php.ini
|
||||
|
||||
# Copy project files
|
||||
COPY . .
|
||||
|
||||
# Set permissions
|
||||
RUN chown -R www-data:www-data /var/www/html
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
# Start Apache
|
||||
CMD ["apache2-foreground"]
|
||||
@@ -0,0 +1,193 @@
|
||||
# ⚡ QUICK START - Mulai Cepat dalam 5 Menit
|
||||
|
||||
## 🎯 Langkah 1: Ekstrak & Tempatkan File
|
||||
|
||||
1. **Extract ZIP** ke folder web Anda:
|
||||
- Windows: `C:\xampp\htdocs\pemetaan-kemiskinan`
|
||||
- Linux: `/var/www/html/pemetaan-kemiskinan`
|
||||
|
||||
2. **Pastikan XAMPP/Web Server JALAN**
|
||||
- Buka XAMPP Control Panel
|
||||
- Klik **"Start"** untuk Apache
|
||||
- Klik **"Start"** untuk MySQL
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Langkah 2: Setup Database (3 Langkah Mudah)
|
||||
|
||||
### Cara A: Menggunakan phpMyAdmin (PALING MUDAH)
|
||||
|
||||
1. **Buka browser** → ketik: `http://localhost/phpmyadmin`
|
||||
2. **Klik menu "Import"** di bagian atas
|
||||
3. **Klik "Choose File"** → pilih file `database.sql` dari folder pemetaan-kemiskinan
|
||||
4. **Klik tombol "Import"** → SELESAI ✅
|
||||
|
||||
Tunggu 5-10 detik, database akan terbuat otomatis dengan semua tabel yang diperlukan.
|
||||
|
||||
### Cara B: Manual (Jika Cara A tidak berhasil)
|
||||
|
||||
1. Buka phpMyAdmin → `http://localhost/phpmyadmin`
|
||||
2. Di sebelah kiri, cari **"Create new database"**
|
||||
3. Ketik nama: `pemetaan_kemiskinan`
|
||||
4. Klik **"Create"**
|
||||
5. Pilih database yang baru dibuat
|
||||
6. Klik tab **"SQL"**
|
||||
7. Copy-paste semua kode dari file `database.sql`
|
||||
8. Klik **"Go"**
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Langkah 3: Verifikasi Koneksi
|
||||
|
||||
1. **Buka file**: `php/koneksi.php`
|
||||
2. **Periksa konfigurasi** (biasanya tidak perlu diubah):
|
||||
```php
|
||||
$host = "localhost";
|
||||
$username = "root";
|
||||
$password = ""; // Kosongkan jika XAMPP default
|
||||
$database = "pemetaan_kemiskinan";
|
||||
```
|
||||
3. **Jika ada password MySQL**, ubah baris:
|
||||
```php
|
||||
$password = "password_anda_di_sini";
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Langkah 4: Buka Aplikasi
|
||||
|
||||
**Buka browser dan ketik:**
|
||||
```
|
||||
http://localhost/pemetaan-kemiskinan/
|
||||
```
|
||||
|
||||
✅ **SELESAI! Aplikasi siap digunakan!**
|
||||
|
||||
---
|
||||
|
||||
## 🎮 Test Aplikasi
|
||||
|
||||
### Test Input Masyarakat Miskin:
|
||||
|
||||
1. Map akan muncul dengan area Pontianak
|
||||
2. Klik tombol di sidebar → Tab "Masyarakat"
|
||||
3. **Klik di peta** untuk set koordinat lokasi
|
||||
4. Isi form dengan data:
|
||||
```
|
||||
Nama: Siti Nur Azizah
|
||||
Tanggal Lahir: 1985-03-15
|
||||
Jenis Kelamin: Perempuan
|
||||
Alamat: Jl. Mahakam No. 25
|
||||
Kelurahan: Sungai Jawi
|
||||
Kecamatan: Pontianak Kota
|
||||
No HP: 081234567890
|
||||
Status BPJS: Ya
|
||||
(Koordinat sudah otomatis dari klik peta)
|
||||
```
|
||||
5. Klik **"Simpan Data"** → Data berhasil disimpan ✅
|
||||
6. Lihat marker merah di peta, dan nama muncul di sidebar list
|
||||
|
||||
### Test Input Rumah Ibadah:
|
||||
|
||||
1. Klik tab **"Rumah Ibadah"** di sidebar
|
||||
2. **Klik di peta** untuk koordinat
|
||||
3. Isi form:
|
||||
```
|
||||
Nama: Masjid Al-Hidayah
|
||||
Jenis: Masjid
|
||||
Alamat: Jl. Diponegoro No. 45
|
||||
Nama Pemimpin: Ustaz Ahmad
|
||||
```
|
||||
4. Klik **"Simpan Data"** → Marker hijau muncul ✅
|
||||
|
||||
---
|
||||
|
||||
## 📱 Interface Penjelasan
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ SIDEBAR (300px) │ MAP (Sisa) │
|
||||
│ │ │
|
||||
│ 📍 Pemetaan Kemiskinan │ Marker Merah │
|
||||
│ [Masyarakat] [Ibadah] │ Masyarakat │
|
||||
│ │ │
|
||||
│ [Search Box] │ Marker Hijau │
|
||||
│ [Filter Dropdown] │ Rumah Ibadah │
|
||||
│ │ │
|
||||
│ - Nama 1 │ │
|
||||
│ - Nama 2 │ Klik di peta │
|
||||
│ - Nama 3 │ = Set Koordinat
|
||||
│ │ │
|
||||
│ [Tombol Hapus] │ Klik Marker │
|
||||
│ │ = Lihat Detail
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ FAQ
|
||||
|
||||
**Q: Koordinat tidak ketangkap saat klik peta?**
|
||||
A: Pastikan modal form sudah terbuka (berwarna putih). Klik dulu field nama atau di peta, baru akan bisa set koordinat otomatis.
|
||||
|
||||
**Q: Data tidak tampil di peta?**
|
||||
A: Cek browser console (F12), atau pastikan latitude longitude valid (antara -90 hingga 90 untuk lat, -180 hingga 180 untuk lng).
|
||||
|
||||
**Q: Database tidak terbuat?**
|
||||
A: Cek di phpMyAdmin apakah database `pemetaan_kemiskinan` sudah ada. Jika belum, buat manual atau coba import ulang file `database.sql`.
|
||||
|
||||
**Q: Error "Access denied" saat jalankan?**
|
||||
A: Password MySQL tidak cocok. Edit file `php/koneksi.php` dan ubah password sesuai konfigurasi MySQL Anda.
|
||||
|
||||
**Q: Peta tidak muncul?**
|
||||
A: Periksa koneksi internet (butuh untuk CDN Leaflet & OpenStreetMap). Atau cek browser console untuk error.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Struktur File Penting
|
||||
|
||||
```
|
||||
pemetaan-kemiskinan/
|
||||
├── index.html ← Buka file ini di browser
|
||||
├── database.sql ← File untuk import database
|
||||
├── config.php ← Konfigurasi umum
|
||||
├── php/
|
||||
│ ├── koneksi.php ← EDIT INI jika ada password MySQL
|
||||
│ ├── simpan_masyarakat.php
|
||||
│ ├── simpan_rumah_ibadah.php
|
||||
│ ├── ambil_data_masyarakat.php
|
||||
│ └── ...
|
||||
├── js/
|
||||
│ └── main.js ← Logic aplikasi
|
||||
└── docs/
|
||||
└── PANDUAN_PHPMY_ADMIN.md ← Dokumentasi detail
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 Jika Ada Masalah
|
||||
|
||||
1. **Cek Browser Console** (Tekan F12):
|
||||
- Lihat tab "Console"
|
||||
- Ada error merah? Catat error message-nya
|
||||
- Refresh halaman (Ctrl+F5)
|
||||
|
||||
2. **Cek phpMyAdmin**:
|
||||
- Database ada?
|
||||
- Tabel ada? (masyarakat_miskin, rumah_ibadah, dll)
|
||||
- Ada data sample?
|
||||
|
||||
3. **Cek File koneksi.php**:
|
||||
- Username & password MySQL cocok?
|
||||
- Nama database benar? (`pemetaan_kemiskinan`)
|
||||
|
||||
4. **Restart Web Server**:
|
||||
- Tutup XAMPP
|
||||
- Buka kembali XAMPP
|
||||
- Start Apache & MySQL
|
||||
|
||||
---
|
||||
|
||||
**✅ Selesai! Nikmati aplikasi pemetaan kemiskinan Anda!**
|
||||
|
||||
*Untuk dokumentasi lengkap, baca file `README.md`*
|
||||
+100
-1
@@ -611,7 +611,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Status BPJS *</label>
|
||||
<select name="status_bpjs" required>
|
||||
<select name="status_bpjs" id="form-status-bpjs" required>
|
||||
<option value="Tidak">Tidak Memiliki</option>
|
||||
<option value="Ya">Sudah Memiliki</option>
|
||||
<option value="Proses">Proses Pendaftaran</option>
|
||||
@@ -619,6 +619,54 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- BPJS Detail Fields (Hanya muncul jika Status BPJS = Ya) -->
|
||||
<div id="bpjs-detail-fields" style="display: none; background: #f0fdf4; border: 1px dashed #4caf50; padding: 15px; border-radius: 8px; margin-bottom: 15px;">
|
||||
<h4 style="margin: 0 0 10px 0; color: #1e3c72; font-size: 13px;">🏥 Informasi Kepesertaan BPJS</h4>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>No. Peserta BPJS *</label>
|
||||
<input type="text" name="bpjs_no_peserta" placeholder="Cth: 0001234567890">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Jenis BPJS</label>
|
||||
<select name="bpjs_jenis_bpjs">
|
||||
<option value="Kesehatan">Kesehatan</option>
|
||||
<option value="Ketenagakerjaan">Ketenagakerjaan</option>
|
||||
<option value="Jaminan Hari Tua">Jaminan Hari Tua</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Tingkat</label>
|
||||
<select name="bpjs_tingkat">
|
||||
<option value="Penerima Bantuan Iuran (PBI)">Penerima Bantuan Iuran (PBI)</option>
|
||||
<option value="Pekerja Penerima Upah">Pekerja Penerima Upah</option>
|
||||
<option value="Pekerja Bukan Penerima Upah">Pekerja Bukan Penerima Upah</option>
|
||||
<option value="Peserta Mandiri">Peserta Mandiri</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Status Aktif</label>
|
||||
<select name="bpjs_status_aktif">
|
||||
<option value="Aktif">Aktif</option>
|
||||
<option value="Nonaktif">Nonaktif</option>
|
||||
<option value="Suspended">Suspended</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Tanggal Daftar *</label>
|
||||
<input type="date" name="bpjs_tanggal_daftar">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Faskes Tingkat 1</label>
|
||||
<input type="text" name="bpjs_faskes_tingkat_1" placeholder="Cth: Puskesmas Pontianak Kota">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Pekerjaan</label>
|
||||
@@ -859,6 +907,57 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL: FORM INPUT BANTUAN -->
|
||||
<div id="modal-form-bantuan" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>Tambah Riwayat Bantuan</h2>
|
||||
<button class="close-btn" onclick="closeModal('modal-form-bantuan')">×</button>
|
||||
</div>
|
||||
<div id="alert-form-bantuan" class="alert"></div>
|
||||
<form id="form-bantuan">
|
||||
<input type="hidden" name="id_masyarakat" id="bantuan-id-masyarakat">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Jenis Bantuan *</label>
|
||||
<input type="text" name="jenis_bantuan" required placeholder="Cth: PKH, BPNT, Bantuan Beras, dll">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Tanggal Menerima *</label>
|
||||
<input type="date" name="tanggal_bantuan" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Nilai Bantuan (Rp) *</label>
|
||||
<input type="number" name="nilai" required placeholder="Cth: 200000">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Satuan</label>
|
||||
<input type="text" name="satuan" value="Rupiah" placeholder="Cth: Rupiah, Paket, dll">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Nama Pemberi Bantuan</label>
|
||||
<input type="text" name="nama_pemberi" placeholder="Cth: Dinas Sosial, Baznas, dll">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Keterangan</label>
|
||||
<textarea name="keterangan" placeholder="Keterangan tambahan bantuan..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="submit" class="btn-primary">Simpan Bantuan</button>
|
||||
<button type="button" class="btn-secondary" onclick="closeModal('modal-form-bantuan')">Batal</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/main.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# PHP-Apache Web Server
|
||||
web:
|
||||
build: .
|
||||
container_name: webgis_web
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- .:/var/www/html
|
||||
environment:
|
||||
- APP_ENV=development
|
||||
- DB_HOST=mysql
|
||||
- DB_USER=root
|
||||
- DB_PASSWORD=root_password
|
||||
- DB_DATABASE=pemetaan_kemiskinan
|
||||
- DB_PORT=3306
|
||||
depends_on:
|
||||
- mysql
|
||||
networks:
|
||||
- webgis_network
|
||||
restart: unless-stopped
|
||||
|
||||
# MySQL Database
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: webgis_mysql
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root_password
|
||||
MYSQL_DATABASE: pemetaan_kemiskinan
|
||||
MYSQL_USER: webgis_user
|
||||
MYSQL_PASSWORD: webgis_password
|
||||
ports:
|
||||
- "3306:3306"
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./database.sql:/docker-entrypoint-initdb.d/database.sql
|
||||
networks:
|
||||
- webgis_network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# phpMyAdmin for database management
|
||||
phpmyadmin:
|
||||
image: phpmyadmin:latest
|
||||
container_name: webgis_phpmyadmin
|
||||
environment:
|
||||
PMA_HOST: mysql
|
||||
PMA_USER: root
|
||||
PMA_PASSWORD: root_password
|
||||
ports:
|
||||
- "8081:80"
|
||||
depends_on:
|
||||
- mysql
|
||||
networks:
|
||||
- webgis_network
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
|
||||
networks:
|
||||
webgis_network:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,134 @@
|
||||
# 📖 Panduan Lengkap: Membuat Database di phpMyAdmin
|
||||
|
||||
## STEP 1: Akses phpMyAdmin
|
||||
1. Buka browser dan akses: `http://localhost/phpmyadmin`
|
||||
- Username: `root`
|
||||
- Password: *(kosongkan atau sesuai konfigurasi)*
|
||||
2. Tekan tombol **Login**
|
||||
|
||||
---
|
||||
|
||||
## STEP 2: Buat Database Baru
|
||||
|
||||
### Cara Manual:
|
||||
1. **Di halaman utama phpMyAdmin**, cari kolom **"Create new database"** di sebelah kiri
|
||||
2. Isikan nama database: `pemetaan_kemiskinan`
|
||||
3. Pilih **Collation**: `utf8mb4_general_ci`
|
||||
4. Klik tombol **Create**
|
||||
|
||||
### Atau menggunakan Import SQL:
|
||||
1. Di menu atas, pilih tab **"Import"**
|
||||
2. Klik **"Choose File"** dan pilih file `database.sql`
|
||||
3. Pastikan encoding: `utf-8`
|
||||
4. Klik **Import** (database akan terbuat otomatis)
|
||||
|
||||
✅ Database berhasil dibuat
|
||||
|
||||
---
|
||||
|
||||
## STEP 3: Verifikasi Tabel-Tabel
|
||||
|
||||
Setelah import atau membuat manual, klik pada database `pemetaan_kemiskinan` di sebelah kiri.
|
||||
|
||||
**Anda seharusnya melihat tabel-tabel berikut:**
|
||||
|
||||
```
|
||||
✓ masyarakat_miskin
|
||||
✓ rumah_ibadah
|
||||
✓ bantuan_riwayat
|
||||
✓ bpjs_record
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## STEP 4: Struktur Tabel (REFERENSI)
|
||||
|
||||
### Tabel: `masyarakat_miskin`
|
||||
| Field | Type | Keterangan |
|
||||
|-------|------|-----------|
|
||||
| id | INT (Primary Key) | ID unik |
|
||||
| nama | VARCHAR(100) | Nama lengkap |
|
||||
| tanggal_lahir | DATE | Tgl lahir (YYYY-MM-DD) |
|
||||
| jenis_kelamin | ENUM('Laki-laki','Perempuan') | - |
|
||||
| alamat | TEXT | Alamat rumah |
|
||||
| latitude | DECIMAL(10,8) | Koordinat lat |
|
||||
| longitude | DECIMAL(11,8) | Koordinat lng |
|
||||
| status_bpjs | ENUM('Ya','Tidak','Proses') | Status BPJS |
|
||||
| no_hp | VARCHAR(15) | Nomor HP |
|
||||
| created_at | TIMESTAMP | Waktu input |
|
||||
|
||||
### Tabel: `rumah_ibadah`
|
||||
| Field | Type | Keterangan |
|
||||
|-------|------|-----------|
|
||||
| id | INT (Primary Key) | ID unik |
|
||||
| nama | VARCHAR(100) | Nama tempat ibadah |
|
||||
| jenis | ENUM('Masjid','Gereja','Vihara','Kelenteng','Lain') | Tipe |
|
||||
| latitude | DECIMAL(10,8) | Koordinat lat |
|
||||
| longitude | DECIMAL(11,8) | Koordinat lng |
|
||||
| alamat | TEXT | Alamat |
|
||||
| keterangan | TEXT | Info tambahan |
|
||||
| created_at | TIMESTAMP | Waktu input |
|
||||
|
||||
### Tabel: `bantuan_riwayat`
|
||||
| Field | Type | Keterangan |
|
||||
|-------|------|-----------|
|
||||
| id | INT (Primary Key) | ID unik |
|
||||
| id_masyarakat | INT | ID masyarakat (foreign key) |
|
||||
| jenis_bantuan | VARCHAR(100) | Tipe bantuan |
|
||||
| tanggal_bantuan | DATE | Tanggal pemberian |
|
||||
| nilai | INT | Nominal (Rp) |
|
||||
| keterangan | TEXT | Catatan |
|
||||
|
||||
### Tabel: `bpjs_record`
|
||||
| Field | Type | Keterangan |
|
||||
|-------|------|-----------|
|
||||
| id | INT (Primary Key) | ID unik |
|
||||
| id_masyarakat | INT | ID masyarakat |
|
||||
| no_peserta | VARCHAR(20) | Nomor peserta BPJS |
|
||||
| tingkat | ENUM('Keluarga','Mandiri','Penerima Bantuan Iuran') | Tipe BPJS |
|
||||
| tanggal_daftar | DATE | Tgl pendaftaran |
|
||||
|
||||
---
|
||||
|
||||
## STEP 5: Cek Koneksi Database (Opsional)
|
||||
|
||||
Jika ingin test koneksi manual:
|
||||
|
||||
1. Buat file `test_koneksi.php` di folder project
|
||||
2. Isi dengan kode ini:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$conn = new mysqli("localhost", "root", "", "pemetaan_kemiskinan");
|
||||
|
||||
if ($conn->connect_error) {
|
||||
die("Koneksi gagal: " . $conn->connect_error);
|
||||
}
|
||||
|
||||
echo "✅ Koneksi berhasil!";
|
||||
?>
|
||||
```
|
||||
|
||||
3. Akses: `http://localhost/pemetaan-kemiskinan/test_koneksi.php`
|
||||
4. Jika muncul pesan hijau = Database siap digunakan ✅
|
||||
|
||||
---
|
||||
|
||||
## TROUBLESHOOTING
|
||||
|
||||
### ❌ "Access denied for user 'root'@'localhost'"
|
||||
- Buka file `config/koneksi.php`
|
||||
- Ubah password sesuai konfigurasi MySQL Anda
|
||||
- Jika menggunakan XAMPP default, kosongkan saja password
|
||||
|
||||
### ❌ "Database pemetaan_kemiskinan tidak ditemukan"
|
||||
- Pastikan sudah run file `database.sql` melalui Import
|
||||
- Atau buat manual: **Create new database** → nama: `pemetaan_kemiskinan`
|
||||
|
||||
### ❌ File upload tidak berfungsi
|
||||
- Cek folder upload di `_uploads/` sudah ada & permission 755
|
||||
- Atau buat manual: klik kanan folder → Properties → Permission → 755
|
||||
|
||||
---
|
||||
|
||||
✅ **Selesai! Database siap digunakan untuk website pemetaan kemiskinan**
|
||||
+80
-1
@@ -634,12 +634,31 @@ function attachEventListeners() {
|
||||
const form_jalan = document.getElementById('form-jalan');
|
||||
const form_polygon = document.getElementById('form-polygon');
|
||||
const form_spbu = document.getElementById('form-spbu');
|
||||
const form_bantuan = document.getElementById('form-bantuan');
|
||||
|
||||
if (form_masyarakat) form_masyarakat.addEventListener('submit', function(e) { e.preventDefault(); submitFormMasyarakat(); });
|
||||
if (form_ibadah) form_ibadah.addEventListener('submit', function(e) { e.preventDefault(); submitFormIbadah(); });
|
||||
if (form_jalan) form_jalan.addEventListener('submit', function(e) { e.preventDefault(); submitFormJalan(); });
|
||||
if (form_polygon) form_polygon.addEventListener('submit', function(e) { e.preventDefault(); submitFormPolygon(); });
|
||||
if (form_spbu) form_spbu.addEventListener('submit', function(e) { e.preventDefault(); submitFormSPBU(); });
|
||||
if (form_bantuan) form_bantuan.addEventListener('submit', function(e) { e.preventDefault(); submitFormBantuan(); });
|
||||
|
||||
// BPJS Fields Toggle
|
||||
const bpjs_status_select = document.getElementById('form-status-bpjs');
|
||||
const bpjs_detail_fields = document.getElementById('bpjs-detail-fields');
|
||||
if (bpjs_status_select && bpjs_detail_fields) {
|
||||
bpjs_status_select.addEventListener('change', function() {
|
||||
if (this.value === 'Ya') {
|
||||
bpjs_detail_fields.style.display = 'block';
|
||||
const dateInput = bpjs_detail_fields.querySelector('input[type="date"]');
|
||||
if (dateInput && !dateInput.value) {
|
||||
dateInput.value = new Date().toISOString().substring(0, 10);
|
||||
}
|
||||
} else {
|
||||
bpjs_detail_fields.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Shortcut keyboard untuk membuka formulir penambahan data baru
|
||||
document.addEventListener('keydown', function(e) {
|
||||
@@ -757,8 +776,30 @@ function submitFormMasyarakat() {
|
||||
.then(handleFetchResponse)
|
||||
.then(result => {
|
||||
if (result.status === 'success') {
|
||||
// Tambahkan detail BPJS jika status_bpjs adalah Ya
|
||||
const status_bpjs = form_data.get('status_bpjs');
|
||||
if (status_bpjs === 'Ya') {
|
||||
const bpjs_data = new FormData();
|
||||
bpjs_data.append('id_masyarakat', result.data.id);
|
||||
bpjs_data.append('no_peserta', form_data.get('bpjs_no_peserta'));
|
||||
bpjs_data.append('jenis_bpjs', form_data.get('bpjs_jenis_bpjs'));
|
||||
bpjs_data.append('tingkat', form_data.get('bpjs_tingkat'));
|
||||
bpjs_data.append('status_aktif', form_data.get('bpjs_status_aktif'));
|
||||
bpjs_data.append('tanggal_daftar', form_data.get('bpjs_tanggal_daftar'));
|
||||
bpjs_data.append('faskes_tingkat_1', form_data.get('bpjs_faskes_tingkat_1'));
|
||||
|
||||
fetch(API_PATH + 'simpan_bpjs.php', {
|
||||
method: 'POST',
|
||||
body: bpjs_data
|
||||
})
|
||||
.then(handleFetchResponse)
|
||||
.catch(err => console.error("Gagal menyimpan detail BPJS:", err));
|
||||
}
|
||||
|
||||
showAlert('alert-form', 'Data berhasil disimpan!', 'success');
|
||||
form.reset();
|
||||
const bpjs_detail_fields = document.getElementById('bpjs-detail-fields');
|
||||
if (bpjs_detail_fields) bpjs_detail_fields.style.display = 'none';
|
||||
setTimeout(() => {
|
||||
closeModal('modal-form-masyarakat');
|
||||
loadMasyarakat();
|
||||
@@ -879,7 +920,45 @@ function hapusData(tipe, id) {
|
||||
}
|
||||
|
||||
function editBantuan(id) {
|
||||
alert('Fitur tambah bantuan dengan ID ' + id + ' akan ditambahkan segera');
|
||||
const form = document.getElementById('form-bantuan');
|
||||
if (form) form.reset();
|
||||
|
||||
const idInput = document.getElementById('bantuan-id-masyarakat');
|
||||
if (idInput) idInput.value = id;
|
||||
|
||||
const dateInput = document.querySelector('#form-bantuan input[name="tanggal_bantuan"]');
|
||||
if (dateInput) dateInput.value = new Date().toISOString().substring(0, 10);
|
||||
|
||||
openModal('modal-form-bantuan');
|
||||
}
|
||||
|
||||
function submitFormBantuan() {
|
||||
const form = document.getElementById('form-bantuan');
|
||||
if (!form) return;
|
||||
const form_data = new FormData(form);
|
||||
|
||||
fetch(API_PATH + 'simpan_bantuan.php', {
|
||||
method: 'POST',
|
||||
body: form_data
|
||||
})
|
||||
.then(handleFetchResponse)
|
||||
.then(result => {
|
||||
if (result.status === 'success') {
|
||||
showAlert('alert-form-bantuan', 'Riwayat bantuan berhasil disimpan!', 'success');
|
||||
form.reset();
|
||||
const citizenId = form_data.get('id_masyarakat');
|
||||
setTimeout(() => {
|
||||
closeModal('modal-form-bantuan');
|
||||
// Refresh detail modal
|
||||
showDetail(citizenId);
|
||||
}, 1000);
|
||||
} else {
|
||||
showAlert('alert-form-bantuan', result.message || 'Gagal menyimpan riwayat bantuan.', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showAlert('alert-form-bantuan', 'Terjadi kesalahan sistem: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
function openModal(modalId) {
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
// ========================================
|
||||
// FILE: php/db_check.php
|
||||
// Skrip Diagnostik dan Sinkronisasi Database
|
||||
// ========================================
|
||||
|
||||
include 'koneksi.php';
|
||||
|
||||
// Timpa header dari koneksi.php agar browser merender HTML dengan benar
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
|
||||
// Matikan output JSON bawaan koneksi.php jika ada error, kita buat custom HTML UI
|
||||
ob_start();
|
||||
|
||||
$errors = [];
|
||||
$success_logs = [];
|
||||
$table_status = [];
|
||||
|
||||
// Daftar tabel yang harus ada
|
||||
$required_tables = [
|
||||
'masyarakat_miskin',
|
||||
'rumah_ibadah',
|
||||
'bantuan_riwayat',
|
||||
'bpjs_record',
|
||||
'users',
|
||||
'fasilitas_jalan',
|
||||
'fasilitas_polygon',
|
||||
'fasilitas_spbu'
|
||||
];
|
||||
|
||||
// 1. Cek Koneksi Database
|
||||
if ($conn->connect_error) {
|
||||
$errors[] = "Koneksi database gagal: " . $conn->connect_error;
|
||||
} else {
|
||||
$success_logs[] = "Koneksi ke database `{$database}` berhasil!";
|
||||
}
|
||||
|
||||
// 2. Baca file database.sql untuk mengambil DDL jika tabel perlu dibuat
|
||||
$sql_content = '';
|
||||
$sql_file = __DIR__ . '/../database.sql';
|
||||
if (file_exists($sql_file)) {
|
||||
$sql_content = file_get_contents($sql_file);
|
||||
$success_logs[] = "File `database.sql` ditemukan dan berhasil dibaca.";
|
||||
} else {
|
||||
$errors[] = "File `database.sql` tidak ditemukan di {$sql_file}. Skrip akan menggunakan DDL cadangan.";
|
||||
}
|
||||
|
||||
// Helper untuk eksekusi query pembuatan tabel cadangan jika database.sql tidak ada
|
||||
$fallback_ddl = [
|
||||
'masyarakat_miskin' => "CREATE TABLE IF NOT EXISTS `masyarakat_miskin` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`nama` varchar(100) NOT NULL,
|
||||
`tanggal_lahir` date NOT NULL,
|
||||
`jenis_kelamin` enum('Laki-laki','Perempuan') NOT NULL,
|
||||
`nik` varchar(20),
|
||||
`alamat` text NOT NULL,
|
||||
`latitude` decimal(10,8) NOT NULL,
|
||||
`longitude` decimal(11,8) NOT NULL,
|
||||
`status_bpjs` enum('Ya','Tidak','Proses') DEFAULT 'Tidak',
|
||||
`no_hp` varchar(15),
|
||||
`pekerjaan` varchar(100),
|
||||
`pendapatan_bulanan` int(11),
|
||||
`jumlah_tanggungan` int(11),
|
||||
`status_rumah` enum('Milik Sendiri','Sewa','Menumpang') DEFAULT 'Menumpang',
|
||||
`kelurahan` varchar(100),
|
||||
`kecamatan` varchar(100),
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
'rumah_ibadah' => "CREATE TABLE IF NOT EXISTS `rumah_ibadah` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`nama` varchar(100) NOT NULL,
|
||||
`jenis` enum('Masjid','Gereja','Vihara','Kelenteng','Sinagog','Lain') NOT NULL,
|
||||
`latitude` decimal(10,8) NOT NULL,
|
||||
`longitude` decimal(11,8) NOT NULL,
|
||||
`alamat` text NOT NULL,
|
||||
`nama_pemimpin` varchar(100),
|
||||
`no_hp_pemimpin` varchar(15),
|
||||
`kapasitas` int(11),
|
||||
`tahun_didirikan` year,
|
||||
`keterangan` text,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
'bantuan_riwayat' => "CREATE TABLE IF NOT EXISTS `bantuan_riwayat` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`id_masyarakat` int(11) NOT NULL,
|
||||
`jenis_bantuan` varchar(100) NOT NULL,
|
||||
`tanggal_bantuan` date NOT NULL,
|
||||
`nilai` int(11) NOT NULL,
|
||||
`satuan` varchar(50),
|
||||
`keterangan` text,
|
||||
`nama_pemberi` varchar(100),
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`id_masyarakat`) REFERENCES `masyarakat_miskin`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
'bpjs_record' => "CREATE TABLE IF NOT EXISTS `bpjs_record` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`id_masyarakat` int(11) NOT NULL,
|
||||
`no_peserta` varchar(20) NOT NULL UNIQUE,
|
||||
`jenis_bpjs` enum('Kesehatan','Ketenagakerjaan','Jaminan Hari Tua') DEFAULT 'Kesehatan',
|
||||
`tingkat` enum('Penerima Bantuan Iuran (PBI)','Pekerja Penerima Upah','Pekerja Bukan Penerima Upah','Peserta Mandiri') DEFAULT 'Penerima Bantuan Iuran (PBI)',
|
||||
`tanggal_daftar` date NOT NULL,
|
||||
`status_aktif` enum('Aktif','Nonaktif','Suspended') DEFAULT 'Aktif',
|
||||
`faskes_tingkat_1` varchar(100),
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`id_masyarakat`) REFERENCES `masyarakat_miskin`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
'users' => "CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`username` varchar(50) NOT NULL UNIQUE,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`nama_lengkap` varchar(100) NOT NULL,
|
||||
`role` enum('Admin','Surveyor','Viewer') DEFAULT 'Surveyor',
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
'fasilitas_jalan' => "CREATE TABLE IF NOT EXISTS `fasilitas_jalan` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`nama` varchar(150) NOT NULL,
|
||||
`geojson` text NOT NULL,
|
||||
`tipe` varchar(50),
|
||||
`keterangan` text,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
'fasilitas_polygon' => "CREATE TABLE IF NOT EXISTS `fasilitas_polygon` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`nama` varchar(150) NOT NULL,
|
||||
`geojson` text NOT NULL,
|
||||
`tipe` varchar(50),
|
||||
`keterangan` text,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
'fasilitas_spbu' => "CREATE TABLE IF NOT EXISTS `fasilitas_spbu` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`nama` varchar(150) NOT NULL,
|
||||
`latitude` decimal(10,8) NOT NULL,
|
||||
`longitude` decimal(11,8) NOT NULL,
|
||||
`alamat` text,
|
||||
`is_24_jam` enum('Ya','Tidak') DEFAULT 'Tidak',
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
|
||||
];
|
||||
|
||||
// Cek dan buat tabel jika belum ada
|
||||
foreach ($required_tables as $table) {
|
||||
$check_table = $conn->query("SHOW TABLES LIKE '{$table}'");
|
||||
if ($check_table && $check_table->num_rows > 0) {
|
||||
// Tabel ada, cek jumlah baris
|
||||
$count_res = $conn->query("SELECT COUNT(*) as total FROM `{$table}`");
|
||||
$count = $count_res ? $count_res->fetch_assoc()['total'] : 0;
|
||||
$table_status[$table] = [
|
||||
'exists' => true,
|
||||
'count' => $count,
|
||||
'action' => 'No action needed'
|
||||
];
|
||||
} else {
|
||||
// Tabel tidak ada, coba buat dari file SQL
|
||||
$created = false;
|
||||
if (!empty($sql_content)) {
|
||||
// parsing DDL dari sql_content secara sederhana (karena multi_query bisa lambat / error untuk tabel spesifik)
|
||||
// Sebagai alternatif, jalankan DDL cadangan agar 100% aman dan presisi
|
||||
$ddl = $fallback_ddl[$table] ?? '';
|
||||
if ($ddl && $conn->query($ddl)) {
|
||||
$created = true;
|
||||
}
|
||||
} else {
|
||||
$ddl = $fallback_ddl[$table] ?? '';
|
||||
if ($ddl && $conn->query($ddl)) {
|
||||
$created = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($created) {
|
||||
$table_status[$table] = [
|
||||
'exists' => true,
|
||||
'count' => 0,
|
||||
'action' => 'Table created successfully'
|
||||
];
|
||||
$success_logs[] = "Tabel `{$table}` berhasil dibuat karena tidak ditemukan.";
|
||||
} else {
|
||||
$table_status[$table] = [
|
||||
'exists' => false,
|
||||
'count' => 0,
|
||||
'action' => 'Failed to create: ' . $conn->error
|
||||
];
|
||||
$errors[] = "Gagal membuat tabel `{$table}`: " . $conn->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Cek Default Admin User
|
||||
if (isset($table_status['users']) && $table_status['users']['exists']) {
|
||||
$check_admin = $conn->query("SELECT id FROM users WHERE username = 'admin'");
|
||||
if ($check_admin && $check_admin->num_rows === 0) {
|
||||
$insert_admin = $conn->query("INSERT INTO `users` (`username`, `password`, `nama_lengkap`, `role`) VALUES
|
||||
('admin', '5f4dcc3b5aa765d61d8327deb882cf99', 'Administrator', 'Admin')");
|
||||
if ($insert_admin) {
|
||||
$success_logs[] = "Akun default admin berhasil ditambahkan.";
|
||||
$table_status['users']['count'] += 1;
|
||||
} else {
|
||||
$errors[] = "Gagal menambahkan akun default admin: " . $conn->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Masukkan Data Sampel jika tabel kosong
|
||||
if (isset($table_status['masyarakat_miskin']) && $table_status['masyarakat_miskin']['exists'] && $table_status['masyarakat_miskin']['count'] == 0) {
|
||||
$insert_sampel = $conn->query("INSERT INTO `masyarakat_miskin`
|
||||
(`id`, `nama`, `tanggal_lahir`, `jenis_kelamin`, `nik`, `alamat`, `latitude`, `longitude`, `status_bpjs`, `no_hp`, `pekerjaan`, `pendapatan_bulanan`, `jumlah_tanggungan`, `status_rumah`, `kelurahan`, `kecamatan`) VALUES
|
||||
(1, 'Siti Nur Azizah', '1985-03-15', 'Perempuan', '6101234567890123', 'Jl. Mahakam No. 25', -0.06120000, 109.34450000, 'Ya', '081234567890', 'Buruh Harian', 1500000, 4, 'Menumpang', 'Sungai Jawi', 'Pontianak Kota')");
|
||||
if ($insert_sampel) {
|
||||
$success_logs[] = "Data sampel warga `Siti Nur Azizah` berhasil ditambahkan.";
|
||||
$table_status['masyarakat_miskin']['count'] = 1;
|
||||
|
||||
// Tambahkan juga riwayat bantuan dan BPJS record yang cocok
|
||||
$conn->query("INSERT INTO `bpjs_record` (`id_masyarakat`, `no_peserta`, `jenis_bpjs`, `tingkat`, `tanggal_daftar`, `status_aktif`, `faskes_tingkat_1`) VALUES
|
||||
(1, '0001234567890', 'Kesehatan', 'Penerima Bantuan Iuran (PBI)', '2020-01-15', 'Aktif', 'Puskesmas Pontianak Kota')");
|
||||
|
||||
$conn->query("INSERT INTO `bantuan_riwayat` (`id_masyarakat`, `jenis_bantuan`, `tanggal_bantuan`, `nilai`, `satuan`, `keterangan`, `nama_pemberi`) VALUES
|
||||
(1, 'Bantuan Pangan Non Tunai (BPNT)', '2026-05-10', 200000, 'Rupiah/Bulan', 'Bantuan Sembako tahap V', 'Dinas Sosial')");
|
||||
|
||||
$success_logs[] = "Data sampel BPJS & Riwayat Bantuan berhasil dihubungkan ke warga.";
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($table_status['rumah_ibadah']) && $table_status['rumah_ibadah']['exists'] && $table_status['rumah_ibadah']['count'] == 0) {
|
||||
$insert_sampel_ibadah = $conn->query("INSERT INTO `rumah_ibadah` (`nama`, `jenis`, `latitude`, `longitude`, `alamat`, `nama_pemimpin`, `no_hp_pemimpin`, `kapasitas`, `tahun_didirikan`) VALUES
|
||||
('Masjid Al-Hidayah', 'Masjid', -0.06150000, 109.34500000, 'Jl. Diponegoro No. 45', 'Ustaz Ahmad', '081234567890', 500, 2005),
|
||||
('Gereja Hati Kudus', 'Gereja', -0.06100000, 109.34400000, 'Jl. Jend Sudirman No. 12', 'Pdt. Bonaventura', '081234567891', 300, 1995)");
|
||||
if ($insert_sampel_ibadah) {
|
||||
$success_logs[] = "Data sampel rumah ibadah (Masjid & Gereja) berhasil ditambahkan.";
|
||||
$table_status['rumah_ibadah']['count'] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Bersihkan buffer output
|
||||
ob_end_clean();
|
||||
|
||||
// Tampilkan halaman Laporan Diagnostik
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Database Deployment Diagnostic - WebGIS</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Outfit', sans-serif;
|
||||
background-color: #0f172a;
|
||||
color: #e2e8f0;
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
background: rgba(30, 41, 59, 0.7);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
h1 {
|
||||
color: #38bdf8;
|
||||
font-weight: 800;
|
||||
margin-top: 0;
|
||||
border-bottom: 2px solid rgba(56, 189, 248, 0.3);
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.status-ok {
|
||||
background-color: #059669;
|
||||
color: #ecfdf5;
|
||||
}
|
||||
.status-error {
|
||||
background-color: #dc2626;
|
||||
color: #fef2f2;
|
||||
}
|
||||
.status-info {
|
||||
background-color: #2563eb;
|
||||
color: #eff6ff;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0;
|
||||
}
|
||||
th, td {
|
||||
text-align: left;
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
th {
|
||||
background-color: rgba(56, 189, 248, 0.1);
|
||||
color: #38bdf8;
|
||||
}
|
||||
.log-section {
|
||||
background-color: rgba(15, 23, 42, 0.6);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-top: 25px;
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
.log-success { color: #34d399; margin-bottom: 5px; }
|
||||
.log-error { color: #f87171; margin-bottom: 5px; }
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background: linear-gradient(135deg, #38bdf8 0%, #0284c7 100%);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
margin-top: 20px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 15px rgba(56, 189, 248, 0.4);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<h1>📊 Status Diagnostik Database WebGIS</h1>
|
||||
|
||||
<h3>Hasil Pengecekan Tabel</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nama Tabel</th>
|
||||
<th>Status Keberadaan</th>
|
||||
<th>Jumlah Baris Data</th>
|
||||
<th>Tindakan Sistem</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($required_tables as $table):
|
||||
$status = $table_status[$table] ?? ['exists' => false, 'count' => 0, 'action' => 'Error'];
|
||||
?>
|
||||
<tr>
|
||||
<td><strong><?php echo htmlspecialchars($table); ?></strong></td>
|
||||
<td>
|
||||
<?php if ($status['exists']): ?>
|
||||
<span class="status-badge status-ok">Tersedia</span>
|
||||
<?php else: ?>
|
||||
<span class="status-badge status-error">Tidak Ditemukan</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo (int)$status['count']; ?> baris</td>
|
||||
<td>
|
||||
<span class="status-badge <?php echo $status['action'] === 'No action needed' ? 'status-ok' : 'status-info'; ?>">
|
||||
<?php echo htmlspecialchars($status['action']); ?>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="log-section">
|
||||
<h4 style="margin: 0 0 10px 0; color: #38bdf8; font-family: sans-serif;">Logs Sistem:</h4>
|
||||
<?php foreach ($success_logs as $log): ?>
|
||||
<div class="log-success">[SUCCESS] <?php echo htmlspecialchars($log); ?></div>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($errors as $err): ?>
|
||||
<div class="log-error">[ERROR] <?php echo htmlspecialchars($err); ?></div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="../index.html" class="btn">Kembali ke Portal WebGIS →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
+34
-10
@@ -16,18 +16,42 @@ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
exit();
|
||||
}
|
||||
|
||||
$host = "localhost";
|
||||
$username = "root";
|
||||
$password = ""; // Jika XAMPP, kosongkan
|
||||
$database = "pemetaan_kemiskinan";
|
||||
// Baca dari Environment Variable (untuk deployment Coolify/server)
|
||||
// Jika tidak ada, fallback ke konfigurasi XAMPP lokal
|
||||
$host = getenv('DB_HOST') ?: ($_SERVER['DB_HOST'] ?? ($_ENV['DB_HOST'] ?? "localhost"));
|
||||
$username = getenv('DB_USER') ?: ($_SERVER['DB_USER'] ?? ($_ENV['DB_USER'] ?? "root"));
|
||||
$password = getenv('DB_PASSWORD') ?: ($_SERVER['DB_PASSWORD'] ?? ($_ENV['DB_PASSWORD'] ?? ""));
|
||||
$database = getenv('DB_DATABASE') ?: ($_SERVER['DB_DATABASE'] ?? ($_ENV['DB_DATABASE'] ?? "pemetaan_kemiskinan"));
|
||||
$port = getenv('DB_PORT') ?: ($_SERVER['DB_PORT'] ?? ($_ENV['DB_PORT'] ?? 3306));
|
||||
|
||||
// KONEKSI MYSQLI
|
||||
$conn = new mysqli($host, $username, $password, $database);
|
||||
// KONEKSI MYSQLI DENGAN LOGIKA FALLBACK
|
||||
$conn = null;
|
||||
|
||||
// CEK KONEKSI
|
||||
if ($conn->connect_error) {
|
||||
sendJSON('error', 'Koneksi database gagal: ' . $conn->connect_error);
|
||||
exit();
|
||||
// Aktifkan throwing exception untuk mysqli agar try-catch berfungsi dengan baik
|
||||
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
|
||||
|
||||
try {
|
||||
// 1. Coba koneksi utama sesuai konfigurasi Environment / Env File
|
||||
$conn = new mysqli($host, $username, $password, $database, (int)$port);
|
||||
} catch (Exception $e) {
|
||||
// 2. Coba koneksi Fallback Pertama: Backup Kredensial Keras Database Coolify (Internal Network)
|
||||
try {
|
||||
$conn = new mysqli("tk4ksw0w40kg080wkk4soww4", "mysql", "KBw0yKLccMMoBOZJCf8WDHAO93uI65om0s4ajnzQEt5mkuh0NaIytoWb7TgR5ciq", "default", 3306);
|
||||
} catch (Exception $e_backup) {
|
||||
// 3. Coba koneksi Fallback Kedua ke Docker Host lokal (host.docker.internal)
|
||||
try {
|
||||
$conn = new mysqli("host.docker.internal", "root", "", "pemetaan_kemiskinan", 3306);
|
||||
} catch (Exception $e_docker) {
|
||||
// 4. Coba koneksi Fallback Ketiga ke Localhost murni (XAMPP default)
|
||||
try {
|
||||
$conn = new mysqli("localhost", "root", "", "pemetaan_kemiskinan", 3306);
|
||||
} catch (Exception $e_local) {
|
||||
// Jika semua gagal, berikan respon error
|
||||
sendJSON('error', 'Koneksi database utama & seluruh fallback gagal. Error Utama: ' . $e->getMessage() . ' | Error Backup: ' . $e_backup->getMessage());
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SET CHARSET UTF-8
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
// ========================================
|
||||
// FILE: php/test_koneksi.php
|
||||
// Alat Tes Koneksi Database Independen
|
||||
// ========================================
|
||||
|
||||
// Set content type to HTML
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
|
||||
$status = null;
|
||||
$message = null;
|
||||
|
||||
// Mengambil input post jika ada
|
||||
$host = isset($_POST['host']) ? trim($_POST['host']) : '';
|
||||
$user = isset($_POST['user']) ? trim($_POST['user']) : '';
|
||||
$pass = isset($_POST['pass']) ? $_POST['pass'] : '';
|
||||
$db = isset($_POST['db']) ? trim($_POST['db']) : '';
|
||||
$port = isset($_POST['port']) ? trim($_POST['port']) : '3306';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Aktifkan error reporting untuk mysqli agar kita mendapat error detail
|
||||
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
|
||||
|
||||
try {
|
||||
$start_time = microtime(true);
|
||||
|
||||
// Coba hubungkan ke MySQL
|
||||
$conn = new mysqli($host, $user, $pass, $db, (int)$port);
|
||||
|
||||
$end_time = microtime(true);
|
||||
$execution_time = round(($end_time - $start_time) * 1000, 2);
|
||||
|
||||
$status = 'success';
|
||||
$message = "Koneksi Berhasil! Terhubung ke server MySQL versi " . $conn->server_info . " dalam " . $execution_time . " ms.";
|
||||
$conn->close();
|
||||
} catch (Exception $e) {
|
||||
$status = 'error';
|
||||
$message = "Koneksi Gagal: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>MySQL Connection Tester</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Outfit', sans-serif;
|
||||
background-color: #0f172a;
|
||||
color: #f1f5f9;
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.card {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
background: rgba(30, 41, 59, 0.7);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
color: #38bdf8;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
border-bottom: 2px solid rgba(56, 189, 248, 0.2);
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 600;
|
||||
color: #94a3b8;
|
||||
font-size: 14px;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 8px;
|
||||
background: #0f172a;
|
||||
color: white;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
}
|
||||
input:focus {
|
||||
outline: none;
|
||||
border-color: #38bdf8;
|
||||
}
|
||||
.btn {
|
||||
width: 100%;
|
||||
background: linear-gradient(135deg, #38bdf8 0%, #0284c7 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
transition: 0.2s;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 15px rgba(56, 189, 248, 0.4);
|
||||
}
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.alert-success {
|
||||
background-color: #dcfce3;
|
||||
color: #166534;
|
||||
border-left: 5px solid #22c55e;
|
||||
}
|
||||
.alert-error {
|
||||
background-color: #fee2e2;
|
||||
color: #991b1b;
|
||||
border-left: 5px solid #ef4444;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="card">
|
||||
<h2>🔌 MySQL Connection Tester</h2>
|
||||
|
||||
<?php if ($status !== null): ?>
|
||||
<div class="alert alert-<?php echo $status; ?>">
|
||||
<strong><?php echo $status === 'success' ? '✔ Sukses' : '❌ Gagal'; ?>:</strong>
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="">
|
||||
<div class="form-group">
|
||||
<label for="host">MySQL Host / IP Address</label>
|
||||
<input type="text" id="host" name="host" value="<?php echo htmlspecialchars($host); ?>" placeholder="Contoh: 103.xxx.xx.xx atau localhost" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="display: flex; gap: 15px;">
|
||||
<div style="flex: 2;">
|
||||
<label for="user">Username</label>
|
||||
<input type="text" id="user" name="user" value="<?php echo htmlspecialchars($user); ?>" placeholder="Contoh: root" required>
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<label for="port">Port</label>
|
||||
<input type="text" id="port" name="port" value="<?php echo htmlspecialchars($port); ?>" placeholder="3306" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pass">Password</label>
|
||||
<input type="password" id="pass" name="pass" value="<?php echo htmlspecialchars($pass); ?>" placeholder="Kosongkan jika tidak ada">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="db">Nama Database</label>
|
||||
<input type="text" id="db" name="db" value="<?php echo htmlspecialchars($db); ?>" placeholder="Contoh: pemetaan_kemiskinan" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">Test Koneksi ⚡</button>
|
||||
</form>
|
||||
|
||||
<p style="text-align: center; margin-top: 20px; margin-bottom: 0; font-size: 13px;">
|
||||
<a href="../index.html" style="color: #38bdf8; text-decoration: none;">← Kembali ke Portal WebGIS</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
# Use official PHP image with Apache
|
||||
FROM php:8.1-apache
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Set ServerName to suppress Apache warnings
|
||||
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
default-mysql-client \
|
||||
git \
|
||||
curl \
|
||||
zip \
|
||||
unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Enable Apache modules
|
||||
RUN a2enmod rewrite \
|
||||
&& a2enmod headers
|
||||
|
||||
# Install PHP extensions
|
||||
RUN docker-php-ext-install \
|
||||
mysqli \
|
||||
pdo \
|
||||
pdo_mysql
|
||||
|
||||
# Set PHP configuration
|
||||
RUN echo "display_errors = On" >> /usr/local/etc/php/conf.d/php.ini \
|
||||
&& echo "error_reporting = E_ALL" >> /usr/local/etc/php/conf.d/php.ini \
|
||||
&& echo "date.timezone = Asia/Jakarta" >> /usr/local/etc/php/conf.d/php.ini
|
||||
|
||||
# Copy project files
|
||||
COPY 01 /var/www/html
|
||||
|
||||
# Set permissions
|
||||
RUN chown -R www-data:www-data /var/www/html
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
# Start Apache
|
||||
CMD ["apache2-foreground"]
|
||||
Reference in New Issue
Block a user