Files
2026-06-11 18:00:11 +07:00

144 lines
6.5 KiB
PHP

<?php
// includes/config.php v2.0
// ============================================================
// Konfigurasi Database & Konstanta Aplikasi
// ============================================================
// ── Database ──────────────────────────────────────────────
define('DB_HOST', getenv('DB_HOST') ?: 'localhost');
define('DB_USER', getenv('DB_USER') ?: 'root');
define('DB_PASS', getenv('DB_PASS') ?: '');
define('DB_NAME', getenv('DB_NAME') ?: 'sig_kemiskinan');
define('DB_CHARSET', 'utf8mb4');
// ── Aplikasi ──────────────────────────────────────────────
define('APP_NAME', 'SIG Kemiskinan v2.0');
define('NOMINATIM_URL', 'https://nominatim.openstreetmap.org');
// ── Upload Foto ────────────────────────────────────────────
define('UPLOAD_DIR', __DIR__ . '/../assets/img/uploads/');
define('UPLOAD_URL', 'assets/img/uploads/');
define('MAX_FOTO_SIZE', 5 * 1024 * 1024); // 5 MB
define('ALLOWED_EXT', ['jpg','jpeg','png','webp']);
// ── Threshold Kategori Kemiskinan (Rp/bulan) ──────────────
// Disesuaikan dengan standar BPS & UMR Kalimantan Barat 2024
define('BATAS_SANGAT_MISKIN', 1500000); // < 1.5jt → sangat_miskin
define('BATAS_MISKIN', 3000000); // < 3jt → miskin
define('BATAS_HAMPIR_MISKIN', 5000000); // < 5jt → hampir_miskin
// >= 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]);
}