function log_activity($action, $meta=''){
global $pdo;
try{
$uid = $_SESSION['admin_id'] ?? null;
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$stmt = $pdo->prepare("INSERT INTO activity_log (user_id, action, meta, ip, user_agent) VALUES (?,?,?,?,?)");
$stmt->execute([$uid, $action, $meta, $ip, $ua]);
} catch(Exception $e){}
}
function has_role($role){
global $pdo;
$uid = $_SESSION['admin_id'] ?? 0;
if(!$uid) return false;
$stmt = $pdo->prepare("SELECT r.name FROM roles r JOIN user_roles ur ON ur.role_id=r.id WHERE ur.user_id=?");
$stmt->execute([$uid]);
$roles = array_map(fn($x)=>$x['name'], $stmt->fetchAll());
return in_array($role, $roles, true);
}
function require_role($roles){
if(!is_array($roles)) $roles = [$roles];
foreach($roles as $r){
if(has_role($r)) return;
}
http_response_code(403);
echo "
403 Forbidden
";
exit;
}
/* --------------------------------------------------------------------------
| CSRF Protection
|-------------------------------------------------------------------------- */
function csrf_token() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function csrf_field() {
echo '';
}
function csrf_verify() {
$sent = $_POST['csrf_token'] ?? '';
$sess = $_SESSION['csrf_token'] ?? '';
if (!$sent || !$sess || !hash_equals($sess, $sent)) {
http_response_code(403);
echo '403 Forbidden (CSRF)';
exit;
}
}
/* --------------------------------------------------------------------------
| Simple Page Cache (optional)
|-------------------------------------------------------------------------- */
function cache_page($key, $ttl_seconds = 60) {
$dir = __DIR__ . '/../storage/cache_pages';
if (!is_dir($dir)) @mkdir($dir, 0755, true);
$file = $dir . '/' . preg_replace('~[^a-zA-Z0-9_\-]~','_', $key) . '.html';
if (file_exists($file) && (time() - filemtime($file)) < $ttl_seconds) {
readfile($file);
exit;
}
ob_start();
register_shutdown_function(function() use ($file) {
$out = ob_get_contents();
if ($out !== false) @file_put_contents($file, $out);
ob_end_flush();
});
}
/* --------------------------------------------------------------------------
| Brute-force protection helpers
|-------------------------------------------------------------------------- */
function login_attempts_bootstrap() {
global $pdo;
try {
$pdo->exec("CREATE TABLE IF NOT EXISTS login_attempts (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(190) NULL,
ip VARCHAR(64) NULL,
success TINYINT(1) NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY idx_user_ip_time (username, ip, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
} catch (Throwable $e) {}
}
function login_is_blocked($username, $ip) {
global $pdo;
login_attempts_bootstrap();
$max = defined('LOGIN_MAX_ATTEMPTS') ? (int)LOGIN_MAX_ATTEMPTS : 5;
$mins = defined('LOGIN_BLOCK_MINUTES') ? (int)LOGIN_BLOCK_MINUTES : 15;
try {
$stmt = $pdo->prepare("SELECT COUNT(*) FROM login_attempts
WHERE success=0 AND created_at >= (NOW() - INTERVAL ? MINUTE)
AND (ip=? OR (username IS NOT NULL AND username=?))");
$stmt->execute([$mins, $ip, $username]);
return ((int)$stmt->fetchColumn()) >= $max;
} catch (Throwable $e) {
return false;
}
}
function login_record_attempt($username, $ip, $success) {
global $pdo;
login_attempts_bootstrap();
try {
$stmt = $pdo->prepare("INSERT INTO login_attempts (username, ip, success) VALUES (?,?,?)");
$stmt->execute([$username ?: null, $ip ?: null, $success ? 1 : 0]);
} catch (Throwable $e) {}
}
function require_any_role($roles) {
if (!is_array($roles)) $roles = [$roles];
foreach ($roles as $r) if (has_role($r)) return;
http_response_code(403);
echo "403 Forbidden";
exit;
}
/* --------------------------------------------------------------------------
| Settings (DB key/value)
|-------------------------------------------------------------------------- */
function settings_bootstrap() {
global $pdo;
try {
$pdo->exec("CREATE TABLE IF NOT EXISTS settings (
`key` VARCHAR(190) PRIMARY KEY,
`value` TEXT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
} catch (Throwable $e) {}
}
function setting($key, $default = '') {
global $pdo;
settings_bootstrap();
try {
$stmt = $pdo->prepare("SELECT value FROM settings WHERE `key`=? LIMIT 1");
$stmt->execute([$key]);
$v = $stmt->fetchColumn();
if ($v === false || $v === null || $v === '') return $default;
return $v;
} catch (Throwable $e) {
return $default;
}
}
function set_setting($key, $value) {
global $pdo;
settings_bootstrap();
try {
$stmt = $pdo->prepare("INSERT INTO settings (`key`,`value`) VALUES (?,?)
ON DUPLICATE KEY UPDATE `value`=VALUES(`value`)");
$stmt->execute([$key, $value]);
return true;
} catch (Throwable $e) {
return false;
}
}
روابي
روابي
حلول أمان متكاملة بمعايير احترافية
الأنظمة
مكافحة الحريق
Sprinkler / Hydrant / Pumps / FM200 وغيرها، مع الاختبارات والتسليم.
إنذار الحريق
Addressable & Conventional مع البرمجة والتكامل والاختبارات.
معدات الوقاية
توريد معدات الوقاية الشخصية وأدوات السلامة واللوحات الإرشادية.
التصميم والاعتماد
إعداد المخططات التنفيذية والملفات الفنية ومتابعة إجراءات الاعتماد.
عقود الصيانة
صيانة دورية لأنظمة السلامة مع تقارير وتوصيات.
حلول متكاملة
حلول شاملة وفق نظام جودة داخلي.