3 * @copyright Copyright (C) 2010-2023, the Friendica project
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\App;
24 use Detection\MobileDetect;
25 use Friendica\Core\Config\Capability\IManageConfigValues;
26 use Friendica\Database\Database;
29 * Mode of the current Friendica Node
31 * @package Friendica\App
35 const LOCALCONFIGPRESENT = 1;
36 const DBAVAILABLE = 2;
37 const DBCONFIGAVAILABLE = 4;
38 const MAINTENANCEDISABLED = 8;
45 const BACKEND_CONTENT_TYPES = ['application/jrd+json', 'text/xml',
46 'application/rss+xml', 'application/atom+xml', 'application/activity+json'];
49 * A list of modules, which are backend methods
53 const BACKEND_MODULES = [
80 * @var int The mode of this Application
86 * @var int Who executes this Application
89 private $executor = self::UNDEFINED;
92 * @var bool True, if the call is a backend call
97 * @var bool True, if the call is a ajax call
102 * @var bool True, if the call is from a mobile device
107 * @var bool True, if the call is from a tablet device
111 public function __construct(int $mode = 0, bool $isBackend = false, bool $isAjax = false, bool $isMobile = false, bool $isTablet = false)
114 $this->isBackend = $isBackend;
115 $this->isAjax = $isAjax;
116 $this->isMobile = $isMobile;
117 $this->isTablet = $isTablet;
123 * - App::MODE_INSTALL : Either the database connection can't be established or the config table doesn't exist
124 * - App::MODE_MAINTENANCE: The maintenance mode has been set
125 * - App::MODE_NORMAL : Normal run with all features enabled
127 * @return Mode returns the determined mode
131 public function determine(string $basePath, Database $database, IManageConfigValues $config): Mode
135 if (!file_exists($basePath . '/config/local.config.php') &&
136 !file_exists($basePath . '/config/local.ini.php') &&
137 !file_exists($basePath . '/.htconfig.php')) {
138 return new Mode($mode);
141 $mode |= Mode::LOCALCONFIGPRESENT;
143 if (!$database->connected()) {
144 return new Mode($mode);
147 $mode |= Mode::DBAVAILABLE;
149 if (!empty($config->get('system', 'maintenance'))) {
150 return new Mode($mode);
153 $mode |= Mode::MAINTENANCEDISABLED;
155 return new Mode($mode, $this->isBackend, $this->isAjax, $this->isMobile, $this->isTablet);
159 * Checks if the site is called via a backend process
161 * @param bool $isBackend True, if the call is from a backend script (daemon, worker, ...)
162 * @param array $server The $_SERVER variable
163 * @param Arguments $args The Friendica App arguments
164 * @param MobileDetect $mobileDetect The mobile detection library
166 * @return Mode returns the determined mode
168 public function determineRunMode(bool $isBackend, array $server, Arguments $args, MobileDetect $mobileDetect): Mode
170 foreach (self::BACKEND_CONTENT_TYPES as $type) {
171 if (strpos(strtolower($server['HTTP_ACCEPT'] ?? ''), $type) !== false) {
176 $isBackend = $isBackend || in_array($args->getModuleName(), static::BACKEND_MODULES);
177 $isMobile = $mobileDetect->isMobile();
178 $isTablet = $mobileDetect->isTablet();
179 $isAjax = strtolower($server['HTTP_X_REQUESTED_WITH'] ?? '') == 'xmlhttprequest';
181 return new Mode($this->mode, $isBackend, $isAjax, $isMobile, $isTablet);
185 * Checks, if the Friendica Node has the given mode
187 * @param int $mode A mode to test
189 * @return bool returns true, if the mode is set
191 public function has(int $mode): bool
193 return ($this->mode & $mode) > 0;
197 * Set the execution mode
199 * @param integer $executor Execution Mode
202 public function setExecutor(int $executor)
204 $this->executor = $executor;
206 // Daemon and worker are always backend
207 if (in_array($executor, [self::DAEMON, self::WORKER])) {
208 $this->isBackend = true;
213 * get the execution mode
215 * @return int Execution Mode
217 public function getExecutor(): int
219 return $this->executor;
223 * Install mode is when the local config file is missing or the database isn't available.
225 * @return bool Whether installation mode is active (local/database configuration files present or not)
227 public function isInstall(): bool
229 return !$this->has(Mode::LOCALCONFIGPRESENT) ||
230 !$this->has(MODE::DBAVAILABLE);
234 * Normal mode is when the local config file is set, the DB schema is installed and the maintenance mode is off.
238 public function isNormal(): bool
240 return $this->has(Mode::LOCALCONFIGPRESENT) &&
241 $this->has(Mode::DBAVAILABLE) &&
242 $this->has(Mode::MAINTENANCEDISABLED);
246 * Returns true, if the call is from a backend node (f.e. from a worker)
248 * @return bool Is it a backend call
250 public function isBackend(): bool
252 return $this->isBackend;
256 * Check if request was an AJAX (xmlhttprequest) request.
258 * @return bool true if it was an AJAX request
260 public function isAjax(): bool
262 return $this->isAjax;
266 * Check if request was a mobile request.
268 * @return bool true if it was an mobile request
270 public function isMobile(): bool
272 return $this->isMobile;
276 * Check if request was a tablet request.
278 * @return bool true if it was an tablet request
280 public function isTablet(): bool
282 return $this->isTablet;