Commit f4e293a6 authored by Administrator's avatar Administrator

Update 12 files via Son of Anton

parent a6d47855
Pipeline #28 canceled with stage
APP_URL=https://hr.al-arcade.com APP_URL=https://hrsystem.caprover.al-arcade.com
APP_DEBUG=false APP_DEBUG=true
APP_KEY=CHANGE-ME-TO-64-CHAR-RANDOM-STRING APP_KEY=al-arcade-hr-v3-2025-secure-key
DB_HOST=srv-captain--mysql-db DB_HOST=srv-captain--mysql-db
DB_PORT=3306 DB_PORT=3306
......
...@@ -11,6 +11,7 @@ RUN apt-get update && apt-get install -y \ ...@@ -11,6 +11,7 @@ RUN apt-get update && apt-get install -y \
libcurl4-openssl-dev \ libcurl4-openssl-dev \
zip unzip curl \ zip unzip curl \
default-mysql-client \ default-mysql-client \
cron \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install \ && docker-php-ext-install \
pdo_mysql \ pdo_mysql \
...@@ -27,6 +28,9 @@ RUN apt-get update && apt-get install -y \ ...@@ -27,6 +28,9 @@ RUN apt-get update && apt-get install -y \
# Apache configuration # Apache configuration
RUN a2enmod rewrite headers RUN a2enmod rewrite headers
# Suppress ServerName warning globally
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf
# PHP configuration # PHP configuration
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY docker/php-custom.ini /usr/local/etc/php/conf.d/99-custom.ini COPY docker/php-custom.ini /usr/local/etc/php/conf.d/99-custom.ini
...@@ -46,11 +50,10 @@ RUN mkdir -p \ ...@@ -46,11 +50,10 @@ RUN mkdir -p \
&& chown -R www-data:www-data /var/www/html/storage \ && chown -R www-data:www-data /var/www/html/storage \
&& chmod -R 775 /var/www/html/storage && chmod -R 775 /var/www/html/storage
# ─── Apache: Set DocumentRoot to /var/www/html/public ─── # Apache vhost
# Do NOT use sed — it causes double-path bugs. Use a clean vhost config instead.
COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf
# Entrypoint for DB initialization # Entrypoint
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh
......
...@@ -21,32 +21,30 @@ use Engine\Scheduler\JobRunner; ...@@ -21,32 +21,30 @@ use Engine\Scheduler\JobRunner;
// Timezone // Timezone
date_default_timezone_set('Africa/Cairo'); date_default_timezone_set('Africa/Cairo');
// Error handling // Error handling — log everything
set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) { set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) {
// Don't throw on suppressed errors
if (!(error_reporting() & $errno)) return false;
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}); });
set_exception_handler(function (\Throwable $e) {
error_log("UNCAUGHT: {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}");
if (!headers_sent()) {
http_response_code(500);
header('Content-Type: text/html');
}
$errorPage = ROOT_PATH . '/templates/errors/500.php';
if (file_exists($errorPage)) { require $errorPage; } else { echo '<h1>500 Internal Server Error</h1>'; }
exit(1);
});
// ─── CONTAINER REGISTRATION ─── // ─── CONTAINER REGISTRATION ───
$container = Container::getInstance(); $container = Container::getInstance();
// Config first — everything depends on it
$container->singleton(Config::class, fn() => new Config()); $container->singleton(Config::class, fn() => new Config());
// Database — everything depends on it
$container->singleton(Connection::class, fn() => new Connection()); $container->singleton(Connection::class, fn() => new Connection());
$container->singleton(SessionManager::class, fn() => new SessionManager());
// Auth layer
$container->singleton(PasswordHasher::class, fn() => new PasswordHasher()); $container->singleton(PasswordHasher::class, fn() => new PasswordHasher());
$container->singleton(SessionManager::class, fn() => new SessionManager());
$container->singleton(RateLimiter::class, fn() => new RateLimiter()); $container->singleton(RateLimiter::class, fn() => new RateLimiter());
$container->singleton(Authenticator::class, fn() => new Authenticator()); $container->singleton(Authenticator::class, fn() => new Authenticator());
$container->singleton(PermissionEngine::class, fn() => new PermissionEngine()); $container->singleton(PermissionEngine::class, fn() => new PermissionEngine());
// Services
$container->singleton(AuditLogger::class, fn() => new AuditLogger()); $container->singleton(AuditLogger::class, fn() => new AuditLogger());
$container->singleton(NotificationManager::class, fn() => new NotificationManager()); $container->singleton(NotificationManager::class, fn() => new NotificationManager());
$container->singleton(EventDispatcher::class, fn() => new EventDispatcher()); $container->singleton(EventDispatcher::class, fn() => new EventDispatcher());
...@@ -61,16 +59,26 @@ $container->singleton(Router::class, fn() => new Router()); ...@@ -61,16 +59,26 @@ $container->singleton(Router::class, fn() => new Router());
// ─── CALCULATION ENGINE ─── // ─── CALCULATION ENGINE ───
$calcEngine = new CalculationEngine(); $calcEngine = new CalculationEngine();
$calculators = require ROOT_PATH . '/config/calculators.php'; $calculatorsFile = ROOT_PATH . '/config/calculators.php';
foreach ($calculators as $name => $class) { if (file_exists($calculatorsFile)) {
$calculators = require $calculatorsFile;
foreach ($calculators as $name => $class) {
$calcEngine->register($name, $class); $calcEngine->register($name, $class);
}
} }
$container->instance(CalculationEngine::class, $calcEngine); $container->instance(CalculationEngine::class, $calcEngine);
// ─── LOAD ALL MODULE ROUTES ─── // ─── LOAD ALL MODULE ROUTES ───
$routeFiles = glob(ROOT_PATH . '/modules/*/routes.php'); $routeFiles = glob(ROOT_PATH . '/modules/*/routes.php');
foreach ($routeFiles as $routeFile) { if ($routeFiles) {
foreach ($routeFiles as $routeFile) {
try {
require_once $routeFile; require_once $routeFile;
} catch (\Throwable $e) {
error_log("ROUTE LOAD ERROR [{$routeFile}]: " . $e->getMessage());
// Don't die — skip broken route files and continue
}
}
} }
return $container; return $container;
\ No newline at end of file
...@@ -7,21 +7,27 @@ use Engine\Core\Container; ...@@ -7,21 +7,27 @@ use Engine\Core\Container;
use Engine\Database\Connection; use Engine\Database\Connection;
use Engine\Auth\PasswordHasher; use Engine\Auth\PasswordHasher;
$db = Container::getInstance()->resolve(Connection::class); try {
$hasher = Container::getInstance()->resolve(PasswordHasher::class); $db = Container::getInstance()->resolve(Connection::class);
$hasher = Container::getInstance()->resolve(PasswordHasher::class);
} catch (\Throwable $e) {
echo "ERROR connecting to database: " . $e->getMessage() . "\n";
exit(1);
}
$username = getenv('SA_USERNAME') ?: 'admin'; $username = getenv('SA_USERNAME') ?: 'admin';
$password = getenv('SA_PASSWORD') ?: 'Alarcade123#'; $password = getenv('SA_PASSWORD') ?: 'Alarcade123#';
$nameEn = getenv('SA_NAME_EN') ?: 'Super Admin'; $nameEn = getenv('SA_NAME_EN') ?: 'Mahmoud Aglan';
$nameAr = getenv('SA_NAME_AR') ?: دير النظام'; $nameAr = getenv('SA_NAME_AR') ?: حمود عجلان';
$exists = $db->fetchOne("SELECT id FROM users WHERE username = ?", [$username]); try {
if ($exists) { $exists = $db->fetchOne("SELECT id FROM users WHERE username = ?", [$username]);
echo "Super admin '{$username}' already exists (ID: {$exists['id']})\n"; if ($exists) {
echo "✅ Super Admin '{$username}' already exists (ID: {$exists['id']}). Skipping.\n";
exit(0); exit(0);
} }
$id = $db->insert('users', [ $id = $db->insert('users', [
'username' => $username, 'username' => $username,
'password_hash' => $hasher->hash($password), 'password_hash' => $hasher->hash($password),
'role' => 'super_admin', 'role' => 'super_admin',
...@@ -30,7 +36,7 @@ $id = $db->insert('users', [ ...@@ -30,7 +36,7 @@ $id = $db->insert('users', [
'national_id' => '00000000000000', 'national_id' => '00000000000000',
'date_of_birth' => '1990-01-01', 'date_of_birth' => '1990-01-01',
'phone_primary' => '+201000000000', 'phone_primary' => '+201000000000',
'address' => 'System', 'address' => 'System Administrator',
'emergency_contact_name' => 'N/A', 'emergency_contact_name' => 'N/A',
'emergency_contact_phone' => '+201000000001', 'emergency_contact_phone' => '+201000000001',
'emergency_contact_relationship' => 'other', 'emergency_contact_relationship' => 'other',
...@@ -41,6 +47,10 @@ $id = $db->insert('users', [ ...@@ -41,6 +47,10 @@ $id = $db->insert('users', [
'activation_date' => date('Y-m-d'), 'activation_date' => date('Y-m-d'),
'is_active' => 1, 'is_active' => 1,
'force_password_change' => 0, 'force_password_change' => 0,
]); ]);
echo "✅ Super admin created: {$username} (ID: {$id})\n"; echo "✅ Super Admin created: {$username} (ID: {$id})\n";
\ No newline at end of file } catch (\Throwable $e) {
echo "ERROR: " . $e->getMessage() . "\n";
exit(1);
}
\ No newline at end of file
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
return [ return [
'name' => 'AL-ARCADE HR Platform', 'name' => 'AL-ARCADE HR Platform',
'version' => '3.0.0', 'version' => '3.0.0',
'url' => getenv('APP_URL') ?: 'https://hrsystem.caprover.al-arcade.com', 'url' => 'https://hrsystem.caprover.al-arcade.com',
'debug' => (bool)(getenv('APP_DEBUG') ?: false), 'debug' => true,
'timezone' => 'Africa/Cairo', 'timezone' => 'Africa/Cairo',
'locale' => 'en', 'locale' => 'en',
'key' => getenv('APP_KEY') ?: 'al-arcade-hr-v3-2025-secure-key-do-not-share-with-anyone-ever', 'key' => 'al-arcade-hr-v3-2025-secure-key-do-not-share',
]; ];
\ No newline at end of file
<?php <?php
return [ return [
'host' => getenv('DB_HOST') ?: 'srv-captain--mysql-db', 'host' => 'srv-captain--mysql-db',
'port' => (int)(getenv('DB_PORT') ?: 3306), 'port' => 3306,
'database' => getenv('DB_NAME') ?: 'al_arcade_hr', 'database' => 'al_arcade_hr',
'username' => getenv('DB_USER') ?: 'root', 'username' => 'root',
'password' => getenv('DB_PASS') ?: 'Alarcade123#', 'password' => 'Alarcade123#',
'charset' => 'utf8mb4', 'charset' => 'utf8mb4',
'collation'=> 'utf8mb4_unicode_ci', 'collation'=> 'utf8mb4_unicode_ci',
'options' => [ 'options' => [
......
<VirtualHost *:80> <VirtualHost *:80>
ServerName hrsystem.caprover.al-arcade.com
ServerAdmin webmaster@localhost ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/public DocumentRoot /var/www/html/public
<Directory /var/www/html/public> <Directory /var/www/html/public>
AllowOverride All AllowOverride All
Require all granted Require all granted
Options -Indexes +FollowSymLinks Options -Indexes +FollowSymLinks -MultiViews
# Disable MultiViews to prevent Apache from doing content negotiation
Options -MultiViews
</Directory> </Directory>
# Pass environment variables to PHP
PassEnv DB_HOST DB_PORT DB_NAME DB_USER DB_PASS
PassEnv SA_USERNAME SA_PASSWORD SA_NAME_EN SA_NAME_AR
PassEnv APP_URL APP_DEBUG APP_KEY
# Deny access to sensitive directories # Deny access to sensitive directories
<DirectoryMatch "^/var/www/html/(engine|config|database|cli|bootstrap|storage|modules|middleware|templates)"> <DirectoryMatch "^/var/www/html/(engine|config|database|cli|bootstrap|storage|modules|middleware|templates)">
Require all denied Require all denied
......
...@@ -5,55 +5,63 @@ echo "===========================================" ...@@ -5,55 +5,63 @@ echo "==========================================="
echo " AL-ARCADE HR Platform v3.0 — Entrypoint" echo " AL-ARCADE HR Platform v3.0 — Entrypoint"
echo "===========================================" echo "==========================================="
# ─── Hardcoded defaults (user doesn't use env vars) ───
export DB_HOST="${DB_HOST:-srv-captain--mysql-db}"
export DB_PORT="${DB_PORT:-3306}"
export DB_NAME="${DB_NAME:-al_arcade_hr}"
export DB_USER="${DB_USER:-root}"
export DB_PASS="${DB_PASS:-Alarcade123#}"
export SA_USERNAME="${SA_USERNAME:-admin}"
export SA_PASSWORD="${SA_PASSWORD:-Alarcade123#}"
export SA_NAME_EN="${SA_NAME_EN:-Mahmoud Aglan}"
export SA_NAME_AR="${SA_NAME_AR:-محمود عجلان}"
# ─── Wait for MySQL ─── # ─── Wait for MySQL ───
echo "[INIT] Waiting for MySQL at ${DB_HOST:-srv-captain--mysql-db}:${DB_PORT:-3306}..." echo "[INIT] Waiting for MySQL at ${DB_HOST}:${DB_PORT}..."
MAX_TRIES=30 MAX_TRIES=60
COUNT=0 COUNT=0
until mysql -h "${DB_HOST:-srv-captain--mysql-db}" -P "${DB_PORT:-3306}" -u "${DB_USER:-root}" -p"${DB_PASS:-Alarcade123#}" -e "SELECT 1" &>/dev/null; do until mysqladmin ping -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" --skip-ssl --silent 2>/dev/null; do
COUNT=$((COUNT+1)) COUNT=$((COUNT+1))
if [ $COUNT -ge $MAX_TRIES ]; then if [ $COUNT -ge $MAX_TRIES ]; then
echo "[ERROR] MySQL not available after ${MAX_TRIES} attempts. Starting Apache anyway..." echo "[ERROR] MySQL not available after ${MAX_TRIES} attempts. Starting Apache anyway..."
break break
fi fi
echo "[INIT] MySQL not ready yet (attempt $COUNT/$MAX_TRIES)..." echo "[INIT] MySQL not ready (attempt $COUNT/$MAX_TRIES)..."
sleep 2 sleep 2
done done
echo "[INIT] MySQL is available." echo "[INIT] MySQL is available."
# ─── Run Schema ─── # ─── Ensure Database Exists ───
DB_NAME="${DB_NAME:-al_arcade_hr}" mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" --skip-ssl \
DB_EXISTS=$(mysql -h "${DB_HOST:-srv-captain--mysql-db}" -P "${DB_PORT:-3306}" -u "${DB_USER:-root}" -p"${DB_PASS:-Alarcade123#}" -se "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='${DB_NAME}'" 2>/dev/null || echo "0") -e "CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>/dev/null || true
if [ "$DB_EXISTS" = "0" ] || [ -z "$DB_EXISTS" ]; then # ─── Check if schema needs to be imported ───
echo "[INIT] Database empty or not found. Running schema..." TABLE_COUNT=$(mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" --skip-ssl \
mysql -h "${DB_HOST:-srv-captain--mysql-db}" -P "${DB_PORT:-3306}" -u "${DB_USER:-root}" -p"${DB_PASS:-Alarcade123#}" < /var/www/html/database/schema.sql 2>&1 || echo "[WARN] Schema import had warnings" -se "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='${DB_NAME}'" 2>/dev/null || echo "0")
echo "[INIT] Schema imported."
if [ "$TABLE_COUNT" = "0" ] || [ -z "$TABLE_COUNT" ]; then
echo "[INIT] Database empty. Running schema..."
mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" --skip-ssl \
< /var/www/html/database/schema.sql 2>&1 || echo "[WARN] Schema import had warnings"
# Seed data
if [ -f /var/www/html/database/seed.sql ]; then if [ -f /var/www/html/database/seed.sql ]; then
echo "[INIT] Running seed SQL..." echo "[INIT] Running seed SQL..."
mysql -h "${DB_HOST:-srv-captain--mysql-db}" -P "${DB_PORT:-3306}" -u "${DB_USER:-root}" -p"${DB_PASS:-Alarcade123#}" "${DB_NAME}" < /var/www/html/database/seed.sql 2>&1 || echo "[WARN] Seed had warnings" mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" --skip-ssl "${DB_NAME}" \
< /var/www/html/database/seed.sql 2>&1 || echo "[WARN] Seed had warnings"
fi fi
# Run PHP seed
if [ -f /var/www/html/cli/seed.php ]; then if [ -f /var/www/html/cli/seed.php ]; then
echo "[INIT] Running PHP seed..." echo "[INIT] Running PHP seed..."
php /var/www/html/cli/seed.php 2>&1 || echo "[WARN] PHP seed had errors" php /var/www/html/cli/seed.php 2>&1 || echo "[WARN] PHP seed had errors"
fi fi
# Create super admin
if [ -f /var/www/html/cli/create-superadmin.php ]; then
echo "[INIT] Creating super admin..."
php /var/www/html/cli/create-superadmin.php 2>&1 || echo "[WARN] Superadmin creation had errors"
fi
else else
echo "[INIT] Database already has ${DB_EXISTS} tables. Skipping schema import." echo "[INIT] Database has ${TABLE_COUNT} tables. Skipping schema."
fi
# Still try to create superadmin if it doesn't exist # ─── Create Super Admin ───
if [ -f /var/www/html/cli/create-superadmin.php ]; then if [ -f /var/www/html/cli/create-superadmin.php ]; then
echo "[INIT] Ensuring super admin exists..."
php /var/www/html/cli/create-superadmin.php 2>&1 || true php /var/www/html/cli/create-superadmin.php 2>&1 || true
fi
fi fi
# ─── Fix permissions ─── # ─── Fix permissions ───
...@@ -62,7 +70,6 @@ chown -R www-data:www-data /var/www/html/storage 2>/dev/null || true ...@@ -62,7 +70,6 @@ chown -R www-data:www-data /var/www/html/storage 2>/dev/null || true
chmod -R 775 /var/www/html/storage 2>/dev/null || true chmod -R 775 /var/www/html/storage 2>/dev/null || true
# ─── Setup cron ─── # ─── Setup cron ───
echo "[INIT] Setting up cron job..."
echo "*/5 * * * * cd /var/www/html && php cron/runner.php >> /var/www/html/storage/logs/cron.log 2>&1" | crontab - 2>/dev/null || true echo "*/5 * * * * cd /var/www/html && php cron/runner.php >> /var/www/html/storage/logs/cron.log 2>&1" | crontab - 2>/dev/null || true
service cron start 2>/dev/null || true service cron start 2>/dev/null || true
...@@ -70,5 +77,4 @@ echo "===========================================" ...@@ -70,5 +77,4 @@ echo "==========================================="
echo " AL-ARCADE HR Platform — Ready!" echo " AL-ARCADE HR Platform — Ready!"
echo "===========================================" echo "==========================================="
# Start Apache
exec "$@" exec "$@"
\ No newline at end of file
...@@ -6,16 +6,34 @@ namespace Engine\Database; ...@@ -6,16 +6,34 @@ namespace Engine\Database;
final class Connection final class Connection
{ {
private \PDO $pdo; private \PDO $pdo;
private static ?Connection $instance = null;
public function __construct() public function __construct()
{ {
$config = require ROOT_PATH . '/config/database.php'; $config = require ROOT_PATH . '/config/database.php';
$dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=%s',
$config['host'], $config['port'], $config['database'], $config['charset'] $dsn = sprintf(
'mysql:host=%s;port=%d;dbname=%s;charset=%s',
$config['host'],
$config['port'],
$config['database'],
$config['charset']
); );
$this->pdo = new \PDO($dsn, $config['username'], $config['password'], $config['options'] ?? []); $options = $config['options'] ?? [];
// Fix MySQL 8.0+ SSL issues in Docker containers
if (!isset($options[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT])) {
$options[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = false;
}
try {
$this->pdo = new \PDO($dsn, $config['username'], $config['password'], $options);
} catch (\PDOException $e) {
// If SSL fails, retry without SSL
$options[\PDO::MYSQL_ATTR_SSL_CA] = '';
$options[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = false;
$this->pdo = new \PDO($dsn, $config['username'], $config['password'], $options);
}
} }
public function getPdo(): \PDO { return $this->pdo; } public function getPdo(): \PDO { return $this->pdo; }
......
<?php <?php
declare(strict_types=1); declare(strict_types=1);
// ─── BOOTSTRAP ─── // ─── SHOW ERRORS IN OUTPUT (until production-stable) ───
$container = require __DIR__ . '/../bootstrap/app.php'; error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('log_errors', '1');
use Engine\Core\{Router, Request, Response}; try {
// ─── BOOTSTRAP ───
$container = require __DIR__ . '/../bootstrap/app.php';
// ─── HANDLE REQUEST ─── use Engine\Core\{Router, Request, Response};
$request = new Request();
$router = $container->resolve(Router::class); // ─── HANDLE REQUEST ───
$request = new Request();
$router = $container->resolve(Router::class);
try {
$response = $router->dispatch($request); $response = $router->dispatch($request);
$response->send();
} catch (\Engine\Auth\ForbiddenException $e) { } catch (\Engine\Auth\ForbiddenException $e) {
$response = $request->wantsJson() http_response_code(403);
? Response::json(['error' => 'Forbidden'], 403) echo '<h1>403 Forbidden</h1><p>' . htmlspecialchars($e->getMessage()) . '</p>';
: Response::html('<h1>403 Forbidden</h1>', 403);
} catch (\Throwable $e) { } catch (\Throwable $e) {
error_log("REQUEST ERROR: {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); // ─── SHOW THE ACTUAL FUCKING ERROR ───
$response = $request->wantsJson() http_response_code(500);
? Response::json(['error' => 'Internal server error'], 500) $msg = $e->getMessage();
: Response::html(file_get_contents(ROOT_PATH . '/templates/errors/500.php') ?: '<h1>500</h1>', 500); $file = $e->getFile();
} $line = $e->getLine();
$trace = $e->getTraceAsString();
$response->send(); error_log("FATAL: {$msg} in {$file}:{$line}\n{$trace}");
\ No newline at end of file
echo <<<HTML
<!DOCTYPE html>
<html>
<head><title>500 — Server Error</title>
<style>
body{font-family:-apple-system,sans-serif;background:#0f172a;color:#e2e8f0;margin:0;padding:40px;min-height:100vh}
h1{color:#ef4444;font-size:2.5em;margin-bottom:10px}
.box{max-width:900px;margin:0 auto}
.error-msg{background:#1e293b;padding:20px;border-radius:8px;border-left:4px solid #ef4444;margin:16px 0;font-size:1.1em;color:#fbbf24;word-wrap:break-word}
.trace{background:#1e293b;padding:16px;border-radius:8px;font-family:monospace;font-size:0.8em;overflow-x:auto;white-space:pre-wrap;color:#94a3b8;margin:16px 0;max-height:500px;overflow-y:auto}
.file{color:#818cf8;font-size:0.9em}
a{color:#6366f1}
</style>
</head>
<body>
<div class="box">
<h1>500 — Application Error</h1>
<div class="error-msg">{$msg}</div>
<div class="file">{$file}:{$line}</div>
<h3 style="margin-top:20px;color:#94a3b8">Stack Trace:</h3>
<div class="trace">{$trace}</div>
<p style="margin-top:20px"><a href="/login">← Try Login</a> · <a href="/dashboard">Dashboard</a></p>
</div>
</body>
</html>
HTML;
}
\ No newline at end of file
<!DOCTYPE html><html><head><title>404</title><link rel="stylesheet" href="/assets/css/app.css"></head> <!DOCTYPE html>
<body class="error-page"><div class="error-container"><h1>404</h1><p>Page not found.</p><a href="/dashboard" class="btn btn-primary">Go Home</a></div></body></html> <html>
\ No newline at end of file <head>
<title>404 — Not Found</title>
<style>
body{font-family:-apple-system,sans-serif;background:#0f172a;color:#e2e8f0;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0}
.box{text-align:center;max-width:500px;padding:40px}
h1{font-size:5em;margin:0;color:#6366f1}
p{color:#94a3b8;margin:16px 0}
a{color:#6366f1;text-decoration:none;padding:10px 24px;border:2px solid #6366f1;border-radius:8px;display:inline-block;margin-top:16px}
a:hover{background:#6366f1;color:white}
</style>
</head>
<body>
<div class="box">
<h1>404</h1>
<p>Page not found.</p>
<a href="/dashboard">Go Home</a>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html> <!DOCTYPE html>
<html><head><title>500 Server Error</title><link rel="stylesheet" href="/assets/css/app.css"></head> <html>
<body class="error-page"><div class="error-container"><h1>500</h1><p>Internal server error.</p><a href="/dashboard" class="btn btn-primary">Go Home</a></div></body></html> <head>
\ No newline at end of file <title>500 — Server Error</title>
<style>
body{font-family:-apple-system,sans-serif;background:#0f172a;color:#e2e8f0;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0}
.box{text-align:center;max-width:500px;padding:40px}
h1{font-size:5em;margin:0;color:#6366f1}
p{color:#94a3b8;margin:16px 0}
a{color:#6366f1;text-decoration:none;padding:10px 24px;border:2px solid #6366f1;border-radius:8px;display:inline-block;margin-top:16px}
a:hover{background:#6366f1;color:white}
</style>
</head>
<body>
<div class="box">
<h1>500</h1>
<p>Internal server error. Check the logs.</p>
<a href="/login">Go to Login</a>
</div>
</body>
</html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment