$showwarning = true;
$warningtext[] = L10n::t('The database update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear.');
}
+ if (Config::get('system', 'update') == Update::FAILED) {
+ $showwarning = true;
+ $warningtext[] = L10n::t('The last update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear. (Some of the errors are possibly inside the logfile.)');
+ }
$last_worker_call = Config::get('system', 'last_worker_execution', false);
if (!$last_worker_call) {
// update config
$configFileSaver = new \Friendica\Util\Config\ConfigFileSaver($a->getBasePath());
- $configFileSaver->addConfigValue('system', 'hostname', parse_url($new_url, PHP_URL_HOST));
+ $configFileSaver->addConfigValue('config', 'hostname', parse_url($new_url, PHP_URL_HOST));
$configFileSaver->saveToConfigFile();
- Config::set('system', 'hostname', parse_url($new_url, PHP_URL_HOST));
Config::set('system', 'url', $new_url);
$a->setBaseURL($new_url);
*/
private $mode;
- /**
- * @var string The App base path
- */
- private $basePath;
-
/**
* @var string The App URL path
*/
*/
public function getBasePath()
{
- return $this->basePath;
+ return $this->config->get('system', 'basepath');
}
/**
/**
* @brief App constructor.
*
- * @param string $basePath The basedir of the app
* @param Configuration $config The Configuration
* @param App\Mode $mode The mode of this Friendica app
* @param LoggerInterface $logger The current app logger
*
* @throws Exception if the Basepath is not usable
*/
- public function __construct($basePath, Configuration $config, App\Mode $mode, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
+ public function __construct(Configuration $config, App\Mode $mode, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
{
BaseObject::setApp($this);
$this->config = $config;
$this->profiler = $profiler;
$this->mode = $mode;
- $cfgBasePath = $this->config->get('system', 'basepath');
- $this->basePath = !empty($cfgBasePath) ? $cfgBasePath : $basePath;
-
- if (!Core\System::isDirectoryUsable($this->getBasePath(), false)) {
- throw new Exception('Basepath \'' . $this->getBasePath() . '\' isn\'t usable.');
- }
- $this->basePath = rtrim($this->getBasePath(), DIRECTORY_SEPARATOR);
$this->checkBackend($isBackend);
$this->checkFriendicaApp();
namespace Friendica\Core;
+use Friendica\App;
+use Friendica\Core\Config\Cache\IConfigCache;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
+use Friendica\Util\Config\ConfigFileLoader;
+use Friendica\Util\Config\ConfigFileSaver;
use Friendica\Util\Strings;
class Update
return;
}
+ // Don't check the status if the last update was failed
+ if (Config::get('system', 'update', Update::SUCCESS, true) == Update::FAILED) {
+ return;
+ }
+
$build = Config::get('system', 'build');
if (empty($build)) {
for ($x = $stored + 1; $x <= $current; $x++) {
$r = self::runUpdateFunction($x, 'pre_update');
if (!$r) {
- break;
+ Config::set('system', 'update', Update::FAILED);
+ Lock::release('dbupdate');
+ return $r;
}
}
);
}
Logger::error('Update ERROR.', ['from' => $stored, 'to' => $current, 'retval' => $retval]);
+ Config::set('system', 'update', Update::FAILED);
Lock::release('dbupdate');
return $retval;
} else {
for ($x = $stored + 1; $x <= $current; $x++) {
$r = self::runUpdateFunction($x, 'update');
if (!$r) {
- break;
+ Config::set('system', 'update', Update::FAILED);
+ Lock::release('dbupdate');
+ return $r;
}
}
self::updateSuccessfull($stored, $current);
}
+ Config::set('system', 'update', Update::SUCCESS);
Lock::release('dbupdate');
}
}
}
}
+ /**
+ * Checks the config settings and saves given config values into the config file
+ *
+ * @param string $basePath The basepath of Friendica
+ * @param App\Mode $mode The Application mode
+ *
+ * @return bool True, if something has been saved
+ */
+ public static function saveConfigToFile($basePath, App\Mode $mode)
+ {
+ $configFileLoader = new ConfigFileLoader($basePath, $mode);
+ $configCache = new Config\Cache\ConfigCache();
+ $configFileLoader->setupCache($configCache);
+ $configFileSaver = new ConfigFileSaver($basePath);
+
+ $updated = false;
+
+ if (self::updateConfigEntry($configCache, $configFileSaver,'config', 'hostname')) {
+ $updated = true;
+ };
+ if (self::updateConfigEntry($configCache, $configFileSaver,'system', 'basepath')) {
+ $updated = true;
+ }
+
+ if (!$configFileSaver->saveToConfigFile()) {
+ Logger::alert('Config entry update failed - maybe wrong permission?');
+ return false;
+ }
+
+ DBA::delete('config', ['cat' => 'config', 'k' => 'hostname']);
+ DBA::delete('config', ['cat' => 'system', 'k' => 'basepath']);
+
+ return $updated;
+ }
+
+ /**
+ * Adds a value to the ConfigFileSave in case it isn't already updated
+ *
+ * @param IConfigCache $configCache The cached config file
+ * @param ConfigFileSaver $configFileSaver The config file saver
+ * @param string $cat The config category
+ * @param string $key The config key
+ *
+ * @return boolean True, if a value was updated
+ *
+ * @throws \Exception if DBA or Logger doesn't work
+ */
+ private static function updateConfigEntry(IConfigCache $configCache, ConfigFileSaver $configFileSaver, $cat, $key)
+ {
+ // check if the config file differs from the whole configuration (= The db contains other values)
+ $fileConfig = $configCache->get($cat, $key);
+
+ $savedConfig = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]);
+
+ if (!DBA::isResult($savedConfig)) {
+ return false;
+ }
+
+ if ($fileConfig !== $savedConfig['v']) {
+ Logger::info('Difference in config found', ['cat' => $cat, 'key' => $key, 'file' => $fileConfig, 'saved' => $savedConfig['v']]);
+ $configFileSaver->addConfigValue($cat, $key, $savedConfig['v']);
+ } else {
+ Logger::info('No Difference in config found', ['cat' => $cat, 'key' => $key, 'value' => $fileConfig, 'saved' => $savedConfig['v']]);
+ }
+
+ return true;
+ }
+
/**
* send the email and do what is needed to do on update fails
*
$logger = Factory\LoggerFactory::create($channel, $config, $profiler);
Factory\LoggerFactory::createDev($channel, $config, $profiler);
- return new App($basePath, $config, $mode, $logger, $profiler, $isBackend);
+ return new App($config, $mode, $logger, $profiler, $isBackend);
}
}
* First loads the default value for all the configuration keys, then the legacy configuration files, then the
* expected local.config.php
*
- * @param IConfigCache The config cache to load to
+ * @param IConfigCache $config The config cache to load to
*
* @throws \Exception
*/
*/
public function addConfigValue($cat, $key, $value)
{
+ $settingsCount = count(array_keys($this->settings));
+
+ for ($i = 0; $i < $settingsCount; $i++) {
+ // if already set, overwrite the value
+ if ($this->settings[$i]['cat'] === $cat &&
+ $this->settings[$i]['key'] === $key) {
+ $this->settings[$i] = ['cat' => $cat, 'key' => $key, 'value' => $value];
+ return;
+ }
+ }
+
$this->settings[] = ['cat' => $cat, 'key' => $key, 'value' => $value];
}
*
* @param string $name The name of the configuration file (default is empty, which means the default name each type)
*
- * @return bool true, if at least one configuration file was successfully updated
+ * @return bool true, if at least one configuration file was successfully updated or nothing to do
*/
public function saveToConfigFile($name = '')
{
+ // If no settings et, return true
+ if (count(array_keys($this->settings)) === 0) {
+ return true;
+ }
+
$saved = false;
// Check for the *.config.php file inside the /config/ path
return [null, null];
}
- $reading = fopen($fullName, 'r');
+ try {
+ $reading = fopen($fullName, 'r');
+ } catch (\Exception $exception) {
+ return [null, null];
+ }
if (!$reading) {
return [null, null];
}
- $writing = fopen($fullName . '.tmp', 'w');
+ try {
+ $writing = fopen($fullName . '.tmp', 'w');
+ } catch (\Exception $exception) {
+ fclose($reading);
+ return [null, null];
+ }
if (!$writing) {
fclose($reading);
fclose($reading);
fclose($writing);
- if (!rename($fullName, $fullName . '.old')) {
+ try {
+ $renamed = rename($fullName, $fullName . '.old');
+ } catch (\Exception $exception) {
+ return false;
+ }
+
+ if (!$renamed) {
+ return false;
+ }
+
+ try {
+ $renamed = rename($fullName . '.tmp', $fullName);
+ } catch (\Exception $exception) {
+ // revert the move of the current config file to have at least the old config
+ rename($fullName . '.old', $fullName);
return false;
}
- if (!rename($fullName . '.tmp', $fullName)) {
+ if (!$renamed) {
// revert the move of the current config file to have at least the old config
rename($fullName . '.old', $fullName);
return false;
// check for each added setting if we have to replace a config line
for ($i = 0; $i < $settingsCount; $i++) {
+ // find the category of the current setting
if (!$categoryFound[$i] && stristr($line, sprintf('[%s]', $this->settings[$i]['cat']))) {
$categoryFound[$i] = true;
+
+ // check the current value
} elseif ($categoryFound[$i] && preg_match_all('/^' . $this->settings[$i]['key'] . '\s*=\s*(.*?)$/', $line, $matches, PREG_SET_ORDER)) {
$line = $this->settings[$i]['key'] . ' = ' . $this->settings[$i]['value'] . PHP_EOL;
$categoryFound[$i] = false;
+
+ // If end of INI file, add the line before the INI end
} elseif ($categoryFound[$i] && (preg_match_all('/^\[.*?\]$/', $line) || preg_match_all('/^INI;.*$/', $line))) {
$categoryFound[$i] = false;
$newLine = $this->settings[$i]['key'] . ' = ' . $this->settings[$i]['value'] . PHP_EOL;
// check for each added setting if we have to replace a config line
for ($i = 0; $i < $settingsCount; $i++) {
+ // check for a non plain config setting (use category too)
if ($this->settings[$i]['cat'] !== 'config' && preg_match_all('/^\$a\-\>config\[\'' . $this->settings[$i]['cat'] . '\'\]\[\'' . $this->settings[$i]['key'] . '\'\]\s*=\s\'*(.*?)\';$/', $line, $matches, PREG_SET_ORDER)) {
$line = '$a->config[\'' . $this->settings[$i]['cat'] . '\'][\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL;
$found[$i] = true;
+
+ // check for a plain config setting (don't use a category)
} elseif ($this->settings[$i]['cat'] === 'config' && preg_match_all('/^\$a\-\>config\[\'' . $this->settings[$i]['key'] . '\'\]\s*=\s\'*(.*?)\';$/', $line, $matches, PREG_SET_ORDER)) {
$line = '$a->config[\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL;
$found[$i] = true;
namespace Friendica\Worker;
use Friendica\BaseObject;
+use Friendica\Core\Config;
use Friendica\Core\Update;
class DBUpdate extends BaseObject
{
public static function execute()
{
- Update::run(self::getApp()->getBasePath());
+ // Just in case the last update wasn't failed
+ if (Config::get('system', 'update', Update::SUCCESS, true) != Update::FAILED) {
+ Update::run(self::getApp()->getBasePath());
+ }
}
}
$config = Factory\ConfigFactory::createConfig($configCache);
Factory\ConfigFactory::createPConfig($configCache);
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
- $this->app = new App($basePath, $config, $mode, $logger, $profiler, false);
+ $this->app = new App($config, $mode, $logger, $profiler, false);
parent::setUp();
$config = Factory\ConfigFactory::createConfig($configCache);
Factory\ConfigFactory::createPConfig($configCache);
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
- $this->app = new App($basePath, $config, $mode, $logger, $profiler, false);
+ $this->app = new App($config, $mode, $logger, $profiler, false);
parent::setUp();
$config = Factory\ConfigFactory::createConfig($configCache);
Factory\ConfigFactory::createPConfig($configCache);
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
- $this->app = new App($basePath, $config, $mode, $logger, $profiler, false);
+ $this->app = new App($config, $mode, $logger, $profiler, false);
parent::setUp();
}
$configFileLoader->setupCache($configCache);
$this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
+ $this->assertEquals('frio', $configCache->get('system', 'theme'));
$this->assertNull($configCache->get('config', 'test_val'));
$this->assertNull($configCache->get('system', 'test_val2'));
- $configFileSaver->addConfigValue('system', 'theme', 'frio');
+ // update values (system and config value)
$configFileSaver->addConfigValue('config', 'admin_email', 'new@mail.it');
- $configFileSaver->addConfigValue('config', 'test_val', 'Testingwith@all.we can');
$configFileSaver->addConfigValue('system', 'theme', 'vier');
+
+ // insert values (system and config value)
+ $configFileSaver->addConfigValue('config', 'test_val', 'Testingwith@all.we can');
+ $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt First');
+
+ // overwrite value
$configFileSaver->addConfigValue('system', 'test_val2', 'TestIt Now');
+
+ // save it
$this->assertTrue($configFileSaver->saveToConfigFile());
$newConfigCache = new ConfigCache();
vfsStream::newFile($fileName)
->at($root)
->setContent(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName));
+
+ $configFileSaver = new ConfigFileSaver($this->root->url());
+
+ $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt Now');
+
+ // wrong mod, so return false if nothing to write
+ $this->assertFalse($configFileSaver->saveToConfigFile());
+ }
+
+ /**
+ * Test the saveToConfigFile() method with nothing to do
+ * @dataProvider dataConfigFiles
+ */
+ public function testNothingToDo($fileName, $filePath, $relativePath)
+ {
+ $this->delConfigFile('local.config.php');
+
+ if (empty($relativePath)) {
+ $root = $this->root;
+ $relativeFullName = $fileName;
+ } else {
+ $root = $this->root->getChild($relativePath);
+ $relativeFullName = $relativePath . DIRECTORY_SEPARATOR . $fileName;
+ }
+
+ vfsStream::newFile($fileName)
+ ->at($root)
+ ->setContent(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName));
+
+ $configFileSaver = new ConfigFileSaver($this->root->url());
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+ $configCache = new ConfigCache();
+ $configFileLoader->setupCache($configCache);
+
+ // save nothing
+ $this->assertTrue($configFileSaver->saveToConfigFile());
+
+ $this->assertTrue($this->root->hasChild($relativeFullName));
+ $this->assertFalse($this->root->hasChild($relativeFullName . '.old'));
+ $this->assertFalse($this->root->hasChild($relativeFullName . '.tmp'));
+
+ $this->assertEquals(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName), file_get_contents($this->root->getChild($relativeFullName)->url()));
}
}
<?php
+use Friendica\BaseObject;
use Friendica\Core\Addon;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Model\GContact;
use Friendica\Model\Item;
use Friendica\Model\User;
-use Friendica\Util\Config\ConfigFileSaver;
use Friendica\Util\DateTimeFormat;
/**
}
/**
- * @see https://github.com/friendica/friendica/pull/6815
- *
+ * @see https://github.com/friendica/friendica/pull/6920
* @return int Success
*/
-function update_1303()
+function update_1305()
{
- $app = \Friendica\BaseObject::getApp();
- $configCache = $app->getConfigCache();
- $configFileSaver = new ConfigFileSaver($app->getBasePath());
-
- $updateConfigEntry = function($cat, $key) use ($configCache, $configFileSaver) {
- // check if the config file differs from the whole configuration (= The db contains other values)
- $fileConfig = $configCache->get($cat, $key);
- if ($fileConfig === '!<unset>!') {
- $fileConfig = null;
- }
- $savedConfig = Config::get($cat, $key, null, true);
- if ($fileConfig !== $savedConfig) {
- Logger::info('Difference in config found', ['cat' => $cat, 'key' => $key, 'file' => $fileConfig, 'saved' => $savedConfig]);
- $configFileSaver->addConfigValue($cat, $key, $savedConfig);
- } else {
- Logger::info('No Difference in config found', ['cat' => $cat, 'key' => $key, 'value' => $fileConfig, 'saved' => $savedConfig]);
- }
- };
-
- $configFileSaver->saveToConfigFile();
-
- $updateConfigEntry('config', 'hostname');
- $updateConfigEntry('system', 'basepath');
- return Update::SUCCESS;
+ $app = BaseObject::getApp();
+ if (Update::saveConfigToFile($app->getBasePath(), $app->getMode())) {
+ return Update::SUCCESS;
+ } else {
+ return Update::FAILED;
+ }
}