'; } // --------------------------------------------------------------------------- // CONTENT ROUTER // --------------------------------------------------------------------------- function scn01_content() { if (function_exists('head_add_css')) { head_add_css('/addon/scn01/view/css/scn01.css'); } if (function_exists('head_add_js')) { head_add_js('/addon/scn01/view/js/scn01.js'); } $association_slug = argv(1) ?? ''; // Index — no association selected if (!$association_slug) { return scn01_render_index(); } $raw = @file_get_contents('addon/vs01/config.json'); $cfg = $raw ? json_decode($raw, true) : []; if (json_last_error() !== JSON_ERROR_NONE || !isset($cfg['associations'][$association_slug])) { return scn01_render_not_found(); } $access = scn01_access_state($association_slug); // POST — submission handler if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($access === 'public') { return scn01_access_wall($association_slug); } if (!scn01_verify_csrf()) { return '
Invalid form token. Please reload and try again.
'; } return scn01_handle_post($association_slug, $access); } // Association landing — carousel + submission form return scn01_render_landing($association_slug, $access); } // --------------------------------------------------------------------------- // NOT FOUND // --------------------------------------------------------------------------- function scn01_render_not_found() { return '
Association not found.
'; } // --------------------------------------------------------------------------- // CSRF // --------------------------------------------------------------------------- function scn01_csrf_token() { if (empty($_SESSION['scn01_csrf'])) { $_SESSION['scn01_csrf'] = bin2hex(random_bytes(16)); } return ''; } function scn01_verify_csrf() { return isset($_POST['scn01_csrf'], $_SESSION['scn01_csrf']) && hash_equals($_SESSION['scn01_csrf'], $_POST['scn01_csrf']); }