Initial WebGIS portal project

This commit is contained in:
2026-06-10 19:53:39 +07:00
commit c0aa8e09d5
62 changed files with 9013 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
header('Content-Type: application/json');
require_once __DIR__ . '/db.php';
$input = json_decode(file_get_contents('php://input'), true);
if (!is_array($input)) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Format request tidak valid.',
]);
exit;
}
$nama = trim((string) ($input['nama'] ?? ''));
$no = trim((string) ($input['no'] ?? ''));
$status24jam = trim((string) ($input['status_24jam'] ?? ''));
$latitude = (float) ($input['latitude'] ?? 0);
$longitude = (float) ($input['longitude'] ?? 0);
if ($nama === '' || $no === '' || $status24jam === '') {
http_response_code(422);
echo json_encode([
'success' => false,
'message' => 'Nama, no, dan status wajib diisi.',
]);
exit;
}
if (!in_array($status24jam, ['24jam', 'tidak'], true)) {
http_response_code(422);
echo json_encode([
'success' => false,
'message' => 'Status harus 24jam atau tidak.',
]);
exit;
}
$stmt = $connection->prepare('INSERT INTO spbu_points (nama, no, status_24jam, latitude, longitude) VALUES (?, ?, ?, ?, ?)');
if (!$stmt) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal menyiapkan query: ' . $connection->error,
]);
exit;
}
$stmt->bind_param('sssdd', $nama, $no, $status24jam, $latitude, $longitude);
if (!$stmt->execute()) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal menyimpan data: ' . $stmt->error,
]);
$stmt->close();
exit;
}
$stmt->close();
echo json_encode([
'success' => true,
'message' => 'Data berhasil disimpan.',
'id' => $connection->insert_id,
]);
+34
View File
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
mysqli_report(MYSQLI_REPORT_OFF);
$host = getenv('SPBU_DB_HOST') ?: getenv('DB_HOST') ?: '127.0.0.1';
$username = getenv('SPBU_DB_USERNAME') ?: getenv('DB_USERNAME') ?: 'root';
$password = getenv('SPBU_DB_PASSWORD') ?: getenv('DB_PASSWORD') ?: '';
$database = getenv('SPBU_DB_DATABASE') ?: 'webgis_spbu';
try {
$connection = new mysqli($host, $username, $password, $database);
} catch (Throwable $exception) {
http_response_code(500);
header('Content-Type: application/json');
echo json_encode([
'success' => false,
'message' => 'Koneksi database gagal. Pastikan MySQL XAMPP sedang berjalan.',
'detail' => $exception->getMessage(),
]);
exit;
}
if (!$connection || $connection->connect_errno) {
http_response_code(500);
header('Content-Type: application/json');
echo json_encode([
'success' => false,
'message' => 'Koneksi database gagal. Pastikan MySQL XAMPP sedang berjalan.',
]);
exit;
}
$connection->set_charset('utf8mb4');
+42
View File
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
$host = getenv('SPBU_DB_HOST') ?: getenv('DB_HOST') ?: '127.0.0.1';
$database = getenv('SPBU_DB_DATABASE') ?: 'webgis_spbu';
$username = getenv('SPBU_DB_USERNAME') ?: getenv('DB_USERNAME') ?: 'root';
$password = getenv('SPBU_DB_PASSWORD') ?: getenv('DB_PASSWORD') ?: '';
$charset = getenv('DB_CHARSET') ?: 'utf8mb4';
set_exception_handler(static function (Throwable $exception): void {
if (!headers_sent()) {
http_response_code(500);
header('Content-Type: application/json');
}
echo json_encode([
'success' => false,
'message' => 'Terjadi kesalahan server.',
'detail' => $exception->getMessage(),
]);
exit;
});
$dsn = "mysql:host={$host};dbname={$database};charset={$charset}";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $username, $password, $options);
} catch (PDOException $exception) {
http_response_code(500);
header('Content-Type: application/json');
echo json_encode([
'success' => false,
'message' => 'Koneksi database gagal: ' . $exception->getMessage(),
]);
exit;
}
+68
View File
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
header('Content-Type: application/json');
require_once __DIR__ . '/db.php';
$input = json_decode(file_get_contents('php://input'), true);
if (!is_array($input)) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Format request tidak valid.',
]);
exit;
}
$id = (int) ($input['id'] ?? 0);
if ($id <= 0) {
http_response_code(422);
echo json_encode([
'success' => false,
'message' => 'ID titik tidak valid.',
]);
exit;
}
$stmt = $connection->prepare('DELETE FROM spbu_points WHERE id = ?');
if (!$stmt) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal menyiapkan query: ' . $connection->error,
]);
exit;
}
$stmt->bind_param('i', $id);
if (!$stmt->execute()) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal menghapus data: ' . $stmt->error,
]);
$stmt->close();
exit;
}
if ($stmt->affected_rows < 1) {
http_response_code(404);
echo json_encode([
'success' => false,
'message' => 'Data dengan ID tersebut tidak ditemukan.',
]);
$stmt->close();
exit;
}
$stmt->close();
echo json_encode([
'success' => true,
'message' => 'Data berhasil dihapus.',
]);
+43
View File
@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db_pdo.php';
require_once __DIR__ . '/spatial_helpers.php';
$input = get_json_input();
$namaPemilik = trim((string) ($input['nama_pemilik'] ?? ''));
$statusKepemilikan = trim((string) ($input['status_kepemilikan'] ?? ''));
$luasM2 = (float) ($input['luas_m2'] ?? 0);
$wkt = sanitize_wkt((string) ($input['wkt'] ?? ''), 'POLYGON');
$allowedStatus = ['SHM', 'HGB', 'HGU', 'HP'];
if ($namaPemilik === '' || !in_array($statusKepemilikan, $allowedStatus, true)) {
json_response(422, [
'success' => false,
'message' => 'Nama pemilik wajib diisi dan status harus SHM/HGB/HGU/HP.',
]);
}
if ($luasM2 <= 0) {
json_response(422, [
'success' => false,
'message' => 'Luas tanah harus lebih dari 0 m2.',
]);
}
$sql = 'INSERT INTO parsil_tanah (nama_pemilik, status_kepemilikan, luas_m2, geom) VALUES (:nama_pemilik, :status_kepemilikan, :luas_m2, ST_GeomFromText(:wkt))';
$stmt = $pdo->prepare($sql);
$stmt->execute([
':nama_pemilik' => $namaPemilik,
':status_kepemilikan' => $statusKepemilikan,
':luas_m2' => $luasM2,
':wkt' => $wkt,
]);
json_response(201, [
'success' => true,
'message' => 'Data parsil tanah berhasil disimpan.',
'id' => (int) $pdo->lastInsertId(),
]);
+30
View File
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db_pdo.php';
require_once __DIR__ . '/spatial_helpers.php';
$input = get_json_input();
$id = (int) ($input['id'] ?? 0);
if ($id <= 0) {
json_response(422, [
'success' => false,
'message' => 'ID parsil tidak valid.',
]);
}
$stmt = $pdo->prepare('DELETE FROM parsil_tanah WHERE id = :id');
$stmt->execute([':id' => $id]);
if ($stmt->rowCount() < 1) {
json_response(404, [
'success' => false,
'message' => 'Data parsil tidak ditemukan.',
]);
}
json_response(200, [
'success' => true,
'message' => 'Data parsil tanah berhasil dihapus.',
]);
+22
View File
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db_pdo.php';
require_once __DIR__ . '/spatial_helpers.php';
$sql = 'SELECT id, nama_pemilik, status_kepemilikan, luas_m2, ST_AsGeoJSON(geom) AS geometry_geojson, created_at, updated_at FROM parsil_tanah ORDER BY id DESC';
$stmt = $pdo->query($sql);
$rows = $stmt->fetchAll();
$data = [];
foreach ($rows as $row) {
$row['id'] = (int) $row['id'];
$row['luas_m2'] = (float) $row['luas_m2'];
$row['geometry_geojson'] = json_decode((string) $row['geometry_geojson'], true);
$data[] = $row;
}
json_response(200, [
'success' => true,
'data' => $data,
]);
+62
View File
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db_pdo.php';
require_once __DIR__ . '/spatial_helpers.php';
$input = get_json_input();
$id = (int) ($input['id'] ?? 0);
$namaPemilik = trim((string) ($input['nama_pemilik'] ?? ''));
$statusKepemilikan = trim((string) ($input['status_kepemilikan'] ?? ''));
$luasM2 = (float) ($input['luas_m2'] ?? 0);
$wkt = sanitize_wkt((string) ($input['wkt'] ?? ''), 'POLYGON');
$allowedStatus = ['SHM', 'HGB', 'HGU', 'HP'];
if ($id <= 0) {
json_response(422, [
'success' => false,
'message' => 'ID parsil tidak valid.',
]);
}
if ($namaPemilik === '' || !in_array($statusKepemilikan, $allowedStatus, true)) {
json_response(422, [
'success' => false,
'message' => 'Nama pemilik wajib diisi dan status harus SHM/HGB/HGU/HP.',
]);
}
if ($luasM2 <= 0) {
json_response(422, [
'success' => false,
'message' => 'Luas tanah harus lebih dari 0 m2.',
]);
}
$sql = 'UPDATE parsil_tanah SET nama_pemilik = :nama_pemilik, status_kepemilikan = :status_kepemilikan, luas_m2 = :luas_m2, geom = ST_GeomFromText(:wkt), updated_at = CURRENT_TIMESTAMP WHERE id = :id';
$stmt = $pdo->prepare($sql);
$stmt->execute([
':id' => $id,
':nama_pemilik' => $namaPemilik,
':status_kepemilikan' => $statusKepemilikan,
':luas_m2' => $luasM2,
':wkt' => $wkt,
]);
if ($stmt->rowCount() < 1) {
$checkStmt = $pdo->prepare('SELECT id FROM parsil_tanah WHERE id = :id LIMIT 1');
$checkStmt->execute([':id' => $id]);
if (!$checkStmt->fetch()) {
json_response(404, [
'success' => false,
'message' => 'Data parsil tidak ditemukan.',
]);
}
}
json_response(200, [
'success' => true,
'message' => 'Data parsil tanah berhasil diperbarui.',
]);
+28
View File
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
header('Content-Type: application/json');
require_once __DIR__ . '/db.php';
$sql = 'SELECT id, nama, no, status_24jam, latitude, longitude, created_at FROM spbu_points ORDER BY id DESC';
$result = $connection->query($sql);
if (!$result) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal mengambil data: ' . $connection->error,
]);
exit;
}
$points = [];
while ($row = $result->fetch_assoc()) {
$points[] = $row;
}
echo json_encode([
'success' => true,
'data' => $points,
]);
+43
View File
@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db_pdo.php';
require_once __DIR__ . '/spatial_helpers.php';
$input = get_json_input();
$namaJalan = trim((string) ($input['nama_jalan'] ?? ''));
$status = trim((string) ($input['status'] ?? ''));
$panjangMeter = (float) ($input['panjang_meter'] ?? 0);
$wkt = sanitize_wkt((string) ($input['wkt'] ?? ''), 'LINESTRING');
$allowedStatus = ['nasional', 'provinsi', 'kabupaten'];
if ($namaJalan === '' || !in_array($status, $allowedStatus, true)) {
json_response(422, [
'success' => false,
'message' => 'Nama jalan wajib diisi dan status harus nasional/provinsi/kabupaten.',
]);
}
if ($panjangMeter <= 0) {
json_response(422, [
'success' => false,
'message' => 'Panjang jalan harus lebih dari 0 meter.',
]);
}
$sql = 'INSERT INTO jalan (nama_jalan, status, panjang_meter, geom) VALUES (:nama_jalan, :status, :panjang_meter, ST_GeomFromText(:wkt))';
$stmt = $pdo->prepare($sql);
$stmt->execute([
':nama_jalan' => $namaJalan,
':status' => $status,
':panjang_meter' => $panjangMeter,
':wkt' => $wkt,
]);
json_response(201, [
'success' => true,
'message' => 'Data jalan berhasil disimpan.',
'id' => (int) $pdo->lastInsertId(),
]);
+30
View File
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db_pdo.php';
require_once __DIR__ . '/spatial_helpers.php';
$input = get_json_input();
$id = (int) ($input['id'] ?? 0);
if ($id <= 0) {
json_response(422, [
'success' => false,
'message' => 'ID jalan tidak valid.',
]);
}
$stmt = $pdo->prepare('DELETE FROM jalan WHERE id = :id');
$stmt->execute([':id' => $id]);
if ($stmt->rowCount() < 1) {
json_response(404, [
'success' => false,
'message' => 'Data jalan tidak ditemukan.',
]);
}
json_response(200, [
'success' => true,
'message' => 'Data jalan berhasil dihapus.',
]);
+22
View File
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db_pdo.php';
require_once __DIR__ . '/spatial_helpers.php';
$sql = 'SELECT id, nama_jalan, status, panjang_meter, ST_AsGeoJSON(geom) AS geometry_geojson, created_at, updated_at FROM jalan ORDER BY id DESC';
$stmt = $pdo->query($sql);
$rows = $stmt->fetchAll();
$data = [];
foreach ($rows as $row) {
$row['id'] = (int) $row['id'];
$row['panjang_meter'] = (float) $row['panjang_meter'];
$row['geometry_geojson'] = json_decode((string) $row['geometry_geojson'], true);
$data[] = $row;
}
json_response(200, [
'success' => true,
'data' => $data,
]);
+62
View File
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db_pdo.php';
require_once __DIR__ . '/spatial_helpers.php';
$input = get_json_input();
$id = (int) ($input['id'] ?? 0);
$namaJalan = trim((string) ($input['nama_jalan'] ?? ''));
$status = trim((string) ($input['status'] ?? ''));
$panjangMeter = (float) ($input['panjang_meter'] ?? 0);
$wkt = sanitize_wkt((string) ($input['wkt'] ?? ''), 'LINESTRING');
$allowedStatus = ['nasional', 'provinsi', 'kabupaten'];
if ($id <= 0) {
json_response(422, [
'success' => false,
'message' => 'ID jalan tidak valid.',
]);
}
if ($namaJalan === '' || !in_array($status, $allowedStatus, true)) {
json_response(422, [
'success' => false,
'message' => 'Nama jalan wajib diisi dan status harus nasional/provinsi/kabupaten.',
]);
}
if ($panjangMeter <= 0) {
json_response(422, [
'success' => false,
'message' => 'Panjang jalan harus lebih dari 0 meter.',
]);
}
$sql = 'UPDATE jalan SET nama_jalan = :nama_jalan, status = :status, panjang_meter = :panjang_meter, geom = ST_GeomFromText(:wkt), updated_at = CURRENT_TIMESTAMP WHERE id = :id';
$stmt = $pdo->prepare($sql);
$stmt->execute([
':id' => $id,
':nama_jalan' => $namaJalan,
':status' => $status,
':panjang_meter' => $panjangMeter,
':wkt' => $wkt,
]);
if ($stmt->rowCount() < 1) {
$checkStmt = $pdo->prepare('SELECT id FROM jalan WHERE id = :id LIMIT 1');
$checkStmt->execute([':id' => $id]);
if (!$checkStmt->fetch()) {
json_response(404, [
'success' => false,
'message' => 'Data jalan tidak ditemukan.',
]);
}
}
json_response(200, [
'success' => true,
'message' => 'Data jalan berhasil diperbarui.',
]);
+47
View File
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
function json_response(int $statusCode, array $payload): void
{
http_response_code($statusCode);
header('Content-Type: application/json');
echo json_encode($payload);
exit;
}
function get_json_input(): array
{
$input = json_decode(file_get_contents('php://input'), true);
if (!is_array($input)) {
json_response(400, [
'success' => false,
'message' => 'Format request tidak valid.',
]);
}
return $input;
}
function sanitize_wkt(string $wkt, string $expectedType): string
{
$trimmed = trim($wkt);
if ($trimmed === '') {
json_response(422, [
'success' => false,
'message' => 'Geometri WKT wajib diisi.',
]);
}
$normalized = strtoupper($trimmed);
if (strpos($normalized, $expectedType . '(') !== 0 && strpos($normalized, $expectedType . ' (') !== 0) {
json_response(422, [
'success' => false,
'message' => 'Tipe geometri tidak sesuai. Diharapkan ' . $expectedType . '.',
]);
}
return $trimmed;
}
+110
View File
@@ -0,0 +1,110 @@
<?php
declare(strict_types=1);
header('Content-Type: application/json');
require_once __DIR__ . '/db.php';
$input = json_decode(file_get_contents('php://input'), true);
if (!is_array($input)) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Format request tidak valid.',
]);
exit;
}
$id = (int) ($input['id'] ?? 0);
$latitude = (float) ($input['latitude'] ?? 0);
$longitude = (float) ($input['longitude'] ?? 0);
if ($id <= 0) {
http_response_code(422);
echo json_encode([
'success' => false,
'message' => 'ID titik tidak valid.',
]);
exit;
}
if (!is_finite($latitude) || !is_finite($longitude)) {
http_response_code(422);
echo json_encode([
'success' => false,
'message' => 'Koordinat latitude atau longitude tidak valid.',
]);
exit;
}
$stmt = $connection->prepare('UPDATE spbu_points SET latitude = ?, longitude = ? WHERE id = ?');
if (!$stmt) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal menyiapkan query update: ' . $connection->error,
]);
exit;
}
$stmt->bind_param('ddi', $latitude, $longitude, $id);
if (!$stmt->execute()) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal memperbarui posisi: ' . $stmt->error,
]);
$stmt->close();
exit;
}
if ($stmt->affected_rows < 1) {
$stmt->close();
$checkStmt = $connection->prepare('SELECT id FROM spbu_points WHERE id = ? LIMIT 1');
if (!$checkStmt) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal memverifikasi data titik: ' . $connection->error,
]);
exit;
}
$checkStmt->bind_param('i', $id);
if (!$checkStmt->execute()) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Gagal memverifikasi data titik: ' . $checkStmt->error,
]);
$checkStmt->close();
exit;
}
$checkResult = $checkStmt->get_result();
if ($checkResult->num_rows < 1) {
http_response_code(404);
echo json_encode([
'success' => false,
'message' => 'Data dengan ID tersebut tidak ditemukan.',
]);
$checkStmt->close();
exit;
}
$checkStmt->close();
}
$stmt->close();
echo json_encode([
'success' => true,
'message' => 'Posisi titik berhasil diperbarui.',
]);