205 lines
6.2 KiB
PHP
205 lines
6.2 KiB
PHP
<?php
|
|
|
|
use MintyPHP\Analyzer;
|
|
use MintyPHP\Buffer;
|
|
use MintyPHP\DB;
|
|
use MintyPHP\Debugger;
|
|
use MintyPHP\Firewall;
|
|
use MintyPHP\Http\AccessControl;
|
|
use MintyPHP\Http\AssetDetector;
|
|
use MintyPHP\Http\LocaleResolver;
|
|
use MintyPHP\Http\Request;
|
|
use MintyPHP\I18n;
|
|
use MintyPHP\Router;
|
|
use MintyPHP\Service\Auth\AuthServicesFactory;
|
|
use MintyPHP\Session;
|
|
use MintyPHP\Support\Flash;
|
|
|
|
// Change directory to project root
|
|
chdir(__DIR__ . '/..');
|
|
// Load the libraries
|
|
require 'vendor/autoload.php';
|
|
// Load the config parameters
|
|
require 'config/config.php';
|
|
// Load the routes
|
|
require 'config/router.php';
|
|
// Register shortcut functions
|
|
require 'lib/Support/helpers.php';
|
|
|
|
// Start the firewall
|
|
Firewall::start();
|
|
|
|
// Start the session
|
|
Session::start();
|
|
$authServicesFactory = new AuthServicesFactory();
|
|
$authService = $authServicesFactory->createAuthService();
|
|
$rememberMeService = $authServicesFactory->createRememberMeService();
|
|
|
|
// Initialize default locale from tenant/app settings
|
|
$defaultLocale = appDefaultLocale();
|
|
if ($defaultLocale !== null) {
|
|
I18n::$defaultLocale = $defaultLocale;
|
|
if (I18n::$locale === '') {
|
|
I18n::$locale = $defaultLocale;
|
|
}
|
|
}
|
|
|
|
// Auto-login from remember-me cookie
|
|
if (empty($_SESSION['user']['id'])) {
|
|
$rememberMeService->autoLoginFromCookie();
|
|
}
|
|
|
|
// Parse request URI and resolve locale
|
|
$originalUri = $_SERVER['REQUEST_URI'] ?? '';
|
|
$_SERVER['MINTY_ORIGINAL_URI'] = $originalUri;
|
|
|
|
$localeResolver = new LocaleResolver();
|
|
$parsedUri = $localeResolver->parseUri($originalUri);
|
|
$pathWithoutLocale = $parsedUri['pathWithoutLocale'];
|
|
$requestedLocale = $parsedUri['locale'];
|
|
$_SERVER['MINTY_LOCALE'] = $requestedLocale;
|
|
|
|
// Rewrite REQUEST_URI without locale segment for router
|
|
if ($parsedUri['hadLocaleInUrl']) {
|
|
$_SERVER['REQUEST_URI'] = $localeResolver->buildUriWithoutLocale(
|
|
$pathWithoutLocale,
|
|
$parsedUri['query']
|
|
);
|
|
}
|
|
|
|
// Resolve effective locale from URL > Session > Cookie > Default
|
|
I18n::$locale = $localeResolver->resolveLocale(
|
|
$requestedLocale,
|
|
$_SESSION['user']['locale'] ?? null,
|
|
$_COOKIE['locale'] ?? null
|
|
);
|
|
|
|
$isAssetRequest = AssetDetector::isAssetRequest($pathWithoutLocale);
|
|
$isApiRequest = str_starts_with($pathWithoutLocale, 'api/');
|
|
|
|
if ($isApiRequest) {
|
|
if (!defined('MINTY_API_REQUEST')) {
|
|
define('MINTY_API_REQUEST', true);
|
|
}
|
|
|
|
// Minty router enforces CSRF for non-GET requests before action execution.
|
|
// Our API is Bearer-token based and does not use form-CSRF, so mark only
|
|
// API write requests as AJAX to bypass the router-level form CSRF gate.
|
|
$requestMethod = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
|
|
$isApiWriteMethod = !in_array($requestMethod, ['GET', 'HEAD', 'OPTIONS'], true);
|
|
if ($isApiWriteMethod && empty($_SERVER['HTTP_X_REQUESTED_WITH'])) {
|
|
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
|
|
}
|
|
}
|
|
|
|
// Refresh tenant context if stale or missing (skip for assets and API requests)
|
|
if (!empty($_SESSION['user']['id']) && !$isAssetRequest && !$isApiRequest) {
|
|
$userId = (int) ($_SESSION['user']['id'] ?? 0);
|
|
if ($userId > 0) {
|
|
$authState = $authService->refreshSessionAuthState($userId);
|
|
if (!empty($authState['logout_required'])) {
|
|
$authService->logout();
|
|
$reason = (string) ($authState['reason'] ?? '');
|
|
if ($reason === 'inactive') {
|
|
Flash::error(t('Account is inactive'), 'login', 'login_inactive');
|
|
} else {
|
|
Flash::error(t('No active tenant assigned'), 'login', 'no_active_tenant');
|
|
}
|
|
Router::redirect('login');
|
|
}
|
|
|
|
$ttl = 120;
|
|
$lastRefresh = (int) ($_SESSION['tenant_snapshot_at'] ?? 0);
|
|
$needsRefresh = empty($_SESSION['current_tenant']) || empty($_SESSION['available_tenants']);
|
|
if ((time() - $lastRefresh) >= $ttl) {
|
|
$needsRefresh = true;
|
|
}
|
|
if ($needsRefresh) {
|
|
$authService->loadTenantDataIntoSession($userId);
|
|
$_SESSION['tenant_snapshot_at'] = time();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($requestedLocale === '' && !$isAssetRequest && !$isApiRequest) {
|
|
$method = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
|
|
if (in_array($method, ['GET', 'HEAD'], true)) {
|
|
$target = Request::withLocale($pathWithoutLocale, I18n::$locale ?? I18n::$defaultLocale);
|
|
$target .= $parsedUri['query'] !== '' ? '?' . $parsedUri['query'] : '';
|
|
Router::redirect($target);
|
|
}
|
|
}
|
|
|
|
// Guard: restrict non-public pages to logged-in users
|
|
$accessControl = new AccessControl();
|
|
$accessControl->requireAuthOrRedirect($pathWithoutLocale, !empty($_SESSION['user']['id']));
|
|
|
|
// Analyze the PHP code
|
|
if (Debugger::$enabled) {
|
|
Analyzer::execute();
|
|
}
|
|
|
|
// Load the action into body
|
|
ob_start();
|
|
if (Router::getTemplateAction()) {
|
|
require Router::getTemplateAction();
|
|
}
|
|
if (ob_get_contents()) {
|
|
ob_end_flush();
|
|
if (!defined('MINTY_ALLOW_OUTPUT') || !MINTY_ALLOW_OUTPUT) {
|
|
trigger_error('MintyPHP template action"' . Router::getTemplateAction() . '" should not send output. Error raised ', E_USER_WARNING);
|
|
}
|
|
} else {
|
|
ob_end_clean();
|
|
}
|
|
if (defined('MINTY_ALLOW_OUTPUT') && MINTY_ALLOW_OUTPUT) {
|
|
Session::end();
|
|
DB::close();
|
|
exit;
|
|
}
|
|
|
|
ob_start();
|
|
if (Router::getAction()) {
|
|
extract(Router::getParameters());
|
|
require Router::getAction();
|
|
}
|
|
if (ob_get_contents()) {
|
|
ob_end_flush();
|
|
if (!defined('MINTY_ALLOW_OUTPUT') || !MINTY_ALLOW_OUTPUT) {
|
|
trigger_error('MintyPHP action "' . Router::getAction() . '" should not send output. Error raised ', E_USER_WARNING);
|
|
}
|
|
} else {
|
|
ob_end_clean();
|
|
}
|
|
if (defined('MINTY_ALLOW_OUTPUT') && MINTY_ALLOW_OUTPUT) {
|
|
Session::end();
|
|
DB::close();
|
|
exit;
|
|
}
|
|
|
|
// End the session
|
|
Session::end();
|
|
|
|
// Close the database connection
|
|
DB::close();
|
|
|
|
if (Router::getTemplateView()) {
|
|
Buffer::start('html');
|
|
if (Router::getView()) {
|
|
require Router::getView();
|
|
}
|
|
|
|
// Show developer toolbar
|
|
if (Debugger::$enabled) {
|
|
Debugger::toolbar();
|
|
}
|
|
|
|
Buffer::end('html');
|
|
// Load body into template
|
|
require Router::getTemplateView();
|
|
} else { // Handle the 'none' template case
|
|
if (Router::getView()) {
|
|
require Router::getView();
|
|
}
|
|
}
|