Source of file ConfigManager.php

Size: 16,459 Bytes - Last Modified: 2020-10-24T02:46:31+00:00

/home/travis/build/NextDom/nextdom-core/src/Managers/ConfigManager.php

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
<?php
/*
* This file is part of the NextDom software (https://github.com/NextDom or http://nextdom.github.io).
* Copyright (c) 2018 NextDom.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/* This file is part of Jeedom.
 *
 * Jeedom is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Jeedom is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
 */

namespace NextDom\Managers;

use NextDom\Helpers\DBHelper;
use NextDom\Helpers\DnsHelper;
use NextDom\Helpers\FileSystemHelper;
use NextDom\Helpers\NetworkHelper;
use NextDom\Helpers\NextDomHelper;
use NextDom\Helpers\Utils;

/**
 * Class ConfigManager
 * @package NextDom\Managers
 */
class ConfigManager
{

    const DB_CLASS_NAME = '`config`';

    /**
     * @var array Default configuration
     */
    private static $defaultConfiguration = [];
    /**
     * @var array Configuration cache
     */
    private static $cache = [];

    /**
     * Save new configuration value in the database
     *
     * @param string $configKey Configuration key
     * @param string|object|array $configValue Configuration value
     * @param string $pluginId Plugin id or core
     *
     * @return boolean Always True (@TODO: No return)
     * @throws \Exception
     */
    public static function save($configKey, $configValue, $pluginId = 'core')
    {
        if (is_object($configValue) || is_array($configValue)) {
            $configValue = json_encode($configValue, JSON_UNESCAPED_UNICODE);
        }
        if (isset(self::$cache[$pluginId . '::' . $configKey])) {
            unset(self::$cache[$pluginId . '::' . $configKey]);
        }
        $defaultConfiguration = self::getDefaultConfiguration($pluginId);
        // Remove configuration from the database if configValue is the same of the default configuration
        if (isset($defaultConfiguration[$pluginId][$configKey]) && $configValue == $defaultConfiguration[$pluginId][$configKey]) {
            self::remove($configKey, $pluginId);
            return true;
        }
        if ($pluginId == 'core') {
            $nextdomConfig = NextDomHelper::getConfiguration($configKey, true);
            if ($nextdomConfig != '' && $nextdomConfig == $configValue) {
                self::remove($configKey);
                return true;
            }
        }

        // Parse new value with preConfig methode
        $configClass = ($pluginId == 'core') ? 'ConfigManager' : $pluginId;
        $configMethod = 'preConfig_' . str_replace(['::', ':'], '_', $configKey);
        if (method_exists($configClass, $configMethod)) {
            $configValue = $configClass::$configMethod($configValue);
        }
        // Save in database
        $values = [
            'plugin' => $pluginId,
            'key' => $configKey,
            'value' => $configValue,
        ];
        $sql = 'REPLACE ' . self::DB_CLASS_NAME . '
                SET `key` = :key,
                    `value` = :value,
                     `plugin` = :plugin';
        DBHelper::exec($sql, $values);

        // Execute postConfig method
        $configMethod = 'postConfig_' . str_replace(['::', ':'], '_', $configKey);
        if (method_exists($configClass, $configMethod)) {
            $configClass::$configMethod($configValue);
        }
        return true;
    }

    /**
     * Get default configuration from default.config.ini
     *
     * Configuration file is in /var/lib/nextdom/config/default.config.ini or
     * NEXTDOM_ROOT/plugins/PLUGIN_ID/core/config/PLUGIN_ID.config.ini
     *
     * @param string $pluginId Target configuration plugin or core
     *
     * @return mixed
     */
    public static function getDefaultConfiguration($pluginId = 'core')
    {
        if (!isset(self::$defaultConfiguration[$pluginId])) {
            if ($pluginId === 'core') {
                self::$defaultConfiguration[$pluginId] = parse_ini_file(NEXTDOM_DATA . '/config/default.config.ini', true);
                $customPath = sprintf("%s/custom/custom.config.ini", NEXTDOM_DATA);
                if (file_exists($customPath)) {
                    $custom = parse_ini_file($customPath, true);
                    self::$defaultConfiguration[$pluginId]['core'] = array_merge(self::$defaultConfiguration[$pluginId]['core'], $custom['core']);
                }
            } else {
                $filename = NEXTDOM_ROOT . '/plugins/' . $pluginId . '/core/config/' . $pluginId . '.config.ini';
                if (is_file($filename)) {
                    self::$defaultConfiguration[$pluginId] = parse_ini_file($filename, true);
                }
            }
        }
        if (!isset(self::$defaultConfiguration[$pluginId])) {
            self::$defaultConfiguration[$pluginId] = [];
        }
        return self::$defaultConfiguration[$pluginId];
    }

