false, 'message' => 'PHP Fatal Error: ' . $error['message'] . ' (line ' . $error['line'] . ')' ]); } }); // Tangkap exception yang tidak tertangkap set_exception_handler(function ($e) { ob_clean(); echo json_encode([ 'success' => false, 'message' => 'Exception: ' . $e->getMessage() ]); exit; }); // Cek apakah config.php ada if (!file_exists(__DIR__ . '/config.php')) { echo json_encode([ 'success' => false, 'message' => 'File config.php tidak ditemukan di: ' . __DIR__ ]); exit; } include 'config.php'; // Buang output apapun yang tidak sengaja tercetak sebelum JSON (misal warning PHP) ob_clean(); $action = $_GET['action'] ?? ''; // ============================================================ // Helper Upload Foto // ============================================================ function uploadFoto($fileKey) { if ( !isset($_FILES[$fileKey]) || $_FILES[$fileKey]['error'] !== UPLOAD_ERR_OK ) { return null; } $uploadDir = 'uploads/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0777, true); } $ext = strtolower(pathinfo($_FILES[$fileKey]['name'], PATHINFO_EXTENSION)); $allowed = ['jpg', 'jpeg', 'png', 'webp']; if (!in_array($ext, $allowed)) { return null; } $filename = uniqid('img_', true) . '.' . $ext; $destination = $uploadDir . $filename; if (move_uploaded_file($_FILES[$fileKey]['tmp_name'], $destination)) { return $filename; } return null; } // ============================================================ // GET DATA // ============================================================ if ($action === 'get_data') { $roadsResult = $conn->query("SELECT * FROM roads ORDER BY id DESC"); $parcelsResult = $conn->query("SELECT * FROM parcels ORDER BY id DESC"); $damagedResult = $conn->query("SELECT * FROM damaged_roads ORDER BY id DESC"); if (!$roadsResult || !$parcelsResult || !$damagedResult) { echo json_encode([ 'success' => false, 'message' => 'Query gagal: ' . $conn->error ]); exit; } $roads = $roadsResult->fetch_all(MYSQLI_ASSOC); $parcels = $parcelsResult->fetch_all(MYSQLI_ASSOC); $damaged = $damagedResult->fetch_all(MYSQLI_ASSOC); foreach ($roads as &$row) { $row['foto_url'] = !empty($row['foto']) ? 'uploads/' . $row['foto'] : null; } foreach ($parcels as &$row) { $row['foto_url'] = !empty($row['foto']) ? 'uploads/' . $row['foto'] : null; } foreach ($damaged as &$row) { $row['foto_url'] = !empty($row['foto']) ? 'uploads/' . $row['foto'] : null; } echo json_encode([ 'success' => true, 'roads' => $roads, 'parcels' => $parcels, 'damaged_roads' => $damaged ]); exit; } // ============================================================ // SEARCH // ============================================================ if ($action === 'search') { $keyword = $_GET['q'] ?? ''; $keyword = $conn->real_escape_string($keyword); $like = "%{$keyword}%"; $roadsSearch = $conn->query(" SELECT id, name, status, length_m AS measure, 'road' AS type FROM roads WHERE name LIKE '$like' OR status LIKE '$like' "); $parcelsSearch = $conn->query(" SELECT id, name, status, area_sqm AS measure, 'parcel' AS type FROM parcels WHERE name LIKE '$like' OR status LIKE '$like' "); $damagedSearch = $conn->query(" SELECT id, name, status, description AS measure, 'damaged' AS type FROM damaged_roads WHERE name LIKE '$like' OR status LIKE '$like' OR description LIKE '$like' "); if (!$roadsSearch || !$parcelsSearch || !$damagedSearch) { echo json_encode([ 'success' => false, 'message' => 'Query pencarian gagal: ' . $conn->error ]); exit; } $roads = $roadsSearch->fetch_all(MYSQLI_ASSOC); $parcels = $parcelsSearch->fetch_all(MYSQLI_ASSOC); $damaged = $damagedSearch->fetch_all(MYSQLI_ASSOC); $results = array_merge( $roads, $parcels, $damaged ); echo json_encode([ 'success' => true, 'data' => $results ]); exit; } // ============================================================ // GET ONE // ============================================================ if ($action === 'get_one') { $id = (int)($_GET['id'] ?? 0); $type = $_GET['type'] ?? ''; switch ($type) { case 'road': $table = 'roads'; break; case 'parcel': $table = 'parcels'; break; case 'damaged': $table = 'damaged_roads'; break; default: echo json_encode([ 'success' => false, 'message' => 'Tipe tidak valid' ]); exit; } $result = $conn->query( "SELECT * FROM $table WHERE id = $id" ); $row = $result->fetch_assoc(); if ($row) { $row['foto_url'] = !empty($row['foto']) ? 'uploads/' . $row['foto'] : null; } echo json_encode([ 'success' => true, 'data' => $row ]); exit; } // ============================================================ // SAVE DATA // ============================================================ if ($action === 'save') { $id = isset($_POST['id']) ? (int)$_POST['id'] : 0; $type = $_POST['type'] ?? ''; $name = $conn->real_escape_string($_POST['name'] ?? ''); $status = $conn->real_escape_string($_POST['status'] ?? ''); $geom = $conn->real_escape_string($_POST['geom'] ?? ''); $measure = $conn->real_escape_string($_POST['measure'] ?? ''); $description = $conn->real_escape_string($_POST['description'] ?? ''); $newFoto = uploadFoto('foto'); if ($type === 'road') { if ($id > 0) { $fotoSql = $newFoto ? ", foto='$newFoto'" : ""; $sql = " UPDATE roads SET name='$name', status='$status', length_m='$measure', geom='$geom' $fotoSql WHERE id=$id "; } else { $fotoVal = $newFoto ? "'$newFoto'" : "NULL"; $sql = " INSERT INTO roads ( name, status, length_m, geom, foto ) VALUES ( '$name', '$status', '$measure', '$geom', $fotoVal ) "; } } elseif ($type === 'parcel') { if ($id > 0) { $fotoSql = $newFoto ? ", foto='$newFoto'" : ""; $sql = " UPDATE parcels SET name='$name', status='$status', area_sqm='$measure', geom='$geom' $fotoSql WHERE id=$id "; } else { $fotoVal = $newFoto ? "'$newFoto'" : "NULL"; $sql = " INSERT INTO parcels ( name, status, area_sqm, geom, foto ) VALUES ( '$name', '$status', '$measure', '$geom', $fotoVal ) "; } } elseif ($type === 'damaged') { if ($id > 0) { $fotoSql = $newFoto ? ", foto='$newFoto'" : ""; $sql = " UPDATE damaged_roads SET name='$name', status='$status', description='$description', geom='$geom' $fotoSql WHERE id=$id "; } else { $fotoVal = $newFoto ? "'$newFoto'" : "NULL"; $sql = " INSERT INTO damaged_roads ( name, status, description, geom, foto ) VALUES ( '$name', '$status', '$description', '$geom', $fotoVal ) "; } } else { echo json_encode([ 'success' => false, 'message' => 'Tipe data tidak valid' ]); exit; } if ($conn->query($sql)) { echo json_encode([ 'success' => true, 'message' => 'Data berhasil disimpan', 'id' => $id > 0 ? $id : $conn->insert_id ]); } else { echo json_encode([ 'success' => false, 'message' => $conn->error ]); } exit; } // ============================================================ // DELETE DATA // ============================================================ if ($action === 'delete') { $id = (int)($_POST['id'] ?? 0); $type = $_POST['type'] ?? ''; switch ($type) { case 'road': $table = 'roads'; break; case 'parcel': $table = 'parcels'; break; case 'damaged': $table = 'damaged_roads'; break; default: echo json_encode([ 'success' => false, 'message' => 'Tipe tidak valid' ]); exit; } $check = $conn->query( "SELECT foto FROM $table WHERE id=$id" ); if ($check && $check->num_rows > 0) { $row = $check->fetch_assoc(); if ( !empty($row['foto']) && file_exists('uploads/' . $row['foto']) ) { unlink('uploads/' . $row['foto']); } } if ($conn->query( "DELETE FROM $table WHERE id=$id" )) { echo json_encode([ 'success' => true, 'message' => 'Data berhasil dihapus' ]); } else { echo json_encode([ 'success' => false, 'message' => $conn->error ]); } exit; } // ============================================================ // ACTION TIDAK DITEMUKAN // ============================================================ echo json_encode([ 'success' => false, 'message' => 'Action tidak ditemukan' ]);