X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FApp.php;h=0dc4b86b95f6520f14bb966e45f552ff6e8ad511;hb=2a7327a41c3ea9b9910c9426956c93761bf56121;hp=eca5c4b7dbda4f7624de6f58386e64aba30fab54;hpb=d487c399dd05e65b4b0990eb7c3ee86b4cc78e22;p=friendica.git diff --git a/src/App.php b/src/App.php index eca5c4b7db..0dc4b86b95 100644 --- a/src/App.php +++ b/src/App.php @@ -4,16 +4,13 @@ */ namespace Friendica; +use Detection\MobileDetect; +use Exception; use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\PConfig; use Friendica\Core\System; -use Friendica\Database\DBM; -use dba; - -use Detection\MobileDetect; - -use Exception; +use Friendica\Database\DBA; require_once 'boot.php'; require_once 'include/dba.php'; @@ -34,9 +31,20 @@ require_once 'include/text.php'; */ class App { - const MODE_NORMAL = 0; - const MODE_INSTALL = 1; - const MODE_MAINTENANCE = 2; + const MODE_LOCALCONFIGPRESENT = 1; + const MODE_DBAVAILABLE = 2; + const MODE_DBCONFIGAVAILABLE = 4; + const MODE_MAINTENANCEDISABLED = 8; + + /** + * @deprecated since version 2008.08 Use App->isInstallMode() instead to check for install mode. + */ + const MODE_INSTALL = 0; + + /** + * @deprecated since version 2008.08 Use the precise mode constant to check for a specific capability instead. + */ + const MODE_NORMAL = App::MODE_LOCALCONFIGPRESENT | App::MODE_DBAVAILABLE | App::MODE_DBCONFIGAVAILABLE | App::MODE_MAINTENANCEDISABLED; public $module_loaded = false; public $module_class = null; @@ -59,7 +67,7 @@ class App public $argv; public $argc; public $module; - public $mode = App::MODE_NORMAL; + public $mode = App::MODE_INSTALL; public $strings; public $basepath; public $urlpath; @@ -132,6 +140,8 @@ class App * @brief App constructor. * * @param string $basepath Path to the app base folder + * + * @throws Exception if the Basepath is not usable */ public function __construct($basepath) { @@ -143,23 +153,6 @@ class App $this->basepath = rtrim($basepath, DIRECTORY_SEPARATOR); - // The order of the following calls is important to ensure proper initialization - $this->loadConfigFiles(); - - $this->loadDatabase(); - - $this->determineMode(); - - $this->determineUrlPath(); - - if ($this->mode === self::MODE_NORMAL) { - Core\Addon::loadHooks(); - - $this->loadAddonConfig(); - } - - $this->loadDefaultTimezone(); - $this->performance['start'] = microtime(true); $this->performance['database'] = 0; $this->performance['database_write'] = 0; @@ -181,21 +174,7 @@ class App $this->callstack['rendering'] = []; $this->callstack['parser'] = []; - $this->page = [ - 'aside' => '', - 'bottom' => '', - 'content' => '', - 'end' => '', - 'footer' => '', - 'htmlhead' => '', - 'nav' => '', - 'page_title' => '', - 'right_aside' => '', - 'template' => '', - 'title' => '' - ]; - - $this->process_id = System::processID('log'); + $this->reload(); set_time_limit(0); @@ -302,6 +281,47 @@ class App $this->register_template_engine('Friendica\Render\FriendicaSmartyEngine'); } + /** + * Reloads the whole app instance + */ + public function reload() + { + // The order of the following calls is important to ensure proper initialization + $this->loadConfigFiles(); + + $this->loadDatabase(); + + $this->determineMode(); + + $this->determineUrlPath(); + + Config::load(); + + if ($this->mode & self::MODE_DBAVAILABLE) { + Core\Addon::loadHooks(); + + $this->loadAddonConfig(); + } + + $this->loadDefaultTimezone(); + + $this->page = [ + 'aside' => '', + 'bottom' => '', + 'content' => '', + 'end' => '', + 'footer' => '', + 'htmlhead' => '', + 'nav' => '', + 'page_title' => '', + 'right_aside' => '', + 'template' => '', + 'title' => '' + ]; + + $this->process_id = System::processID('log'); + } + /** * Load the configuration files * @@ -310,7 +330,8 @@ class App */ private function loadConfigFiles() { - $this->loadConfigFile($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'defaults.ini.php'); + $this->loadConfigFile($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'config.ini.php'); + $this->loadConfigFile($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'settings.ini.php'); // Legacy .htconfig.php support if (file_exists($this->basepath . DIRECTORY_SEPARATOR . '.htpreconfig.php')) { @@ -323,6 +344,15 @@ class App $a = $this; include $this->basepath . DIRECTORY_SEPARATOR . '.htconfig.php'; + + $this->setConfigValue('database', 'hostname', $db_host); + $this->setConfigValue('database', 'username', $db_user); + $this->setConfigValue('database', 'password', $db_pass); + $this->setConfigValue('database', 'database', $db_data); + if (isset($a->config['system']['db_charset'])) { + $this->setConfigValue('database', 'charset', $a->config['system']['db_charset']); + } + unset($db_host, $db_user, $db_pass, $db_data); if (isset($default_timezone)) { @@ -334,16 +364,21 @@ class App $this->setConfigValue('system', 'pidfile', $pidfile); unset($pidfile); } + + if (isset($lang)) { + $this->setConfigValue('system', 'language', $lang); + unset($lang); + } } if (file_exists($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php')) { - $this->loadConfigFile($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php'); + $this->loadConfigFile($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php', true); } } /** * Tries to load the specified configuration file into the App->config array. - * Overwrites previously set values. + * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config. * * The config format is INI and the template for configuration files is the following: * @@ -356,9 +391,10 @@ class App * // Keep this line * * @param type $filepath + * @param bool $overwrite Force value overwrite if the config key already exists * @throws Exception */ - public function loadConfigFile($filepath) + public function loadConfigFile($filepath, $overwrite = false) { if (!file_exists($filepath)) { throw new Exception('Error parsing non-existent config file ' . $filepath); @@ -372,9 +408,13 @@ class App throw new Exception('Error parsing config file ' . $filepath); } - foreach($config as $category => $values) { - foreach($values as $key => $value) { - $this->setConfigValue($category, $key, $value); + foreach ($config as $category => $values) { + foreach ($values as $key => $value) { + if ($overwrite) { + $this->setConfigValue($category, $key, $value); + } else { + $this->setDefaultConfigValue($category, $key, $value); + } } } } @@ -390,9 +430,9 @@ class App // Loads addons default config Core\Addon::callHooks('load_config'); - // Load the local config file again in case there are overwritten addon config - if (file_exists($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php')) { - $this->loadConfigFile($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php'); + // Load the local addon config file to overwritten default addon config values + if (file_exists($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'addon.ini.php')) { + $this->loadConfigFile($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'addon.ini.php', true); } } @@ -429,8 +469,14 @@ class App * * To get /path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING */ - if (!empty($_SERVER['SCRIPT_URL']) && !empty($_SERVER['QUERY_STRING'])) { - $path = trim(dirname($_SERVER['SCRIPT_URL'], substr_count(trim($_SERVER['QUERY_STRING'], '/'), '/') + 1), '/'); + if (!empty($_SERVER['SCRIPT_URL'])) { + // Module + if (!empty($_SERVER['QUERY_STRING'])) { + $path = trim(dirname($_SERVER['SCRIPT_URL'], substr_count(trim($_SERVER['QUERY_STRING'], '/'), '/') + 1), '/'); + } else { + // Root page + $path = trim($_SERVER['SCRIPT_URL'], '/'); + } if ($path && $path != $this->urlpath) { $this->urlpath = $path; @@ -449,35 +495,37 @@ class App */ private function determineMode() { - $this->mode = App::MODE_INSTALL; + $this->mode = 0; - // Missing local config files: MODE_INSTALL if (!file_exists($this->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php') && !file_exists($this->basepath . DIRECTORY_SEPARATOR . '.htconfig.php')) { return; } - // Missing DB connection: ERROR - if (!\dba::connected()) { - System::unavailable(); + $this->mode |= App::MODE_LOCALCONFIGPRESENT; + + if (!DBA::connected()) { + return; } - // Working DB connection, missing tables: MODE_INSTALL - if (\dba::fetch_first("SHOW TABLES LIKE 'config'") === false) { + $this->mode |= App::MODE_DBAVAILABLE; + + if (DBA::fetchFirst("SHOW TABLES LIKE 'config'") === false) { return; } - // Maintenance mode check + $this->mode |= App::MODE_DBCONFIGAVAILABLE; + if (Config::get('system', 'maintenance')) { - $this->mode = App::MODE_MAINTENANCE; - } else { - $this->mode = App::MODE_NORMAL; + return; } + + $this->mode |= App::MODE_MAINTENANCEDISABLED; } public function loadDatabase() { - if (\dba::connected()) { + if (DBA::connected()) { return; } @@ -489,35 +537,39 @@ class App // Use environment variables for mysql if they are set beforehand if (!empty(getenv('MYSQL_HOST')) - && !empty(getenv('MYSQL_PORT')) && (!empty(getenv('MYSQL_USERNAME')) || !empty(getenv('MYSQL_USER'))) - && !empty(getenv('MYSQL_PASSWORD')) + && getenv('MYSQL_PASSWORD') !== false && !empty(getenv('MYSQL_DATABASE'))) { - $db_host = getenv('MYSQL_HOST') . ':' . getenv('MYSQL_PORT'); - + $db_host = getenv('MYSQL_HOST'); + if (!empty(getenv('MYSQL_PORT'))) { + $db_host .= ':' . getenv('MYSQL_PORT'); + } if (!empty(getenv('MYSQL_USERNAME'))) { $db_user = getenv('MYSQL_USERNAME'); - } elseif (!empty(getenv('MYSQL_USER'))) { + } else { $db_user = getenv('MYSQL_USER'); } - - $db_pass = getenv('MYSQL_PASSWORD'); + $db_pass = (string) getenv('MYSQL_PASSWORD'); $db_data = getenv('MYSQL_DATABASE'); - }elseif (file_exists($this->basepath . DIRECTORY_SEPARATOR . '.htconfig.php')) { - $a = new \stdClass(); - include $this->basepath . DIRECTORY_SEPARATOR . '.htconfig.php'; - $charset = isset($a->config["system"]["db_charset"]) ? $a->config["system"]["db_charset"] : $charset; - - unset($a); } $stamp1 = microtime(true); - \dba::connect($db_host, $db_user, $db_pass, $db_data, $charset); + DBA::connect($db_host, $db_user, $db_pass, $db_data, $charset); unset($db_host, $db_user, $db_pass, $db_data, $charset); - $this->save_timestamp($stamp1, "network"); + $this->save_timestamp($stamp1, 'network'); + } + + /** + * Install mode is when the local config file is missing or the DB schema hasn't been installed yet. + * + * @return bool + */ + public function isInstallMode() + { + return !($this->mode & App::MODE_LOCALCONFIGPRESENT) || !($this->mode & App::MODE_DBCONFIGAVAILABLE); } /** @@ -994,7 +1046,7 @@ class App } } - $processlist = DBM::processlist(); + $processlist = DBA::processlist(); if ($processlist['list'] != '') { logger('Processcheck: Processes: ' . $processlist['amount'] . ' - Processlist: ' . $processlist['list'], LOGGER_DEBUG); @@ -1027,7 +1079,11 @@ class App $meminfo = []; foreach ($memdata as $line) { - list($key, $val) = explode(':', $line); + $data = explode(':', $line); + if (count($data) != 2) { + continue; + } + list($key, $val) = $data; $meminfo[$key] = (int) trim(str_replace('kB', '', $val)); $meminfo[$key] = (int) ($meminfo[$key] / 1024); } @@ -1078,19 +1134,30 @@ class App return false; } - public function proc_run($args) + /** + * Executes a child process with 'proc_open' + * + * @param string $command The command to execute + * @param array $args Arguments to pass to the command ( [ 'key' => value, 'key2' => value2, ... ] + */ + public function proc_run($command, $args) { if (!function_exists('proc_open')) { return; } - array_unshift($args, $this->getConfigValue('config', 'php_path', 'php')); + $cmdline = $this->getConfigValue('config', 'php_path', 'php') . ' ' . escapeshellarg($command); - for ($x = 0; $x < count($args); $x ++) { - $args[$x] = escapeshellarg($args[$x]); - } + foreach ($args as $key => $value) { + if (!is_null($value) && is_bool($value) && !$value) { + continue; + } - $cmdline = implode(' ', $args); + $cmdline .= ' --' . $key; + if (!is_null($value) && !is_bool($value)) { + $cmdline .= ' ' . $value; + } + } if ($this->min_memory_reached()) { return; @@ -1182,6 +1249,20 @@ class App return $return; } + /** + * Sets a default value in the config cache. Ignores already existing keys. + * + * @param string $cat Config category + * @param string $k Config key + * @param mixed $v Default value to set + */ + private function setDefaultConfigValue($cat, $k, $v) + { + if (!isset($this->config[$cat][$k])) { + $this->setConfigValue($cat, $k, $v); + } + } + /** * Sets a value in the config cache. Accepts raw output from the config table * @@ -1259,11 +1340,11 @@ class App // Only arrays are serialized in database, so we have to unserialize sparingly $value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v; - if (!isset($this->config[$uid])) { + if (!isset($this->config[$uid]) || !is_array($this->config[$uid])) { $this->config[$uid] = []; } - if (!isset($this->config[$uid][$cat])) { + if (!isset($this->config[$uid][$cat]) || !is_array($this->config[$uid][$cat])) { $this->config[$uid][$cat] = []; } @@ -1311,7 +1392,7 @@ class App */ public function getCurrentTheme() { - if ($this->mode == App::MODE_INSTALL) { + if ($this->isInstallMode()) { return ''; } @@ -1345,22 +1426,18 @@ class App if ($this->profile_uid && ($this->profile_uid != local_user())) { // Allow folks to override user themes and always use their own on their own site. // This works only if the user is on the same server - $user = dba::selectFirst('user', ['theme'], ['uid' => $this->profile_uid]); - if (DBM::is_result($user) && !PConfig::get(local_user(), 'system', 'always_my_theme')) { + $user = DBA::selectFirst('user', ['theme'], ['uid' => $this->profile_uid]); + if (DBA::isResult($user) && !PConfig::get(local_user(), 'system', 'always_my_theme')) { $page_theme = $user['theme']; } } - if (!empty($_SESSION)) { - $user_theme = defaults($_SESSION, 'theme', $system_theme); - } else { - $user_theme = $system_theme; - } + $user_theme = Core\Session::get('theme', $system_theme); // Specific mobile theme override - if (($this->is_mobile || $this->is_tablet) && defaults($_SESSION, 'show-mobile', true)) { + if (($this->is_mobile || $this->is_tablet) && Core\Session::get('show-mobile', true)) { $system_mobile_theme = Config::get('system', 'mobile-theme'); - $user_mobile_theme = defaults($_SESSION, 'mobile-theme', $system_mobile_theme); + $user_mobile_theme = Core\Session::get('mobile-theme', $system_mobile_theme); // --- means same mobile theme as desktop if (!empty($user_mobile_theme) && $user_mobile_theme !== '---') {