setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); } catch (PDOException $e) { die("Database connection failed: " . $e->getMessage()); } // Load language files, which now uses the $pdo object from this script require_once __DIR__ . '/language.php'; // Start session is now in language.php // session_start(); // Error reporting for development is now handled in language.php based on settings /* ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); */ // Function to check if a table exists function tableExists($pdo, $tableName) { try { $result = $pdo->query("SELECT 1 FROM {$tableName} LIMIT 1"); } catch (Exception $e) { return false; } return $result !== false; } // Function to check if a column exists in a table function columnExists($pdo, $tableName, $columnName) { try { $result = $pdo->query("SELECT {$columnName} FROM {$tableName} LIMIT 1"); } catch (Exception $e) { return false; } return $result !== false; } // Initialize database schema if tables don't exist $db_initialized = tableExists($pdo, 'users'); if ($db_initialized) { // For existing installations, run migration checks if (!columnExists($pdo, 'users', 'role')) { $pdo->exec("ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'user'"); $pdo->exec("UPDATE users SET role = 'admin' WHERE id = 1"); } // Add show_search_bar setting if it doesn't exist $stmt = $pdo->prepare("SELECT value FROM settings WHERE key = 'show_search_bar'"); $stmt->execute(); if (!$stmt->fetch()) { $pdo->prepare("INSERT INTO settings (key, value) VALUES (?, ?)")->execute(['show_search_bar', '1']); } } if (!$db_initialized) { // Create users table $pdo->exec(" CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'user' ) "); // Insert a default user (e.g., admin/password) $default_password = password_hash('password', PASSWORD_DEFAULT); $stmt = $pdo->prepare("INSERT INTO users (username, password, role) VALUES (?, ?, ?)"); $stmt->execute(['admin', $default_password, 'admin']); // Create settings table $pdo->exec(" CREATE TABLE settings ( key TEXT PRIMARY KEY, value TEXT ) "); // Insert default settings $default_settings = [ 'dashboard_protected' => '0', 'remember_me_duration' => '2 weeks', 'open_new_tab' => '1', 'language' => 'en', 'favicon_extractor_url' => 'https://favicon.hibbit.cloud', 'debug_mode' => '0', 'show_search_bar' => '1', 'theme' => 'transparent', 'background_image_url' => '', 'background_brightness' => '50', 'background_saturation' => '100', 'pexels_api_key' => 'VaNzz6B9q31971WDf1h4TjwEvgib6XvXQp58AhJnX7dGqDawavi7SQAd', 'custom_css' => '', 'theme_transparency' => '40' ]; $stmt = $pdo->prepare("INSERT INTO settings (key, value) VALUES (?, ?)"); foreach ($default_settings as $key => $value) { $stmt->execute([$key, $value]); } // Create categories table $pdo->exec(" CREATE TABLE categories ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, sort_order INTEGER ) "); // Create bookmarks table $pdo->exec(" CREATE TABLE bookmarks ( id INTEGER PRIMARY KEY AUTOINCREMENT, category_id INTEGER, title TEXT NOT NULL, url TEXT NOT NULL, icon TEXT, is_favorite INTEGER DEFAULT 0, sort_order INTEGER, FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE CASCADE ) "); } // Check if tabs table exists if (!tableExists($pdo, 'tabs')) { $pdo->exec(" CREATE TABLE tabs ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, user_id INTEGER, sort_order INTEGER, background_image_url TEXT, background_brightness INTEGER DEFAULT 100, background_saturation INTEGER DEFAULT 100, theme TEXT DEFAULT 'dark', theme_transparency INTEGER DEFAULT 85, login_token VARCHAR(255) UNIQUE, FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE SET NULL ) "); // Insert a default tab $default_token = bin2hex(random_bytes(16)); $pdo->prepare("INSERT INTO tabs (name, sort_order, login_token) VALUES (?, ?, ?)") ->execute(['Default', 1, $default_token]); } // Migration: Add sort_order to tabs table if it doesn't exist if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'sort_order')) { $pdo->exec("ALTER TABLE tabs ADD COLUMN sort_order INTEGER"); // Initialize sort order based on existing IDs $pdo->exec("UPDATE tabs SET sort_order = id"); } // Migration: Add new columns to tabs table if they don't exist if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'background_image_url')) { $pdo->exec("ALTER TABLE tabs ADD COLUMN background_image_url TEXT"); } if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'background_brightness')) { $pdo->exec("ALTER TABLE tabs ADD COLUMN background_brightness INTEGER DEFAULT 100"); } if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'background_saturation')) { $pdo->exec("ALTER TABLE tabs ADD COLUMN background_saturation INTEGER DEFAULT 100"); } if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'theme')) { $pdo->exec("ALTER TABLE tabs ADD COLUMN theme TEXT DEFAULT 'dark'"); } if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'theme_transparency')) { $pdo->exec("ALTER TABLE tabs ADD COLUMN theme_transparency INTEGER DEFAULT 85"); } // Migration: Add column_count to tabs table if it doesn't exist if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'column_count')) { $pdo->exec("ALTER TABLE tabs ADD COLUMN column_count INTEGER DEFAULT 5"); } // Migration: Add show_search_bar to tabs table if it doesn't exist if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'show_search_bar')) { $pdo->exec("ALTER TABLE tabs ADD COLUMN show_search_bar INTEGER DEFAULT 1"); } // Check if tab_id column exists in bookmarks table if (!columnExists($pdo, 'bookmarks', 'tab_id')) { $pdo->exec("ALTER TABLE bookmarks ADD COLUMN tab_id INTEGER"); // Set default tab_id for existing bookmarks $pdo->exec("UPDATE bookmarks SET tab_id = 1"); } // Check if tab_id column exists in categories table if (!columnExists($pdo, 'categories', 'tab_id')) { $pdo->exec("ALTER TABLE categories ADD COLUMN tab_id INTEGER"); // Set default tab_id for existing categories $pdo->exec("UPDATE categories SET tab_id = 1"); } // Create tab_viewer_access table if (!tableExists($pdo, 'tab_viewer_access')) { $pdo->exec(" CREATE TABLE tab_viewer_access ( user_id INTEGER NOT NULL, tab_id INTEGER NOT NULL, PRIMARY KEY (user_id, tab_id), FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE, FOREIGN KEY (tab_id) REFERENCES tabs (id) ON DELETE CASCADE ) "); } // Create user_tab_visibility table if (!tableExists($pdo, 'user_tab_visibility')) { $pdo->exec(" CREATE TABLE user_tab_visibility ( user_id INTEGER NOT NULL, tab_id INTEGER NOT NULL, PRIMARY KEY (user_id, tab_id), FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE, FOREIGN KEY (tab_id) REFERENCES tabs (id) ON DELETE CASCADE ) "); } // Load all settings into a global variable for easy access try { $settings_stmt = $pdo->query("SELECT key, value FROM settings"); $settings = $settings_stmt->fetchAll(PDO::FETCH_KEY_PAIR); $GLOBALS['settings'] = $settings; // Make it globally available } catch (PDOException $e) { // If settings can't be loaded, initialize as empty array to prevent fatal errors $settings = []; $GLOBALS['settings'] = []; } // Set timezone, default to UTC date_default_timezone_set($settings['timezone'] ?? 'UTC');