117 lines
4.3 KiB
PHP
117 lines
4.3 KiB
PHP
<?php
|
|
/**
|
|
* Saqel Application Bootstrap Loader
|
|
* Handles PSR-4 Autoloading, security settings, and strict error handling.
|
|
*/
|
|
|
|
// Define absolute path to application root (saqel/backend)
|
|
define('APP_ROOT', dirname(__DIR__));
|
|
|
|
// 1. PSR-4 Autoloader
|
|
spl_autoload_register(function ($class) {
|
|
$prefix = 'App\\';
|
|
$base_dir = APP_ROOT . '/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_once $file;
|
|
}
|
|
});
|
|
|
|
// 2. Load Environment Variables with Multi-Path Fallback
|
|
try {
|
|
// Production secrets belong outside the web/document root. Do not load
|
|
// backend/.env: it may be a placeholder and must never shadow the real
|
|
// CloudPanel environment file.
|
|
$envPath = getenv('SAQEL_ENV_FILE') ?: '/home/intaleqapp-saqel/.env';
|
|
$loaded = false;
|
|
if (file_exists($envPath)) {
|
|
\App\Core\Env::load($envPath);
|
|
define('LOADED_ENV_PATH', $envPath);
|
|
$loaded = true;
|
|
|
|
// Support either GEMINI_API_KEYS=key1,key2 or the legacy singular
|
|
// variable containing a comma-separated pool. Legacy services receive
|
|
// one safe key; services with round-robin support consume the pool.
|
|
$geminiPool = trim((string)(getenv('GEMINI_API_KEYS') ?: getenv('GEMINI_KEY') ?: ''));
|
|
$geminiKeys = array_values(array_filter(array_map('trim', explode(',', $geminiPool))));
|
|
if (!empty($geminiKeys)) {
|
|
putenv('GEMINI_API_KEYS=' . implode(',', $geminiKeys));
|
|
$_ENV['GEMINI_API_KEYS'] = implode(',', $geminiKeys);
|
|
$_SERVER['GEMINI_API_KEYS'] = implode(',', $geminiKeys);
|
|
putenv('GEMINI_KEY=' . $geminiKeys[0]);
|
|
$_ENV['GEMINI_KEY'] = $geminiKeys[0];
|
|
$_SERVER['GEMINI_KEY'] = $geminiKeys[0];
|
|
}
|
|
}
|
|
|
|
if (!$loaded) {
|
|
define('LOADED_ENV_PATH', 'NOT_FOUND');
|
|
error_log("⚠️ [Env Warning] .env file not found in any candidate path");
|
|
}
|
|
} catch (\Exception $e) {
|
|
error_log('Env Load Error: ' . $e->getMessage());
|
|
if (!defined('LOADED_ENV_PATH')) {
|
|
define('LOADED_ENV_PATH', 'ERROR: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
foreach (['ENCRYPTION_KEY', 'HMAC_SALT', 'JWT_SECRET'] as $requiredSecret) {
|
|
if (!getenv($requiredSecret)) {
|
|
throw new \RuntimeException("Missing required security secret: {$requiredSecret}");
|
|
}
|
|
}
|
|
|
|
// 3. Configure Error Reporting based on environment
|
|
$isDebug = filter_var(getenv('APP_DEBUG'), FILTER_VALIDATE_BOOLEAN);
|
|
|
|
if ($isDebug) {
|
|
ini_set('display_errors', '1');
|
|
ini_set('display_startup_errors', '1');
|
|
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
|
|
} else {
|
|
ini_set('display_errors', '0');
|
|
error_reporting(0);
|
|
}
|
|
|
|
// 4. Global Uncaught Exception Handler (JSON for APIs / Clean HTML for web)
|
|
set_exception_handler(function (\Throwable $e) {
|
|
$isDebug = filter_var(getenv('APP_DEBUG'), FILTER_VALIDATE_BOOLEAN);
|
|
|
|
error_log('[EXCEPTION] ' . get_class($e) . ': ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
|
|
|
|
$isApi = str_starts_with($_SERVER['REQUEST_URI'] ?? '', '/api');
|
|
|
|
if (!headers_sent()) {
|
|
http_response_code(500);
|
|
if ($isApi) {
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
} else {
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
}
|
|
}
|
|
|
|
if ($isApi) {
|
|
$body = [
|
|
'status' => 'error',
|
|
'message' => $isDebug ? $e->getMessage() : 'حدث خطأ غير متوقع في الخادم',
|
|
'debug' => $isDebug ? [
|
|
'exception' => get_class($e),
|
|
'file' => $e->getFile(),
|
|
'line' => $e->getLine(),
|
|
] : null
|
|
];
|
|
echo json_encode($body, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
|
} else {
|
|
echo "<!DOCTYPE html><html dir='rtl' lang='ar'><head><meta charset='UTF-8'><title>خطأ في الخادم</title><style>body{font-family:sans-serif;background:#0B132B;color:#fff;padding:40px;text-align:center;}</style></head><body><h2>⚠️ حدث خطأ في الخادم</h2><p>" . htmlspecialchars($e->getMessage()) . "</p></body></html>";
|
|
}
|
|
exit(1);
|
|
});
|