$value) { if (substr($name, 0, 5) == 'HTTP_') { $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; } elseif ($name == 'CONTENT_TYPE') { $headers['Content-Type'] = $value; } elseif ($name == 'CONTENT_LENGTH') { $headers['Content-Length'] = $value; } elseif ($name == 'AUTHORIZATION') { $headers['Authorization'] = $value; } } if (!isset($headers['Authorization']) && isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } return $headers; } } // 1. PSR-4 Autoloader spl_autoload_register(function ($class) { $prefix = 'App\\'; $base_dir = __DIR__ . '/../app/'; $len = strlen($prefix); if (strncmp($prefix, $class, $len) !== 0) { return; } $relative_class = substr($class, $len); $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php'; if (file_exists($file)) { require $file; } }); // 2. Load Global Handler & Configurations \App\Exceptions\Handler::register(); $securityConfig = require __DIR__ . '/../config/security.php'; $appConfig = require __DIR__ . '/../config/app.php'; // 3. Set Security Headers foreach ($securityConfig['headers'] as $header => $value) { header("{$header}: {$value}"); } // 4. Handle CORS & OPTIONS Preflight header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS"); header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With, X-CSRF-Token"); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit(); } // 5. Simple Custom Router & Subdirectory Base URL Adaptation $scriptName = $_SERVER['SCRIPT_NAME'] ?? ''; $baseDir = rtrim(str_replace('/index.php', '', $scriptName), '/'); // e.g. "/ttm/public" or "/ttm" $appBaseDir = preg_replace('#/public$#', '', $baseDir); // e.g. "/ttm" or "" if (!defined('BASE_URL')) { define('BASE_URL', $appBaseDir); } $rawUri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH); $uri = $rawUri; if (BASE_URL !== '' && strncmp($uri, BASE_URL, strlen(BASE_URL)) === 0) { $uri = substr($uri, strlen(BASE_URL)); } if (strncmp($uri, '/public', 7) === 0) { $uri = substr($uri, 7); } if ($uri === '' || $uri === false) { $uri = '/'; } $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; // Support fallback query parameter API routing (?api=/api/v1/...) for XAMPP servers without Apache mod_rewrite $queryApi = $_GET['api'] ?? $_GET['endpoint'] ?? null; if ($queryApi !== null && $queryApi !== '') { $uri = '/' . ltrim((string)$queryApi, '/'); if (strncmp($uri, '/api/v1/', 8) !== 0 && strncmp($uri, 'api/v1/', 7) !== 0) { $uri = '/api/v1/' . ltrim($uri, '/'); } if (($pos = strpos($uri, '?')) !== false) { $uri = substr($uri, 0, $pos); } } // 5.1 REST API Routes (/api/v1/...) if (strncmp($uri, '/api/v1/', 8) === 0) { ini_set('display_errors', '0'); header('Content-Type: application/json; charset=utf-8'); // Auth Routes if ($uri === '/api/v1/auth/login' && $method === 'POST') { (new \App\Controllers\AuthController())->login(); exit(); } if ($uri === '/api/v1/auth/verify-2fa' && $method === 'POST') { (new \App\Controllers\AuthController())->verifyTwoFactor(); exit(); } // Queue & Smart Queue AI Routes if ($uri === '/api/v1/queues' && $method === 'GET') { (new \App\Controllers\QueueController())->index(); exit(); } if ($uri === '/api/v1/queues/walkin' && $method === 'POST') { (new \App\Controllers\QueueController())->walkin(); exit(); } if ($uri === '/api/v1/queues/smart-assign' && $method === 'POST') { (new \App\Controllers\QueueController())->smartAssign(); exit(); } if (preg_match('#^/api/v1/queues/(\d+)/status$#', $uri, $matches) && $method === 'PUT') { (new \App\Controllers\QueueController())->updateStatus((int)$matches[1]); exit(); } // Clinical & SOAP Note Routes if ($uri === '/api/v1/clinical/soap' && $method === 'POST') { (new \App\Controllers\ClinicalController())->storeSoap(); exit(); } if (preg_match('#^/api/v1/clinical/patient/(\d+)$#', $uri, $matches) && $method === 'GET') { (new \App\Controllers\ClinicalController())->getPatientHistory((int)$matches[1]); exit(); } // HIS / HOSxP & HL7 FHIR Integration Routes if ($uri === '/api/v1/his/sync' && $method === 'POST') { (new \App\Controllers\HisController())->syncPatient(); exit(); } if ($uri === '/api/v1/his/smartcard' && $method === 'GET') { (new \App\Controllers\HisController())->readSmartCard(); exit(); } if ($uri === '/api/v1/fhir/encounter' && $method === 'POST') { (new \App\Controllers\HisController())->exportFhir(); exit(); } // POS Billing & Thermal Printer Routes if ($uri === '/api/v1/billing/checkout' && $method === 'POST') { (new \App\Controllers\BillingController())->checkout(); exit(); } if (preg_match('#^/api/v1/billing/print-ticket/(\d+)$#', $uri, $matches) && $method === 'GET') { (new \App\Controllers\BillingController())->printTicket((int)$matches[1]); exit(); } // Dashboard KPI & Report Routes if ($uri === '/api/v1/reports/kpi' && $method === 'GET') { (new \App\Controllers\ReportController())->kpi(); exit(); } if ($uri === '/api/v1/reports/export' && $method === 'GET') { (new \App\Controllers\ReportController())->export(); exit(); } // Services & Rooms Routes if ($uri === '/api/v1/services' && $method === 'GET') { (new \App\Controllers\ServiceController())->index(); exit(); } if ($uri === '/api/v1/rooms' && $method === 'GET') { (new \App\Controllers\RoomController())->index(); exit(); } // Therapists Routes if ($uri === '/api/v1/therapists' && $method === 'GET') { (new \App\Controllers\TherapistController())->index(); exit(); } if (preg_match('#^/api/v1/therapists/(\d+)/availability$#', $uri, $matches) && ($method === 'PUT' || $method === 'PATCH')) { (new \App\Controllers\TherapistController())->toggleAvailability((int)$matches[1]); exit(); } // Patients Routes if ($uri === '/api/v1/patients/search' && $method === 'GET') { (new \App\Controllers\PatientController())->search(); exit(); } if ($uri === '/api/v1/patients' && $method === 'POST') { (new \App\Controllers\PatientController())->store(); exit(); } // Settings Routes if ($uri === '/api/v1/settings' && $method === 'GET') { (new \App\Controllers\SettingController())->index(); exit(); } if ($uri === '/api/v1/settings' && ($method === 'PUT' || $method === 'POST')) { (new \App\Controllers\SettingController())->update(); exit(); } // Default 404 API Not Found \App\Helpers\Response::error("API Endpoint Not Found: {$method} {$uri}", 404); } // 5.2 Frontend GUI & PWA View Router session_start(); // Support fallback query parameter routing (?page=... or ?route=...) for servers without Apache mod_rewrite $queryPage = $_GET['page'] ?? $_GET['p'] ?? $_GET['route'] ?? $_GET['url'] ?? null; if ($queryPage !== null && $queryPage !== '') { $uri = '/' . ltrim((string)$queryPage, '/'); // Remove query parameters if any were included in uri string if (($pos = strpos($uri, '?')) !== false) { $uri = substr($uri, 0, $pos); } } $viewMap = [ '/' => 'dashboard/index.php', '/index.php' => 'dashboard/index.php', '/dashboard' => 'dashboard/index.php', '/login' => 'auth/login.php', '/verify-2fa' => 'auth/verify_2fa.php', '/queue' => 'queue/index.php', '/tv' => 'display/tv.php', '/clinical' => 'clinical/soap.php', '/clinical/soap' => 'clinical/soap.php', '/patient' => 'patient/index.php', '/room' => 'room/index.php', '/pos' => 'billing/pos.php', '/billing' => 'billing/pos.php', '/reports' => 'report/index.php', '/report' => 'report/index.php', '/his' => 'his/index.php', '/his-sync' => 'his/index.php', '/settings' => 'admin/settings.php', '/admin/settings' => 'admin/settings.php', ]; $activeMenuMap = [ '/' => 'dashboard', '/index.php' => 'dashboard', '/dashboard' => 'dashboard', '/queue' => 'queue', '/tv' => 'tv', '/clinical' => 'soap', '/clinical/soap' => 'soap', '/patient' => 'patient', '/room' => 'room', '/pos' => 'billing', '/billing' => 'billing', '/reports' => 'reports', '/report' => 'reports', '/his' => 'his', '/his-sync' => 'his', '/settings' => 'settings', '/admin/settings' => 'settings', ]; $viewFile = $viewMap[$uri] ?? 'dashboard/index.php'; // Default dashboard or 404 $activeMenu = $activeMenuMap[$uri] ?? 'dashboard'; $fullPath = __DIR__ . '/views/' . $viewFile; if (file_exists($fullPath)) { $contentView = $fullPath; // Include master layout which will include the $contentView view inside require __DIR__ . '/views/layout/master.php'; } else { http_response_code(404); echo "

404 Not Found - View ({$viewFile}) does not exist for URI: {$uri}

"; }