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;
}
}
روابي
روابي
حلول أمان متكاملة بمعايير احترافية
من نحن
مؤسسة روابي السلامة الأمنية تأسست عام 1439هـ (2017م) وتقدم حلول سلامة متكاملة للمنشآت داخل المملكة، من التوريد إلى التصميم والتنفيذ والاعتماد والصيانة.
فريق هندسي متخصص
حلول متكاملة
جودة داخلية
رؤيتنا أن نكون الخيار الأول لحلول السلامة والحماية من الحريق للمشاريع داخل المملكة.
رسالتنا تقديم خدمات هندسية احترافية بمعايير عالية تضمن سلامة الأرواح والممتلكات وتحقيق رضا العملاء.
قيمنا الالتزام، الجودة، الأمان، الموثوقية، التحسين المستمر.
نطاق أعمالنا توريد | تصميم | تنفيذ | اعتماد مخططات | صيانة
بيانات التواصل
الهاتف: 0598880777
البريد: info@rawabiksa.com
WhatsApp: 966598880777
الموقع: www.RawabiKSA.com
حمايتكم أولوياتنا
© 2026 Rawabi
سجل تجاري: 2051065405 | الرقم الضريبي: 300393184100003