commit 240728285f14f348c92bbb8a6d48ba8177d91a8b Author: Muhammad Fathur Rahman Date: Wed Jun 10 20:22:46 2026 +0700 Initial commit diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..f9b3fbe --- /dev/null +++ b/.htaccess @@ -0,0 +1,7 @@ +DirectoryIndex index.php login.php + +RewriteEngine On + +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^api/?$ api.php [L] \ No newline at end of file diff --git a/api.php b/api.php new file mode 100644 index 0000000..ad5049a --- /dev/null +++ b/api.php @@ -0,0 +1,401 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); +} catch (PDOException $e) { + http_response_code(500); + echo json_encode(["success" => false, "message" => "Koneksi gagal: " . $e->getMessage()]); + exit(); +} + +$method = $_SERVER['REQUEST_METHOD']; +$input = json_decode(file_get_contents("php://input"), true) ?? []; +$resource = strtolower($_GET['resource'] ?? ''); + +switch ($resource) { + case 'ibadah': handleIbadah($pdo, $method, $input); break; + case 'miskin': handleMiskin($pdo, $method, $input); break; + case 'bantuan': handleBantuan($pdo, $method, $input); break; + default: + http_response_code(404); + echo json_encode(["success" => false, "message" => "Resource '$resource' tidak ditemukan. Gunakan: ibadah, miskin, bantuan"]); +} + +// ════════════════════════════════════════════════════════════════ +// RUMAH IBADAH +// ════════════════════════════════════════════════════════════════ +function handleIbadah($pdo, $method, $input) { + $validKategori = ['Masjid', 'Gereja', 'Gereja Katolik', 'Pura', 'Vihara', 'Klenteng']; + + switch ($method) { + case 'GET': + try { + $s = $pdo->query("SELECT * FROM rumah_ibadah ORDER BY kategori, nama_ibadah ASC"); + echo json_encode(["success" => true, "data" => $s->fetchAll()]); + } catch (Exception $e) { + echo json_encode(["success" => true, "data" => [], "warning" => "Tabel belum ada: " . $e->getMessage()]); + } + break; + + case 'POST': + if (isOperator()) { + http_response_code(403); + echo json_encode([ + "success" => false, + "message" => "Operator tidak punya akses ini" + ]); + return; + } + + foreach (['nama_ibadah', 'kategori', 'latitude', 'longitude', 'radius_meter'] as $f) { + if (!isset($input[$f]) || $input[$f] === '') { + http_response_code(400); + echo json_encode(["success" => false, "message" => "Field '$f' wajib diisi"]); + return; + } + } + if (!in_array($input['kategori'], $validKategori)) { + http_response_code(400); + echo json_encode(["success" => false, "message" => "Kategori tidak valid. Pilih: " . implode(', ', $validKategori)]); + return; + } + $s = $pdo->prepare( + "INSERT INTO rumah_ibadah (nama_ibadah, kategori, radius_meter, keterangan, alamat, latitude, longitude) + VALUES (?, ?, ?, ?, ?, ?, ?)" + ); + $s->execute([ + trim($input['nama_ibadah']), + $input['kategori'], + (int)$input['radius_meter'], + trim($input['keterangan'] ?? ''), + trim($input['alamat'] ?? ''), + (float)$input['latitude'], + (float)$input['longitude'], + ]); + echo json_encode(["success" => true, "message" => "Rumah ibadah disimpan", "id" => $pdo->lastInsertId()]); + break; + + case 'PUT': + if (isOperator()) { + http_response_code(403); + echo json_encode([ + "success" => false, + "message" => "Operator tidak punya akses ini" + ]); + return; + } + if (!isset($input['id'])) { + http_response_code(400); echo json_encode(["success" => false, "message" => "ID diperlukan"]); return; + } + if (!in_array($input['kategori'], $validKategori)) { + http_response_code(400); + echo json_encode(["success" => false, "message" => "Kategori tidak valid"]); + return; + } + $s = $pdo->prepare( + "UPDATE rumah_ibadah SET nama_ibadah=?, kategori=?, radius_meter=?, keterangan=?, alamat=?, latitude=?, longitude=? + WHERE id=?" + ); + $s->execute([ + trim($input['nama_ibadah']), + $input['kategori'], + (int)$input['radius_meter'], + trim($input['keterangan'] ?? ''), + trim($input['alamat'] ?? ''), + (float)$input['latitude'], + (float)$input['longitude'], + (int)$input['id'], + ]); + echo json_encode(["success" => true, "message" => "Rumah ibadah diperbarui"]); + break; + + case 'DELETE': + if (isOperator()) { + http_response_code(403); + echo json_encode([ + "success" => false, + "message" => "Operator tidak punya akses ini" + ]); + return; + } + + $id = $_GET['id'] ?? $input['id'] ?? null; + if (!$id) { http_response_code(400); echo json_encode(["success" => false, "message" => "ID diperlukan"]); return; } + $pdo->prepare("DELETE FROM rumah_ibadah WHERE id=?")->execute([(int)$id]); + echo json_encode(["success" => true, "message" => "Rumah ibadah dihapus"]); + break; + + default: + http_response_code(405); + echo json_encode(["success" => false, "message" => "Method tidak diizinkan"]); + } +} + +// ════════════════════════════════════════════════════════════════ +// PENDUDUK MISKIN +// ════════════════════════════════════════════════════════════════ +function handleMiskin($pdo, $method, $input) { + $validKelas = ['Kelas I', 'Kelas II', 'Kelas III']; + + switch ($method) { + case 'GET': + try { + // Urutkan: Kelas I dulu (prioritas tertinggi), lalu dalam jangkauan dulu + $s = $pdo->query( + "SELECT * FROM penduduk_miskin + ORDER BY + FIELD(kelas_kemiskinan, 'Kelas I', 'Kelas II', 'Kelas III'), + nama_kk ASC" + ); + echo json_encode(["success" => true, "data" => $s->fetchAll()]); + } catch (Exception $e) { + echo json_encode(["success" => true, "data" => [], "warning" => "Tabel belum ada: " . $e->getMessage()]); + } + break; + + case 'POST': + if (isOperator()) { + http_response_code(403); + echo json_encode([ + "success" => false, + "message" => "Operator tidak punya akses ini" + ]); + return; + } + + foreach (['nama_kk', 'latitude', 'longitude'] as $f) { + if (!isset($input[$f]) || $input[$f] === '') { + http_response_code(400); + echo json_encode(["success" => false, "message" => "Field '$f' wajib diisi"]); + return; + } + } + if (!empty($input['kelas_kemiskinan']) && !in_array($input['kelas_kemiskinan'], $validKelas)) { + http_response_code(400); + echo json_encode(["success" => false, "message" => "Kelas kemiskinan tidak valid"]); + return; + } + $s = $pdo->prepare( + "INSERT INTO penduduk_miskin (nama_kk, jumlah_jiwa, kelas_kemiskinan, keterangan, alamat, dalam_jangkauan, latitude, longitude) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)" + ); + $s->execute([ + trim($input['nama_kk']), + (int)($input['jumlah_jiwa'] ?? 1), + $input['kelas_kemiskinan'] ?? 'Kelas I', + trim($input['keterangan'] ?? ''), + trim($input['alamat'] ?? ''), + (int)($input['dalam_jangkauan'] ?? 0), + (float)$input['latitude'], + (float)$input['longitude'], + ]); + echo json_encode(["success" => true, "message" => "Data penduduk miskin disimpan", "id" => $pdo->lastInsertId()]); + break; + + case 'PUT': + if (isOperator()) { + http_response_code(403); + echo json_encode([ + "success" => false, + "message" => "Operator tidak punya akses ini" + ]); + return; + } + if (!isset($input['id'])) { + http_response_code(400); echo json_encode(["success" => false, "message" => "ID diperlukan"]); return; + } + $s = $pdo->prepare( + "UPDATE penduduk_miskin SET nama_kk=?, jumlah_jiwa=?, kelas_kemiskinan=?, keterangan=?, alamat=?, dalam_jangkauan=?, latitude=?, longitude=? + WHERE id=?" + ); + $s->execute([ + trim($input['nama_kk']), + (int)($input['jumlah_jiwa'] ?? 1), + $input['kelas_kemiskinan'] ?? 'Kelas I', + trim($input['keterangan'] ?? ''), + trim($input['alamat'] ?? ''), + (int)($input['dalam_jangkauan'] ?? 0), + (float)$input['latitude'], + (float)$input['longitude'], + (int)$input['id'], + ]); + echo json_encode(["success" => true, "message" => "Data penduduk miskin diperbarui"]); + break; + + case 'DELETE': + if (isOperator()) { + http_response_code(403); + echo json_encode([ + "success" => false, + "message" => "Operator tidak punya akses ini" + ]); + return; + } + + $id = $_GET['id'] ?? $input['id'] ?? null; + if (!$id) { http_response_code(400); echo json_encode(["success" => false, "message" => "ID diperlukan"]); return; } + $pdo->prepare("DELETE FROM penduduk_miskin WHERE id=?")->execute([(int)$id]); + echo json_encode(["success" => true, "message" => "Data penduduk miskin dihapus"]); + break; + + default: + http_response_code(405); + echo json_encode(["success" => false, "message" => "Method tidak diizinkan"]); + } +} +// ════════════════════════════════════════════════════════════════ +// RIWAYAT BANTUAN +// ════════════════════════════════════════════════════════════════ +function handleBantuan($pdo, $method, $input) { + switch ($method) { + + // GET?resource=bantuan&id_miskin=N — ambil riwayat bantuan 1 KK + case 'GET': + $idMiskin = (int)($_GET['id_miskin'] ?? 0); + if (!$idMiskin) { + http_response_code(400); + echo json_encode(["success"=>false,"message"=>"Parameter id_miskin diperlukan"]); + return; + } + $s = $pdo->prepare( + "SELECT *, DATEDIFF(CURDATE(), tanggal) AS hari_lalu + FROM riwayat_bantuan + WHERE id_miskin = ? + ORDER BY tanggal DESC" + ); + $s->execute([$idMiskin]); + $rows = $s->fetchAll(); + + // Hitung apakah sudah dapat bantuan hari ini + $sudahHariIni = false; + if (!empty($rows) && $rows[0]['hari_lalu'] == 0) { + $sudahHariIni = true; + } + + echo json_encode([ + "success" => true, + "data" => $rows, + "sudah_hari_ini" => $sudahHariIni, + ]); + break; + + // POST — tambah riwayat bantuan baru + case 'POST': + if (isOperator()) { + $idMiskin = (int)($input['id_miskin'] ?? 0); + $idIbadah = myIbadahId(); + + $sMiskin = $pdo->prepare( + "SELECT latitude, longitude + FROM penduduk_miskin + WHERE id=?" + ); + $sMiskin->execute([$idMiskin]); + $mk = $sMiskin->fetch(); + + $sIbadah = $pdo->prepare( + "SELECT latitude, longitude, radius_meter + FROM rumah_ibadah + WHERE id=?" + ); + $sIbadah->execute([$idIbadah]); + $ib = $sIbadah->fetch(); + + if (!$mk || !$ib) { + http_response_code(403); + echo json_encode([ + "success" => false, + "message" => "Akses ditolak" + ]); + return; + } + + $jarak = haversine( + $mk['latitude'], + $mk['longitude'], + $ib['latitude'], + $ib['longitude'] + ); + + if ($jarak > $ib['radius_meter']) { + http_response_code(403); + echo json_encode([ + "success" => false, + "message" => "KK ini di luar radius ibadah Anda" + ]); + return; + } + } + + foreach (['id_miskin','jenis_bantuan'] as $f) { + if (empty($input[$f])) { + http_response_code(400); + echo json_encode(["success"=>false,"message"=>"Field '$f' wajib diisi"]); + return; + } + } + $tanggal = $input['tanggal'] ?? date('Y-m-d'); // default hari ini + $s = $pdo->prepare( + "INSERT INTO riwayat_bantuan (id_miskin, tanggal, jenis_bantuan, keterangan, diberikan_oleh) + VALUES (?, ?, ?, ?, ?)" + ); + $s->execute([ + (int)$input['id_miskin'], + $tanggal, + trim($input['jenis_bantuan']), + trim($input['keterangan'] ?? ''), + trim($input['diberikan_oleh'] ?? ''), + ]); + echo json_encode(["success"=>true,"message"=>"Riwayat bantuan disimpan","id"=>$pdo->lastInsertId()]); + break; + + // DELETE?id=N — hapus satu riwayat bantuan + case 'DELETE': + $id = $_GET['id'] ?? $input['id'] ?? null; + if (!$id) { http_response_code(400); echo json_encode(["success"=>false,"message"=>"ID diperlukan"]); return; } + $pdo->prepare("DELETE FROM riwayat_bantuan WHERE id=?")->execute([(int)$id]); + echo json_encode(["success"=>true,"message"=>"Riwayat dihapus"]); + break; + + default: + http_response_code(405); + echo json_encode(["success"=>false,"message"=>"Method tidak diizinkan"]); + } +} +function haversine($lat1, $lon1, $lat2, $lon2) +{ + $R = 6371000; // meter + + $dLat = deg2rad($lat2 - $lat1); + $dLon = deg2rad($lon2 - $lon1); + + $a = + sin($dLat / 2) * sin($dLat / 2) + + cos(deg2rad($lat1)) * + cos(deg2rad($lat2)) * + sin($dLon / 2) * + sin($dLon / 2); + + return $R * 2 * atan2( + sqrt($a), + sqrt(1 - $a) + ); +} +?> \ No newline at end of file diff --git a/auth.php b/auth.php new file mode 100644 index 0000000..d0f3410 --- /dev/null +++ b/auth.php @@ -0,0 +1,31 @@ + false, + 'message' => 'Belum login', + 'redirect' => 'login.php' + ]); + exit; + } +} + +function isAdmin() { return ($_SESSION['role'] ?? '') === 'admin'; } +function isOperator() { return ($_SESSION['role'] ?? '') === 'operator'; } +function myIbadahId() { return (int)($_SESSION['id_ibadah'] ?? 0); } +function myUserId() { return (int)($_SESSION['user_id'] ?? 0); } \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..50fd3c0 --- /dev/null +++ b/index.php @@ -0,0 +1,2118 @@ + + + + + + + WebGIS — Pemetaan Penduduk Miskin + + + + + + + + + +
+ +
+

