]> git.mxchange.org Git - friendica.git/blob - src/App/Mode.php
AP endpoints are now cached
[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                 'post',
72                 'pubsub',
73                 'pubsubhubbub',
74                 'receive',
75                 'rsd_xml',
76                 'salmon',
77                 'statistics_json',
78                 'xrd',
79         ];
80
81         /***
82          * @var int The mode of this Application
83          *
84          */
85         private $mode;
86
87         /***
88          * @var int Who executes this Application
89          *
90          */
91         private $executor = self::UNDEFINED;
92
93         /**
94          * @var bool True, if the call is a backend call
95          */
96         private $isBackend;
97
98         /**
99          * @var bool True, if the call is a ajax call
100          */
101         private $isAjax;
102
103         /**
104          * @var bool True, if the call is from a mobile device
105          */
106         private $isMobile;
107
108         /**
109          * @var bool True, if the call is from a tablet device
110          */
111         private $isTablet;
112
113         public function __construct(int $mode = 0, bool $isBackend = false, bool $isAjax = false, bool $isMobile = false, bool $isTablet = false)
114         {
115                 $this->mode      = $mode;
116                 $this->isBackend = $isBackend;
117                 $this->isAjax    = $isAjax;
118                 $this->isMobile  = $isMobile;
119                 $this->isTablet  = $isTablet;
120         }
121
122         /**
123          * Sets the App mode
124          *
125          * - App::MODE_INSTALL    : Either the database connection can't be established or the config table doesn't exist
126          * - App::MODE_MAINTENANCE: The maintenance mode has been set
127          * - App::MODE_NORMAL     : Normal run with all features enabled
128          *
129          * @return Mode returns the determined mode
130          *
131          * @throws \Exception
132          */
133         public function determine(BasePath $basepath, Database $database, Cache $configCache)
134         {
135                 $mode = 0;
136
137                 $basepathName = $basepath->getPath();
138
139                 if (!file_exists($basepathName . '/config/local.config.php')
140                     && !file_exists($basepathName . '/config/local.ini.php')
141                     && !file_exists($basepathName . '/.htconfig.php')) {
142                         return new Mode($mode);
143                 }
144
145                 $mode |= Mode::LOCALCONFIGPRESENT;
146
147                 if (!$database->connected()) {
148                         return new Mode($mode);
149                 }
150
151                 $mode |= Mode::DBAVAILABLE;
152
153                 if ($database->fetchFirst("SHOW TABLES LIKE 'config'") === false) {
154                         return new Mode($mode);
155                 }
156
157                 $mode |= Mode::DBCONFIGAVAILABLE;
158
159                 if (!empty($configCache->get('system', 'maintenance')) ||
160                     // Don't use Config or Configuration here because we're possibly BEFORE initializing the Configuration,
161                     // so this could lead to a dependency circle
162                     !empty($database->selectFirst('config', ['v'], ['cat' => 'system', 'k' => 'maintenance'])['v'])) {
163                         return new Mode($mode);
164                 }
165
166                 $mode |= Mode::MAINTENANCEDISABLED;
167
168                 return new Mode($mode, $this->isBackend, $this->isAjax, $this->isMobile, $this->isTablet);
169         }
170
171         /**
172          * Checks if the site is called via a backend process
173          *
174          * @param bool             $isBackend    True, if the call is from a backend script (daemon, worker, ...)
175          * @param array            $server       The $_SERVER variable
176          * @param Arguments        $args         The Friendica App arguments
177          * @param MobileDetect     $mobileDetect The mobile detection library
178          *
179          * @return Mode returns the determined mode
180          */
181         public function determineRunMode(bool $isBackend, array $server, Arguments $args, MobileDetect $mobileDetect)
182         {
183                 foreach (self::BACKEND_CONTENT_TYPES as $type) {
184                         if (strpos(strtolower($server['HTTP_ACCEPT'] ?? ''), $type) !== false) {
185                                 $isBackend = true;
186                         }
187                 }
188
189                 $isBackend = $isBackend || in_array($args->getModuleName(), static::BACKEND_MODULES);
190                 $isMobile  = $mobileDetect->isMobile();
191                 $isTablet  = $mobileDetect->isTablet();
192                 $isAjax    = strtolower($server['HTTP_X_REQUESTED_WITH'] ?? '') == 'xmlhttprequest';
193
194                 return new Mode($this->mode, $isBackend, $isAjax, $isMobile, $isTablet);
195         }
196
197         /**
198          * Checks, if the Friendica Node has the given mode
199          *
200          * @param int $mode A mode to test
201          *
202          * @return bool returns true, if the mode is set
203          */
204         public function has($mode)
205         {
206                 return ($this->mode & $mode) > 0;
207         }
208
209         /**
210          * Set the execution mode
211          *
212          * @param integer $executor Execution Mode
213          * @return void
214          */
215         public function setExecutor(int $executor)
216         {
217                 $this->executor = $executor;
218
219                 // Daemon and worker are always backend
220                 if (in_array($executor, [self::DAEMON, self::WORKER])) {
221                         $this->isBackend = true;
222                 }
223         }
224
225         /*isBackend = true;*
226          * get the execution mode
227          *
228          * @return int Execution Mode
229          */
230         public function getExecutor()
231         {
232                 return $this->executor;
233         }
234
235         /**
236          * Install mode is when the local config file is missing or the DB schema hasn't been installed yet.
237          *
238          * @return bool
239          */
240         public function isInstall()
241         {
242                 return !$this->has(Mode::LOCALCONFIGPRESENT) ||
243                        !$this->has(MODE::DBCONFIGAVAILABLE);
244         }
245
246         /**
247          * Normal mode is when the local config file is set, the DB schema is installed and the maintenance mode is off.
248          *
249          * @return bool
250          */
251         public function isNormal()
252         {
253                 return $this->has(Mode::LOCALCONFIGPRESENT) &&
254                        $this->has(Mode::DBAVAILABLE) &&
255                        $this->has(Mode::DBCONFIGAVAILABLE) &&
256                        $this->has(Mode::MAINTENANCEDISABLED);
257         }
258
259         /**
260          * Returns true, if the call is from a backend node (f.e. from a worker)
261          *
262          * @return bool Is it a backend call
263          */
264         public function isBackend()
265         {
266                 return $this->isBackend;
267         }
268
269         /**
270          * Check if request was an AJAX (xmlhttprequest) request.
271          *
272          * @return bool true if it was an AJAX request
273          */
274         public function isAjax()
275         {
276                 return $this->isAjax;
277         }
278
279         /**
280          * Check if request was a mobile request.
281          *
282          * @return bool true if it was an mobile request
283          */
284         public function isMobile()
285         {
286                 return $this->isMobile;
287         }
288
289         /**
290          * Check if request was a tablet request.
291          *
292          * @return bool true if it was an tablet request
293          */
294         public function isTablet()
295         {
296                 return $this->isTablet;
297         }
298 }