]> git.mxchange.org Git - friendica.git/blob - src/App/Mode.php
Merge pull request #12583 from annando/delivery-queue
[friendica.git] / src / App / Mode.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
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.
11  *
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.
16  *
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/>.
19  *
20  */
21
22 namespace Friendica\App;
23
24 use Detection\MobileDetect;
25 use Friendica\Core\Config\ValueObject\Cache;
26 use Friendica\Database\Database;
27 use Friendica\Util\BasePath;
28
29 /**
30  * Mode of the current Friendica Node
31  *
32  * @package Friendica\App
33  */
34 class Mode
35 {
36         const LOCALCONFIGPRESENT  = 1;
37         const DBAVAILABLE         = 2;
38         const DBCONFIGAVAILABLE   = 4;
39         const MAINTENANCEDISABLED = 8;
40
41         const UNDEFINED = 0;
42         const INDEX = 1;
43         const DAEMON = 2;
44         const WORKER = 3;
45
46         const BACKEND_CONTENT_TYPES = ['application/jrd+json', 'text/xml',
47                 'application/rss+xml', 'application/atom+xml', 'application/activity+json'];
48
49         /**
50          * A list of modules, which are backend methods
51          *
52          * @var array
53          */
54         const BACKEND_MODULES = [
55                 '_well_known',
56                 'api',
57                 'dfrn_notify',
58                 'feed',
59                 'fetch',
60                 'followers',
61                 'following',
62                 'hcard',
63                 'hostxrd',
64                 'inbox',
65                 'manifest',
66                 'nodeinfo',
67                 'noscrape',
68                 'objects',
69                 'outbox',
70                 'poco',
71                 'pubsub',
72                 'pubsubhubbub',
73                 'receive',
74                 'rsd_xml',
75                 'salmon',
76                 'statistics_json',
77                 'xrd',
78         ];
79
80         /***
81          * @var int The mode of this Application
82          *
83          */
84         private $mode;
85
86         /***
87          * @var int Who executes this Application
88          *
89          */
90         private $executor = self::UNDEFINED;
91
92         /**
93          * @var bool True, if the call is a backend call
94          */
95         private $isBackend;
96
97         /**
98          * @var bool True, if the call is a ajax call
99          */
100         private $isAjax;
101
102         /**
103          * @var bool True, if the call is from a mobile device
104          */
105         private $isMobile;
106
107         /**
108          * @var bool True, if the call is from a tablet device
109          */
110         private $isTablet;
111
112         public function __construct(int $mode = 0, bool $isBackend = false, bool $isAjax = false, bool $isMobile = false, bool $isTablet = false)
113         {
114                 $this->mode      = $mode;
115                 $this->isBackend = $isBackend;
116                 $this->isAjax    = $isAjax;
117                 $this->isMobile  = $isMobile;
118                 $this->isTablet  = $isTablet;
119         }
120
121         /**
122          * Sets the App mode
123          *
124          * - App::MODE_INSTALL    : Either the database connection can't be established or the config table doesn't exist
125          * - App::MODE_MAINTENANCE: The maintenance mode has been set
126          * - App::MODE_NORMAL     : Normal run with all features enabled
127          *
128          * @return Mode returns the determined mode
129          *
130          * @throws \Exception
131          */
132         public function determine(BasePath $basepath, Database $database, Cache $configCache): Mode
133         {
134                 $mode = 0;
135
136                 $basepathName = $basepath->getPath();
137
138                 if (!file_exists($basepathName . '/config/local.config.php')
139                     && !file_exists($basepathName . '/config/local.ini.php')
140                     && !file_exists($basepathName . '/.htconfig.php')) {
141                         return new Mode($mode);
142                 }
143
144                 $mode |= Mode::LOCALCONFIGPRESENT;
145
146                 if (!$database->connected()) {
147                         return new Mode($mode);
148                 }
149
150                 $mode |= Mode::DBAVAILABLE;
151
152                 if ($database->fetchFirst("SHOW TABLES LIKE 'config'") === false) {
153                         return new Mode($mode);
154                 }
155
156                 $mode |= Mode::DBCONFIGAVAILABLE;
157
158                 if (!empty($configCache->get('system', 'maintenance')) ||
159                     // Don't use Config or Configuration here because we're possibly BEFORE initializing the Configuration,
160                     // so this could lead to a dependency circle
161                     !empty($database->selectFirst('config', ['v'], ['cat' => 'system', 'k' => 'maintenance'])['v'])) {
162                         return new Mode($mode);
163                 }
164
165                 $mode |= Mode::MAINTENANCEDISABLED;
166
167                 return new Mode($mode, $this->isBackend, $this->isAjax, $this->isMobile, $this->isTablet);
168         }
169
170         /**
171          * Checks if the site is called via a backend process
172          *
173          * @param bool             $isBackend    True, if the call is from a backend script (daemon, worker, ...)
174          * @param array            $server       The $_SERVER variable
175          * @param Arguments        $args         The Friendica App arguments
176          * @param MobileDetect     $mobileDetect The mobile detection library
177          *
178          * @return Mode returns the determined mode
179          */
180         public function determineRunMode(bool $isBackend, array $server, Arguments $args, MobileDetect $mobileDetect): Mode
181         {
182                 foreach (self::BACKEND_CONTENT_TYPES as $type) {
183                         if (strpos(strtolower($server['HTTP_ACCEPT'] ?? ''), $type) !== false) {
184                                 $isBackend = true;
185                         }
186                 }
187
188                 $isBackend = $isBackend || in_array($args->getModuleName(), static::BACKEND_MODULES);
189                 $isMobile  = $mobileDetect->isMobile();
190                 $isTablet  = $mobileDetect->isTablet();
191                 $isAjax    = strtolower($server['HTTP_X_REQUESTED_WITH'] ?? '') == 'xmlhttprequest';
192
193                 return new Mode($this->mode, $isBackend, $isAjax, $isMobile, $isTablet);
194         }
195
196         /**
197          * Checks, if the Friendica Node has the given mode
198          *
199          * @param int $mode A mode to test
200          *
201          * @return bool returns true, if the mode is set
202          */
203         public function has(int $mode): bool
204         {
205                 return ($this->mode & $mode) > 0;
206         }
207
208         /**
209          * Set the execution mode
210          *
211          * @param integer $executor Execution Mode
212          * @return void
213          */
214         public function setExecutor(int $executor)
215         {
216                 $this->executor = $executor;
217
218                 // Daemon and worker are always backend
219                 if (in_array($executor, [self::DAEMON, self::WORKER])) {
220                         $this->isBackend = true;
221                 }
222         }
223
224         /*isBackend = true;*
225          * get the execution mode
226          *
227          * @return int Execution Mode
228          */
229         public function getExecutor(): int
230         {
231                 return $this->executor;
232         }
233
234         /**
235          * Install mode is when the local config file is missing or the DB schema hasn't been installed yet.
236          *
237          * @return bool Whether installation mode is active (local/database configuration files present or not)
238          */
239         public function isInstall(): bool
240         {
241                 return !$this->has(Mode::LOCALCONFIGPRESENT) ||
242                        !$this->has(MODE::DBCONFIGAVAILABLE);
243         }
244
245         /**
246          * Normal mode is when the local config file is set, the DB schema is installed and the maintenance mode is off.
247          *
248          * @return bool
249          */
250         public function isNormal(): bool
251         {
252                 return $this->has(Mode::LOCALCONFIGPRESENT) &&
253                        $this->has(Mode::DBAVAILABLE) &&
254                        $this->has(Mode::DBCONFIGAVAILABLE) &&
255                        $this->has(Mode::MAINTENANCEDISABLED);
256         }
257
258         /**
259          * Returns true, if the call is from a backend node (f.e. from a worker)
260          *
261          * @return bool Is it a backend call
262          */
263         public function isBackend(): bool
264         {
265                 return $this->isBackend;
266         }
267
268         /**
269          * Check if request was an AJAX (xmlhttprequest) request.
270          *
271          * @return bool true if it was an AJAX request
272          */
273         public function isAjax(): bool
274         {
275                 return $this->isAjax;
276         }
277
278         /**
279          * Check if request was a mobile request.
280          *
281          * @return bool true if it was an mobile request
282          */
283         public function isMobile(): bool
284         {
285                 return $this->isMobile;
286         }
287
288         /**
289          * Check if request was a tablet request.
290          *
291          * @return bool true if it was an tablet request
292          */
293         public function isTablet(): bool
294         {
295                 return $this->isTablet;
296         }
297 }