WebGIS Pemetaan Penduduk Miskin

+
Berbasis Partisipasi Rumah Ibadah
+
+
+ + 👤 + + [] + + + + + Logout + + + +
+
+ + +
+ Rumah Ibadah +
+
🕌Masjid
+
Gereja
+
Katolik
+
🛕Pura
+
☸️Vihara
+
🏮Klenteng
+
+
+ Penduduk Miskin +
+
Terjangkau
+
Terjangkau (Kritis)
+
Tidak Terjangkau
+
Tidak Terjangkau (Kritis)
+
+
+ Kelas +
+
Kelas ISangat Miskin
+
Kelas IIMiskin
+
Kelas IIIHampir Miskin
+
+
+ + +
+ +
+ Rumah Ibadah + + + + + + +
+ Penduduk + + +
+ Ekspor + + +
Pilih mode lalu klik di peta untuk menambah data.
+
+ + +
+ + + + + +
+
+
+
+ + + + + + + + + + + +
OK
+ + + + + + + + + + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..ca1b825 --- /dev/null +++ b/login.php @@ -0,0 +1,108 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $username = trim($_POST['username'] ?? ''); + $password = $_POST['password'] ?? ''; + + $s = $pdo->prepare("SELECT * FROM users WHERE username=? AND aktif=1"); + $s->execute([$username]); + $user = $s->fetch(PDO::FETCH_ASSOC); + + if ($user && password_verify($password, $user['password_hash'])) { + $_SESSION['user_id'] = $user['id']; + $_SESSION['username'] = $user['username']; + $_SESSION['role'] = $user['role']; + $_SESSION['id_ibadah'] = $user['id_ibadah']; + $_SESSION['nama'] = $user['nama_lengkap']; + header('Location: index.php'); + exit; + } else { + $error = 'Username atau password salah'; + } +} +?> + + + + + + Login — WebGIS Kemiskinan + + + + +
+ +

