X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FApp.php;h=0015405c46bea5892cc634282f50c6c87d62d3f8;hb=41663c7592abe55a958632c3a48265e0a8544d2b;hp=9fb63ce6792e1d1f21b13cad6663adc239b24fc8;hpb=920ffab43948d4a3081d248eb2e9f6dd5b1398e6;p=friendica.git diff --git a/src/App.php b/src/App.php index 9fb63ce679..0015405c46 100644 --- a/src/App.php +++ b/src/App.php @@ -10,9 +10,7 @@ use DOMXPath; use Exception; use Friendica\Database\DBA; use Friendica\Network\HTTPException\InternalServerErrorException; - -require_once 'boot.php'; -require_once 'include/text.php'; +use Psr\Log\LoggerInterface; /** * @@ -34,8 +32,6 @@ class App public $query_string = ''; public $config = []; public $page = []; - public $pager = []; - public $page_offset; public $profile; public $profile_uid; public $user; @@ -106,6 +102,16 @@ class App */ private $isAjax; + /** + * @var MobileDetect + */ + public $mobileDetect; + + /** + * @var LoggerInterface The current logger of this App + */ + private $logger; + /** * Register a stylesheet file path to be included in the
tag of every page. * Inclusion is done in App->initHead(). @@ -114,6 +120,7 @@ class App * @see initHead() * * @param string $path + * @throws InternalServerErrorException */ public function registerStylesheet($path) { @@ -130,6 +137,7 @@ class App * @see initFooter() * * @param string $path + * @throws InternalServerErrorException */ public function registerFooterScript($path) { @@ -138,53 +146,24 @@ class App $this->footerScripts[] = trim($url, '/'); } - /** - * @brief An array for all theme-controllable parameters - * - * Mostly unimplemented yet. Only options 'template_engine' and - * beyond are used. - */ - public $theme = [ - 'sourcename' => '', - 'videowidth' => 425, - 'videoheight' => 350, - 'force_max_items' => 0, - 'stylesheet' => '', - 'template_engine' => 'smarty3', - ]; - - /** - * @brief An array of registered template engines ('name'=>'class name') - */ - public $template_engines = []; - - /** - * @brief An array of instanced template engines ('name'=>'instance') - */ - public $template_engine_instance = []; public $process_id; public $queue; - private $ldelim = [ - 'internal' => '', - 'smarty3' => '{{' - ]; - private $rdelim = [ - 'internal' => '', - 'smarty3' => '}}' - ]; private $scheme; private $hostname; /** * @brief App constructor. * - * @param string $basePath Path to the app base folder - * @param bool $isBackend Whether it is used for backend or frontend (Default true=backend) + * @param string $basePath Path to the app base folder + * @param LoggerInterface $logger Logger of this application + * @param bool $isBackend Whether it is used for backend or frontend (Default true=backend) * * @throws Exception if the Basepath is not usable */ - public function __construct($basePath, $isBackend = true) + public function __construct($basePath, LoggerInterface $logger, $isBackend = true) { + $this->logger = $logger; + if (!static::isDirectoryUsable($basePath, false)) { throw new Exception('Basepath ' . $basePath . ' isn\'t usable.'); } @@ -248,7 +227,7 @@ class App set_include_path( get_include_path() . PATH_SEPARATOR . $this->getBasePath() . DIRECTORY_SEPARATOR . 'include' . PATH_SEPARATOR - . $this->getBasePath(). DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR + . $this->getBasePath() . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR . $this->getBasePath()); if (!empty($_SERVER['QUERY_STRING']) && strpos($_SERVER['QUERY_STRING'], 'pagename=') === 0) { @@ -303,25 +282,18 @@ class App $this->module = 'home'; } - // See if there is any page number information, and initialise pagination - $this->pager['page'] = !empty($_GET['page']) && intval($_GET['page']) > 0 ? intval($_GET['page']) : 1; - $this->pager['itemspage'] = 50; - $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage']; - - if ($this->pager['start'] < 0) { - $this->pager['start'] = 0; - } - $this->pager['total'] = 0; - // Detect mobile devices $mobile_detect = new MobileDetect(); + + $this->mobileDetect = $mobile_detect; + $this->is_mobile = $mobile_detect->isMobile(); $this->is_tablet = $mobile_detect->isTablet(); $this->isAjax = strtolower(defaults($_SERVER, 'HTTP_X_REQUESTED_WITH', '')) == 'xmlhttprequest'; // Register template engines - $this->registerTemplateEngine('Friendica\Render\FriendicaSmartyEngine'); + Core\Renderer::registerTemplateEngine('Friendica\Render\FriendicaSmartyEngine'); } /** @@ -340,6 +312,21 @@ class App return $this->mode; } + /** + * Returns the Logger of the Application + * + * @return LoggerInterface The Logger + * @throws InternalServerErrorException when the logger isn't created + */ + public function getLogger() + { + if (empty($this->logger)) { + throw new InternalServerErrorException('Logger of the Application is not defined'); + } + + return $this->logger; + } + /** * Reloads the whole app instance */ @@ -367,30 +354,32 @@ class App Core\L10n::init(); $this->process_id = Core\System::processID('log'); + + Core\Logger::setLogger($this->logger); } /** * Load the configuration files * * First loads the default value for all the configuration keys, then the legacy configuration files, then the - * expected local.ini.php + * expected local.config.php */ private function loadConfigFiles() { - $this->loadConfigFile($this->getBasePath() . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'config.ini.php'); - $this->loadConfigFile($this->getBasePath() . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'settings.ini.php'); + $this->loadConfigFile($this->getBasePath() . '/config/defaults.config.php'); + $this->loadConfigFile($this->getBasePath() . '/config/settings.config.php'); // Legacy .htconfig.php support - if (file_exists($this->getBasePath() . DIRECTORY_SEPARATOR . '.htpreconfig.php')) { + if (file_exists($this->getBasePath() . '/.htpreconfig.php')) { $a = $this; - include $this->getBasePath() . DIRECTORY_SEPARATOR . '.htpreconfig.php'; + include $this->getBasePath() . '/.htpreconfig.php'; } // Legacy .htconfig.php support - if (file_exists($this->getBasePath() . DIRECTORY_SEPARATOR . '.htconfig.php')) { + if (file_exists($this->getBasePath() . '/.htconfig.php')) { $a = $this; - include $this->getBasePath() . DIRECTORY_SEPARATOR . '.htconfig.php'; + include $this->getBasePath() . '/.htconfig.php'; $this->setConfigValue('database', 'hostname', $db_host); $this->setConfigValue('database', 'username', $db_user); @@ -418,33 +407,26 @@ class App } } - if (file_exists($this->getBasePath() . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php')) { - $this->loadConfigFile($this->getBasePath() . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php', true); + if (file_exists($this->getBasePath() . '/config/local.config.php')) { + $this->loadConfigFile($this->getBasePath() . '/config/local.config.php', true); + } elseif (file_exists($this->getBasePath() . '/config/local.ini.php')) { + $this->loadINIConfigFile($this->getBasePath() . '/config/local.ini.php', true); } } /** - * Tries to load the specified configuration file into the App->config array. + * Tries to load the specified legacy configuration file into the App->config array. * 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: - * - * $values) { - foreach ($values as $key => $value) { - if ($overwrite) { - $this->setConfigValue($category, $key, $value); - } else { - $this->setDefaultConfigValue($category, $key, $value); - } - } + $this->loadConfigArray($config, $overwrite); + } + + /** + * Tries to load the specified configuration file into the App->config array. + * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config. + * + * The config format is PHP array and the template for configuration files is the following: + * + * [ + * 'key' => 'value', + * ], + * ]; + * + * @param string $filepath + * @param bool $overwrite Force value overwrite if the config key already exists + * @throws Exception + */ + public function loadConfigFile($filepath, $overwrite = false) + { + if (!file_exists($filepath)) { + throw new Exception('Error loading non-existent config file ' . $filepath); } + + $config = include($filepath); + + if (!is_array($config)) { + throw new Exception('Error loading config file ' . $filepath); + } + + $this->loadConfigArray($config, $overwrite); } /** * Loads addons configuration files * - * First loads all activated addons default configuration throught the load_config hook, then load the local.ini.php + * First loads all activated addons default configuration through the load_config hook, then load the local.config.php * again to overwrite potential local addon configuration. */ private function loadAddonConfig() { // Loads addons default config - Core\Addon::callHooks('load_config'); + Core\Hook::callAll('load_config'); // Load the local addon config file to overwritten default addon config values - if (file_exists($this->getBasePath() . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'addon.ini.php')) { - $this->loadConfigFile($this->getBasePath() . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'addon.ini.php', true); + if (file_exists($this->getBasePath() . '/config/addon.config.php')) { + $this->loadConfigFile($this->getBasePath() . '/config/addon.config.php', true); + } elseif (file_exists($this->getBasePath() . '/config/addon.ini.php')) { + $this->loadINIConfigFile($this->getBasePath() . '/config/addon.ini.php', true); + } + } + + /** + * Tries to load the specified configuration array into the App->config array. + * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config. + * + * @param array $config + * @param bool $overwrite Force value overwrite if the config key already exists + */ + private function loadConfigArray(array $config, $overwrite = false) + { + foreach ($config as $category => $values) { + foreach ($values as $key => $value) { + if ($overwrite) { + $this->setConfigValue($category, $key, $value); + } else { + $this->setDefaultConfigValue($category, $key, $value); + } + } } } @@ -517,6 +544,7 @@ class App $relative_script_path = defaults($_SERVER, 'REDIRECT_URI' , $relative_script_path); $relative_script_path = defaults($_SERVER, 'REDIRECT_SCRIPT_URL', $relative_script_path); $relative_script_path = defaults($_SERVER, 'SCRIPT_URL' , $relative_script_path); + $relative_script_path = defaults($_SERVER, 'REQUEST_URI' , $relative_script_path); $this->urlPath = $this->getConfigValue('system', 'urlpath'); @@ -528,7 +556,7 @@ class App if (!empty($relative_script_path)) { // Module if (!empty($_SERVER['QUERY_STRING'])) { - $path = trim(dirname($relative_script_path, substr_count(trim($_SERVER['QUERY_STRING'], '/'), '/') + 1), '/'); + $path = trim(rdirname($relative_script_path, substr_count(trim($_SERVER['QUERY_STRING'], '/'), '/') + 1), '/'); } else { // Root page $path = trim($relative_script_path, '/'); @@ -554,7 +582,7 @@ class App // Use environment variables for mysql if they are set beforehand if (!empty(getenv('MYSQL_HOST')) - && (!empty(getenv('MYSQL_USERNAME')) || !empty(getenv('MYSQL_USER'))) + && !empty(getenv('MYSQL_USERNAME') || !empty(getenv('MYSQL_USER'))) && getenv('MYSQL_PASSWORD') !== false && !empty(getenv('MYSQL_DATABASE'))) { @@ -590,6 +618,7 @@ class App * finally for PWD * * @return string + * @throws InternalServerErrorException */ public function getBasePath() { @@ -649,6 +678,7 @@ class App * * @param bool $ssl Whether to append http or https under SSL_POLICY_SELFSIGN * @return string Friendica server base URL + * @throws InternalServerErrorException */ public function getBaseURL($ssl = false) { @@ -673,7 +703,7 @@ class App $this->hostname = Core\Config::get('config', 'hostname'); } - return $scheme . '://' . $this->hostname . (!empty($this->getURLPath()) ? '/' . $this->getURLPath() : '' ); + return $scheme . '://' . $this->hostname . !empty($this->getURLPath() ? '/' . $this->getURLPath() : '' ); } /** @@ -682,6 +712,7 @@ class App * Clears the baseurl cache to prevent inconsistencies * * @param string $url + * @throws InternalServerErrorException */ public function setBaseURL($url) { @@ -704,8 +735,8 @@ class App $this->urlPath = trim($parsed['path'], '\\/'); } - if (file_exists($this->getBasePath() . DIRECTORY_SEPARATOR . '.htpreconfig.php')) { - include $this->getBasePath() . DIRECTORY_SEPARATOR . '.htpreconfig.php'; + if (file_exists($this->getBasePath() . '/.htpreconfig.php')) { + include $this->getBasePath() . '/.htpreconfig.php'; } if (Core\Config::get('config', 'hostname') != '') { @@ -732,23 +763,6 @@ class App return $this->urlPath; } - public function setPagerTotal($n) - { - $this->pager['total'] = intval($n); - } - - public function setPagerItemsPage($n) - { - $this->pager['itemspage'] = ((intval($n) > 0) ? intval($n) : 0); - $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage']; - } - - public function setPagerPage($n) - { - $this->pager['page'] = $n; - $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage']; - } - /** * Initializes App->page['htmlhead']. * @@ -780,8 +794,8 @@ class App $this->page['title'] = $this->config['sitename']; } - if (!empty($this->theme['stylesheet'])) { - $stylesheet = $this->theme['stylesheet']; + if (!empty(Core\Renderer::$theme['stylesheet'])) { + $stylesheet = Core\Renderer::$theme['stylesheet']; } else { $stylesheet = $this->getCurrentThemeStylesheetPath(); } @@ -798,17 +812,14 @@ class App $touch_icon = 'images/friendica-128.png'; } - // get data wich is needed for infinite scroll on the network page - $infinite_scroll = infinite_scroll_data($this->module); - - Core\Addon::callHooks('head', $this->page['htmlhead']); + Core\Hook::callAll('head', $this->page['htmlhead']); - $tpl = get_markup_template('head.tpl'); + $tpl = Core\Renderer::getMarkupTemplate('head.tpl'); /* put the head template at the beginning of page['htmlhead'] * since the code added by the modules frequently depends on it * being first */ - $this->page['htmlhead'] = replace_macros($tpl, [ + $this->page['htmlhead'] = Core\Renderer::replaceMacros($tpl, [ '$baseurl' => $this->getBaseURL(), '$local_user' => local_user(), '$generator' => 'Friendica' . ' ' . FRIENDICA_VERSION, @@ -818,7 +829,6 @@ class App '$update_interval' => $interval, '$shortcut_icon' => $shortcut_icon, '$touch_icon' => $touch_icon, - '$infinite_scroll' => $infinite_scroll, '$block_public' => intval(Core\Config::get('system', 'block_public')), '$stylesheets' => $this->stylesheets, ]) . $this->page['htmlhead']; @@ -851,20 +861,20 @@ class App */ if ($this->is_mobile || $this->is_tablet) { if (isset($_SESSION['show-mobile']) && !$_SESSION['show-mobile']) { - $link = 'toggle_mobile?address=' . curPageURL(); + $link = 'toggle_mobile?address=' . urlencode(curPageURL()); } else { - $link = 'toggle_mobile?off=1&address=' . curPageURL(); + $link = 'toggle_mobile?off=1&address=' . urlencode(curPageURL()); } - $this->page['footer'] .= replace_macros(get_markup_template("toggle_mobile_footer.tpl"), [ + $this->page['footer'] .= Core\Renderer::replaceMacros(Core\Renderer::getMarkupTemplate("toggle_mobile_footer.tpl"), [ '$toggle_link' => $link, '$toggle_text' => Core\L10n::t('toggle mobile') ]); } - Core\Addon::callHooks('footer', $this->page['footer']); + Core\Hook::callAll('footer', $this->page['footer']); - $tpl = get_markup_template('footer.tpl'); - $this->page['footer'] = replace_macros($tpl, [ + $tpl = Core\Renderer::getMarkupTemplate('footer.tpl'); + $this->page['footer'] = Core\Renderer::replaceMacros($tpl, [ '$baseurl' => $this->getBaseURL(), '$footerScripts' => $this->footerScripts, ]) . $this->page['footer']; @@ -876,118 +886,23 @@ class App * @param string $origURL * * @return string The cleaned url + * @throws InternalServerErrorException */ public function removeBaseURL($origURL) { // Remove the hostname from the url if it is an internal link - $nurl = normalise_link($origURL); - $base = normalise_link($this->getBaseURL()); + $nurl = Util\Strings::normaliseLink($origURL); + $base = Util\Strings::normaliseLink($this->getBaseURL()); $url = str_replace($base . '/', '', $nurl); // if it is an external link return the orignal value - if ($url == normalise_link($origURL)) { + if ($url == Util\Strings::normaliseLink($origURL)) { return $origURL; } else { return $url; } } - /** - * @brief Register template engine class - * - * @param string $class - */ - private function registerTemplateEngine($class) - { - $v = get_class_vars($class); - if (!empty($v['name'])) { - $name = $v['name']; - $this->template_engines[$name] = $class; - } else { - echo "template engine $class cannot be registered without a name.\n"; - die(); - } - } - - /** - * @brief Return template engine instance. - * - * If $name is not defined, return engine defined by theme, - * or default - * - * @return object Template Engine instance - */ - public function getTemplateEngine() - { - $template_engine = defaults($this->theme, 'template_engine', 'smarty3'); - - if (isset($this->template_engines[$template_engine])) { - if (isset($this->template_engine_instance[$template_engine])) { - return $this->template_engine_instance[$template_engine]; - } else { - $class = $this->template_engines[$template_engine]; - $obj = new $class; - $this->template_engine_instance[$template_engine] = $obj; - return $obj; - } - } - - echo "template engine $template_engine is not registered!\n"; - exit(); - } - - /** - * @brief Returns the active template engine. - * - * @return string the active template engine - */ - public function getActiveTemplateEngine() - { - return $this->theme['template_engine']; - } - - /** - * sets the active template engine - * - * @param string $engine the template engine (default is Smarty3) - */ - public function setActiveTemplateEngine($engine = 'smarty3') - { - $this->theme['template_engine'] = $engine; - } - - /** - * Gets the right delimiter for a template engine - * - * Currently: - * Internal = '' - * Smarty3 = '{{' - * - * @param string $engine The template engine (default is Smarty3) - * - * @return string the right delimiter - */ - public function getTemplateLeftDelimiter($engine = 'smarty3') - { - return $this->ldelim[$engine]; - } - - /** - * Gets the left delimiter for a template engine - * - * Currently: - * Internal = '' - * Smarty3 = '}}' - * - * @param string $engine The template engine (default is Smarty3) - * - * @return string the left delimiter - */ - public function getTemplateRightDelimiter($engine = 'smarty3') - { - return $this->rdelim[$engine]; - } - /** * Saves a timestamp for a value - f.e. a call * Necessary for profiling Friendica @@ -1025,6 +940,7 @@ class App * Returns the current UserAgent as a String * * @return string the UserAgent as a String + * @throws InternalServerErrorException */ public function getUserAgent() { @@ -1133,10 +1049,10 @@ class App $processlist = DBA::processlist(); if ($processlist['list'] != '') { - logger('Processcheck: Processes: ' . $processlist['amount'] . ' - Processlist: ' . $processlist['list'], LOGGER_DEBUG); + Core\Logger::log('Processcheck: Processes: ' . $processlist['amount'] . ' - Processlist: ' . $processlist['list'], Core\Logger::DEBUG); if ($processlist['amount'] > $max_processes) { - logger('Processcheck: Maximum number of processes for ' . $process . ' tasks (' . $max_processes . ') reached.', LOGGER_DEBUG); + Core\Logger::log('Processcheck: Maximum number of processes for ' . $process . ' tasks (' . $max_processes . ') reached.', Core\Logger::DEBUG); return true; } } @@ -1148,6 +1064,7 @@ class App * @brief Checks if the minimal memory is reached * * @return bool Is the memory limit reached? + * @throws InternalServerErrorException */ public function isMinMemoryReached() { @@ -1173,16 +1090,16 @@ class App $meminfo[$key] = (int) ($meminfo[$key] / 1024); } - if (!isset($meminfo['MemAvailable']) || !isset($meminfo['MemFree'])) { + if (!isset($meminfo['MemFree'])) { return false; } - $free = $meminfo['MemAvailable'] + $meminfo['MemFree']; + $free = $meminfo['MemFree']; $reached = ($free < $min_memory); if ($reached) { - logger('Minimal memory reached: ' . $free . '/' . $meminfo['MemTotal'] . ' - limit ' . $min_memory, LOGGER_DEBUG); + Core\Logger::log('Minimal memory reached: ' . $free . '/' . $meminfo['MemTotal'] . ' - limit ' . $min_memory, Core\Logger::DEBUG); } return $reached; @@ -1192,6 +1109,7 @@ class App * @brief Checks if the maximum load is reached * * @return bool Is the load reached? + * @throws InternalServerErrorException */ public function isMaxLoadReached() { @@ -1212,7 +1130,7 @@ class App $load = Core\System::currentLoad(); if ($load) { if (intval($load) > $maxsysload) { - logger('system: load ' . $load . ' for ' . $process . ' tasks (' . $maxsysload . ') too high.'); + Core\Logger::log('system: load ' . $load . ' for ' . $process . ' tasks (' . $maxsysload . ') too high.'); return true; } } @@ -1224,6 +1142,7 @@ class App * * @param string $command The command to execute * @param array $args Arguments to pass to the command ( [ 'key' => value, 'key2' => value2, ... ] + * @throws InternalServerErrorException */ public function proc_run($command, $args) { @@ -1254,7 +1173,7 @@ class App $resource = proc_open($cmdline . ' &', [], $foo, $this->getBasePath()); } if (!is_resource($resource)) { - logger('We got no resource for command ' . $cmdline, LOGGER_DEBUG); + Core\Logger::log('We got no resource for command ' . $cmdline, Core\Logger::DEBUG); return; } proc_close($resource); @@ -1280,32 +1199,35 @@ class App /** * @brief Checks if a given directory is usable for the system * + * @param $directory + * @param bool $check_writable * @return boolean the directory is usable + * @throws Exception */ public static function isDirectoryUsable($directory, $check_writable = true) { if ($directory == '') { - logger('Directory is empty. This shouldn\'t happen.', LOGGER_DEBUG); + Core\Logger::log('Directory is empty. This shouldn\'t happen.', Core\Logger::DEBUG); return false; } if (!file_exists($directory)) { - logger('Path "' . $directory . '" does not exist for user ' . self::getSystemUser(), LOGGER_DEBUG); + Core\Logger::log('Path "' . $directory . '" does not exist for user ' . self::getSystemUser(), Core\Logger::DEBUG); return false; } if (is_file($directory)) { - logger('Path "' . $directory . '" is a file for user ' . self::getSystemUser(), LOGGER_DEBUG); + Core\Logger::log('Path "' . $directory . '" is a file for user ' . self::getSystemUser(), Core\Logger::DEBUG); return false; } if (!is_dir($directory)) { - logger('Path "' . $directory . '" is not a directory for user ' . self::getSystemUser(), LOGGER_DEBUG); + Core\Logger::log('Path "' . $directory . '" is not a directory for user ' . self::getSystemUser(), Core\Logger::DEBUG); return false; } if ($check_writable && !is_writable($directory)) { - logger('Path "' . $directory . '" is not writable for user ' . self::getSystemUser(), LOGGER_DEBUG); + Core\Logger::log('Path "' . $directory . '" is not writable for user ' . self::getSystemUser(), Core\Logger::DEBUG); return false; } @@ -1458,6 +1380,7 @@ class App * Generates the site's default sender email address * * @return string + * @throws InternalServerErrorException */ public function getSenderEmailAddress() { @@ -1478,6 +1401,7 @@ class App * Returns the current theme name. * * @return string the name of the current theme + * @throws InternalServerErrorException */ public function getCurrentTheme() { @@ -1485,14 +1409,18 @@ class App return ''; } - //// @TODO Compute the current theme only once (this behavior has - /// already been implemented, but it didn't work well - - /// https://github.com/friendica/friendica/issues/5092) - $this->computeCurrentTheme(); + if (!$this->currentTheme) { + $this->computeCurrentTheme(); + } return $this->currentTheme; } + public function setCurrentTheme($theme) + { + $this->currentTheme = $theme; + } + /** * Computes the current theme name based on the node settings, the user settings and the device type * @@ -1555,6 +1483,7 @@ class App * Provide a sane default if nothing is chosen or the specified theme does not exist. * * @return string + * @throws InternalServerErrorException */ public function getCurrentThemeStylesheetPath() { @@ -1603,7 +1532,7 @@ class App // and www.example.com vs example.com. // We will only change the url to an ip address if there is no existing setting - if (empty($url) || (!link_compare($url, $this->getBaseURL())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->getHostName()))) { + if (empty($url) || (!Util\Strings::compareLink($url, $this->getBaseURL())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->getHostName()))) { Core\Config::set('system', 'url', $this->getBaseURL()); } } @@ -1647,7 +1576,7 @@ class App } Core\Session::init(); - Core\Addon::callHooks('init_1'); + Core\Hook::callAll('init_1'); } // Exclude the backend processes from the session management @@ -1678,7 +1607,7 @@ class App } else { // Someone came with an invalid parameter, maybe as a DDoS attempt // We simply stop processing here - logger("Invalid ZRL parameter " . $_GET['zrl'], LOGGER_DEBUG); + Core\Logger::log("Invalid ZRL parameter " . $_GET['zrl'], Core\Logger::DEBUG); Core\System::httpExit(403, ['title' => '403 Forbidden']); } } @@ -1714,7 +1643,7 @@ class App $this->module = 'maintenance'; } else { $this->checkURL(); - check_db(false); + Core\Update::check(false); Core\Addon::loadAddons(); Core\Hook::loadHooks(); } @@ -1817,37 +1746,28 @@ class App } if (!empty($_SERVER['QUERY_STRING']) && ($_SERVER['QUERY_STRING'] === 'q=internal_error.html') && isset($dreamhost_error_hack)) { - logger('index.php: dreamhost_error_hack invoked. Original URI =' . $_SERVER['REQUEST_URI']); + Core\Logger::log('index.php: dreamhost_error_hack invoked. Original URI =' . $_SERVER['REQUEST_URI']); $this->internalRedirect($_SERVER['REQUEST_URI']); } - logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' . $_SERVER['QUERY_STRING'], LOGGER_DEBUG); + Core\Logger::log('index.php: page not found: ' . $_SERVER['REQUEST_URI'] . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' . $_SERVER['QUERY_STRING'], Core\Logger::DEBUG); header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . Core\L10n::t('Not Found')); - $tpl = get_markup_template("404.tpl"); - $this->page['content'] = replace_macros($tpl, [ + $tpl = Core\Renderer::getMarkupTemplate("404.tpl"); + $this->page['content'] = Core\Renderer::replaceMacros($tpl, [ '$message' => Core\L10n::t('Page not found.') ]); } } - // Load current theme info - $theme_info_file = 'view/theme/' . $this->getCurrentTheme() . '/theme.php'; - if (file_exists($theme_info_file)) { - require_once $theme_info_file; - } - - // initialise content region - if ($this->getMode()->isNormal()) { - Core\Addon::callHooks('page_content_top', $this->page['content']); - } + $content = ''; - // Call module functions + // Initialize module that can set the current theme in the init() method, either directly or via App->profile_uid if ($this->module_loaded) { $this->page['page_title'] = $this->module; $placeholder = ''; - Core\Addon::callHooks($this->module . '_mod_init', $placeholder); + Core\Hook::callAll($this->module . '_mod_init', $placeholder); call_user_func([$this->module_class, 'init']); @@ -1856,37 +1776,47 @@ class App if (!$this->error) { call_user_func([$this->module_class, 'rawContent']); } + } - if (function_exists(str_replace('-', '_', $this->getCurrentTheme()) . '_init')) { - $func = str_replace('-', '_', $this->getCurrentTheme()) . '_init'; - $func($this); - } + // Load current theme info after module has been initialized as theme could have been set in module + $theme_info_file = 'view/theme/' . $this->getCurrentTheme() . '/theme.php'; + if (file_exists($theme_info_file)) { + require_once $theme_info_file; + } + if (function_exists(str_replace('-', '_', $this->getCurrentTheme()) . '_init')) { + $func = str_replace('-', '_', $this->getCurrentTheme()) . '_init'; + $func($this); + } + + if ($this->module_loaded) { if (! $this->error && $_SERVER['REQUEST_METHOD'] === 'POST') { - Core\Addon::callHooks($this->module . '_mod_post', $_POST); + Core\Hook::callAll($this->module . '_mod_post', $_POST); call_user_func([$this->module_class, 'post']); } if (! $this->error) { - Core\Addon::callHooks($this->module . '_mod_afterpost', $placeholder); + Core\Hook::callAll($this->module . '_mod_afterpost', $placeholder); call_user_func([$this->module_class, 'afterpost']); } if (! $this->error) { - $arr = ['content' => $this->page['content']]; - Core\Addon::callHooks($this->module . '_mod_content', $arr); - $this->page['content'] = $arr['content']; + $arr = ['content' => $content]; + Core\Hook::callAll($this->module . '_mod_content', $arr); + $content = $arr['content']; $arr = ['content' => call_user_func([$this->module_class, 'content'])]; - Core\Addon::callHooks($this->module . '_mod_aftercontent', $arr); - $this->page['content'] .= $arr['content']; + Core\Hook::callAll($this->module . '_mod_aftercontent', $arr); + $content .= $arr['content']; } + } - if (function_exists(str_replace('-', '_', $this->getCurrentTheme()) . '_content_loaded')) { - $func = str_replace('-', '_', $this->getCurrentTheme()) . '_content_loaded'; - $func($this); - } + // initialise content region + if ($this->getMode()->isNormal()) { + Core\Hook::callAll('page_content_top', $this->page['content']); } + $this->page['content'] .= $content; + /* Create the page head after setting the language * and getting any auth credentials. * @@ -1909,11 +1839,11 @@ class App } // Report anything which needs to be communicated in the notification area (before the main body) - Core\Addon::callHooks('page_end', $this->page['content']); + Core\Hook::callAll('page_end', $this->page['content']); // Add the navigation (menu) template if ($this->module != 'install' && $this->module != 'maintenance') { - $this->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []); + $this->page['htmlhead'] .= Core\Renderer::replaceMacros(Core\Renderer::getMarkupTemplate('nav_head.tpl'), []); $this->page['nav'] = Content\Nav::build($this); } @@ -1939,14 +1869,14 @@ class App // And then append it to the target $target->documentElement->appendChild($item); } - } - if (isset($_GET["mode"]) && ($_GET["mode"] == "raw")) { - header("Content-type: text/html; charset=utf-8"); + if ($_GET["mode"] == "raw") { + header("Content-type: text/html; charset=utf-8"); - echo substr($target->saveHTML(), 6, -8); + echo substr($target->saveHTML(), 6, -8); - exit(); + exit(); + } } $page = $this->page; @@ -1984,6 +1914,9 @@ class App // Theme templates expect $a as an App instance $a = $this; + // Used as is in view/php/default.php + $lang = Core\L10n::getCurrentLang(); + /// @TODO Looks unsafe (remote-inclusion), is maybe not but Core\Theme::getPathForFile() uses file_exists() but does not escape anything require_once $template; } @@ -1999,7 +1932,7 @@ class App */ public function internalRedirect($toUrl = '', $ssl = false) { - if (filter_var($toUrl, FILTER_VALIDATE_URL)) { + if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) { throw new InternalServerErrorException("'$toUrl is not a relative path, please use System::externalRedirectTo"); } @@ -2012,11 +1945,11 @@ class App * Should only be used if it isn't clear if the URL is either internal or external * * @param string $toUrl The target URL - * + * @throws InternalServerErrorException */ public function redirect($toUrl) { - if (filter_var($toUrl, FILTER_VALIDATE_URL)) { + if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) { Core\System::externalRedirect($toUrl); } else { $this->internalRedirect($toUrl);