UAS SIG Proyek WebGis

This commit is contained in:
L4zyL4mb
2026-06-10 21:46:56 +07:00
commit df18a7a99a
35 changed files with 8977 additions and 0 deletions
+171
View File
@@ -0,0 +1,171 @@
<?php
// api/foto.php v2.0
// ============================================================
// API Upload & Kelola Foto Rumah + GPS Geo-tagging
// ============================================================
require_once __DIR__ . '/../includes/config.php';
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit;
$method = $_SERVER['REQUEST_METHOD'];
$db = getDB();
// Pastikan folder upload ada
if (!is_dir(UPLOAD_DIR)) mkdir(UPLOAD_DIR, 0755, true);
switch ($method) {
// ════════════════════════════════════════════════════════
// GET Ambil daftar foto per penduduk
// ════════════════════════════════════════════════════════
case 'GET':
$pendudukId = $_GET['penduduk_id'] ?? null;
if (!$pendudukId) {
header('Content-Type: application/json');
jsonResponse(['success' => false, 'error' => 'penduduk_id diperlukan'], 400);
}
$stmt = $db->prepare("
SELECT f.*, u.nama AS nama_petugas
FROM foto_rumah f
LEFT JOIN users u ON u.id = f.diambil_oleh
WHERE f.penduduk_id = ?
ORDER BY f.is_primary DESC, f.created_at ASC
");
$stmt->execute([$pendudukId]);
header('Content-Type: application/json');
jsonResponse(['success' => true, 'data' => $stmt->fetchAll()]);
break;
// ════════════════════════════════════════════════════════
// POST Upload foto baru
// ════════════════════════════════════════════════════════
case 'POST':
header('Content-Type: application/json');
$pendudukId = (int)($_POST['penduduk_id'] ?? 0);
if (!$pendudukId) jsonResponse(['success' => false, 'error' => 'penduduk_id diperlukan'], 400);
// Cek penduduk ada
$cek = $db->prepare("SELECT id FROM penduduk_miskin WHERE id = ?");
$cek->execute([$pendudukId]);
if (!$cek->fetch()) jsonResponse(['success' => false, 'error' => 'Data penduduk tidak ditemukan'], 404);
if (!isset($_FILES['foto']) || $_FILES['foto']['error'] !== UPLOAD_ERR_OK) {
$errCode = $_FILES['foto']['error'] ?? 'no_file';
jsonResponse(['success' => false, 'error' => "Upload gagal (kode: $errCode)"], 400);
}
$file = $_FILES['foto'];
$tmpPath = $file['tmp_name'];
$origName = $file['name'];
$fileSize = $file['size'];
// Validasi ukuran
if ($fileSize > MAX_FOTO_SIZE) {
jsonResponse(['success' => false, 'error' => 'Ukuran file maksimal 5 MB'], 413);
}
// Validasi ekstensi & MIME type
$ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $tmpPath);
finfo_close($finfo);
$allowedMime = ['image/jpeg','image/png','image/webp'];
if (!in_array($ext, ALLOWED_EXT) || !in_array($mime, $allowedMime)) {
jsonResponse(['success' => false, 'error' => 'Format file tidak didukung (jpg/png/webp)'], 415);
}
// Generate nama file unik
$newName = 'foto_' . $pendudukId . '_' . time() . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
$destPath = UPLOAD_DIR . $newName;
$relPath = UPLOAD_URL . $newName;
if (!move_uploaded_file($tmpPath, $destPath)) {
jsonResponse(['success' => false, 'error' => 'Gagal menyimpan file'], 500);
}
// Cek apakah ini foto pertama → jadikan primary
$countStmt = $db->prepare("SELECT COUNT(*) FROM foto_rumah WHERE penduduk_id = ?");
$countStmt->execute([$pendudukId]);
$isPrimary = ($countStmt->fetchColumn() == 0) ? 1 : 0;
// Koordinat GPS dari POST (dari browser Geolocation atau EXIF)
$latFoto = isset($_POST['lat_foto']) && $_POST['lat_foto'] !== '' ? (float)$_POST['lat_foto'] : null;
$lngFoto = isset($_POST['lng_foto']) && $_POST['lng_foto'] !== '' ? (float)$_POST['lng_foto'] : null;
$accuracy = isset($_POST['accuracy_meter']) && $_POST['accuracy_meter'] !== '' ? (float)$_POST['accuracy_meter']
: (isset($_POST['accuracy']) && $_POST['accuracy'] !== '' ? (float)$_POST['accuracy'] : null);
// Jika user set is_primary = 1, nonaktifkan primary lain dulu
$isPrimaryReq = isset($_POST['is_primary']) && (int)$_POST['is_primary'] === 1;
if ($isPrimaryReq) {
$db->prepare("UPDATE foto_rumah SET is_primary = 0 WHERE penduduk_id = ?")
->execute([$pendudukId]);
$isPrimary = 1;
}
// diambil_oleh: support field name lama (user_id) dan baru (diambil_oleh)
$diambilOleh = $_POST['diambil_oleh'] ?? $_POST['user_id'] ?? null;
$db->prepare("
INSERT INTO foto_rumah (penduduk_id, file_path, lat_foto, lng_foto, accuracy_meter, is_primary, ukuran_kb, keterangan, diambil_oleh)
VALUES (?,?,?,?,?,?,?,?,?)
")->execute([
$pendudukId,
$relPath,
$latFoto,
$lngFoto,
$accuracy,
$isPrimary,
(int)round($fileSize / 1024),
$_POST['keterangan'] ?? null,
$diambilOleh ? (int)$diambilOleh : null,
]);
$newId = (int)$db->lastInsertId();
jsonResponse([
'success' => true,
'id' => $newId,
'file_path' => $relPath,
'is_primary'=> $isPrimary,
'message' => 'Foto berhasil diupload',
]);
break;
// ════════════════════════════════════════════════════════
// DELETE Hapus foto
// ════════════════════════════════════════════════════════
case 'DELETE':
header('Content-Type: application/json');
$id = (int)($_GET['id'] ?? 0);
if (!$id) jsonResponse(['success' => false, 'error' => 'ID diperlukan'], 400);
$stmt = $db->prepare("SELECT * FROM foto_rumah WHERE id = ?");
$stmt->execute([$id]);
$foto = $stmt->fetch();
if (!$foto) jsonResponse(['success' => false, 'error' => 'Foto tidak ditemukan'], 404);
// Hapus file fisik
$filePath = __DIR__ . '/../' . $foto['file_path'];
if (file_exists($filePath)) @unlink($filePath);
$db->prepare("DELETE FROM foto_rumah WHERE id = ?")->execute([$id]);
// Jika foto yang dihapus adalah primary, set foto lain jadi primary
if ($foto['is_primary']) {
$next = $db->prepare("SELECT id FROM foto_rumah WHERE penduduk_id = ? ORDER BY created_at ASC LIMIT 1");
$next->execute([$foto['penduduk_id']]);
$nextFoto = $next->fetch();
if ($nextFoto) {
$db->prepare("UPDATE foto_rumah SET is_primary = 1 WHERE id = ?")->execute([$nextFoto['id']]);
}
}
jsonResponse(['success' => true, 'message' => 'Foto berhasil dihapus']);
break;
default:
header('Content-Type: application/json');
jsonResponse(['success' => false, 'error' => 'Method tidak diizinkan'], 405);
}