initial commit

This commit is contained in:
Abimanyu Ridho
2026-06-11 11:09:32 +07:00
commit 5ab7251f4f
30 changed files with 5828 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Deny from all
</IfModule>
# Disable directory listing
Options -Indexes
+9
View File
@@ -0,0 +1,9 @@
<?php
return [
'host' => 'localhost',
'user' => 'root',
'pass' => 'password',
'name' => 'webgis_poverty',
'charset' => 'utf8mb4',
];
+52
View File
@@ -0,0 +1,52 @@
<?php
// api/config/database.php
mysqli_report(MYSQLI_REPORT_OFF);
if (!function_exists('loadDatabaseConfig')) {
function loadDatabaseConfig(): array {
$config = [
'host' => getenv('DB_HOST') ?: 'localhost',
'user' => getenv('DB_USER') ?: 'root',
'pass' => getenv('DB_PASS') ?: '',
'name' => getenv('DB_NAME') ?: 'webgis_poverty',
'charset' => getenv('DB_CHARSET') ?: 'utf8mb4',
];
$localConfigFile = __DIR__ . '/database.local.php';
if (is_file($localConfigFile)) {
$localConfig = require $localConfigFile;
if (is_array($localConfig)) {
$config = array_merge($config, array_intersect_key($localConfig, $config));
}
}
return $config;
}
}
$dbConfig = loadDatabaseConfig();
define('DB_HOST', $dbConfig['host']);
define('DB_USER', $dbConfig['user']);
define('DB_PASS', $dbConfig['pass']);
define('DB_NAME', $dbConfig['name']);
define('DB_CHARSET', $dbConfig['charset']);
function getDB(): mysqli {
static $conn = null;
if ($conn === null) {
$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($conn->connect_error) {
error_log('DB connection failed: ' . $conn->connect_error);
http_response_code(500);
echo json_encode([
'status' => 'error',
'message' => 'Koneksi database gagal'
]);
exit;
}
$conn->set_charset(DB_CHARSET);
}
return $conn;
}
+112
View File
@@ -0,0 +1,112 @@
<?php
// api/data_jalan.php
require_once __DIR__ . '/config/database.php';
require_once __DIR__ . '/helpers/response.php';
setCORSHeaders();
$db = getDB();
$method = getMethod();
requireWriteAuth($method);
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
switch ($method) {
case 'GET':
if ($id > 0) {
$stmt = $db->prepare(
"SELECT id, nama_jalan, status_jalan,
panjang_meter, keterangan,
CAST(geojson AS CHAR) AS geojson,
created_at
FROM data_jalan WHERE id = ?"
);
$stmt->bind_param('i', $id);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
if (!$row) sendError('Data tidak ditemukan', 404);
// Parse geojson string menjadi object
$row['geojson'] = json_decode($row['geojson']);
$row['panjang_meter'] = (float)$row['panjang_meter'];
sendSuccess($row);
} else {
$rows = [];
$res = $db->query(
"SELECT id, nama_jalan, status_jalan,
panjang_meter, keterangan,
CAST(geojson AS CHAR) AS geojson,
created_at
FROM data_jalan ORDER BY created_at DESC"
);
while ($r = $res->fetch_assoc()) {
$r['geojson'] = json_decode($r['geojson']);
$r['panjang_meter'] = (float)$r['panjang_meter'];
$rows[] = $r;
}
sendSuccess($rows);
}
break;
case 'POST':
$body = getBody();
foreach (['nama_jalan','status_jalan','geojson','panjang_meter'] as $f) {
if (!isset($body[$f])) sendError("Field '$f' wajib diisi");
}
// Validasi GeoJSON LineString
$geo = is_array($body['geojson'])
? $body['geojson']
: json_decode($body['geojson'], true);
if (!$geo || $geo['type'] !== 'LineString') {
sendError('GeoJSON harus bertipe LineString');
}
$geoStr = json_encode($geo);
$panjang = (float)$body['panjang_meter'];
$stmt = $db->prepare(
"INSERT INTO data_jalan
(nama_jalan, status_jalan, panjang_meter, keterangan, geojson)
VALUES (?, ?, ?, ?, ?)"
);
$stmt->bind_param('ssdss',
$body['nama_jalan'], $body['status_jalan'],
$panjang, $body['keterangan'], $geoStr
);
executeOrFail($stmt, 'Gagal menyimpan data jalan');
sendSuccess(['id' => $db->insert_id], 'Data jalan berhasil disimpan', 201);
break;
case 'PUT':
if ($id <= 0) sendError('ID wajib disertakan');
$body = getBody();
$geo = is_array($body['geojson'])
? $body['geojson']
: json_decode($body['geojson'], true);
$geoStr = json_encode($geo);
$panjang = (float)$body['panjang_meter'];
$stmt = $db->prepare(
"UPDATE data_jalan
SET nama_jalan=?, status_jalan=?,
panjang_meter=?, keterangan=?, geojson=?
WHERE id=?"
);
$stmt->bind_param('ssdssi',
$body['nama_jalan'], $body['status_jalan'],
$panjang, $body['keterangan'], $geoStr, $id
);
executeOrFail($stmt, 'Gagal memperbarui data jalan');
sendSuccess(null, 'Data jalan berhasil diperbarui');
break;
case 'DELETE':
if ($id <= 0) sendError('ID wajib disertakan');
$stmt = $db->prepare("DELETE FROM data_jalan WHERE id=?");
$stmt->bind_param('i', $id);
executeOrFail($stmt, 'Gagal menghapus data jalan');
$stmt->affected_rows > 0
? sendSuccess(null, 'Data jalan berhasil dihapus')
: sendError('Data tidak ditemukan', 404);
break;
default:
sendError('Method tidak diizinkan', 405);
}
+112
View File
@@ -0,0 +1,112 @@
<?php
// api/data_persil.php
require_once __DIR__ . '/config/database.php';
require_once __DIR__ . '/helpers/response.php';
setCORSHeaders();
$db = getDB();
$method = getMethod();
requireWriteAuth($method);
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
switch ($method) {
case 'GET':
if ($id > 0) {
$stmt = $db->prepare(
"SELECT id, nama_pemilik, no_sertifikat, jenis_hak,
luas_m2, keterangan,
CAST(geojson AS CHAR) AS geojson,
created_at
FROM data_parsil WHERE id = ?"
);
$stmt->bind_param('i', $id);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
if (!$row) sendError('Data tidak ditemukan', 404);
$row['geojson'] = json_decode($row['geojson']);
$row['luas_m2'] = (float)$row['luas_m2'];
sendSuccess($row);
} else {
$rows = [];
$res = $db->query(
"SELECT id, nama_pemilik, no_sertifikat, jenis_hak,
luas_m2, keterangan,
CAST(geojson AS CHAR) AS geojson,
created_at
FROM data_parsil ORDER BY created_at DESC"
);
while ($r = $res->fetch_assoc()) {
$r['geojson'] = json_decode($r['geojson']);
$r['luas_m2'] = (float)$r['luas_m2'];
$rows[] = $r;
}
sendSuccess($rows);
}
break;
case 'POST':
$body = getBody();
foreach (['nama_pemilik','jenis_hak','geojson','luas_m2'] as $f) {
if (!isset($body[$f])) sendError("Field '$f' wajib diisi");
}
$geo = is_array($body['geojson'])
? $body['geojson']
: json_decode($body['geojson'], true);
if (!$geo || $geo['type'] !== 'Polygon') {
sendError('GeoJSON harus bertipe Polygon');
}
$geoStr = json_encode($geo);
$luas = (float)$body['luas_m2'];
$stmt = $db->prepare(
"INSERT INTO data_parsil
(nama_pemilik, no_sertifikat, jenis_hak, luas_m2, keterangan, geojson)
VALUES (?, ?, ?, ?, ?, ?)"
);
$stmt->bind_param('sssdss',
$body['nama_pemilik'], $body['no_sertifikat'],
$body['jenis_hak'], $luas,
$body['keterangan'], $geoStr
);
executeOrFail($stmt, 'Gagal menyimpan data persil');
sendSuccess(['id' => $db->insert_id], 'Data persil berhasil disimpan', 201);
break;
case 'PUT':
if ($id <= 0) sendError('ID wajib disertakan');
$body = getBody();
$geo = is_array($body['geojson'])
? $body['geojson']
: json_decode($body['geojson'], true);
$geoStr = json_encode($geo);
$luas = (float)$body['luas_m2'];
$stmt = $db->prepare(
"UPDATE data_parsil
SET nama_pemilik=?, no_sertifikat=?, jenis_hak=?,
luas_m2=?, keterangan=?, geojson=?
WHERE id=?"
);
$stmt->bind_param('sssdssi',
$body['nama_pemilik'], $body['no_sertifikat'],
$body['jenis_hak'], $luas,
$body['keterangan'], $geoStr, $id
);
executeOrFail($stmt, 'Gagal memperbarui data persil');
sendSuccess(null, 'Data persil berhasil diperbarui');
break;
case 'DELETE':
if ($id <= 0) sendError('ID wajib disertakan');
$stmt = $db->prepare("DELETE FROM data_parsil WHERE id=?");
$stmt->bind_param('i', $id);
executeOrFail($stmt, 'Gagal menghapus data persil');
$stmt->affected_rows > 0
? sendSuccess(null, 'Data persil berhasil dihapus')
: sendError('Data tidak ditemukan', 404);
break;
default:
sendError('Method tidak diizinkan', 405);
}
+100
View File
@@ -0,0 +1,100 @@
<?php
// api/helpers/response.php
function setCORSHeaders(): void {
header('Content-Type: application/json; charset=utf-8');
header('Vary: Origin');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Token');
header('X-Content-Type-Options: nosniff');
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
$allowed = false;
if ($origin !== '') {
$origin = trim($origin);
$allowedOrigins = parseAllowedOrigins(getenv('CORS_ALLOWED_ORIGINS') ?: '');
if (!empty($allowedOrigins)) {
$allowed = in_array($origin, $allowedOrigins, true);
} else {
$allowed = (bool)preg_match('/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/', $origin);
}
if ($allowed) {
header('Access-Control-Allow-Origin: ' . $origin);
}
}
if (getMethod() === 'OPTIONS') {
http_response_code(($origin !== '' && !$allowed) ? 403 : 204);
exit;
}
}
function parseAllowedOrigins(string $raw): array {
$parts = array_map('trim', explode(',', $raw));
return array_values(array_filter($parts, static fn ($v) => $v !== ''));
}
function sendJSON(mixed $data, int $code = 200): void {
http_response_code($code);
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
exit;
}
function sendSuccess(mixed $data = null, string $message = 'OK', int $code = 200): void {
sendJSON(['status' => 'success', 'message' => $message, 'data' => $data], $code);
}
function sendError(string $message, int $code = 400): void {
sendJSON(['status' => 'error', 'message' => $message], $code);
}
function requireWriteAuth(string $method): void {
if (!in_array($method, ['POST', 'PUT', 'DELETE'], true)) {
return;
}
$expected = (string)(getenv('API_WRITE_TOKEN') ?: '');
if ($expected === '') {
return;
}
$provided = (string)($_SERVER['HTTP_X_API_TOKEN'] ?? '');
if ($provided === '') {
$auth = (string)($_SERVER['HTTP_AUTHORIZATION'] ?? '');
if (preg_match('/Bearer\s+(.+)/i', $auth, $m)) {
$provided = trim($m[1]);
}
}
if ($provided === '' || !hash_equals($expected, $provided)) {
sendError('Unauthorized', 401);
}
}
function executeOrFail(mysqli_stmt $stmt, string $defaultMessage = 'Operasi database gagal'): void {
if ($stmt->execute()) {
return;
}
$errno = $stmt->errno;
$error = $stmt->error;
error_log('DB stmt error [' . $errno . ']: ' . $error);
if ($errno === 1062) {
sendError('Data duplikat terdeteksi', 409);
}
if ($errno === 1451 || $errno === 1452) {
sendError('Relasi data tidak valid', 422);
}
sendError($defaultMessage, 500);
}
function getBody(): array {
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
return is_array($data) ? $data : [];
}
function getMethod(): string {
return strtoupper($_SERVER['REQUEST_METHOD']);
}
+100
View File
@@ -0,0 +1,100 @@
<?php
// api/log_bantuan.php
require_once __DIR__ . '/config/database.php';
require_once __DIR__ . '/helpers/response.php';
setCORSHeaders();
$db = getDB();
$method = getMethod();
requireWriteAuth($method);
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$pmId = isset($_GET['penduduk_miskin_id']) ? (int)$_GET['penduduk_miskin_id'] : 0;
switch ($method) {
case 'GET':
if ($pmId > 0) {
// Semua log untuk satu penduduk miskin
$stmt = $db->prepare(
"SELECT lb.*,
ri.nama AS nama_rumah_ibadah,
ri.jenis AS jenis_rumah_ibadah
FROM log_bantuan lb
JOIN rumah_ibadah ri ON ri.id = lb.rumah_ibadah_id
WHERE lb.penduduk_miskin_id = ?
ORDER BY lb.tanggal_bantuan DESC"
);
$stmt->bind_param('i', $pmId);
$stmt->execute();
$rows = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
sendSuccess($rows);
} elseif ($id > 0) {
$stmt = $db->prepare(
"SELECT lb.*,
ri.nama AS nama_rumah_ibadah,
pm.nama AS nama_penduduk
FROM log_bantuan lb
JOIN rumah_ibadah ri ON ri.id = lb.rumah_ibadah_id
JOIN penduduk_miskin pm ON pm.id = lb.penduduk_miskin_id
WHERE lb.id = ?"
);
$stmt->bind_param('i', $id);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$row ? sendSuccess($row) : sendError('Data tidak ditemukan', 404);
} else {
// Semua log bantuan dengan statistik
$sql = "SELECT lb.*,
ri.nama AS nama_rumah_ibadah,
pm.nama AS nama_penduduk
FROM log_bantuan lb
JOIN rumah_ibadah ri ON ri.id = lb.rumah_ibadah_id
JOIN penduduk_miskin pm ON pm.id = lb.penduduk_miskin_id
ORDER BY lb.tanggal_bantuan DESC
LIMIT 200";
$rows = $db->query($sql)->fetch_all(MYSQLI_ASSOC);
sendSuccess($rows);
}
break;
case 'POST':
$body = getBody();
foreach (['penduduk_miskin_id','rumah_ibadah_id','tipe_bantuan','tanggal_bantuan'] as $f) {
if (empty($body[$f])) sendError("Field '$f' wajib diisi");
}
$nilai = isset($body['nilai_bantuan']) && $body['nilai_bantuan'] !== ''
? (float)$body['nilai_bantuan'] : null;
$stmt = $db->prepare(
"INSERT INTO log_bantuan
(penduduk_miskin_id, rumah_ibadah_id, tipe_bantuan,
sub_kategori, keterangan, tanggal_bantuan, nilai_bantuan)
VALUES (?, ?, ?, ?, ?, ?, ?)"
);
$stmt->bind_param(
'iissssd',
$body['penduduk_miskin_id'],
$body['rumah_ibadah_id'],
$body['tipe_bantuan'],
$body['sub_kategori'],
$body['keterangan'],
$body['tanggal_bantuan'],
$nilai
);
executeOrFail($stmt, 'Gagal mencatat log bantuan');
sendSuccess(['id' => $db->insert_id], 'Log bantuan berhasil dicatat', 201);
break;
case 'DELETE':
if ($id <= 0) sendError('ID wajib disertakan');
$stmt = $db->prepare("DELETE FROM log_bantuan WHERE id=?");
$stmt->bind_param('i', $id);
executeOrFail($stmt, 'Gagal menghapus log bantuan');
$stmt->affected_rows > 0
? sendSuccess(null, 'Log bantuan berhasil dihapus')
: sendError('Data tidak ditemukan', 404);
break;
default:
sendError('Method tidak diizinkan', 405);
}
+221
View File
@@ -0,0 +1,221 @@
<?php
// api/penduduk_miskin.php
require_once __DIR__ . '/config/database.php';
require_once __DIR__ . '/helpers/response.php';
setCORSHeaders();
$db = getDB();
$method = getMethod();
requireWriteAuth($method);
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
// Endpoint khusus: recalc proximity semua penduduk miskin sekaligus
if ($method === 'POST' && isset($_GET['action']) && $_GET['action'] === 'recalc_all') {
requireWriteAuth('POST');
$allPm = $db->query("SELECT id, latitude, longitude FROM penduduk_miskin");
$updated = 0;
while ($pm = $allPm->fetch_assoc()) {
$prox = hitungProximity($db, (float)$pm['latitude'], (float)$pm['longitude']);
$statusP = $prox['status'];
$riId = $prox['rumah_ibadah_id'];
$stmt = $db->prepare(
"UPDATE penduduk_miskin SET status_proximity=?, rumah_ibadah_id=? WHERE id=?"
);
$stmt->bind_param('sii', $statusP, $riId, $pm['id']);
$stmt->execute();
$updated++;
}
sendSuccess(['updated' => $updated], "Proximity $updated data diperbarui");
}
switch ($method) {
// ── GET ───────────────────────────────────────────────────────────
case 'GET':
if ($id > 0) {
$stmt = $db->prepare(
"SELECT pm.*,
ri.nama AS nama_rumah_ibadah,
ri.jenis AS jenis_rumah_ibadah
FROM penduduk_miskin pm
LEFT JOIN rumah_ibadah ri ON ri.id = pm.rumah_ibadah_id
WHERE pm.id = ?"
);
$stmt->bind_param('i', $id);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
if (!$row) sendError('Data tidak ditemukan', 404);
$row['latitude'] = (float)$row['latitude'];
$row['longitude'] = (float)$row['longitude'];
// Ambil ringkasan log bantuan
$stmtLog = $db->prepare(
"SELECT tipe_bantuan, COUNT(*) AS jumlah
FROM log_bantuan
WHERE penduduk_miskin_id = ?
GROUP BY tipe_bantuan"
);
$stmtLog->bind_param('i', $id);
$stmtLog->execute();
$logs = [];
$resLog = $stmtLog->get_result();
while ($l = $resLog->fetch_assoc()) $logs[] = $l;
$row['ringkasan_bantuan'] = $logs;
sendSuccess($row);
} else {
// GET semua + proximity recalculation cache
$sql = "SELECT pm.id, pm.nama, pm.no_wa, pm.nik, pm.alamat,
pm.jumlah_anggota, pm.latitude, pm.longitude,
pm.status_proximity, pm.rumah_ibadah_id,
ri.nama AS nama_rumah_ibadah,
-- hitung berapa kali dapat bantuan
(SELECT COUNT(*) FROM log_bantuan lb
WHERE lb.penduduk_miskin_id = pm.id) AS total_bantuan,
(SELECT COUNT(*) FROM log_bantuan lb
WHERE lb.penduduk_miskin_id = pm.id
AND lb.tipe_bantuan = 'Pemberdayaan') AS bantuan_pemberdayaan,
(SELECT COUNT(*) FROM log_bantuan lb
WHERE lb.penduduk_miskin_id = pm.id
AND lb.tipe_bantuan = 'Konsumtif') AS bantuan_konsumtif
FROM penduduk_miskin pm
LEFT JOIN rumah_ibadah ri ON ri.id = pm.rumah_ibadah_id
ORDER BY pm.created_at DESC";
$result = $db->query($sql);
$rows = [];
while ($r = $result->fetch_assoc()) {
$r['latitude'] = (float)$r['latitude'];
$r['longitude'] = (float)$r['longitude'];
$r['total_bantuan'] = (int)$r['total_bantuan'];
$r['bantuan_pemberdayaan'] = (int)$r['bantuan_pemberdayaan'];
$r['bantuan_konsumtif'] = (int)$r['bantuan_konsumtif'];
$rows[] = $r;
}
sendSuccess($rows);
}
break;
// ── POST ──────────────────────────────────────────────────────────
case 'POST':
$body = getBody();
foreach (['nama', 'latitude', 'longitude'] as $f) {
if (empty($body[$f]) && $body[$f] !== 0) sendError("Field '$f' wajib diisi");
}
// Hitung proximity ke semua rumah ibadah
$proximity = hitungProximity($db, $body['latitude'], $body['longitude']);
$stmt = $db->prepare(
"INSERT INTO penduduk_miskin
(nama, no_wa, nik, alamat, jumlah_anggota,
latitude, longitude, status_proximity, rumah_ibadah_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
$jumlah = isset($body['jumlah_anggota']) ? (int)$body['jumlah_anggota'] : 1;
$statusP = $proximity['status'];
$riId = $proximity['rumah_ibadah_id'];
$stmt->bind_param(
'ssssiddsi',
$body['nama'], $body['no_wa'], $body['nik'],
$body['alamat'], $jumlah,
$body['latitude'], $body['longitude'],
$statusP, $riId
);
executeOrFail($stmt, 'Gagal menyimpan data penduduk miskin');
$newId = $db->insert_id;
sendSuccess(
['id' => $newId, 'proximity' => $proximity],
'Penduduk Miskin berhasil disimpan',
201
);
break;
// ── PUT ───────────────────────────────────────────────────────────
case 'PUT':
if ($id <= 0) sendError('ID wajib disertakan');
$body = getBody();
$proximity = hitungProximity($db, $body['latitude'], $body['longitude']);
$statusP = $proximity['status'];
$riId = $proximity['rumah_ibadah_id'];
$jumlah = isset($body['jumlah_anggota']) ? (int)$body['jumlah_anggota'] : 1;
$stmt = $db->prepare(
"UPDATE penduduk_miskin
SET nama=?, no_wa=?, nik=?, alamat=?, jumlah_anggota=?,
latitude=?, longitude=?, status_proximity=?, rumah_ibadah_id=?
WHERE id=?"
);
$stmt->bind_param(
'ssssiddsii',
$body['nama'], $body['no_wa'], $body['nik'],
$body['alamat'], $jumlah,
$body['latitude'], $body['longitude'],
$statusP, $riId, $id
);
executeOrFail($stmt, 'Gagal memperbarui data penduduk miskin');
sendSuccess(['proximity' => $proximity], 'Data berhasil diperbarui');
break;
// ── DELETE ────────────────────────────────────────────────────────
case 'DELETE':
if ($id <= 0) sendError('ID wajib disertakan');
$stmt = $db->prepare("DELETE FROM penduduk_miskin WHERE id=?");
$stmt->bind_param('i', $id);
executeOrFail($stmt, 'Gagal menghapus data penduduk miskin');
$stmt->affected_rows > 0
? sendSuccess(null, 'Data berhasil dihapus')
: sendError('Data tidak ditemukan', 404);
break;
default:
sendError('Method tidak diizinkan', 405);
}
// ─────────────────────────────────────────────────────────────────────────────
// HELPER: Hitung proximity penduduk miskin terhadap semua rumah ibadah
// Menggunakan Haversine formula di PHP untuk validasi server-side
// ─────────────────────────────────────────────────────────────────────────────
function hitungProximity(mysqli $db, float $lat, float $lng): array {
$result = $db->query(
"SELECT id, nama, latitude, longitude, radius_meter FROM rumah_ibadah"
);
$status = 'luar_radius';
$riId = null;
$riNama = null;
$minDistAll = PHP_INT_MAX; // jarak ke RI terdekat (apapun statusnya)
$minDistIn = PHP_INT_MAX; // jarak ke RI terdekat yang dalam radius
while ($ri = $result->fetch_assoc()) {
$dist = haversine($lat, $lng, (float)$ri['latitude'], (float)$ri['longitude']);
// Lacak jarak terdekat secara keseluruhan (untuk field jarak_meter)
if ($dist < $minDistAll) {
$minDistAll = $dist;
}
// Cek apakah titik ini masuk dalam radius RI ini
if ($dist <= (int)$ri['radius_meter'] && $dist < $minDistIn) {
$minDistIn = $dist;
$status = 'dalam_radius';
$riId = (int)$ri['id'];
$riNama = $ri['nama'];
}
}
return [
'status' => $status,
'rumah_ibadah_id' => $riId,
'nama_rumah_ibadah' => $riNama,
'jarak_meter' => round($minDistAll, 2)
];
}
function haversine(float $lat1, float $lng1, float $lat2, float $lng2): float {
$R = 6371000; // radius bumi dalam meter
$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));
}
+112
View File
@@ -0,0 +1,112 @@
<?php
// api/rumah_ibadah.php
require_once __DIR__ . '/config/database.php';
require_once __DIR__ . '/helpers/response.php';
setCORSHeaders();
$db = getDB();
$method = getMethod();
requireWriteAuth($method);
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
switch ($method) {
// ── GET: ambil semua atau satu data ──────────────────────────────
case 'GET':
if ($id > 0) {
$stmt = $db->prepare(
"SELECT id, nama, jenis, alamat, no_wa,
latitude, longitude, radius_meter,
created_at
FROM rumah_ibadah WHERE id = ?"
);
$stmt->bind_param('i', $id);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
if ($row) {
$row['latitude'] = (float)$row['latitude'];
$row['longitude'] = (float)$row['longitude'];
$row['radius_meter'] = (int)$row['radius_meter'];
}
$row ? sendSuccess($row) : sendError('Data tidak ditemukan', 404);
} else {
$sql = "SELECT id, nama, jenis, alamat, no_wa,
latitude, longitude, radius_meter,
created_at
FROM rumah_ibadah ORDER BY created_at DESC";
$result = $db->query($sql);
$rows = [];
while ($r = $result->fetch_assoc()) {
$r['latitude'] = (float)$r['latitude'];
$r['longitude'] = (float)$r['longitude'];
$r['radius_meter'] = (int)$r['radius_meter'];
$rows[] = $r;
}
sendSuccess($rows);
}
break;
// ── POST: tambah data baru ────────────────────────────────────────
case 'POST':
$body = getBody();
$required = ['nama', 'jenis', 'latitude', 'longitude', 'radius_meter'];
foreach ($required as $field) {
if (empty($body[$field]) && $body[$field] !== 0) {
sendError("Field '$field' wajib diisi");
}
}
$stmt = $db->prepare(
"INSERT INTO rumah_ibadah
(nama, jenis, alamat, no_wa, latitude, longitude, radius_meter)
VALUES (?, ?, ?, ?, ?, ?, ?)"
);
$stmt->bind_param(
'ssssddi',
$body['nama'],
$body['jenis'],
$body['alamat'],
$body['no_wa'],
$body['latitude'],
$body['longitude'],
$body['radius_meter']
);
executeOrFail($stmt, 'Gagal menyimpan rumah ibadah');
$newId = $db->insert_id;
sendSuccess(['id' => $newId], 'Rumah Ibadah berhasil disimpan', 201);
break;
// ── PUT: update data ──────────────────────────────────────────────
case 'PUT':
if ($id <= 0) sendError('ID wajib disertakan');
$body = getBody();
$stmt = $db->prepare(
"UPDATE rumah_ibadah
SET nama=?, jenis=?, alamat=?, no_wa=?,
latitude=?, longitude=?, radius_meter=?
WHERE id=?"
);
$stmt->bind_param(
'ssssddii',
$body['nama'], $body['jenis'],
$body['alamat'], $body['no_wa'],
$body['latitude'], $body['longitude'],
$body['radius_meter'], $id
);
executeOrFail($stmt, 'Gagal memperbarui rumah ibadah');
sendSuccess(null, 'Rumah Ibadah berhasil diperbarui');
break;
// ── DELETE: hapus data ────────────────────────────────────────────
case 'DELETE':
if ($id <= 0) sendError('ID wajib disertakan');
$stmt = $db->prepare("DELETE FROM rumah_ibadah WHERE id=?");
$stmt->bind_param('i', $id);
executeOrFail($stmt, 'Gagal menghapus rumah ibadah');
$stmt->affected_rows > 0
? sendSuccess(null, 'Rumah Ibadah berhasil dihapus')
: sendError('Data tidak ditemukan', 404);
break;
default:
sendError('Method tidak diizinkan', 405);
}
+105
View File
@@ -0,0 +1,105 @@
<?php
// api/spbu.php
require_once __DIR__ . '/config/database.php';
require_once __DIR__ . '/helpers/response.php';
setCORSHeaders();
$db = getDB();
$method = getMethod();
requireWriteAuth($method);
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
switch ($method) {
case 'GET':
if ($id > 0) {
$stmt = $db->prepare(
"SELECT id, nama, no_wa, alamat, buka_24jam,
latitude, longitude, created_at
FROM spbu WHERE id = ?"
);
$stmt->bind_param('i', $id);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
if (!$row) sendError('Data tidak ditemukan', 404);
$row['latitude'] = (float)$row['latitude'];
$row['longitude'] = (float)$row['longitude'];
$row['buka_24jam']= (bool)$row['buka_24jam'];
sendSuccess($row);
} else {
$rows = [];
if (isset($_GET['buka_24jam'])) {
$val = (int)$_GET['buka_24jam'];
$stmt = $db->prepare(
"SELECT id, nama, no_wa, alamat, buka_24jam,
latitude, longitude, created_at
FROM spbu WHERE buka_24jam = ? ORDER BY nama"
);
$stmt->bind_param('i', $val);
$stmt->execute();
$res = $stmt->get_result();
} else {
$res = $db->query(
"SELECT id, nama, no_wa, alamat, buka_24jam,
latitude, longitude, created_at
FROM spbu ORDER BY nama"
);
}
while ($r = $res->fetch_assoc()) {
$r['latitude'] = (float)$r['latitude'];
$r['longitude'] = (float)$r['longitude'];
$r['buka_24jam']= (bool)$r['buka_24jam'];
$rows[] = $r;
}
sendSuccess($rows);
}
break;
case 'POST':
$body = getBody();
foreach (['nama','latitude','longitude'] as $f) {
if (empty($body[$f]) && $body[$f] !== 0) sendError("Field '$f' wajib diisi");
}
$buka = isset($body['buka_24jam']) ? (int)(bool)$body['buka_24jam'] : 0;
$stmt = $db->prepare(
"INSERT INTO spbu (nama, no_wa, alamat, buka_24jam, latitude, longitude)
VALUES (?, ?, ?, ?, ?, ?)"
);
$stmt->bind_param('sssidd',
$body['nama'], $body['no_wa'], $body['alamat'],
$buka, $body['latitude'], $body['longitude']
);
executeOrFail($stmt, 'Gagal menyimpan data SPBU');
sendSuccess(['id' => $db->insert_id], 'SPBU berhasil disimpan', 201);
break;
case 'PUT':
if ($id <= 0) sendError('ID wajib disertakan');
$body = getBody();
$buka = isset($body['buka_24jam']) ? (int)(bool)$body['buka_24jam'] : 0;
$stmt = $db->prepare(
"UPDATE spbu
SET nama=?, no_wa=?, alamat=?, buka_24jam=?, latitude=?, longitude=?
WHERE id=?"
);
$stmt->bind_param('sssiddi',
$body['nama'], $body['no_wa'], $body['alamat'],
$buka, $body['latitude'], $body['longitude'], $id
);
executeOrFail($stmt, 'Gagal memperbarui data SPBU');
sendSuccess(null, 'SPBU berhasil diperbarui');
break;
case 'DELETE':
if ($id <= 0) sendError('ID wajib disertakan');
$stmt = $db->prepare("DELETE FROM spbu WHERE id=?");
$stmt->bind_param('i', $id);
executeOrFail($stmt, 'Gagal menghapus data SPBU');
$stmt->affected_rows > 0
? sendSuccess(null, 'SPBU berhasil dihapus')
: sendError('Data tidak ditemukan', 404);
break;
default:
sendError('Method tidak diizinkan', 405);
}