    /**
     * Remove key from the database
     *
     * @param string $configKey Config key to remove (* for all config from plugin)
     * @param string $pluginId Plugin id or core
     *
     * @return boolean Always True
     * @throws \Exception
     */
    public static function remove($configKey, $pluginId = 'core')
    {
        if ($configKey == "*" && $pluginId != 'core') {
            $values = [
                'plugin' => $pluginId,
            ];
            $sql = 'DELETE FROM ' . self::DB_CLASS_NAME . '
                    WHERE `plugin` = :plugin';
            return DBHelper::getOne($sql, $values);
        } else {
            $values = [
                'plugin' => $pluginId,
                'key' => $configKey,
            ];
            $sql = 'DELETE FROM ' . self::DB_CLASS_NAME . '
                    WHERE `key` = :key
                        AND `plugin` = :plugin';
            DBHelper::exec($sql, $values);
            if (isset(self::$cache[$pluginId . '::' . $configKey])) {
                unset(self::$cache[$pluginId . '::' . $configKey]);
            }
        }
        return null;
    }

    /**
     * Get configuration by key
     *
     * @param string $configKey nom de la clé dont on veut la valeur
     * @param string $pluginId Plugin id or core
     * @param string $defaultValue Default value if config key is not found
     * @param bool $forceRefresh Force to refresh the value in the cache
     *
     * @return mixed Key value
     * @throws \Exception
     */
    public static function byKey($configKey, $pluginId = 'core', $defaultValue = '', $forceRefresh = false)
    {
        if (!$forceRefresh && isset(self::$cache[$pluginId . '::' . $configKey])) {
            return self::$cache[$pluginId . '::' . $configKey];
        }
        $values = [
            'plugin' => $pluginId,
            'key' => $configKey,
        ];
        $sql = 'SELECT `value`
                FROM ' . self::DB_CLASS_NAME . '
                WHERE `key` = :key
                AND `plugin` = :plugin';
        $value = DBHelper::getOne($sql, $values);
        if ($value['value'] === '' || $value['value'] === null) {
            if ($defaultValue !== '') {
                self::$cache[$pluginId . '::' . $configKey] = $defaultValue;
            } else {
                $defaultConfiguration = self::getDefaultConfiguration($pluginId);
                if (isset($defaultConfiguration[$pluginId][$configKey])) {
                    self::$cache[$pluginId . '::' . $configKey] = $defaultConfiguration[$pluginId][$configKey];
                }
            }
        } else {
            self::$cache[$pluginId . '::' . $configKey] = Utils::isJson($value['value'], $value['value']);
        }
        return isset(self::$cache[$pluginId . '::' . $configKey]) ? self::$cache[$pluginId . '::' . $configKey] : '';
    }

    /**
     * Get configuration by multiple keys
     *
     * @param $configKeys
     * @param string $pluginId Plugin id or core
     * @param string $defaultValue Default value if config key is not found
     *
     * @return array Keys values
     * @throws \Exception
     */
    public static function byKeys($configKeys, $pluginId = 'core', $defaultValue = '')
    {
        if (!is_array($configKeys) || count($configKeys) == 0) {
            return [];
        }
        $values = [
            'plugin' => $pluginId,
        ];
        $keys = '(\'' . implode('\',\'', $configKeys) . '\')';
        $sql = 'SELECT `key`,`value`
                FROM ' . self::DB_CLASS_NAME . '
                WHERE `key` IN ' . $keys . '
                    AND `plugin` = :plugin';
        $values = DBHelper::getAll($sql, $values);
        $result = [];
        foreach ($values as $value) {
            $result[$value['key']] = $value['value'];
        }
        $defaultConfiguration = self::getDefaultConfiguration($pluginId);
        foreach ($configKeys as $key) {
            if (isset($result[$key])) {
                $result[$key] = Utils::isJson($result[$key], $result[$key]);
            } elseif (isset($defaultConfiguration[$pluginId][$key])) {
                $result[$key] = $defaultConfiguration[$pluginId][$key];
            } else {
                if (is_array($defaultValue)) {
                    if (isset($defaultValue[$key])) {
                        $result[$key] = $defaultValue[$key];
                    } else {
                        $result[$key] = '';
                    }
                } else {
                    $result[$key] = $defaultValue;
                }
            }
            self::$cache[$pluginId . '::' . $key] = $result[$key];
        }
        return $result;
    }

    /**
     * Find config key in database
     *
     * @param string $configKey nom de la clé dont on veut la valeur
     * @param string $pluginId Plugin id or core
     * @return mixed
     * @throws \Exception
     */
    public static function searchKey($configKey, $pluginId = 'core')
    {
        $values = [
            'plugin' => $pluginId,
            'key' => '%' . $configKey . '%',
        ];
        $sql = 'SELECT *
                FROM ' . self::DB_CLASS_NAME . '
                WHERE `key` LIKE :key
                AND `plugin`= :plugin';
        $results = DBHelper::getAll($sql, $values);
        foreach ($results as &$result) {
            $result['value'] = Utils::isJson($result['value'], $result['value']);
        }
        return $results;
    }

