Files
Siro/backend/core/bootstrap.php
Hamza-Ayed 50a5308f43 Fix #20: DDL removal from register.php, CORS policy, secret leak
- Removed ALTER TABLE DDL statements from Admin/auth/register.php (belongs in migration scripts)
- Added validated CORS with configurable allowed origins via CORS_ALLOWED_ORIGINS env var
- Removed  assignment in load_env.php (secrets no longer exposed in superglobal)
2026-06-17 07:51:01 +03:00

109 lines
4.0 KiB
PHP

<?php
// ============================================================
// core/bootstrap.php
// البوابة الرئيسية الموحدة لكل التطبيق
// ============================================================
declare(strict_types=1);
// 1. إعدادات الأخطاء والـ Headers الأساسية
// اجعل القيمة true لتفعيل عرض الأخطاء (التطوير)، أو false لإخفائها (التشغيل الفعلي)
$debugMode = getenv('APP_DEBUG') === 'true';
if ($debugMode) {
error_reporting(E_ALL);
ini_set('display_errors', '1');
} else {
error_reporting(0);
ini_set('display_errors', '0');
}
ini_set('log_errors', '1');
// تحديد مسار اللوج بشكل ديناميكي (محلياً أو سيرفر)
$logPath = getenv('ERROR_LOG_PATH') ?: (__DIR__ . '/../logs/php_errors.log');
ini_set('error_log', $logPath);
header_remove('X-Powered-By');
header('Content-Type: application/json; charset=UTF-8');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
header("Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'");
header("Referrer-Policy: strict-origin-when-cross-origin");
header("Permissions-Policy: geolocation=(), microphone=(), camera=()");
header("X-XSS-Protection: 1; mode=block");
// CORS مع التحقق من المصدر المسموح
$allowedOrigins = array_map('trim', explode(',', getenv('CORS_ALLOWED_ORIGINS') ?: 'https://siromove.com,https://admin.siromove.com'));
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins)) {
header("Access-Control-Allow-Origin: $origin");
header('Access-Control-Allow-Credentials: true');
}
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-FP, X-HMAC-Auth, X-Internal-Key');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
// 2. Autoload
$vendorPath = realpath(__DIR__ . '/../../vendor/autoload.php');
if ($vendorPath) require_once $vendorPath;
// 3. Helpers & Env
require_once __DIR__ . '/helpers.php';
// تحديد مسار الـ .env بشكل ديناميكي
$envFile = getenv('ENV_FILE_PATH') ?: (__DIR__ . '/../.env');
loadEnvironment($envFile);
// 4. Redis Connection (Singleton)
$redis = null;
try {
if (extension_loaded('redis')) {
$redis = new Redis();
$redisHost = getenv('REDIS_HOST') ?: '127.0.0.1';
$redisPort = (int)(getenv('REDIS_PORT') ?: 6379);
$redisPass = getenv('REDIS_PASSWORD');
if ($redis->connect($redisHost, $redisPort, 1.5)) {
if ($redisPass) $redis->auth($redisPass);
$redis->setOption(Redis::OPT_PREFIX, 'siro:');
} else {
$redis = null;
}
}
} catch (Exception $e) {
error_log("[REDIS] Connection failed: " . $e->getMessage());
$redis = null;
}
// 5. تحميل الـ Services الأساسية
require_once __DIR__ . '/Security/EncryptionHelper.php';
require_once __DIR__ . '/Database/Database.php';
require_once __DIR__ . '/Auth/RateLimiter.php';
require_once __DIR__ . '/Auth/JwtService.php';
// لا نحمّل OtpService و FcmService إلا عند الحاجة (Lazy)
// 6. تهيئة Encryption Helper العام (للتوافقية)
// يتم استخدام .enckey (32 بايت) لتشفير البيانات
$encKeyPath = getenv('ENCRYPTION_KEY_PATH');
$encKey = '';
if ($encKeyPath && file_exists($encKeyPath)) {
$encKey = trim(@file_get_contents($encKeyPath) ?: '');
}
if (!$encKey) {
$encKey = getenv('ENC_KEY') ?: '';
}
if (!$encKey || strlen($encKey) !== 32) {
error_log("[FATAL] Encryption key (.enckey) is missing or invalid length (must be 32 bytes).");
http_response_code(500);
exit(json_encode(['error' => 'Server configuration error: Encryption key issue']));
}
$encryptionHelper = new EncryptionHelper($encKey);