WebGIS Pemetaan Kemiskinan

+

Berbasis Partisipasi Rumah Ibadah

+ + +
+ + +
+ + + + + + + +
+
+ + \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..ee222ca --- /dev/null +++ b/logout.php @@ -0,0 +1,5 @@ + false, "message" => "Hanya menerima POST"]); + exit(); +} + +// ── KONFIGURASI ────────────────────────────────────────────── +$uploadDir = __DIR__ . '/uploads/'; +$uploadUrl = 'http://localhost/web_gis/01/uploads/'; +$maxSize = 5 * 1024 * 1024; // 5 MB +$allowedExt = ['jpg', 'jpeg', 'png', 'webp']; + +// Buat folder uploads jika belum ada +if (!is_dir($uploadDir)) { + mkdir($uploadDir, 0755, true); +} + +// ── VALIDASI ───────────────────────────────────────────────── +$type = $_POST['type'] ?? ''; // 'rumah' atau 'kk' +if (!in_array($type, ['rumah', 'kk'])) { + http_response_code(400); + echo json_encode(["success" => false, "message" => "Parameter 'type' harus 'rumah' atau 'kk'"]); + exit(); +} + +$idMiskin = (int)($_POST['id_miskin'] ?? 0); +if ($idMiskin <= 0) { + http_response_code(400); + echo json_encode(["success" => false, "message" => "Parameter 'id_miskin' tidak valid"]); + exit(); +} + +if (empty($_FILES['foto']) || $_FILES['foto']['error'] !== UPLOAD_ERR_OK) { + $errMsg = [ + UPLOAD_ERR_INI_SIZE => 'File terlalu besar (melebihi batas php.ini)', + UPLOAD_ERR_FORM_SIZE => 'File terlalu besar', + UPLOAD_ERR_PARTIAL => 'Upload tidak lengkap', + UPLOAD_ERR_NO_FILE => 'Tidak ada file yang diupload', + UPLOAD_ERR_NO_TMP_DIR => 'Folder temporary tidak ditemukan', + UPLOAD_ERR_CANT_WRITE => 'Gagal menulis file', + ]; + $code = $_FILES['foto']['error'] ?? UPLOAD_ERR_NO_FILE; + echo json_encode(["success" => false, "message" => $errMsg[$code] ?? 'Error upload tidak dikenal']); + exit(); +} + +// Validasi ukuran +if ($_FILES['foto']['size'] > $maxSize) { + echo json_encode(["success" => false, "message" => "Ukuran file maksimal 5 MB"]); + exit(); +} + +// Validasi ekstensi +$ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION)); +if (!in_array($ext, $allowedExt)) { + echo json_encode(["success" => false, "message" => "Format file harus JPG, PNG, atau WebP"]); + exit(); +} + +// Validasi MIME type (keamanan tambahan) +$finfo = finfo_open(FILEINFO_MIME_TYPE); +$mimeType = finfo_file($finfo, $_FILES['foto']['tmp_name']); +finfo_close($finfo); +$allowedMime = ['image/jpeg', 'image/png', 'image/webp']; +if (!in_array($mimeType, $allowedMime)) { + echo json_encode(["success" => false, "message" => "Tipe file tidak valid"]); + exit(); +} + +// ── SIMPAN FILE ────────────────────────────────────────────── +// Nama file: miskin_{id}_{type}_{timestamp}.{ext} +$filename = "miskin_{$idMiskin}_{$type}_" . time() . ".{$ext}"; +$destPath = $uploadDir . $filename; + +if (!move_uploaded_file($_FILES['foto']['tmp_name'], $destPath)) { + echo json_encode(["success" => false, "message" => "Gagal menyimpan file"]); + exit(); +} + +// ── UPDATE DATABASE ────────────────────────────────────────── +$host = "localhost"; +$dbname = "webgis_spbu"; +$username = "root"; +$password = ""; + +try { + $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Ambil foto lama untuk dihapus + $s = $pdo->prepare("SELECT foto_rumah, foto_kk FROM penduduk_miskin WHERE id=?"); + $s->execute([$idMiskin]); + $row = $s->fetch(PDO::FETCH_ASSOC); + + $col = $type === 'rumah' ? 'foto_rumah' : 'foto_kk'; + + // Hapus file lama jika ada + if ($row && !empty($row[$col])) { + $oldFile = $uploadDir . basename($row[$col]); + if (file_exists($oldFile)) unlink($oldFile); + } + + // Simpan path baru ke DB + $pdo->prepare("UPDATE penduduk_miskin SET {$col}=? WHERE id=?")->execute([$filename, $idMiskin]); + + echo json_encode([ + "success" => true, + "message" => "Foto berhasil diupload", + "filename" => $filename, + "url" => $uploadUrl . $filename, + ]); +} catch (PDOException $e) { + // File sudah tersimpan tapi DB gagal — hapus file + if (file_exists($destPath)) unlink($destPath); + echo json_encode(["success" => false, "message" => "DB error: " . $e->getMessage()]); +} +?> \ No newline at end of file diff --git a/uploads/miskin_24_kk_1780996699.jpg b/uploads/miskin_24_kk_1780996699.jpg new file mode 100644 index 0000000..5707753 Binary files /dev/null and b/uploads/miskin_24_kk_1780996699.jpg differ diff --git a/uploads/miskin_24_rumah_1780996694.jpg b/uploads/miskin_24_rumah_1780996694.jpg new file mode 100644 index 0000000..b457604 Binary files /dev/null and b/uploads/miskin_24_rumah_1780996694.jpg differ diff --git a/uploads/miskin_4_kk_1779623726.jpg b/uploads/miskin_4_kk_1779623726.jpg new file mode 100644 index 0000000..5707753 Binary files /dev/null and b/uploads/miskin_4_kk_1779623726.jpg differ diff --git a/uploads/miskin_4_rumah_1779623721.jpg b/uploads/miskin_4_rumah_1779623721.jpg new file mode 100644 index 0000000..b457604 Binary files /dev/null and b/uploads/miskin_4_rumah_1779623721.jpg differ