true, 'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off', 'samesite' => 'Lax', 'path' => '/']); session_start(); header('Cache-Control: no-store'); header('X-Content-Type-Options: nosniff'); header("Content-Security-Policy: default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none'; base-uri 'self'"); if (empty($_SESSION['csrf'])) $_SESSION['csrf'] = bin2hex(random_bytes(32)); } date_default_timezone_set('Asia/Jakarta'); const CATEGORIES = [1 => 'Matematika', 2 => 'Sinonim', 3 => 'Antonim', 4 => 'Padanan kata', 5 => 'Kepribadian']; const STAGES = [0 => 'Calon kandidat', 1 => 'Tidak dilanjutkan', 2 => 'Tes offline & interview', 3 => 'Diterima', 99 => 'Demo / arsip']; function e($value) { return htmlspecialchars(str_replace("\0", '', (string)$value), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } function redirect($url) { header('Location: ' . $url); exit; } function csrf_field() { echo ''; } function verify_csrf() { if (!hash_equals($_SESSION['csrf'], (string)($_POST['csrf'] ?? ''))) { http_response_code(403); exit('Sesi formulir tidak valid. Muat ulang halaman.'); } } function require_admin() { if (empty($_SESSION['admin_id']) || time() - ($_SESSION['admin_active'] ?? 0) > 3600) { unset($_SESSION['admin_id']); redirect('login.php'); } $_SESSION['admin_active'] = time(); } function db() { static $connection; if ($connection) return $connection; mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); require __DIR__ . '/../includes/conn.php'; $connection = $conn; $connection->set_charset('utf8mb4'); return $connection; } function query($sql, $types = '', $params = []) { $statement = db()->prepare($sql); if ($types !== '') $statement->bind_param($types, ...$params); $statement->execute(); return $statement; } function rows($sql, $types = '', $params = []) { return query($sql, $types, $params)->get_result()->fetch_all(MYSQLI_ASSOC); } function one($sql, $types = '', $params = []) { return rows($sql, $types, $params)[0] ?? null; } function threshold() { return max(0, (int)(getenv('REC_PASS_SCORE') ?: 300)); } function fail_page($message, $status = 503) { http_response_code($status); page_start('Layanan belum siap'); echo '

Layanan belum siap

' . e($message) . '

'; page_end(); exit; } set_exception_handler(function ($error) { error_log('Recruitment admin: ' . $error->getMessage()); if (PHP_SAPI === 'cli') { fwrite(STDERR, "Operasi gagal. Periksa konfigurasi database dan migrasi admin.\n"); exit(1); } fail_page('Periksa koneksi database dan jalankan migrasi tabel admin sesuai petunjuk instalasi.'); }); function page_start($title, $active = '') { $GLOBALS['admin_layout'] = $active !== ''; ?><?=e($title)?> · Nurinda Recruitment
Human Capital / Recruitment
Admin workspace
RECRUITMENT MANAGEMENT

' : '') . '
'; }