171 lines
7.8 KiB
PHP
171 lines
7.8 KiB
PHP
<?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);
|
||
} |