diff --git a/public/index.php b/public/index.php index 1929802..254143b 100644 --- a/public/index.php +++ b/public/index.php @@ -34,16 +34,26 @@ $db = $prerequisites->getDatabase(); // Make sure the initial setup is complete unless we're already heading to setup if (!(preg_match('/setup$/', $path))) { - // Make sure required tables (user, settings) are populated - $user_count = (int) $db->query("SELECT COUNT(*) FROM user")->fetchColumn(); - $settings_count = (int) $db->query("SELECT COUNT(*) FROM settings")->fetchColumn(); + try { + // Make sure required tables (user, settings) are populated + $user_count = (int) $db->query("SELECT COUNT(*) FROM user")->fetchColumn(); + $settings_count = (int) $db->query("SELECT COUNT(*) FROM settings")->fetchColumn(); - // If either required table has no records, redirect to setup. - if ($user_count === 0 || $settings_count === 0){ - $init = require APP_ROOT . '/config/init.php'; - header('Location: ' . $init['base_path'] . 'setup'); + // If either required table has no records, redirect to setup. + if ($user_count === 0 || $settings_count === 0){ + $init = require APP_ROOT . '/config/init.php'; + header('Location: ' . $init['base_path'] . 'setup'); + exit; + } + } catch (Exception $e) { + // Database error during setup validation - show error page + error_log("Database error during setup validation: " . $e->getMessage()); + http_response_code(500); + echo "

Database Error

"; + echo "

Cannot validate setup status. The database may be corrupted or locked.

"; + echo "

Please check your installation or contact your hosting provider.

