= 5jt → mampu // ── Notifikasi ──────────────────────────────────────────── define('DATA_USANG_HARI', 30); // data > 30 hari belum update = notif usang // ============================================================ // FUNGSI: Koneksi Database (Singleton PDO) // ============================================================ function getDB(): PDO { static $pdo = null; if ($pdo === null) { $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=" . DB_CHARSET; $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; try { $pdo = new PDO($dsn, DB_USER, DB_PASS, $options); } catch (PDOException $e) { http_response_code(500); die(json_encode(['success' => false, 'error' => 'Database connection failed: ' . $e->getMessage()])); } } return $pdo; } // ============================================================ // FUNGSI: Response JSON // ============================================================ function jsonResponse(mixed $data, int $code = 200): void { http_response_code($code); header('Content-Type: application/json; charset=utf-8'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization'); echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } // ============================================================ // FUNGSI: Baca Input (JSON body atau $_POST) // ============================================================ function getInput(): array { $raw = file_get_contents('php://input'); $data = json_decode($raw, true); if (json_last_error() !== JSON_ERROR_NONE) { $data = $_POST; } return $data ?? []; } // ============================================================ // FUNGSI: Hitung Jarak Haversine (meter) // ============================================================ function haversine(float $lat1, float $lng1, float $lat2, float $lng2): float { $R = 6371000; $dLat = deg2rad($lat2 - $lat1); $dLng = deg2rad($lng2 - $lng1); $a = sin($dLat/2)**2 + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLng/2)**2; return $R * 2 * atan2(sqrt($a), sqrt(1 - $a)); } // ============================================================ // FUNGSI: Hitung Kategori Kemiskinan Otomatis // ============================================================ function hitungKategori(?float $penghasilan): string { if ($penghasilan === null || $penghasilan < BATAS_SANGAT_MISKIN) return 'sangat_miskin'; if ($penghasilan < BATAS_MISKIN) return 'miskin'; if ($penghasilan < BATAS_HAMPIR_MISKIN) return 'hampir_miskin'; return 'mampu'; } // ============================================================ // FUNGSI: Assign Rumah Ibadah (kompatibel v1.1) // ============================================================ function assignRumahIbadah(int $pendudukId): void { try { $db = getDB(); $p = $db->prepare("SELECT lat, lng FROM penduduk_miskin WHERE id = ?"); $p->execute([$pendudukId]); $row = $p->fetch(); if (!$row) return; $ibadahList = $db->query("SELECT id, lat, lng, radius FROM rumah_ibadah")->fetchAll(); $closest = null; $closestDist = PHP_FLOAT_MAX; foreach ($ibadahList as $ri) { $dist = haversine((float)$row['lat'], (float)$row['lng'], (float)$ri['lat'], (float)$ri['lng']); if ($dist <= $ri['radius'] && $dist < $closestDist) { $closest = $ri['id']; $closestDist = $dist; } } $db->prepare("UPDATE penduduk_miskin SET rumah_ibadah_id = ?, jarak_ke_ibadah = ? WHERE id = ?") ->execute([$closest, $closest ? round($closestDist, 2) : null, $pendudukId]); } catch (\Exception $e) { /* abaikan error assign ibadah */ } } function reassignAll(): void { $db = getDB(); $all = $db->query("SELECT id FROM penduduk_miskin")->fetchAll(); foreach ($all as $row) assignRumahIbadah((int)$row['id']); } // ============================================================ // FUNGSI: Catat Riwayat Verifikasi // ============================================================ function catatRiwayat(int $pendudukId, int $userId, string $aksi, ?string $catatan = null, ?array $dataLama = null): void { $db = getDB(); $db->prepare(" INSERT INTO riwayat_verifikasi (penduduk_id, user_id, aksi, catatan, data_lama) VALUES (?, ?, ?, ?, ?) ")->execute([$pendudukId, $userId, $aksi, $catatan, $dataLama ? json_encode($dataLama, JSON_UNESCAPED_UNICODE) : null]); }