Files
UAS_WEBGIS_MichelleOlivia_D…/sig-kemiskinan/api/foto.php
T
2026-06-10 21:46:56 +07:00

171 lines
7.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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);
}