"; exit; - }; + } } /* @@ -83,7 +93,7 @@ if ($method === 'POST' && $path != 'setup') { if (!Session::isValid($_POST['csrf_token'])) { // Invalid session - redirect to /login Log::info('Attempt to POST with invalid session. Redirecting to login.'); - header('Location: ' . Util::buildRelativeUrl($app->config->basePath, 'login')); + header('Location: ' . Util::buildRelativeUrl($app['config']->basePath, 'login')); exit; } } else { diff --git a/src/Controller/CssController/CssController.php b/src/Controller/CssController/CssController.php index b48fbf4..f372b89 100644 --- a/src/Controller/CssController/CssController.php +++ b/src/Controller/CssController/CssController.php @@ -112,29 +112,35 @@ class CssController extends Controller { } // Set the theme back to default - $app['config']->cssId = null; - $app['config'] = $app['config']->save(); - - // Set flash message - Session::setFlashMessage('success', 'Theme ' . $cssFilename . ' deleted.'); + try { + $app['config']->cssId = null; + $app['config'] = $app['config']->save(); + Session::setFlashMessage('success', 'Theme ' . $cssFilename . ' deleted.'); + } catch (Exception $e) { + Log::error("Failed to update config after deleting theme: " . $e->getMessage()); + Session::setFlashMessage('error', 'Theme deleted but failed to update settings'); + } } private function handleSetTheme() { global $app; - if ($_POST['selectCssFile']){ - // Set custom theme - $app['config']->cssId = $_POST['selectCssFile']; - } else { - // Set default theme - $app['config']->cssId = null; + try { + if ($_POST['selectCssFile']){ + // Set custom theme + $app['config']->cssId = $_POST['selectCssFile']; + } else { + // Set default theme + $app['config']->cssId = null; + } + + // Update the site theme + $app['config'] = $app['config']->save(); + Session::setFlashMessage('success', 'Theme applied.'); + } catch (Exception $e) { + Log::error("Failed to save theme setting: " . $e->getMessage()); + Session::setFlashMessage('error', 'Failed to apply theme'); } - - // Update the site theme - $app['config'] = $app['config']->save(); - - // Set flash message - Session::setFlashMessage('success', 'Theme applied.'); } private function handleUpload() { diff --git a/src/Controller/FeedController/FeedController.php b/src/Controller/FeedController/FeedController.php index b20b687..2adf9d6 100644 --- a/src/Controller/FeedController/FeedController.php +++ b/src/Controller/FeedController/FeedController.php @@ -5,10 +5,15 @@ class FeedController extends Controller { public function __construct() { global $app; - $tickModel = new TickModel($app['db'], $app['config']); - $this->ticks = $tickModel->getPage($app['config']->itemsPerPage); - - Log::debug("Loaded " . count($this->ticks) . " ticks for feeds"); + try { + $tickModel = new TickModel($app['db'], $app['config']); + $this->ticks = $tickModel->getPage($app['config']->itemsPerPage); + Log::debug("Loaded " . count($this->ticks) . " ticks for feeds"); + } catch (Exception $e) { + Log::error("Failed to load ticks for feed: " . $e->getMessage()); + // Provide empty feed rather than crashing - RSS readers can handle this + $this->ticks = []; + } } public function rss(){ diff --git a/src/Framework/Log/Log.php b/src/Framework/Log/Log.php index 08a818b..c54751e 100644 --- a/src/Framework/Log/Log.php +++ b/src/Framework/Log/Log.php @@ -19,7 +19,12 @@ class Log { // (should be handled by Prerequisites, but doesn't hurt) $logDir = dirname(self::$logFile); if (!is_dir($logDir)) { - mkdir($logDir, 0770, true); + try { + mkdir($logDir, 0770, true); + } catch (Exception $e) { + // Fall back to error_log if we can't create log directory + error_log("Failed to create log directory {$logDir}: " . $e->getMessage()); + } } } @@ -61,35 +66,45 @@ class Log { $logEntry = "[{$timestamp}] {$level}: " . Util::getClientIp() . "{$context} - {$message}\n"; // Rotate if we're at the max file size (1000 lines) - if (file_exists(self::$logFile)) { - $lineCount = count(file(self::$logFile)); - if ($lineCount >= self::$maxLines) { - self::rotate(); - Log::info("Log rotated at {$timestamp}"); + try { + if (file_exists(self::$logFile)) { + $lineCount = count(file(self::$logFile)); + if ($lineCount >= self::$maxLines) { + self::rotate(); + Log::info("Log rotated at {$timestamp}"); + } } - } - file_put_contents(self::$logFile, $logEntry, FILE_APPEND | LOCK_EX); + file_put_contents(self::$logFile, $logEntry, FILE_APPEND | LOCK_EX); + } catch (Exception $e) { + // Fall back to error_log if file operations fail + error_log("Log write failed: " . $e->getMessage() . " - Original message: " . trim($logEntry)); + } } private static function rotate() { - // Rotate existing history files: tkr.4.log -> tkr.5.log, etc. - for ($i = self::$maxFiles - 1; $i >= 1; $i--) { - $oldFile = self::$logFile . '.' . $i; - $newFile = self::$logFile . '.' . ($i + 1); + try { + // Rotate existing history files: tkr.4.log -> tkr.5.log, etc. + for ($i = self::$maxFiles - 1; $i >= 1; $i--) { + $oldFile = self::$logFile . '.' . $i; + $newFile = self::$logFile . '.' . ($i + 1); - if (file_exists($oldFile)) { - if ($i == self::$maxFiles - 1) { - unlink($oldFile); // Delete oldest log if we already have 5 files of history - } else { - rename($oldFile, $newFile); // Bump the file number up by one + if (file_exists($oldFile)) { + if ($i == self::$maxFiles - 1) { + unlink($oldFile); // Delete oldest log if we already have 5 files of history + } else { + rename($oldFile, $newFile); // Bump the file number up by one + } } } - } - // Move current active log to .1 - if (file_exists(self::$logFile)) { - rename(self::$logFile, self::$logFile . '.1'); + // Move current active log to .1 + if (file_exists(self::$logFile)) { + rename(self::$logFile, self::$logFile . '.1'); + } + } catch (Exception $e) { + // Log rotation failure - not critical, just continue + error_log("Log rotation failed: " . $e->getMessage()); } } } \ No newline at end of file