Revert "application/xrd+xml" backend content type
[friendica.git/.git] / src / App / Mode.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2020, Friendica
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\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 BACKEND_CONTENT_TYPES = ['application/jrd+json', 'text/xml',
42                 'application/rss+xml', 'application/atom+xml', 'application/activity+json'];
43
44         /***
45          * @var int The mode of this Application
46          *
47          */
48         private $mode;
49
50         /**
51          * @var bool True, if the call is a backend call
52          */
53         private $isBackend;
54
55         /**
56          * @var bool True, if the call is a ajax call
57          */
58         private $isAjax;
59
60         /**
61          * @var bool True, if the call is from a mobile device
62          */
63         private $isMobile;
64
65         /**
66          * @var bool True, if the call is from a tablet device
67          */
68         private $isTablet;
69
70         public function __construct(int $mode = 0, bool $isBackend = false, bool $isAjax = false, bool $isMobile = false, bool $isTablet = false)
71         {
72                 $this->mode      = $mode;
73                 $this->isBackend = $isBackend;
74                 $this->isAjax    = $isAjax;
75                 $this->isMobile  = $isMobile;
76                 $this->isTablet  = $isTablet;
77         }
78
79         /**
80          * Sets the App mode
81          *
82          * - App::MODE_INSTALL    : Either the database connection can't be established or the config table doesn't exist
83          * - App::MODE_MAINTENANCE: The maintenance mode has been set
84          * - App::MODE_NORMAL     : Normal run with all features enabled
85          *
86          * @return Mode returns the determined mode
87          *
88          * @throws \Exception
89          */
90         public function determine(BasePath $basepath, Database $database, Cache $configCache)
91         {
92                 $mode = 0;
93
94                 $basepathName = $basepath->getPath();
95
96                 if (!file_exists($basepathName . '/config/local.config.php')
97                     && !file_exists($basepathName . '/config/local.ini.php')
98                     && !file_exists($basepathName . '/.htconfig.php')) {
99                         return new Mode($mode);
100                 }
101
102                 $mode |= Mode::LOCALCONFIGPRESENT;
103
104                 if (!$database->connected()) {
105                         return new Mode($mode);
106                 }
107
108                 $mode |= Mode::DBAVAILABLE;
109
110                 if ($database->fetchFirst("SHOW TABLES LIKE 'config'") === false) {
111                         return new Mode($mode);
112                 }
113
114                 $mode |= Mode::DBCONFIGAVAILABLE;
115
116                 if (!empty($configCache->get('system', 'maintenance')) ||
117                     // Don't use Config or Configuration here because we're possibly BEFORE initializing the Configuration,
118                     // so this could lead to a dependency circle
119                     !empty($database->selectFirst('config', ['v'], ['cat' => 'system', 'k' => 'maintenance'])['v'])) {
120                         return new Mode($mode);
121                 }
122
123                 $mode |= Mode::MAINTENANCEDISABLED;
124
125                 return new Mode($mode, $this->isBackend, $this->isAjax, $this->isMobile, $this->isTablet);
126         }
127
128         /**
129          * Checks if the site is called via a backend process
130          *
131          * @param bool         $isBackend    True, if the call is from a backend script (daemon, worker, ...)
132          * @param Module       $module       The pre-loaded module (just name, not class!)
133          * @param array        $server       The $_SERVER variable
134          * @param MobileDetect $mobileDetect The mobile detection library
135          *
136          * @return Mode returns the determined mode
137          */
138         public function determineRunMode(bool $isBackend, Module $module, array $server, MobileDetect $mobileDetect)
139         {
140                 foreach (self::BACKEND_CONTENT_TYPES as $type) {
141                         if (strpos(strtolower($server['HTTP_ACCEPT'] ?? ''), $type) !== false) {
142                                 $isBackend = true;
143                         }
144                 }
145
146                 $isBackend = $isBackend || $module->isBackend();
147                 $isMobile  = $mobileDetect->isMobile();
148                 $isTablet  = $mobileDetect->isTablet();
149                 $isAjax    = strtolower($server['HTTP_X_REQUESTED_WITH'] ?? '') == 'xmlhttprequest';
150
151                 return new Mode($this->mode, $isBackend, $isAjax, $isMobile, $isTablet);
152         }
153
154         /**
155          * Checks, if the Friendica Node has the given mode
156          *
157          * @param int $mode A mode to test
158          *
159          * @return bool returns true, if the mode is set
160          */
161         public function has($mode)
162         {
163                 return ($this->mode & $mode) > 0;
164         }
165
166
167         /**
168          * Install mode is when the local config file is missing or the DB schema hasn't been installed yet.
169          *
170          * @return bool
171          */
172         public function isInstall()
173         {
174                 return !$this->has(Mode::LOCALCONFIGPRESENT) ||
175                        !$this->has(MODE::DBCONFIGAVAILABLE);
176         }
177
178         /**
179          * Normal mode is when the local config file is set, the DB schema is installed and the maintenance mode is off.
180          *
181          * @return bool
182          */
183         public function isNormal()
184         {
185                 return $this->has(Mode::LOCALCONFIGPRESENT) &&
186                        $this->has(Mode::DBAVAILABLE) &&
187                        $this->has(Mode::DBCONFIGAVAILABLE) &&
188                        $this->has(Mode::MAINTENANCEDISABLED);
189         }
190
191         /**
192          * Returns true, if the call is from a backend node (f.e. from a worker)
193          *
194          * @return bool Is it a backend call
195          */
196         public function isBackend()
197         {
198                 return $this->isBackend;
199         }
200
201         /**
202          * Check if request was an AJAX (xmlhttprequest) request.
203          *
204          * @return bool true if it was an AJAX request
205          */
206         public function isAjax()
207         {
208                 return $this->isAjax;
209         }
210
211         /**
212          * Check if request was a mobile request.
213          *
214          * @return bool true if it was an mobile request
215          */
216         public function isMobile()
217         {
218                 return $this->isMobile;
219         }
220
221         /**
222          * Check if request was a tablet request.
223          *
224          * @return bool true if it was an tablet request
225          */
226         public function isTablet()
227         {
228                 return $this->isTablet;
229         }
230 }