diff --git a/core/database/migrations/2025_12_25_000000_initial_schema.php b/core/database/migrations/2025_12_25_000000_initial_schema.php index cde5ac1e09..24c85988e0 100644 --- a/core/database/migrations/2025_12_25_000000_initial_schema.php +++ b/core/database/migrations/2025_12_25_000000_initial_schema.php @@ -297,7 +297,7 @@ public function up(): void $indexPrefix = \DB::getTablePrefix() . $table->getTable(); $table->comment('Site content (documents) - main table storing all site pages, documents, and content resources'); $table->increments('id'); - $table->string('type', 20)->default('document')->index('typeidx'); + $table->string('type', 20)->default('document')->index("{$indexPrefix}_typeidx"); $table->string('contentType', 50)->default('text/html'); $table->string('pagetitle')->default(''); $table->string('longtitle')->default(''); @@ -354,9 +354,9 @@ public function up(): void $table->unsignedInteger('descendant'); $table->unsignedInteger('depth'); - $table->index('ancestor', 'closure_ancestor_idx'); - $table->index('descendant', 'closure_descendant_idx'); - $table->index('depth', 'closure_depth_idx'); + $table->index('ancestor', "{$indexPrefix}_closure_ancestor_idx"); + $table->index('descendant', "{$indexPrefix}_closure_descendant_idx"); + $table->index('depth', "{$indexPrefix}_closure_depth_idx"); $table->unique(['ancestor', 'descendant'], "{$indexPrefix}_ix_unique_path"); }); diff --git a/install/src/controllers/connection.php b/install/src/controllers/connection.php index 18861156a8..6268de6b1a 100644 --- a/install/src/controllers/connection.php +++ b/install/src/controllers/connection.php @@ -1,6 +1,6 @@ 'MySQL', 'pgsql' => 'PostgreSQL']; +$dbTypes = ['mysql' => 'MySQL', 'pgsql' => 'PostgreSQL', 'sqlite' => 'SQLite']; // Determine upgradeability $upgradeable = 0; @@ -50,6 +50,14 @@ $conn = false; $result = false; } + } elseif ($database_type === 'sqlite') { + try { + $conn = new PDO('sqlite:' . $database_name); + $result = true; + } catch (PDOException $e) { + $conn = false; + $result = false; + } } if (!$conn || !$result) { $upgradeable = (isset($_POST['installmode']) && $_POST['installmode'] === 'new') ? 0 : 2; @@ -92,12 +100,18 @@ $pos = strpos($database_collation, '.'); $database_charset = ($pos !== false) ? substr($database_collation, $pos + 1) : 'utf8'; $database_connection_charset = $database_charset; + } elseif ($database_type === 'sqlite') { + $database_collation = 'utf8'; + $database_charset = 'utf8'; + $database_connection_charset = 'utf8'; } } else { if ($database_type === 'mysql') { $database_collation = 'utf8mb4_general_ci'; } elseif ($database_type === 'pgsql') { $database_collation = 'en_US.utf8'; + } elseif ($database_type === 'sqlite') { + $database_collation = 'utf8'; } } @@ -107,6 +121,8 @@ $database_connection_method = 'SET CHARACTER SET'; } elseif ($database_type === 'pgsql') { $database_connection_method = 'SET client_encoding'; + } elseif ($database_type === 'sqlite') { + $database_connection_method = ''; } } $ph['databaseTypeOptions'] = ''; diff --git a/install/src/controllers/connection/collation.php b/install/src/controllers/connection/collation.php index 464cb32fba..5b651c9ead 100644 --- a/install/src/controllers/connection/collation.php +++ b/install/src/controllers/connection/collation.php @@ -89,6 +89,10 @@ } $output .= ''; break; + case 'sqlite': + $output .= ''; + $output .= ''; + break; } echo $output; } catch (Exception $e) { diff --git a/install/src/controllers/connection/databasetest.php b/install/src/controllers/connection/databasetest.php index 42b298cbc1..278f8e46ff 100644 --- a/install/src/controllers/connection/databasetest.php +++ b/install/src/controllers/connection/databasetest.php @@ -14,7 +14,11 @@ $database_charset = getDatabaseCharset($database_collation, $driver); try { - $dbh = new PDO($driver . ':host=' . $host . ';dbname=' . $database_name, $uid, $pwd); + if ($driver === 'sqlite') { + $dbh = new PDO('sqlite:' . EVO_CORE_PATH . "database/$database_name.sqlite"); + } else { + $dbh = new PDO($driver . ':host=' . $host . ';dbname=' . $database_name, $uid, $pwd); + } switch ($driver) { case 'pgsql': $result = $dbh->query("SELECT * FROM pg_settings WHERE name='client_encoding'"); @@ -79,6 +83,18 @@ exit(); } break; + case 'sqlite': + try { + $result = $dbh->query("SELECT COUNT(*) FROM {$tableprefix}site_content"); + } catch (PDOException $e) { + // no table is expected + } + + if ($dbh->errorCode() == 0) { + echo $output . '' . $_lang['status_failed_table_prefix_already_in_use'] . ''; + exit(); + } + break; } } catch (PDOException $e) { @@ -89,7 +105,11 @@ } try { - $dbh = new PDO($driver . ':host=' . $host . ($driver === 'pgsql' ? ';dbname=postgres' : ''), $uid, $pwd); + if ($driver === 'sqlite') { + $dbh = new PDO('sqlite:' . EVO_CORE_PATH . "database/$database_name.sqlite"); + } else { + $dbh = new PDO($driver . ':host=' . $host . ($driver === 'pgsql' ? ';dbname=postgres' : ''), $uid, $pwd); + } switch ($driver) { case 'pgsql': try { @@ -118,6 +138,8 @@ exit(); } break; + case 'sqlite': + break; } echo $output . ' ' . $_lang['status_passed'] . ''; diff --git a/install/src/controllers/connection/servertest.php b/install/src/controllers/connection/servertest.php index 046dcd2763..6eb5a805ed 100644 --- a/install/src/controllers/connection/servertest.php +++ b/install/src/controllers/connection/servertest.php @@ -6,7 +6,11 @@ $output = $_lang['status_connecting']; try { - $dbh = new PDO($method . ':host=' . $host . ($method === 'pgsql' ? ';dbname=postgres' : ''), $uid, $pwd); + if ($method === 'sqlite') { + $dbh = new PDO('sqlite::memory:'); + } else { + $dbh = new PDO($method . ':host=' . $host . ($method === 'pgsql' ? ';dbname=postgres' : ''), $uid, $pwd); + } $output .= ' ' . $_lang['status_passed_server'] . ''; } catch (PDOException $e) { $output .= ' ' . $_lang['status_failed'] . ' ' . $e->getMessage() . ''; diff --git a/install/src/controllers/install.php b/install/src/controllers/install.php index 2dda0034ed..38fe1f3f35 100644 --- a/install/src/controllers/install.php +++ b/install/src/controllers/install.php @@ -71,7 +71,11 @@ global $conn; try { - $dbh = new PDO($_POST['database_type'] . ':host=' . $_POST['databasehost'] . ';dbname=' . $_POST['database_name'], $database_user, $database_password); + if ($_POST['database_type'] === 'sqlite') { + $dbh = new PDO('sqlite:' . $_POST['database_name']); + } else { + $dbh = new PDO($_POST['database_type'] . ':host=' . $_POST['databasehost'] . ';dbname=' . $_POST['database_name'], $database_user, $database_password); + } include dirname(__DIR__) . '/processor/result.php'; @@ -109,6 +113,9 @@ $confph['database_engine'] = ", 'innodb'"; } break; + case 'sqlite': + $confph['database_port'] = ''; + break; } $configString = file_get_contents(dirname(__DIR__, 2) . '/stubs/files/config/database/connections/default.tpl'); $configString = parse($configString, $confph); diff --git a/install/src/controllers/options.php b/install/src/controllers/options.php index 122c47d660..57d16d6578 100644 --- a/install/src/controllers/options.php +++ b/install/src/controllers/options.php @@ -76,6 +76,16 @@ if (!isset($database_connection_method) || empty($database_connection_method)) { $database_connection_method = 'SET client_encoding'; } + } elseif ($db_config['driver'] === 'sqlite') { + try { + $conn = new PDO('sqlite:' . $db_config['database']); + $database_collation = 'utf8'; + $database_charset = 'utf8'; + $database_connection_charset = 'utf8'; + $database_connection_method = ''; + } catch (PDOException $e) { + // + } } $_POST['database_name'] = $db_config['database']; diff --git a/install/src/controllers/summary.php b/install/src/controllers/summary.php index f7a8fddf2a..8950380c19 100644 --- a/install/src/controllers/summary.php +++ b/install/src/controllers/summary.php @@ -211,13 +211,22 @@ function f_owc($path, $data, $mode = null) $database_charset = substr($database_collation, 0, strpos($database_collation, '_') - 1); $database_connection_charset = $_POST['database_connection_charset']; $database_connection_method = $_POST['database_connection_method']; - $dbase = '`' . strip_tags($_POST['database_name']) . '`'; + if ($database_type === 'sqlite') { + $database_name = strip_tags($_POST['database_name']); // TODO: replace strip_tags with validation everywhere + $dbase = EVO_CORE_PATH . "database/$database_name.sqlite"; + } else { + $dbase = '`' . strip_tags($_POST['database_name']) . '`'; + } $table_prefix = strip_tags($_POST['tableprefix']); } echo '
' . $_lang['creating_database_connection']; $host = explode(':', $database_server, 2); try { - $dbh = new PDO($database_type . ':host=' . $database_server . ';dbname=' . $_POST['database_name'], $database_user, $database_password); + if ($database_type === 'sqlite') { + $dbh = new PDO('sqlite:' . $dbase); + } else { + $dbh = new PDO($database_type . ':host=' . $database_server . ';dbname=' . $_POST['database_name'], $database_user, $database_password); + } echo '' . $_lang['ok'] . '
'; } catch (PDOException $e) { $errors++; @@ -226,7 +235,7 @@ function f_owc($path, $data, $mode = null) } // check the database collation if not specified in the configuration -if (!isset ($database_connection_charset) || empty ($database_connection_charset)) { +if ($database_type === 'mysql' && empty ($database_connection_charset)) { if (!$rs = mysqli_query($conn, "show session variables like 'collation_database'")) { $rs = mysqli_query($conn, "show session variables like 'collation_server'"); } diff --git a/install/src/functions.php b/install/src/functions.php index 9ca7d68f51..1390a3c91e 100644 --- a/install/src/functions.php +++ b/install/src/functions.php @@ -44,6 +44,8 @@ function getDatabaseCharset($database_collation, $driver): string { $database_charset = 'UTF8'; } $database_charset = str_ireplace(['utf-8', 'utf8'], 'UTF8', $database_charset); + } elseif ($driver === 'sqlite') { + $database_charset = 'utf8'; } else { // MySQL 5.7 & 8.0: "utf8mb4_general_ci", "utf8_unicode_ci", "latin1_swedish_ci" // MySQL 8.0+: "utf8mb4_0900_ai_ci" (with version number) @@ -70,20 +72,20 @@ function install_sessionCheck() echo ' -' . $_lang["session_problem"] . '
- -' . $_lang["session_problem"] . '
+ +