PDO::ERRMODE_EXCEPTION] ); $pdo->exec("CREATE TABLE IF NOT EXISTS sqlite_mirror_rows ( source_db VARCHAR(255) NOT NULL, table_name VARCHAR(128) NOT NULL, row_key VARCHAR(255) NOT NULL, row_json LONGTEXT NOT NULL, synced_at BIGINT NOT NULL, PRIMARY KEY(source_db,table_name,row_key) )"); return $pdo; } function mirrorAllSQLiteDatabases(): array { $main = storagePath((string)getConfigVal('database.main_db', 'db/chat.sqlite')); $files = is_file($main) ? [$main] : []; $archiveRoot = storagePath((string)getConfigVal('archive.archive_dir', 'archive')); foreach (glob($archiveRoot . '/*/*/*.sqlite') ?: [] as $file) $files[] = $file; $mysql = mysqlMirrorConnection(); $upsert = $mysql->prepare("INSERT INTO sqlite_mirror_rows (source_db,table_name,row_key,row_json,synced_at) VALUES (?,?,?,?,?) ON DUPLICATE KEY UPDATE row_json=VALUES(row_json),synced_at=VALUES(synced_at)"); $count = 0; foreach ($files as $file) { $sqlite = new PDO('sqlite:' . $file); $sqlite->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); $tables = $sqlite->query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'") ->fetchAll(PDO::FETCH_COLUMN); foreach ($tables as $table) { $quoted = '"' . str_replace('"', '""', $table) . '"'; foreach ($sqlite->query("SELECT rowid AS _mirror_rowid,* FROM $quoted") as $row) { $key = (string)($row['id'] ?? $row['_mirror_rowid']); unset($row['_mirror_rowid']); $source = str_starts_with($file, ROOT_DIR . '/') ? substr($file, strlen(ROOT_DIR) + 1) : $file; $upsert->execute([ $source, $table, $key, json_encode($row, JSON_UNESCAPED_SLASHES), time(), ]); $count++; } } } return ['databases' => count($files), 'rows' => $count]; }