diff --git a/lam/HISTORY b/lam/HISTORY
index c7c079646..f64845d5e 100644
--- a/lam/HISTORY
+++ b/lam/HISTORY
@@ -1,4 +1,5 @@
December 2025 9.4
+ - Main configuration and server profiles require latest file format (introduced in 9.0) (389)
- LAM Pro:
-> SMS sending can be done with email2SMS providers (465)
diff --git a/lam/docs/manual-sources/chapter-installation.xml b/lam/docs/manual-sources/chapter-installation.xml
index 8f7c65c64..9c761534e 100644
--- a/lam/docs/manual-sources/chapter-installation.xml
+++ b/lam/docs/manual-sources/chapter-installation.xml
@@ -608,6 +608,18 @@
version. Unless explicitly noticed there is no need to install an
intermediate release.
+
+ 9.3 -> 9.4
+
+ New configuration format for main
+ configuration and server profiles is enforced. Please save your main
+ configuration and all server profiles with LAM 9.0 - 9.3 before
+ upgrading. You can also export your configuration and import all
+ server profiles and main configuration. This format change does not
+ apply if you use MySQL for configuration
+ storage.
+
+
9.2 -> 9.3
diff --git a/lam/lib/config.inc b/lam/lib/config.inc
index 3b1feae1e..1edd7a6f0 100644
--- a/lam/lib/config.inc
+++ b/lam/lib/config.inc
@@ -570,66 +570,19 @@ class ServerProfilePersistenceStrategyFiles implements ServerProfilePersistenceS
$config = new LAMConfig();
$confFilePath = $this->getPath($name);
if (!is_file($confFilePath)) {
+ logNewMessage(LOG_ERR, 'No such file ' . $confFilePath);
throw new LAMException(_('Unable to read file.'));
}
$file = @fopen($confFilePath, "r");
if (!$file) {
+ logNewMessage(LOG_ERR, 'Unable to open for reading: ' . $confFilePath);
throw new LAMException(_('Unable to read file.'));
}
$json = fread($file, 1000000);
$data = json_decode($json, true);
if ($data === null) {
- fclose($file);
- $file = @fopen($confFilePath, "r");
- $data = [];
- $moduleSettings = [];
- $typeSettings = [];
- $toolSettings = [];
- $jobSettings = [];
- while (!feof($file)) {
- $line = fgets($file, 1000000);
- $line = trim($line); // remove spaces at the beginning and end
- if (($line === "") || ($line[0] === "#")) {
- continue; // ignore comments and empty lines
- }
- // search keywords
- $parts = explode(': ', $line);
- $keyword = $parts[0];
- $keyword = trim($keyword, ':');
- $startIndex = strlen($keyword) + 2;
- $value = (count($parts) > 1) ? substr($line, $startIndex) : '';
- if (!in_array($keyword, ['modules', 'types', 'tools', 'jobs'])) {
- $data[$keyword] = $value;
- }
- else {
- $subKeyword = $parts[1];
- $startIndex = $startIndex + strlen($subKeyword) + 2;
- $option = substr($line, $startIndex);
- if (empty($option)) {
- continue;
- }
- // module settings
- if ($keyword === 'modules') {
- $moduleSettings[$subKeyword] = explode(LAMConfig::LINE_SEPARATOR, $option);
- }
- // type settings
- if ($keyword === 'types') {
- $typeSettings[$subKeyword] = $option;
- }
- // tool settings
- if ($keyword === 'tools') {
- $toolSettings[$subKeyword] = $option;
- }
- // job settings
- if ($keyword === 'jobs') {
- $jobSettings[$subKeyword] = explode(LAMConfig::LINE_SEPARATOR, $option);
- }
- }
- }
- $data['moduleSettings'] = $moduleSettings;
- $data['typeSettings'] = $typeSettings;
- $data['toolSettings'] = $toolSettings;
- $data['jobSettings'] = $jobSettings;
+ logNewMessage(LOG_ERR, 'Unable to read JSON from ' . $confFilePath);
+ throw new LAMException(_('Unable to read file.'));
}
fclose($file);
$config->importData($data);
@@ -3211,25 +3164,7 @@ class LAMCfgMain {
$this->importData($data);
}
else {
- // fallback to old format
- fclose($file);
- $file = @fopen($this->conffile, "r");
- while (!feof($file)) {
- $line = fgets($file, 1000000);
- $line = trim($line); // remove spaces at the beginning and end
- if (($line === "") || ($line[0] === "#")) {
- continue; // ignore comments
- }
- // search keywords
- for ($i = 0; $i < count($this->settings); $i++) {
- $keyword = $this->settings[$i];
- $keylen = strlen($keyword);
- if (strtolower(substr($line, 0, $keylen + 2)) === strtolower($keyword . ": ")) {
- $this->$keyword = substr($line, $keylen + 2, strlen($line) - $keylen - 2);
- break;
- }
- }
- }
+ throw new LAMException(_('The config file is not readable.'));
}
fclose($file);
}
diff --git a/lam/templates/login.php b/lam/templates/login.php
index 304ed3347..0a0afc07c 100644
--- a/lam/templates/login.php
+++ b/lam/templates/login.php
@@ -215,7 +215,7 @@ setlanguage(); // setting correct language
* @throws LAMException error rendering login page
*/
function display_LoginPage(?LAMLicenseValidator $licenseValidator, ?string $error_message, ?string $errorDetails = null, ?string $extraMessage = null): void {
- $config_object = $_SESSION['config'];
+ $config_object = $_SESSION['config'] ?? null;
$cfgMain = $_SESSION["cfgMain"];
if (!($cfgMain instanceof LAMCfgMain)) {
die();
@@ -263,6 +263,9 @@ function display_LoginPage(?LAMLicenseValidator $licenseValidator, ?string $erro
echo "
";
}
}
+ elseif ($error_message !== null) {
+ StatusMessage("ERROR", $error_message);
+ }
else {
StatusMessage('WARN', _('Please enter the configuration and create a server profile.'));
}
diff --git a/lam/tests/utils/configuration.inc b/lam/tests/utils/configuration.inc
index d980ccef4..ab189b60d 100644
--- a/lam/tests/utils/configuration.inc
+++ b/lam/tests/utils/configuration.inc
@@ -36,6 +36,9 @@ function testCreateDefaultConfig() {
unlink($cfgPath);
}
touch($cfgPath);
+ $fileHandle = fopen($cfgPath, 'w');
+ fwrite($fileHandle, '{}');
+ fclose($fileHandle);
$serverProfilePersistenceManager = new ServerProfilePersistenceManager();
$config = $serverProfilePersistenceManager->loadProfile(LAMConfigTest::FILE_NAME);
$_SESSION['config'] = $config;