    /**
     * Generate Key with letters and numbers
     *
     * @param int $nbCharacters Number of characters of the key
     *
     * @return string Key with $nbCharacters
     *
     * @throws \Exception
     */
    public static function genKey($nbCharacters = 32)
    {
        $key = '';
        $availableCharacters = "abcdefghijklmnpqrstuvwxy1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for ($i = 0; $i < $nbCharacters; $i++) {
            if (function_exists('random_int')) {
                $key .= $availableCharacters[random_int(0, strlen($availableCharacters) - 1)];
            } else {
                $key .= $availableCharacters[rand(0, strlen($availableCharacters) - 1)];
            }
        }
        return $key;
    }

    /**
     * Get enabled plugins
     *
     * @return array List of enabled plugins
     * @throws \Exception
     * @deprecated Use getEnabledPlugins
     *
     */
    public static function getPluginEnable()
    {
        trigger_error('The function getEnabledPlugins is deprecated, use getEnabledPlugins', E_USER_DEPRECATED);
        return self::getEnabledPlugins();
    }

    /**
     * Get enabled plugins
     *
     * @return array List of enabled plugins
     * @throws \Exception
     */
    public static function getEnabledPlugins()
    {
        $sql = 'SELECT `value`,`plugin`
                FROM ' . self::DB_CLASS_NAME . '
                WHERE `key` = \'active\'';
        $values = DBHelper::getAll($sql);
        $result = [];
        foreach ($values as $value) {
            $result[$value['plugin']] = $value['value'];
        }
        return $result;
    }

    /**
     * Get log level for all plugins
     *
     * @return array Log level of all plugins
     * @throws \Exception
     */
    public static function getLogLevelPlugin()
    {
        $sql = 'SELECT `value`,`key`
                FROM ' . self::DB_CLASS_NAME . '
                WHERE `key` LIKE \'log::level::%\'';
        $values = DBHelper::getAll($sql);
        $return = [];
        foreach ($values as $value) {
            $return[$value['key']] = Utils::isJson($value['value'], $value['value']);
        }
        return $return;
    }

    /**
     * Method called on core::allowDns config change
     *
     * @param mixed $newValue New value of core::allowDns
     * @throws \NextDom\Exceptions\CoreException
     * @throws \Throwable
     */
    public static function postConfig_market_allowDNS($newValue)
    {
        if ($newValue == 1) {
            if (!DnsHelper::dnsRun()) {
                DnsHelper::dnsStart();
            }
        } else {
            if (DnsHelper::dnsRun()) {
                DnsHelper::dnsStop();
            }
        }
    }

    public static function postConfig_interface_advance_vertCentering($_value){
        CacheManager::flushWidget();
    }

    public static function postConfig_object_summary($_value){
        try {
            foreach (JeeObjectManager::all() as $object) {
                $object->cleanSummary();
            }
        } catch (\Exception $e) {

        }
    }

    public static function checkValueBetween($_value, $_min = null, $_max = null)
    {
        if ($_min !== null && $_value < $_min) {
            return $_min;
        }
        if ($_max !== null && $_value > $_max) {
            return $_max;
        }
        if (is_nan($_value) || $_value === '') {
            return ($_min !== 0) ? $_min : 0;
        }
        return $_value;
    }

    /**
     * Method called on core::market_password config change (hash the password)
     *
     * @param mixed $newValue New market password
     *
     * @return string Password hash
     */
    public static function preConfig_market_password($newValue)
    {
        if (!Utils::isSha1($newValue)) {
            return sha1($newValue);
        }
        return $newValue;
    }

    public static function preConfig_widget_margin($_value)
    {
        return self::checkValueBetween($_value, 0);
    }

    public static function preConfig_widget_step_width($_value)
    {
        return self::checkValueBetween($_value, 1);
    }

    public static function preConfig_widget_step_height($_value)
    {
        return self::checkValueBetween($_value, 1);
    }

    public static function preConfig_css_background_opacity($_value)
    {
        return self::checkValueBetween($_value, 0, 1);
    }

    public static function preConfig_css_border_radius($_value)
    {
        return self::checkValueBetween($_value, 0, 1);
    }

    public static function preConfig_name($_value)
    {
        return str_replace(array('\\', '/', "'", '"'), '', $_value);
    }

    public static function preConfig_info_latitude($_value)
    {
        return str_replace(',', '.', $_value);
    }

    public static function preConfig_info_longitude($_value)
    {
        return str_replace(',', '.', $_value);
    }

    public static function preConfig_tts_engine($_value)
    {
        try {
            if ($_value != ConfigManager::byKey('tts::engine')) {
                FileSystemHelper::rrmdir(NextDomHelper::getTmpFolder('tts'));
            }
        } catch (\Exception $e) {

        }
        return $_value;
    }
}