172 lines
6.3 KiB
PHP
172 lines
6.3 KiB
PHP
<?php
|
|
// includes/helpers.php
|
|
require_once __DIR__ . '/../config/app.php';
|
|
require_once __DIR__ . '/../config/database.php';
|
|
|
|
/* ============================================================
|
|
HTTP Response helpers
|
|
============================================================ */
|
|
function jsonSuccess($data = [], string $message = 'OK', int $code = 200): void {
|
|
http_response_code($code);
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
echo json_encode(['success' => true, 'message' => $message, 'data' => $data], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
function jsonError(string $message = 'Error', int $code = 400, array $errors = []): void {
|
|
http_response_code($code);
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
echo json_encode(['success' => false, 'message' => $message, 'errors' => $errors], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
/* ============================================================
|
|
Input sanitization
|
|
============================================================ */
|
|
function sanitize(string $val): string {
|
|
return htmlspecialchars(strip_tags(trim($val)), ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
function getBody(): array {
|
|
$raw = file_get_contents('php://input');
|
|
$data = json_decode($raw, true);
|
|
return is_array($data) ? $data : [];
|
|
}
|
|
|
|
function required(array $data, array $fields): array {
|
|
$errors = [];
|
|
foreach ($fields as $f) {
|
|
if (!isset($data[$f]) || trim((string)$data[$f]) === '') {
|
|
$errors[] = "Field '$f' wajib diisi";
|
|
}
|
|
}
|
|
return $errors;
|
|
}
|
|
|
|
/* ============================================================
|
|
Session / Auth
|
|
============================================================ */
|
|
function startSession(): void {
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_name(SESSION_NAME);
|
|
session_start();
|
|
}
|
|
}
|
|
|
|
function currentUser(): ?array {
|
|
startSession();
|
|
return $_SESSION['user'] ?? null;
|
|
}
|
|
|
|
function requireAuth(array $allowedRoles = []): array {
|
|
$user = currentUser();
|
|
if (!$user) jsonError('Unauthorized - silakan login', 401);
|
|
if (!empty($allowedRoles) && !in_array($user['id_role'], $allowedRoles)) {
|
|
jsonError('Forbidden - hak akses tidak cukup', 403);
|
|
}
|
|
return $user;
|
|
}
|
|
|
|
function login(string $username, string $password): array|false {
|
|
$db = getDB();
|
|
$stmt = $db->prepare(
|
|
"SELECT u.*, r.nama_role FROM user u JOIN role r ON u.id_role = r.id
|
|
WHERE u.username = ? AND u.aktif = 1 LIMIT 1"
|
|
);
|
|
$stmt->execute([$username]);
|
|
$user = $stmt->fetch();
|
|
if (!$user || !password_verify($password, $user['password_hash'])) return false;
|
|
|
|
// Update last_login
|
|
$db->prepare("UPDATE user SET last_login = NOW() WHERE id = ?")->execute([$user['id']]);
|
|
unset($user['password_hash']);
|
|
return $user;
|
|
}
|
|
|
|
/* ============================================================
|
|
Activity Log
|
|
============================================================ */
|
|
function logActivity(string $aksi, string $tabel = '', string $idRecord = '',
|
|
array $dataLama = [], array $dataBaru = []): void {
|
|
try {
|
|
$user = currentUser();
|
|
$db = getDB();
|
|
$db->prepare(
|
|
"INSERT INTO log_aktivitas (id_user, aksi, tabel, id_record, data_lama, data_baru, ip_address)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
)->execute([
|
|
$user['id'] ?? null,
|
|
$aksi, $tabel, $idRecord,
|
|
$dataLama ? json_encode($dataLama, JSON_UNESCAPED_UNICODE) : null,
|
|
$dataBaru ? json_encode($dataBaru, JSON_UNESCAPED_UNICODE) : null,
|
|
$_SERVER['REMOTE_ADDR'] ?? null,
|
|
]);
|
|
} catch (Throwable $e) { /* silent */ }
|
|
}
|
|
|
|
/* ============================================================
|
|
Haversine distance (km)
|
|
============================================================ */
|
|
function haversine(float $lat1, float $lng1, float $lat2, float $lng2): float {
|
|
$R = 6371;
|
|
$dLat = deg2rad($lat2 - $lat1);
|
|
$dLng = deg2rad($lng2 - $lng1);
|
|
$a = sin($dLat/2)**2 + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLng/2)**2;
|
|
return $R * 2 * asin(sqrt($a));
|
|
}
|
|
|
|
/* ============================================================
|
|
Pagination helper
|
|
============================================================ */
|
|
function paginate(array $data, int $page, int $perPage = 20): array {
|
|
$total = count($data);
|
|
$pages = (int)ceil($total / $perPage);
|
|
$offset = ($page - 1) * $perPage;
|
|
return [
|
|
'items' => array_slice($data, $offset, $perPage),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'per_page' => $perPage,
|
|
'pages' => $pages,
|
|
];
|
|
}
|
|
|
|
/* ============================================================
|
|
Validasi umur vs pendidikan
|
|
============================================================ */
|
|
function validasiPendidikan(int $umur, string $pendidikanTerakhir, string $statusPendidikan): array {
|
|
$warnings = [];
|
|
if ($umur >= 7 && $umur <= 15) {
|
|
if ($statusPendidikan === 'tidak_sekolah') {
|
|
$warnings[] = "Anak usia $umur tahun seharusnya masih sekolah (wajib belajar 9 tahun)";
|
|
}
|
|
if (!in_array($pendidikanTerakhir, ['SD','SMP','tidak_sekolah'])) {
|
|
$warnings[] = "Pendidikan terakhir tidak sesuai untuk usia $umur tahun";
|
|
}
|
|
} elseif ($umur >= 16 && $umur <= 18) {
|
|
if ($statusPendidikan === 'tidak_sekolah' && in_array($pendidikanTerakhir, ['tidak_sekolah','SD'])) {
|
|
$warnings[] = "Remaja usia $umur tahun disarankan melanjutkan ke SMA/SMK";
|
|
}
|
|
}
|
|
return $warnings;
|
|
}
|
|
|
|
/* ============================================================
|
|
Upload foto helper
|
|
============================================================ */
|
|
function uploadFoto(array $file, string $subfolder = 'foto_laporan'): string|false {
|
|
$allowed = ['image/jpeg','image/png','image/webp'];
|
|
if (!in_array($file['type'], $allowed)) return false;
|
|
if ($file['size'] > 5 * 1024 * 1024) return false;
|
|
|
|
$dir = UPLOAD_DIR . $subfolder . '/';
|
|
if (!is_dir($dir)) mkdir($dir, 0755, true);
|
|
|
|
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
|
|
$filename = uniqid('img_', true) . '.' . strtolower($ext);
|
|
$dest = $dir . $filename;
|
|
|
|
if (!move_uploaded_file($file['tmp_name'], $dest)) return false;
|
|
return $subfolder . '/' . $filename;
|
|
}
|