ソースを参照

- html: PDO patches

Dmitriev Roman 4 ヶ月 前
コミット
a4bf1d774b
4 ファイル変更557 行追加497 行削除
  1. 0 1
      html/admin/users/edituser.php
  2. 95 153
      html/inc/auth.utils.php
  3. 25 5
      html/inc/common.php
  4. 437 338
      html/inc/sql.php

+ 0 - 1
html/admin/users/edituser.php

@@ -3,7 +3,6 @@ require_once($_SERVER["DOCUMENT_ROOT"] . "/inc/auth.php");
 require_once($_SERVER["DOCUMENT_ROOT"] . "/inc/languages/" . HTML_LANG . ".php");
 require_once($_SERVER["DOCUMENT_ROOT"] . "/inc/idfilter.php");
 
-
 $default_sort = 'ip_int';
 require_once($_SERVER['DOCUMENT_ROOT'] . "/inc/sortfilter.php");
 

+ 95 - 153
html/inc/auth.utils.php

@@ -46,7 +46,6 @@ function log_session_debug($db, $message, $data = null) {
 // Инициализация сессий в БД
 function init_db_sessions($db) {
     log_session_debug($db, "Initializing database sessions");
-    // Настройка обработчиков сессий
     session_set_save_handler(
         'sess_open',
         'sess_close',
@@ -59,56 +58,50 @@ function init_db_sessions($db) {
 }
 
 // Обработчики сессий
-function sess_open($savePath, $sessionName) { 
+function sess_open($savePath, $sessionName) {
     global $db_link;
     log_session_debug($db_link, "Session opened", ['savePath' => $savePath, 'sessionName' => $sessionName]);
-    return true; 
+    return true;
 }
 
-function sess_close() { 
+function sess_close() {
     global $db_link;
     log_session_debug($db_link, "Session closed");
-    return true; 
+    return true;
 }
 
 function sess_read($sessionId) {
     global $db_link;
     log_session_debug($db_link, "Reading session", ['sessionId' => $sessionId]);
-    
-    $sessionId = db_escape($db_link, $sessionId);
-    $result = mysqli_query($db_link, "SELECT data FROM ".SESSION_TABLE." WHERE id = '$sessionId'");
-    
-    if (!$result) {
-        $error = mysqli_error($db_link);
-        LOG_DEBUG($db_link, "Session read failed: " . $error);
-        log_session_debug($db_link, "Session read query failed", $error);
-        return '';
-    }
-    
-    $data = mysqli_num_rows($result) ? mysqli_fetch_assoc($result)['data'] : '';
+
+    $stmt = $db_link->prepare("SELECT data FROM " . SESSION_TABLE . " WHERE id = ?");
+    $stmt->execute([$sessionId]);
+    $row = $stmt->fetch(PDO::FETCH_ASSOC);
+
+    $data = $row ? $row['data'] : '';
     log_session_debug($db_link, "Session data retrieved", ['length' => strlen($data), 'exists' => !empty($data)]);
-    
+
     return $data;
 }
 
 function sess_write($sessionId, $data) {
     global $db_link;
     log_session_debug($db_link, "Writing session", ['sessionId' => $sessionId, 'data_length' => strlen($data)]);
-    
-    $sessionId = db_escape($db_link, $sessionId);
-    $data = db_escape($db_link, $data);
+
     $time = time();
-    $query = "INSERT INTO ".SESSION_TABLE." (id, data, last_accessed) 
-              VALUES ('$sessionId', '$data', $time)
-              ON DUPLICATE KEY UPDATE data = '$data', last_accessed = $time";
+    $stmt = $db_link->prepare("INSERT INTO " . SESSION_TABLE . " (id, data, last_accessed)
+        VALUES (?, ?, ?)
+        ON DUPLICATE KEY UPDATE data = ?, last_accessed = ?");
+
+    $success = $stmt->execute([$sessionId, $data, $time, $data, $time]);
 
-    if (!mysqli_query($db_link, $query)) {
-        $error = mysqli_error($db_link);
-        LOG_DEBUG($db_link, "Session write failed: " . $error);
+    if (!$success) {
+        $error = $stmt->errorInfo();
+        LOG_DEBUG($db_link, "Session write failed: " . print_r($error, true));
         log_session_debug($db_link, "Session write query failed", $error);
         return false;
     }
-    
+
     log_session_debug($db_link, "Session write successful");
     return true;
 }
@@ -116,15 +109,17 @@ function sess_write($sessionId, $data) {
 function sess_destroy($sessionId) {
     global $db_link;
     log_session_debug($db_link, "Destroying session", ['sessionId' => $sessionId]);
-    
-    $sessionId = db_escape($db_link, $sessionId);
-    if (!mysqli_query($db_link, "DELETE FROM ".SESSION_TABLE." WHERE id = '$sessionId'")) {
-        $error = mysqli_error($db_link);
-        LOG_DEBUG($db_link, "Session destroy failed: " . $error);
+
+    $stmt = $db_link->prepare("DELETE FROM " . SESSION_TABLE . " WHERE id = ?");
+    $success = $stmt->execute([$sessionId]);
+
+    if (!$success) {
+        $error = $stmt->errorInfo();
+        LOG_DEBUG($db_link, "Session destroy failed: " . print_r($error, true));
         log_session_debug($db_link, "Session destroy query failed", $error);
         return false;
     }
-    
+
     log_session_debug($db_link, "Session destroy successful");
     return true;
 }
@@ -132,20 +127,22 @@ function sess_destroy($sessionId) {
 function sess_gc($maxLifetime) {
     global $db_link;
     log_session_debug($db_link, "Running session GC", ['maxLifetime' => $maxLifetime]);
-    
+
     $old = time() - $maxLifetime;
-    if (!mysqli_query($db_link, "DELETE FROM ".SESSION_TABLE." WHERE last_accessed < $old")) {
-        $error = mysqli_error($db_link);
-        LOG_DEBUG($db_link, "Session GC failed: " . $error);
+    $stmt = $db_link->prepare("DELETE FROM " . SESSION_TABLE . " WHERE last_accessed < ?");
+    $success = $stmt->execute([$old]);
+
+    if (!$success) {
+        $error = $stmt->errorInfo();
+        LOG_DEBUG($db_link, "Session GC failed: " . print_r($error, true));
         log_session_debug($db_link, "Session GC query failed", $error);
         return false;
     }
-    
+
     log_session_debug($db_link, "Session GC completed");
     return true;
 }
 
-
 function login($db) {
     log_session_debug($db, "Login function started", [
         'session_status' => session_status(),
@@ -158,22 +155,17 @@ function login($db) {
     $redirect_url = getSafeRedirectUrl(DEFAULT_PAGE);
 
     if ($redirect_url == DEFAULT_PAGE) {
-        // 1. Сначала получаем путь из оригинального URL
         $current_path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
         $current_path = $current_path ? rtrim($current_path, '/') : '/';
-        // 2. Подготавливаем пути для сравнения
         $login_path = rtrim(LOGIN_PAGE, '/');
         $logout_path = rtrim(LOGOUT_PAGE, '/');
-        // 3. Сравниваем пути
         if ($current_path !== $login_path && $current_path !== $logout_path) {
-            // 4. Кодируем 
             $redirect_url = safeUrlEncode($_SERVER['REQUEST_URI']);
-            }
         }
+    }
 
     log_session_debug($db, "Redirect URL determined", ['redirect_url' => $redirect_url]);
 
-    // 1. Проверка активной сессии
     if (!empty($_SESSION['user_id'])) {
         log_session_debug($db, "Found user_id in session, validating", ['user_id' => $_SESSION['user_id']]);
         if (validate_session($db)) {
@@ -186,45 +178,40 @@ function login($db) {
         log_session_debug($db, "No user_id found in session");
     }
 
-    // 2. Проверка API-авторизации (для API-запросов)
     if (strpos($_SERVER['REQUEST_URI'], '/api.php') === 0) {
         log_session_debug($db, "API request detected, attempting silent auth");
         return IsSilentAuthenticated($db);
     }
 
-    // 4. Проверка логина/пароля из POST-данных (обычная форма входа)
     if (!empty($_POST['login']) && !empty($_POST['password'])) {
         log_session_debug($db, "POST login attempt", ['login' => $_POST['login']]);
         if (authenticate_by_credentials($db, $_POST['login'], $_POST['password'])) {
             LOG_INFO($db, "Logged in customer id: ".$_SESSION['user_id']." name: ".$_SESSION['login']." from ".$_SESSION['ip']." with acl: ".$_SESSION['acl']." url: ".$redirect_url);
             log_session_debug($db, "Login successful via credentials");
-            
-            // Немедленно сохраняем сессию
+
             session_write_close();
-            // И перезапускаем для отправки куки браузеру
             session_start();
-            
+
             return true;
         }
-        // Неудачная попытка входа
         log_session_debug($db, "Login failed via credentials");
-        sleep(1); // Защита от брутфорса
+        sleep(1);
     } else {
         log_session_debug($db, "No POST credentials provided");
     }
 
-    // 5. Если ни один метод не сработал - требовать авторизацию
     log_session_debug($db, "All auth methods failed, calling logout");
-    logout($db,FALSE,$redirect_url);
+    logout($db, FALSE, $redirect_url);
     exit;
 }
 
-function authenticate_by_credentials($db,$login,$password) {
+function authenticate_by_credentials($db, $login, $password) {
     log_session_debug($db, "Authenticating by credentials", ['login' => $login]);
 
-    $login = db_escape($db, trim($login));
-    $query = "SELECT * FROM `Customers` WHERE Login='{$login}'";
-    $user = get_record_sql($db, $query);
+    $login = trim($login);
+    $stmt = $db->prepare("SELECT * FROM `Customers` WHERE Login = ?");
+    $stmt->execute([$login]);
+    $user = $stmt->fetch(PDO::FETCH_ASSOC);
 
     if (empty($user)) {
         log_session_debug($db, "User not found in database");
@@ -242,7 +229,6 @@ function authenticate_by_credentials($db,$login,$password) {
 
     log_session_debug($db, "Password verified, creating session");
 
-    // Создание сессии
     $regenerate_result = session_regenerate_id(true);
     log_session_debug($db, "Session regenerate result", ['success' => $regenerate_result, 'new_sid' => session_id()]);
 
@@ -257,30 +243,20 @@ function authenticate_by_credentials($db,$login,$password) {
 
     log_session_debug($db, "Session data populated", $_SESSION);
 
-    // Запись сессии в БД
-    $sessionId = db_escape($db, session_id());
-    $ip = db_escape($db, $_SESSION['ip']);
-    $userAgent = db_escape($db, $_SESSION['user_agent']);
+    $sessionId = session_id();
+    $ip = $_SESSION['ip'];
+    $userAgent = $_SESSION['user_agent'];
     $time = time();
 
-    // Запись в БД
-    $sessionId = db_escape($db, session_id());
-    $query = "INSERT INTO ".USER_SESSIONS_TABLE." 
-        (session_id, user_id, ip_address, user_agent, created_at, last_activity) 
-        VALUES (
-            '$sessionId',
-            {$user['id']},
-            '$ip',
-            '$userAgent',
-            $time,
-            $time
-        )";
-        
-    log_session_debug($db, "Executing user session insert query", ['query' => $query]);
-    
-    if (!mysqli_query($db, $query)) {
-        $error = mysqli_error($db);
-        LOG_DEBUG($db, "Session DB error: ".$error);
+    $stmt = $db->prepare("INSERT INTO " . USER_SESSIONS_TABLE . "
+        (session_id, user_id, ip_address, user_agent, created_at, last_activity)
+        VALUES (?, ?, ?, ?, ?, ?)");
+
+    $success = $stmt->execute([$sessionId, $user['id'], $ip, $userAgent, $time, $time]);
+
+    if (!$success) {
+        $error = $stmt->errorInfo();
+        LOG_DEBUG($db, "Session DB error: " . print_r($error, true));
         log_session_debug($db, "User session insert failed", $error);
         return false;
     }
@@ -296,8 +272,7 @@ function validate_session($db) {
         'current_ua' => ($_SERVER['HTTP_USER_AGENT'] ?? '')
     ]);
 
-    // Проверка IP и User-Agent
-    if ($_SESSION['ip'] !== get_client_ip() || 
+    if ($_SESSION['ip'] !== get_client_ip() ||
         $_SESSION['user_agent'] !== ($_SERVER['HTTP_USER_AGENT'] ?? '')) {
         log_session_debug($db, "Session validation failed - IP or User-Agent mismatch", [
             'session_ip' => $_SESSION['ip'],
@@ -309,35 +284,21 @@ function validate_session($db) {
         return false;
     }
 
-    // Проверка активности сессии в БД
-    $sessionId = db_escape($db, session_id());
-    $result = mysqli_query($db, 
-        "SELECT 1 
-         FROM ".USER_SESSIONS_TABLE." 
-         WHERE 
-            session_id = '$sessionId' AND
-            user_id = {$_SESSION['user_id']} AND
-            is_active = 1
-         LIMIT 1");
-
-    if (!$result) {
-        $error = mysqli_error($db);
-        log_session_debug($db, "Session validation query failed", $error);
-        logout($db);
-        return false;
-    }
+    $sessionId = session_id();
+    $stmt = $db->prepare("SELECT 1
+        FROM " . USER_SESSIONS_TABLE . "
+        WHERE session_id = ? AND user_id = ? AND is_active = 1
+        LIMIT 1");
 
-    if (mysqli_num_rows($result) === 0) {
+    $stmt->execute([$sessionId, $_SESSION['user_id']]);
+    if ($stmt->rowCount() === 0) {
         log_session_debug($db, "Session validation failed - no active session in database");
         logout($db);
         return false;
     }
 
-    // Обновление времени активности
-    mysqli_query($db, 
-        "UPDATE ".USER_SESSIONS_TABLE." 
-         SET last_activity = ".time()." 
-         WHERE session_id = '$sessionId'");
+    $stmt = $db->prepare("UPDATE " . USER_SESSIONS_TABLE . " SET last_activity = ? WHERE session_id = ?");
+    $stmt->execute([time(), $sessionId]);
 
     log_session_debug($db, "Session validation successful");
     return true;
@@ -357,7 +318,6 @@ function get_client_ip() {
     return $ip;
 }
 
-// Авторизация по API-ключу (без пароля)
 function IsSilentAuthenticated($db) {
     log_session_debug($db, "Silent authentication attempt");
 
@@ -366,11 +326,10 @@ function IsSilentAuthenticated($db) {
         return true;
     }
 
-    $auth_ip = get_user_ip();
+    $auth_ip = get_client_ip();
     $api_key = '';
     $login = '';
 
-    // Получаем ключ из GET или POST
     if (!empty($_GET['api_key'])) {
         $api_key = trim($_GET['api_key']);
     } elseif (!empty($_POST['api_key'])) {
@@ -390,32 +349,24 @@ function IsSilentAuthenticated($db) {
         return false;
     }
 
-    // Экранирование и подготовка
-    $login = db_escape($db, $login);
-    $api_key = db_escape($db, $api_key);
+    $stmt = $db->prepare("SELECT id, rights FROM Customers WHERE Login = ? AND api_key = ? LIMIT 1");
+    $stmt->execute([$login, $api_key]);
 
-    // Ищем пользователя с таким логином и API-ключом
-    $query = "SELECT id, rights FROM Customers 
-              WHERE Login = '$login' AND api_key = '$api_key' 
-              LIMIT 1";
-    $result = mysqli_query($db, $query);
-
-    if (!$result || mysqli_num_rows($result) === 0) {
+    if ($stmt->rowCount() === 0) {
         LOG_DEBUG($db, "API auth failed for: $login");
         log_session_debug($db, "Silent auth failed - user not found or invalid API key");
         return false;
     }
 
-    $user = mysqli_fetch_assoc($result);
+    $user = $stmt->fetch(PDO::FETCH_ASSOC);
 
-    // Создаем сессию
     $_SESSION = [
         'user_id'    => $user['id'],
         'login'      => $login,
         'acl'        => $user['rights'],
         'ip'         => $auth_ip,
         'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
-        'api_auth'   => true // Метка API-аутентификации
+        'api_auth'   => true
     ];
 
     log_session_debug($db, "Silent auth successful", ['user_id' => $user['id'], 'login' => $login]);
@@ -423,7 +374,6 @@ function IsSilentAuthenticated($db) {
     return true;
 }
 
-// Выход из системы (полная версия)
 function logout($db, $silent = FALSE, $redirect_url = DEFAULT_PAGE) {
     log_session_debug($db, "Logout function called", [
         'silent' => $silent,
@@ -433,30 +383,24 @@ function logout($db, $silent = FALSE, $redirect_url = DEFAULT_PAGE) {
     ]);
 
     if (session_status() === PHP_SESSION_ACTIVE) {
-        $user_info = isset($_SESSION['user_id']) ? 
-            "customer id: ".$_SESSION['user_id']." name: ".$_SESSION['login']." from ".$_SESSION['ip']." with acl: ".$_SESSION['acl'] : 
+        $user_info = isset($_SESSION['user_id']) ?
+            "customer id: ".$_SESSION['user_id']." name: ".$_SESSION['login']." from ".$_SESSION['ip']." with acl: ".$_SESSION['acl'] :
             "no user session data";
-            
+
         LOG_INFO($db, "Logout " . $user_info);
-        
-        // Деактивация сессии в БД
+
         $sessionId = session_id();
         if ($sessionId) {
-            $sessionId = db_escape($db, $sessionId);
-            $result = mysqli_query($db, 
-                "UPDATE ".USER_SESSIONS_TABLE." 
-                 SET is_active = 0 
-                 WHERE session_id = '$sessionId'");
+            $stmt = $db->prepare("UPDATE " . USER_SESSIONS_TABLE . " SET is_active = 0 WHERE session_id = ?");
+            $result = $stmt->execute([$sessionId]);
             log_session_debug($db, "Session deactivation query executed", ['success' => (bool)$result]);
         }
-        
-        // Очистка данных
+
         $_SESSION = [];
         session_destroy();
-        
+
         if (!headers_sent()) {
             setcookie(session_name(), '', time() - SESSION_LIFETIME, '/');
-            // Удаление авторизационной куки (если есть)
             if (isset($_COOKIE['Auth'])) {
                 setcookie('Auth', '', time() - SESSION_LIFETIME, '/');
             }
@@ -465,15 +409,15 @@ function logout($db, $silent = FALSE, $redirect_url = DEFAULT_PAGE) {
     } else {
         log_session_debug($db, "Logout - no active session to destroy");
     }
-    
-    if (!$silent and !headers_sent()) {
+
+    if (!$silent && !headers_sent()) {
         log_session_debug($db, "Performing redirect after logout");
-        if ($redirect_url == DEFAULT_PAGE or empty($redirect_url) or $redirect_url=='/') {
-            header('Location: '.LOGIN_PAGE);
-            } else {
-            header('Location: '.LOGIN_PAGE.'?redirect_url='.$redirect_url);
-            }
+        if ($redirect_url == DEFAULT_PAGE || empty($redirect_url) || $redirect_url == '/') {
+            header('Location: ' . LOGIN_PAGE);
+        } else {
+            header('Location: ' . LOGIN_PAGE . '?redirect_url=' . urlencode($redirect_url));
         }
+    }
 }
 
 // Инициализация системы сессий
@@ -484,18 +428,16 @@ init_db_sessions($db_link);
 log_session_debug($db_link, "Before session_start check");
 if (session_status() !== PHP_SESSION_ACTIVE) {
     log_session_debug($db_link, "Starting session");
-    
-    // Исправляем домен - убираем порт
+
     $domain_parts = explode(':', $_SERVER['HTTP_HOST']);
     $clean_domain = $domain_parts[0];
-    
-    // Старт сессии с безопасными настройками
+
     session_start([
         'cookie_lifetime' => SESSION_LIFETIME,
         'cookie_path' => '/',
-        'cookie_domain' => $clean_domain, // Без порта!
+        'cookie_domain' => $clean_domain,
         'cookie_secure' => isset($_SERVER['HTTPS']),
-        'cookie_httponly' => true, // Включаем httponly для безопасности
+        'cookie_httponly' => true,
         'cookie_samesite' => 'Lax',
         'gc_maxlifetime' => SESSION_LIFETIME,
     ]);
@@ -511,4 +453,4 @@ if (session_status() !== PHP_SESSION_ACTIVE) {
     ]);
 }
 
-log_session_debug($db_link, "=== SESSION DEBUG END ===");
+log_session_debug($db_link, "=== SESSION DEBUG END ===");

+ 25 - 5
html/inc/common.php

@@ -2730,17 +2730,35 @@ function write_log($db, $msg, $level = L_INFO, $auth_id = 0)
     // Безопасное получение данных сессии
     $currentIp = filter_var($_SESSION['ip'] ?? '127.0.0.1', FILTER_VALIDATE_IP) ?: '127.0.0.1';
     $currentLogin = htmlspecialchars($_SESSION['login'] ?? 'http', ENT_QUOTES, 'UTF-8');
+    
     if (!isset($msg)) { return; }
+    
     // Для уровня L_DEBUG пишем в error_log
     if ($level === L_DEBUG) {
         error_log("DEBUG: " . $msg);
         return;
     }
-    // пишем в БД
-    $stmt = mysqli_prepare($db, "INSERT INTO worklog(customer, message, level, auth_id, ip) VALUES (?, ?, ?, ?, ?)");
-    mysqli_stmt_bind_param($stmt, 'ssiis', $currentLogin, $msg, $level, $auth_id, $currentIp);
-    mysqli_stmt_execute($stmt);
-    mysqli_stmt_close($stmt);
+    
+    try {
+        // Используем подготовленный запрос PDO напрямую
+        $stmt = $db->prepare("INSERT INTO worklog(customer, message, level, auth_id, ip) 
+                               VALUES (:customer, :message, :level, :auth_id, :ip)");
+        
+        $result = $stmt->execute([
+            ':customer' => $currentLogin,
+            ':message' => $msg,
+            ':level' => $level,
+            ':auth_id' => $auth_id,
+            ':ip' => $currentIp
+        ]);
+        
+        return $result;
+        
+    } catch (PDOException $e) {
+        // В случае ошибки логируем в error_log, чтобы избежать рекурсии
+        error_log("Error writing log to database: " . $e->getMessage());
+        return false;
+    }
 }
 
 function print_year_select($year_name, $year)
@@ -3773,3 +3791,5 @@ $config["init"] = 1;
 
 clean_dns_cache($db_link);
 //clean_unreferensed_rules($db_link);
+
+$config["debug"] = 1;

+ 437 - 338
html/inc/sql.php

@@ -3,46 +3,107 @@ if (! defined("CONFIG")) die("Not defined");
 
 if (! defined("SQL")) { die("Not defined"); }
 
-function db_escape($connection, $string) {
-    // Определяем тип подключения
+function db_escape($connection, $value) {
+    // Обработка специальных значений
+    if ($value === null) {
+        return '';
+    }
+    
+    if (is_bool($value)) {
+        return $value ? 1 : 0;
+    }
+    
+    if (is_int($value) || is_float($value)) {
+        return $value;
+    }
+    
+    // Для строковых значений
+    $string = (string)$value;
+    
     if ($connection instanceof PDO) {
-        return $connection->quote($string);
+        // PDO::quote() может вернуть false при ошибке
+        try {
+            $quoted = $connection->quote($string);
+            if ($quoted === false) {
+                // Если quote() не сработал, используем addslashes
+                return addslashes($string);
+            }
+            // Убираем внешние кавычки
+            if (strlen($quoted) >= 2 && $quoted[0] === "'" && $quoted[strlen($quoted)-1] === "'") {
+                return substr($quoted, 1, -1);
+            }
+            return $quoted;
+        } catch (Exception $e) {
+            // В случае ошибки возвращаем addslashes
+            return addslashes($string);
+        }
     } elseif ($connection instanceof mysqli) {
         return mysqli_real_escape_string($connection, $string);
     } elseif (is_resource($connection) && get_resource_type($connection) === 'mysql link') {
-        // Для устаревшего mysql_*
         return mysql_real_escape_string($string, $connection);
     } elseif ($connection instanceof PostgreSQL) {
-        // Для PostgreSQL
         return pg_escape_string($connection, $string);
     } else {
-        // Фолбэк
         return addslashes($string);
     }
 }
 
 function new_connection ($db_host, $db_user, $db_password, $db_name)
 {
-mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
-
-$result = mysqli_connect($db_host,$db_user,$db_password,$db_name);
-
-if (! $result) {
-    echo "Error connect to MYSQL " . PHP_EOL;
-    echo "Errno: " . mysqli_connect_errno() . PHP_EOL;
-    echo "Error message: " . mysqli_connect_error() . PHP_EOL;
-    exit();
-    }
-
-/* enable utf8 */
-if (!mysqli_set_charset($result,'utf8mb4')) {
-    printf("Error loading utf8: %s\n", mysqli_error($result));
-    exit();
+    // Создаем временный логгер для отладки до установки соединения
+    $temp_debug_message = function($message) {
+        error_log("DB_CONNECTION_DEBUG: " . $message);
+    };
+    
+    $temp_debug_message("Starting new_connection function");
+    $temp_debug_message("DB parameters - host: $db_host, user: $db_user, db: $db_name");
+    
+    try {
+        $temp_debug_message("Constructing DSN");
+        $dsn = "mysql:host=$db_host;dbname=$db_name;charset=utf8mb4";
+        $temp_debug_message("DSN: $dsn");
+        
+        $options = [
+            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+            PDO::ATTR_EMULATE_PREPARES => false,
+            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
+        ];
+        
+        $temp_debug_message("Attempting to create PDO connection");
+        $temp_debug_message("PDO options: " . json_encode($options));
+        
+        $result = new PDO($dsn, $db_user, $db_password, $options);
+        
+        // Теперь у нас есть соединение, можем использовать LOG_DEBUG
+        $temp_debug_message("PDO connection created successfully");
+        $temp_debug_message("PDO connection info: " . $result->getAttribute(PDO::ATTR_CONNECTION_STATUS));
+        $temp_debug_message("PDO client version: " . $result->getAttribute(PDO::ATTR_CLIENT_VERSION));
+        $temp_debug_message("PDO server version: " . $result->getAttribute(PDO::ATTR_SERVER_VERSION));
+        
+        // Проверка кодировки
+        $stmt = $result->query("SHOW VARIABLES LIKE 'character_set_connection'");
+        $charset = $stmt->fetch(PDO::FETCH_ASSOC);
+        $temp_debug_message("Database character set: " . ($charset['Value'] ?? 'not set'));
+        
+        return $result;
+        
+    } catch (PDOException $e) {
+        // Логируем ошибку через error_log, так как соединение не установлено
+        error_log("DB_CONNECTION_ERROR: Failed to connect to MySQL");
+        error_log("DB_CONNECTION_ERROR: DSN: mysql:host=$db_host;dbname=$db_name;charset=utf8mb4");
+        error_log("DB_CONNECTION_ERROR: User: $db_user");
+        error_log("DB_CONNECTION_ERROR: Error code: " . $e->getCode());
+        error_log("DB_CONNECTION_ERROR: Error message: " . $e->getMessage());
+        error_log("DB_CONNECTION_ERROR: Trace: " . $e->getTraceAsString());
+        
+        // Также выводим в консоль для немедленной обратной связи
+        echo "Error connect to MySQL " . PHP_EOL;
+        echo "Error message: " . $e->getMessage() . PHP_EOL;
+        echo "DSN: mysql:host=$db_host;dbname=$db_name;charset=utf8mb4" . PHP_EOL;
+        
+        exit();
     }
-
-//mysqli_options($result, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
-
-return $result;
 }
 
 /**
@@ -163,6 +224,81 @@ function is_assoc($array) {
     return array_keys($array) !== range(0, count($array) - 1);
 }
 
+/**
+ * Нормализует значение поля: преобразует NULL в 0 для числовых полей или в пустую строку для строковых
+ * 
+ * @param string $key Имя поля
+ * @param mixed $value Значение поля
+ * @return mixed Нормализованное значение
+ */
+function normalize_field_value($key, $value) {
+    if ($value === null or $value === 'NULL') {
+        // Регулярное выражение для определения числовых полей
+        $numeric_field_pattern = '/\b(?:
+            # ID поля
+            id|_id|
+            # Числовые счетчики
+            count|_count|num|port|size|level|status|type|bytes|byte|
+            # Временные метки
+            _time|_timestamp|_at|time|timestamp|
+            # Сетевые/трафик
+            _in|_out|_int|forward|gateway|ip_int|quota|step|
+            # Сетевые ID
+            vlan|index|snmp|protocol|router|subnet|target|vendor|
+            # Флаги/boolean (tinyint)
+            action|active|blocked|changed|connected|default|deleted|dhcp|
+            discovery|draft|dynamic|enabled|free|hotspot|link|nagios|netflow|
+            notify|office|permanent|poe|queue|rights|save|skip|static|uniq|uplink|vpn
+        )\b/ix';
+        
+        if (preg_match($numeric_field_pattern, $key)) {
+            return 0;
+        } else {
+            return '';
+        }
+    }
+    
+    return $value;
+}
+
+/**
+ * Нормализует всю запись (ассоциативный массив)
+ * 
+ * @param array $record Запись из БД
+ * @return array Нормализованная запись
+ */
+function normalize_record($record) {
+    if (!is_array($record) || empty($record)) {
+        return $record;
+    }
+    
+    $normalized = [];
+    foreach ($record as $key => $value) {
+        $normalized[$key] = normalize_field_value($key, $value);
+    }
+    
+    return $normalized;
+}
+
+/**
+ * Нормализует массив записей
+ * 
+ * @param array $records Массив записей из БД
+ * @return array Нормализованные записи
+ */
+function normalize_records($records) {
+    if (!is_array($records) || empty($records)) {
+        return $records;
+    }
+    
+    $normalized = [];
+    foreach ($records as $index => $record) {
+        $normalized[$index] = normalize_record($record);
+    }
+    
+    return $normalized;
+}
+
 function run_sql($db, $query)
 {
     // Проверка прав доступа для UPDATE, DELETE, INSERT
@@ -185,28 +321,29 @@ function run_sql($db, $query)
             return false;
         }
     }
+    
     // Выполняем запрос
-    $sql_result = mysqli_query($db, $query);
-    if (!$sql_result) {
-        LOG_ERROR($db, "At simple SQL: $query :" . mysqli_error($db));
+    try {
+        $stmt = $db->query($query);
+        
+        // Возвращаем результат в зависимости от типа запроса
+        if (preg_match('/^\s*SELECT/i', $query)) {
+            // Для SELECT возвращаем PDOStatement
+            return $stmt;
+        } elseif (preg_match('/^\s*INSERT/i', $query)) {
+            // Для INSERT возвращаем ID вставленной записи
+            return $db->lastInsertId();
+        } elseif (preg_match('/^\s*(UPDATE|DELETE)/i', $query)) {
+            // Для UPDATE/DELETE возвращаем количество затронутых строк
+            return $stmt->rowCount();
+        }
+        // Для других типов запросов возвращаем результат как есть
+        return $stmt;
+        
+    } catch (PDOException $e) {
+        LOG_ERROR($db, "At simple SQL: $query :" . $e->getMessage());
         return false;
     }
-    // Возвращаем результат в зависимости от типа запроса
-    if (preg_match('/^\s*SELECT/i', $query)) {
-        // Для SELECT возвращаем результат запроса
-        return $sql_result;
-    } elseif (preg_match('/^\s*INSERT/i', $query)) {
-        // Для INSERT возвращаем ID вставленной записи
-        return mysqli_insert_id($db);
-    } elseif (preg_match('/^\s*UPDATE/i', $query)) {
-        // Для UPDATE возвращаем 1 (успех)
-        return 1;
-    } elseif (preg_match('/^\s*DELETE/i', $query)) {
-        // Для DELETE также возвращаем 1 (успех)
-        return 1;
-    }
-    // Для других типов запросов возвращаем результат как есть
-    return $sql_result;
 }
 
 function get_count_records($db, $table, $filter)
@@ -219,27 +356,115 @@ function get_count_records($db, $table, $filter)
     return 0;
 }
 
-function get_single_field($db, $sql)
-{
-    $t_count = get_record_sql($db, $sql);
-    if (!empty($t_count) && is_array($t_count)) {
-        // Получаем все значения и берем первое
-        $values = array_values($t_count);
-        return !empty($values) ? $values[0] : 0;
+/**
+ * Получить одну запись из таблицы по фильтру
+ */
+function get_record($db, $table, $filter) {
+    if (!isset($table) || !isset($filter)) {
+        return null;
     }
-    return 0;
+    
+    if (preg_match('/=$/', $filter)) {
+        LOG_ERROR($db, "Search record ($table) with illegal filter $filter! Skip command.");
+        return null;
+    }
+    
+    $sql = "SELECT * FROM $table WHERE $filter";
+    return get_record_sql($db, $sql);
 }
 
-function get_id_record($db, $table, $filter)
-{
-    if (isset($filter)) {
-        $filter = 'WHERE ' . $filter;
+/**
+ * Получить несколько записей из таблицы по фильтру
+ */
+function get_records($db, $table, $filter = '') {
+    if (!isset($table)) {
+        return [];
+    }
+    
+    if (!empty($filter)) {
+        if (preg_match('/=$/', $filter)) {
+            LOG_ERROR($db, "Search record ($table) with illegal filter $filter! Skip command.");
+            return [];
+        }
+        $filter = "WHERE $filter";
+    }
+    
+    $sql = "SELECT * FROM $table $filter";
+    return get_records_sql($db, $sql);
+}
+
+/**
+ * Получить одну запись по произвольному SQL-запросу
+ */
+function get_record_sql($db, $sql) {
+    if (empty($sql)) {
+        return null;
+    }
+    
+    // Добавляем LIMIT 1, если его нет
+    if (!preg_match('/\bLIMIT\s+\d+$/i', $sql)) {
+        $sql .= " LIMIT 1";
+    }
+    
+    $result = get_records_sql($db, $sql);
+    
+    // Возвращаем первую запись или null
+    return !empty($result) ? $result[0] : null;
+}
+
+/**
+ * Получить несколько записей по произвольному SQL-запросу
+ */
+function get_records_sql($db, $sql) {
+    $result = [];
+    
+    if (empty($sql)) {
+        return $result;
     }
-    $t_record = get_record_sql($db, "SELECT id FROM $table $filter");
-    if (!empty($t_record) and isset($t_record['id'])) { return $t_record['id']; }
+    
+    try {
+        $stmt = $db->query($sql);
+        $records = $stmt->fetchAll(PDO::FETCH_ASSOC);
+        
+        if (!empty($records)) {
+            $result = normalize_records($records);
+        }
+        
+        return $result;
+        
+    } catch (PDOException $e) {
+        LOG_ERROR($db, "SQL: $sql : " . $e->getMessage());
+        return $result;
+    }
+}
+
+
+/**
+ * Получить одно значение поля по SQL-запросу
+ */
+function get_single_field($db, $sql) {
+    $record = get_record_sql($db, $sql);
+    
+    if (!empty($record) && is_array($record)) {
+        // Получаем первое значение из записи
+        return reset($record) ?: 0;
+    }
+    
     return 0;
 }
 
+/**
+ * Получить ID записи из таблицы по фильтру
+ */
+function get_id_record($db, $table, $filter) {
+    if (empty($filter)) {
+        return 0;
+    }
+    
+    $record = get_record($db, $table, $filter);
+    return !empty($record['id']) ? $record['id'] : 0;
+}
+
 function set_changed($db, $id)
 {
     $auth['changed'] = 1;
@@ -317,179 +542,6 @@ function allow_update($table, $action = 'update', $field = '')
     return 0;
 }
 
-function get_record($db, $table, $filter)
-{
-    if (!isset($table)) {
-#        LOG_ERROR($db, "Search in unknown table! Skip command.");
-        return;
-    }
-    if (!isset($filter)) {
-#        LOG_ERROR($db, "Search filter is empty! Skip command.");
-        return;
-    }
-    if (preg_match('/=$/', $filter)) {
-        LOG_ERROR($db, "Search record ($table) with illegal filter $filter! Skip command.");
-        return;
-    }
-    $get_sql = "SELECT * FROM $table WHERE $filter LIMIT 1";
-    $get_record = mysqli_query($db, $get_sql);
-    if (!$get_record) {
-        LOG_ERROR($db, "SQL: $get_sql :" . mysqli_error($db));
-        return;
-    }
-    $fields = [];
-    while ($field = mysqli_fetch_field($get_record)) {
-        $f_table = $field->table;
-        $f_name = $field->name;
-        $fields[$f_table][$f_name] = $field;
-    }
-    $record = mysqli_fetch_array($get_record, MYSQLI_ASSOC);
-    $result = NULL;
-    if (!empty($record)) {
-        foreach ($record as $key => $value) {
-            if (!isset($value) or $value === 'NULL' or $value == NULL) {
-                if (!empty($key) and !empty($fields[$table]) and !empty($fields[$table][$key])) {
-                    if (in_array($fields[$table][$key]->type, MYSQL_FIELD_DIGIT)) {
-                        $value = 0;
-                    }
-                    if (in_array($fields[$table][$key]->type, MYSQL_FIELD_STRING)) {
-                        $value = '';
-                    }
-                }
-            }
-            if (!empty($key)) {
-                $result[$key] = $value;
-            }
-        }
-    }
-    return $result;
-}
-
-function get_records($db, $table, $filter)
-{
-    $result = [];
-    if (!isset($table)) {
-        return $result;
-    }
-    if (isset($filter) and preg_match('/=$/', $filter)) {
-        LOG_ERROR($db, "Search record ($table) with illegal filter $filter! Skip command.");
-        return $result;
-    }
-    $s_filter = '';
-    if (isset($filter)) {
-        $s_filter = 'WHERE ' . $filter;
-    }
-    $get_sql = "SELECT * FROM $table $s_filter";
-    $get_record = mysqli_query($db, $get_sql);
-    if (!$get_record) {
-        LOG_ERROR($db, "SQL: $get_sql :" . mysqli_error($db));
-        return $result;
-    }
-    $fields = [];
-    while ($field = mysqli_fetch_field($get_record)) {
-        $f_table = $field->table;
-        $f_name = $field->name;
-        $fields[$f_table][$f_name] = $field;
-    }
-    $index = 0;
-    while ($rec = mysqli_fetch_array($get_record, MYSQLI_ASSOC)) {
-        foreach ($rec as $key => $value) {
-            if (!isset($value) or $value === 'NULL' or $value == NULL) {
-                if (!empty($key) and !empty($fields[$table]) and !empty($fields[$table][$key])) {
-                    if (in_array($fields[$table][$key]->type, MYSQL_FIELD_DIGIT)) {
-                        $value = 0;
-                    }
-                    if (in_array($fields[$table][$key]->type, MYSQL_FIELD_STRING)) {
-                        $value = '';
-                    }
-                }
-            }
-            $result[$index][$key] = $value;
-        }
-        $index++;
-    }
-    return $result;
-}
-
-function get_records_sql($db, $sql)
-{
-    $result = [];
-    if (empty($sql)) {
-#        LOG_ERROR($db, "Empty query! Skip command.");
-        return $result;
-    }
-    $records = mysqli_query($db, $sql);
-    if (!$records) {
-        LOG_ERROR($db, "SQL: $sql :" . mysqli_error($db));
-        return $result;
-    }
-    $fields = [];
-    //we assume that fields with the same name have the same type
-    while ($field = mysqli_fetch_field($records)) {
-        $f_name = $field->name;
-        $fields[$f_name] = $field;
-    }
-    $index = 0;
-    while ($rec = mysqli_fetch_array($records, MYSQLI_ASSOC)) {
-        foreach ($rec as $key => $value) {
-            if (!isset($value) or $value === 'NULL' or $value == NULL) {
-                if (!empty($key) and !empty($fields[$key])) {
-                    if (in_array($fields[$key]->type, MYSQL_FIELD_DIGIT)) {
-                        $value = 0;
-                    }
-                    if (in_array($fields[$key]->type, MYSQL_FIELD_STRING)) {
-                        $value = '';
-                    }
-                }
-            }
-            if (!empty($key)) {
-                $result[$index][$key] = $value;
-            }
-        }
-        $index++;
-    }
-    return $result;
-}
-
-function get_record_sql($db, $sql)
-{
-    $result = NULL;
-    if (!isset($sql)) {
-#        LOG_ERROR($db, "Empty query! Skip command.");
-        return $result;
-    }
-    $record = mysqli_query($db, $sql . " LIMIT 1");
-    if (!isset($record)) {
-        LOG_ERROR($db, "SQL: $sql LIMIT 1: " . mysqli_error($db));
-        return $result;
-    }
-    $fields = [];
-    //we assume that fields with the same name have the same type
-    while ($field = mysqli_fetch_field($record)) {
-        $f_name = $field->name;
-        $fields[$f_name] = $field;
-    }
-    $rec = mysqli_fetch_array($record, MYSQLI_ASSOC);
-    if (!empty($rec)) {
-        foreach ($rec as $key => $value) {
-            if (!isset($value) or $value === 'NULL' or $value == NULL) {
-                if (!empty($key) and !empty($fields[$key])) {
-                    if (in_array($fields[$key]->type, MYSQL_FIELD_DIGIT)) {
-                        $value = 0;
-                    }
-                    if (in_array($fields[$key]->type, MYSQL_FIELD_STRING)) {
-                        $value = '';
-                    }
-                }
-            }
-            if (!empty($key)) {
-                $result[$key] = $value;
-            }
-        }
-    }
-    return $result;
-}
-
 function update_record($db, $table, $filter, $newvalue)
 {
     if (!isset($table)) {
@@ -515,8 +567,13 @@ function update_record($db, $table, $filter, $newvalue)
     }
 
     $old_sql = "SELECT * FROM $table WHERE $filter";
-    $old_record = mysqli_query($db, $old_sql) or LOG_ERROR($db, "SQL: $old_sql :" . mysqli_error($db));
-    $old = mysqli_fetch_array($old_record, MYSQLI_ASSOC);
+    try {
+        $stmt = $db->query($old_sql);
+        $old = $stmt->fetch(PDO::FETCH_ASSOC);
+    } catch (PDOException $e) {
+        LOG_ERROR($db, "SQL: $old_sql :" . $e->getMessage());
+        return;
+    }
 
     $rec_id = NULL;
     if (!empty($old['id'])) {
@@ -524,7 +581,8 @@ function update_record($db, $table, $filter, $newvalue)
     }
 
     $changed_log = '';
-    $run_sql = '';
+    $set_parts = [];
+    $params = [];
     $network_changed = 0;
     $dhcp_changed = 0;
     $dns_changed = 0;
@@ -568,7 +626,7 @@ function update_record($db, $table, $filter, $newvalue)
             $value = '';
         }
         $value = trim($value);
-        if (strcmp($old[$key], $value) == 0) {
+        if (isset($old[$key]) && strcmp($old[$key], $value) == 0) {
             continue;
         }
         if ($table === "User_auth") {
@@ -588,9 +646,10 @@ function update_record($db, $table, $filter, $newvalue)
             }
         }
         if (!preg_match('/password/i', $key)) {
-            $changed_log = $changed_log . " $key => $value (old: $old[$key]),";
+            $changed_log = $changed_log . " $key => $value (old: " . ($old[$key] ?? '') . "),";
         }
-        $run_sql = $run_sql . " `" . $key . "`='" . db_escape($db, $value) . "',";
+        $set_parts[] = "`$key` = ?";
+        $params[] = $value;
     }
 
     if ($table === "User_auth" and $dns_changed) {
@@ -664,37 +723,47 @@ function update_record($db, $table, $filter, $newvalue)
         }
     }
 
-    if (empty($run_sql)) {
+    if (empty($set_parts)) {
         return 1;
     }
 
     if ($network_changed) {
-        $run_sql = $run_sql . " `changed`='1',";
+        $set_parts[] = "`changed` = '1'";
     }
 
     if ($dhcp_changed) {
-        $run_sql = $run_sql . " `dhcp_changed`='1',";
+        $set_parts[] = "`dhcp_changed` = '1'";
     }
 
     $changed_log = substr_replace($changed_log, "", -1);
-    $run_sql = substr_replace($run_sql, "", -1);
+    $run_sql = implode(", ", $set_parts);
 
     if ($table === 'User_auth') {
         $changed_time = GetNowTimeString();
-        $run_sql = $run_sql . ", `changed_time`='" . $changed_time . "'";
+        $run_sql .= ", `changed_time` = ?";
+        $params[] = $changed_time;
     }
 
     $new_sql = "UPDATE $table SET $run_sql WHERE $filter";
     LOG_DEBUG($db, "Run sql: $new_sql");
-    $sql_result = mysqli_query($db, $new_sql) or LOG_ERROR($db, "SQL: $new_sql :" . mysqli_error($db));
-    if (!$sql_result) {
-        LOG_ERROR($db, "UPDATE Request: $new_sql :" . mysqli_error($db));
+    
+    try {
+        $stmt = $db->prepare($new_sql);
+        $sql_result = $stmt->execute($params);
+        
+        if (!$sql_result) {
+            LOG_ERROR($db, "UPDATE Request: $new_sql");
+            return;
+        }
+        if ($table !== "sessions") {
+            LOG_VERBOSE($db, "Change table $table WHERE $filter set $changed_log");
+        }
+        return $sql_result;
+        
+    } catch (PDOException $e) {
+        LOG_ERROR($db, "SQL: $new_sql :" . $e->getMessage());
         return;
     }
-    if ($table !== "sessions") {
-        LOG_VERBOSE($db, "Change table $table WHERE $filter set $changed_log");
-    }
-    return $sql_result;
 }
 
 function delete_record($db, $table, $filter)
@@ -717,8 +786,13 @@ function delete_record($db, $table, $filter)
     }
 
     $old_sql = "SELECT * FROM $table WHERE $filter";
-    $old_record = mysqli_query($db, $old_sql) or LOG_ERROR($db, "SQL: $old_sql :" . mysqli_error($db));
-    $old = mysqli_fetch_array($old_record, MYSQLI_ASSOC);
+    try {
+        $stmt = $db->query($old_sql);
+        $old = $stmt->fetch(PDO::FETCH_ASSOC);
+    } catch (PDOException $e) {
+        LOG_ERROR($db, "SQL: $old_sql :" . $e->getMessage());
+        return;
+    }
 
     $rec_id = NULL;
     if (!empty($old['id'])) {
@@ -757,11 +831,16 @@ function delete_record($db, $table, $filter)
         $changed_time = GetNowTimeString();
         $new_sql = "UPDATE $table SET deleted=1, changed=1, `changed_time`='" . $changed_time . "' WHERE $filter";
         LOG_DEBUG($db, "Run sql: $new_sql");
-        $sql_result = mysqli_query($db, $new_sql) or LOG_ERROR($db, "SQL: $new_sql :" . mysqli_error($db));
-        if (!$sql_result) {
-            LOG_ERROR($db, "UPDATE Request (from delete): " . mysqli_error($db));
-            return;
+        try {
+            $sql_result = $db->exec($new_sql);
+            if ($sql_result === false) {
+                LOG_ERROR($db, "UPDATE Request (from delete)");
+                return;
             }
+        } catch (PDOException $e) {
+            LOG_ERROR($db, "SQL: $new_sql :" . $e->getMessage());
+            return;
+        }
         //dns - A-record
         if (!empty($old['dns_name']) and !empty($old['ip']) and !$old['dns_ptr_only']  and !preg_match('/\.$/', $old['dns_name'])) {
             $del_dns['name_type'] = 'A';
@@ -810,9 +889,14 @@ function delete_record($db, $table, $filter)
     if ($delete_it) {
         $new_sql = "DELETE FROM $table WHERE $filter";
         LOG_DEBUG($db, "Run sql: $new_sql");
-        $sql_result = mysqli_query($db, $new_sql) or LOG_ERROR($db, "SQL: $new_sql :" . mysqli_error($db));
-        if (!$sql_result) {
-            LOG_ERROR($db, "DELETE Request: $new_sql : " . mysqli_error($db));
+        try {
+            $sql_result = $db->exec($new_sql);
+            if ($sql_result === false) {
+                LOG_ERROR($db, "DELETE Request: $new_sql");
+                return;
+            }
+        } catch (PDOException $e) {
+            LOG_ERROR($db, "SQL: $new_sql : " . $e->getMessage());
             return;
         }
     } else { return; }
@@ -841,6 +925,7 @@ function insert_record($db, $table, $newvalue)
     $changed_log = '';
     $field_list = '';
     $value_list = '';
+    $params = [];
     foreach ($newvalue as $key => $value) {
         if (empty($value) and $value != '0') {
             $value = '';
@@ -850,7 +935,8 @@ function insert_record($db, $table, $newvalue)
         }
         $field_list = $field_list . "`" . $key . "`,";
         $value = trim($value);
-        $value_list = $value_list . "'" . db_escape($db, $value) . "',";
+        $value_list = $value_list . "?,";
+        $params[] = $value;
     }
     if (empty($value_list)) {
         return;
@@ -861,53 +947,62 @@ function insert_record($db, $table, $newvalue)
     $value_list = substr_replace($value_list, "", -1);
     $new_sql = "insert into $table(" . $field_list . ") values(" . $value_list . ")";
     LOG_DEBUG($db, "Run sql: $new_sql");
-    $sql_result = mysqli_query($db, $new_sql) or LOG_ERROR($db, "SQL: $new_sql :" . mysqli_error($db));
-    if (!$sql_result) {
-        LOG_ERROR($db, "INSERT Request:" . mysqli_error($db));
-        return;
-    }
-    $last_id = mysqli_insert_id($db);
-    if ($table !== "sessions") {
-        LOG_VERBOSE($db, "Create record in table $table: $changed_log with id: $last_id");
-    }
-    if ($table === 'User_auth') {
-        run_sql($db, "UPDATE User_auth SET changed=1, dhcp_changed=1 WHERE id=" . $last_id);
-    }
-
-    if ($table === 'User_auth_alias') {
-        //dns
-        if (!empty($newvalue['alias'])  and !preg_match('/\.$/', $newvalue['alias'])) {
-            $add_dns['name_type'] = 'CNAME';
-            $add_dns['name'] = $newvalue['alias'];
-            $add_dns['value'] = get_dns_name($db, $newvalue['auth_id']);
-            $add_dns['type'] = 'add';
-            $add_dns['auth_id'] = $newvalue['auth_id'];
-            insert_record($db, 'dns_queue', $add_dns);
+    
+    try {
+        $stmt = $db->prepare($new_sql);
+        $sql_result = $stmt->execute($params);
+        
+        if (!$sql_result) {
+            LOG_ERROR($db, "INSERT Request");
+            return;
+        }
+        $last_id = $db->lastInsertId();
+        if ($table !== "sessions") {
+            LOG_VERBOSE($db, "Create record in table $table: $changed_log with id: $last_id");
+        }
+        if ($table === 'User_auth') {
+            run_sql($db, "UPDATE User_auth SET changed=1, dhcp_changed=1 WHERE id=" . $last_id);
         }
-    }
 
-    if ($table === 'User_auth') {
-        //dns - A-record
-        if (!empty($newvalue['dns_name']) and !empty($newvalue['ip']) and !$newvalue['dns_ptr_only']  and !preg_match('/\.$/', $newvalue['dns_name'])) {
-            $add_dns['name_type'] = 'A';
-            $add_dns['name'] = $newvalue['dns_name'];
-            $add_dns['value'] = $newvalue['ip'];
-            $add_dns['type'] = 'add';
-            $add_dns['auth_id'] = $last_id;
-            insert_record($db, 'dns_queue', $add_dns);
+        if ($table === 'User_auth_alias') {
+            //dns
+            if (!empty($newvalue['alias'])  and !preg_match('/\.$/', $newvalue['alias'])) {
+                $add_dns['name_type'] = 'CNAME';
+                $add_dns['name'] = $newvalue['alias'];
+                $add_dns['value'] = get_dns_name($db, $newvalue['auth_id']);
+                $add_dns['type'] = 'add';
+                $add_dns['auth_id'] = $newvalue['auth_id'];
+                insert_record($db, 'dns_queue', $add_dns);
+            }
         }
-        //dns - ptr
-        if (!empty($newvalue['dns_name']) and !empty($newvalue['ip']) and $newvalue['dns_ptr_only'] and !preg_match('/\.$/', $newvalue['dns_name'])) {
-            $add_dns['name_type'] = 'PTR';
-            $add_dns['name'] = $newvalue['dns_name'];
-            $add_dns['value'] = $newvalue['ip'];
-            $add_dns['type'] = 'add';
-            $add_dns['auth_id'] = $last_id;
-            insert_record($db, 'dns_queue', $add_dns);
+
+        if ($table === 'User_auth') {
+            //dns - A-record
+            if (!empty($newvalue['dns_name']) and !empty($newvalue['ip']) and !$newvalue['dns_ptr_only']  and !preg_match('/\.$/', $newvalue['dns_name'])) {
+                $add_dns['name_type'] = 'A';
+                $add_dns['name'] = $newvalue['dns_name'];
+                $add_dns['value'] = $newvalue['ip'];
+                $add_dns['type'] = 'add';
+                $add_dns['auth_id'] = $last_id;
+                insert_record($db, 'dns_queue', $add_dns);
+            }
+            //dns - ptr
+            if (!empty($newvalue['dns_name']) and !empty($newvalue['ip']) and $newvalue['dns_ptr_only'] and !preg_match('/\.$/', $newvalue['dns_name'])) {
+                $add_dns['name_type'] = 'PTR';
+                $add_dns['name'] = $newvalue['dns_name'];
+                $add_dns['value'] = $newvalue['ip'];
+                $add_dns['type'] = 'add';
+                $add_dns['auth_id'] = $last_id;
+                insert_record($db, 'dns_queue', $add_dns);
+            }
         }
-    }
 
-    return $last_id;
+        return $last_id;
+        
+    } catch (PDOException $e) {
+        LOG_ERROR($db, "SQL: $new_sql :" . $e->getMessage());
+        return;
+    }
 }
 
 function dump_record($db, $table, $filter)
@@ -937,46 +1032,50 @@ function get_diff_rec($db, $table, $filter, $newvalue, $only_changed = false)
         return '';
     }
     $old_sql = "SELECT * FROM `$table` WHERE $filter";
-    $result = mysqli_query($db, $old_sql);
-    if (!$result) {
-        LOG_ERROR($db, "SQL: $old_sql :" . mysqli_error($db));
-        return '';
-    }
-    $old = mysqli_fetch_array($result, MYSQLI_ASSOC);
-    if (!$old) {
-        // Запись не найдена — возможно, ошибка или новая запись
-        return "Record not found for filter: $filter";
-    }
-    $changed = [];
-    $unchanged = [];
-    foreach ($newvalue as $key => $new_val) {
-        // Пропускаем ключи, которых нет в старой записи (например, служебные поля)
-        if (!array_key_exists($key, $old)) {
-            continue;
+    try {
+        $stmt = $db->query($old_sql);
+        $old = $stmt->fetch(PDO::FETCH_ASSOC);
+        
+        if (!$old) {
+            // Запись не найдена — возможно, ошибка или новая запись
+            return "Record not found for filter: $filter";
         }
-        $old_val = $old[$key];
-        // Сравниваем как строки, но аккуратно с null
-        $old_str = ($old_val === null) ? '' : (string)$old_val;
-        $new_str = ($new_val === null) ? '' : (string)$new_val;
-        if ($old_str !== $new_str) {
-            $changed[$key] = $new_str . ' [ old: ' . $old_str . ' ]';
+        
+        $changed = [];
+        $unchanged = [];
+        foreach ($newvalue as $key => $new_val) {
+            // Пропускаем ключи, которых нет в старой записи (например, служебные поля)
+            if (!array_key_exists($key, $old)) {
+                continue;
+            }
+            $old_val = $old[$key];
+            // Сравниваем как строки, но аккуратно с null
+            $old_str = ($old_val === null) ? '' : (string)$old_val;
+            $new_str = ($new_val === null) ? '' : (string)$new_val;
+            if ($old_str !== $new_str) {
+                $changed[$key] = $new_str . ' [ old: ' . $old_str . ' ]';
+            } else {
+                $unchanged[$key] = $old_val;
+            }
+        }
+        if ($only_changed) {
+            return empty($changed) ? '' : hash_to_text($changed);
+        }
+        $output = '';
+        if (!empty($changed)) {
+            $output .= hash_to_text($changed);
         } else {
-            $unchanged[$key] = $old_val;
+            $output .= "# no changes";
         }
+        if (!empty($unchanged)) {
+            $output .= "\r\nHas not changed:\r\n" . hash_to_text($unchanged);
+        }
+        return $output;
+        
+    } catch (PDOException $e) {
+        LOG_ERROR($db, "SQL: $old_sql :" . $e->getMessage());
+        return '';
     }
-    if ($only_changed) {
-        return empty($changed) ? '' : hash_to_text($changed);
-    }
-    $output = '';
-    if (!empty($changed)) {
-        $output .= hash_to_text($changed);
-    } else {
-        $output .= "# no changes";
-    }
-    if (!empty($unchanged)) {
-        $output .= "\r\nHas not changed:\r\n" . hash_to_text($unchanged);
-    }
-    return $output;
 }
 
 function delete_user_auth($db, $id) {
@@ -1064,4 +1163,4 @@ function record_to_txt($db, $table, $id) {
 
 $db_link = new_connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
 
-?>
+?>