]> git.mxchange.org Git - friendica.git/blob - src/Core/Config/Util/ConfigFileManager.php
Fix: Pagination in search result works again
[friendica.git] / src / Core / Config / Util / ConfigFileManager.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, 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\Core\Config\Util;
23
24 use Friendica\Core\Addon;
25 use Friendica\Core\Config\Exception\ConfigFileException;
26 use Friendica\Core\Config\ValueObject\Cache;
27
28 /**
29  * The ConfigFileLoader loads and saves config-files and stores them in a ConfigCache ( @see Cache )
30  *
31  * It is capable of loading the following config files:
32  * - *.config.php   (current)
33  * - *.ini.php      (deprecated)
34  * - *.htconfig.php (deprecated)
35  */
36 class ConfigFileManager
37 {
38         /**
39          * The default name of the user defined legacy config file
40          *
41          * @var string
42          */
43         const CONFIG_HTCONFIG = 'htconfig';
44
45         /**
46          * The config file, where overrides per admin page/console are saved at
47          *
48          * @var string
49          */
50         const CONFIG_DATA_FILE = 'node.config.php';
51
52         /**
53          * The sample string inside the configs, which shouldn't get loaded
54          *
55          * @var string
56          */
57         const SAMPLE_END = '-sample';
58
59         /**
60          * @var string
61          */
62         private $baseDir;
63         /**
64          * @var string
65          */
66         private $configDir;
67         /**
68          * @var string
69          */
70         private $staticDir;
71
72         /**
73          * @var array
74          */
75         private $server;
76
77         /**
78          * @param string $baseDir   The base
79          * @param string $configDir
80          * @param string $staticDir
81          */
82         public function __construct(string $baseDir, string $configDir, string $staticDir, array $server = [])
83         {
84                 $this->baseDir   = $baseDir;
85                 $this->configDir = $configDir;
86                 $this->staticDir = $staticDir;
87                 $this->server    = $server;
88         }
89
90         /**
91          * Load the configuration files into an configuration cache
92          *
93          * First loads the default value for all the configuration keys, then the legacy configuration files, then the
94          * expected local.config.php
95          *
96          * @param Cache $configCache The config cache to load to
97          * @param bool  $raw         Set up the raw config format
98          *
99          * @throws ConfigFileException
100          */
101         public function setupCache(Cache $configCache, bool $raw = false)
102         {
103                 // Load static config files first, the order is important
104                 $configCache->load($this->loadStaticConfig('defaults'), Cache::SOURCE_STATIC);
105                 $configCache->load($this->loadStaticConfig('settings'), Cache::SOURCE_STATIC);
106
107                 // try to load the legacy config first
108                 $configCache->load($this->loadLegacyConfig('htpreconfig'), Cache::SOURCE_FILE);
109                 $configCache->load($this->loadLegacyConfig('htconfig'), Cache::SOURCE_FILE);
110
111                 // Now load every other config you find inside the 'config/' directory
112                 $this->loadCoreConfig($configCache);
113
114                 $configCache->load($this->loadEnvConfig(), Cache::SOURCE_ENV);
115
116                 // In case of install mode, add the found basepath (because there isn't a basepath set yet
117                 if (!$raw && empty($configCache->get('system', 'basepath'))) {
118                         // Setting at least the basepath we know
119                         $configCache->set('system', 'basepath', $this->baseDir, Cache::SOURCE_FILE);
120                 }
121         }
122
123         /**
124          * Tries to load the static core-configuration and returns the config array.
125          *
126          * @param string $name The name of the configuration
127          *
128          * @return array The config array (empty if no config found)
129          *
130          * @throws ConfigFileException if the configuration file isn't readable
131          */
132         private function loadStaticConfig(string $name): array
133         {
134                 $configName = $this->staticDir . DIRECTORY_SEPARATOR . $name . '.config.php';
135                 $iniName    = $this->staticDir . DIRECTORY_SEPARATOR . $name . '.ini.php';
136
137                 if (file_exists($configName)) {
138                         return $this->loadConfigFile($configName);
139                 } else if (file_exists($iniName)) {
140                         return $this->loadINIConfigFile($iniName);
141                 } else {
142                         return [];
143                 }
144         }
145
146         /**
147          * Tries to load the specified core-configuration into the config cache.
148          *
149          * @param Cache $configCache The Config cache
150          *
151          * @throws ConfigFileException if the configuration file isn't readable
152          */
153         private function loadCoreConfig(Cache $configCache)
154         {
155                 // try to load legacy ini-files first
156                 foreach ($this->getConfigFiles(true) as $configFile) {
157                         $configCache->load($this->loadINIConfigFile($configFile), Cache::SOURCE_FILE);
158                 }
159
160                 // try to load supported config at last to overwrite it
161                 foreach ($this->getConfigFiles() as $configFile) {
162                         $configCache->load($this->loadConfigFile($configFile), Cache::SOURCE_FILE);
163                 }
164         }
165
166         /**
167          * Tries to load the specified addon-configuration and returns the config array.
168          *
169          * @param string $name The name of the configuration
170          *
171          * @return array The config array (empty if no config found)
172          *
173          * @throws ConfigFileException if the configuration file isn't readable
174          */
175         public function loadAddonConfig(string $name): array
176         {
177                 $filepath = $this->baseDir . DIRECTORY_SEPARATOR .   // /var/www/html/
178                                         Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/
179                                         $name . DIRECTORY_SEPARATOR .            // openstreetmap/
180                                         'config' . DIRECTORY_SEPARATOR .         // config/
181                                         $name . ".config.php";                   // openstreetmap.config.php
182
183                 if (file_exists($filepath)) {
184                         return $this->loadConfigFile($filepath);
185                 } else {
186                         return [];
187                 }
188         }
189
190         /**
191          * Tries to load environment specific variables, based on the `env.config.php` mapping table
192          *
193          * @return array The config array (empty if no config was found)
194          *
195          * @throws ConfigFileException if the configuration file isn't readable
196          */
197         protected function loadEnvConfig(): array
198         {
199                 $filepath = $this->staticDir . DIRECTORY_SEPARATOR .   // /var/www/html/static/
200                                         "env.config.php";                          // env.config.php
201
202                 if (!file_exists($filepath)) {
203                         return [];
204                 }
205
206                 $envConfig = $this->loadConfigFile($filepath);
207
208                 $return = [];
209
210                 foreach ($envConfig as $envKey => $configStructure) {
211                         if (isset($this->server[$envKey])) {
212                                 $return[$configStructure[0]][$configStructure[1]] = $this->server[$envKey];
213                         }
214                 }
215
216                 return $return;
217         }
218
219         /**
220          * Get the config files of the config-directory
221          *
222          * @param bool $ini True, if scan for ini-files instead of config files
223          *
224          * @return array
225          */
226         private function getConfigFiles(bool $ini = false): array
227         {
228                 $files = scandir($this->configDir);
229                 $found = [];
230
231                 $filePattern = ($ini ? '*.ini.php' : '*.config.php');
232
233                 // Don't load sample files
234                 $sampleEnd = self::SAMPLE_END . ($ini ? '.ini.php' : '.config.php');
235
236                 foreach ($files as $filename) {
237                         if (fnmatch($filePattern, $filename) &&
238                                 substr_compare($filename, $sampleEnd, -strlen($sampleEnd)) &&
239                                 $filename !== self::CONFIG_DATA_FILE) {
240                                 $found[] = $this->configDir . '/' . $filename;
241                         }
242                 }
243
244                 return $found;
245         }
246
247         /**
248          * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array.
249          *
250          * @param string $name The name of the config file (default is empty, which means .htconfig.php)
251          *
252          * @return array The configuration array (empty if no config found)
253          *
254          * @deprecated since version 2018.09
255          */
256         private function loadLegacyConfig(string $name = ''): array
257         {
258                 $name     = !empty($name) ? $name : self::CONFIG_HTCONFIG;
259                 $fullName = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php';
260
261                 $config = [];
262                 if (file_exists($fullName)) {
263                         $a         = new \stdClass();
264                         $a->config = [];
265                         include $fullName;
266
267                         $htConfigCategories = array_keys($a->config);
268
269                         // map the legacy configuration structure to the current structure
270                         foreach ($htConfigCategories as $htConfigCategory) {
271                                 if (is_array($a->config[$htConfigCategory])) {
272                                         $keys = array_keys($a->config[$htConfigCategory]);
273
274                                         foreach ($keys as $key) {
275                                                 $config[$htConfigCategory][$key] = $a->config[$htConfigCategory][$key];
276                                         }
277                                 } else {
278                                         $config['config'][$htConfigCategory] = $a->config[$htConfigCategory];
279                                 }
280                         }
281
282                         unset($a);
283
284                         if (isset($db_host)) {
285                                 $config['database']['hostname'] = $db_host;
286                                 unset($db_host);
287                         }
288                         if (isset($db_user)) {
289                                 $config['database']['username'] = $db_user;
290                                 unset($db_user);
291                         }
292                         if (isset($db_pass)) {
293                                 $config['database']['password'] = $db_pass;
294                                 unset($db_pass);
295                         }
296                         if (isset($db_data)) {
297                                 $config['database']['database'] = $db_data;
298                                 unset($db_data);
299                         }
300                         if (isset($config['system']['db_charset'])) {
301                                 $config['database']['charset'] = $config['system']['db_charset'];
302                         }
303                         if (isset($pidfile)) {
304                                 $config['system']['pidfile'] = $pidfile;
305                                 unset($pidfile);
306                         }
307                         if (isset($default_timezone)) {
308                                 $config['system']['default_timezone'] = $default_timezone;
309                                 unset($default_timezone);
310                         }
311                         if (isset($lang)) {
312                                 $config['system']['language'] = $lang;
313                                 unset($lang);
314                         }
315                 }
316
317                 return $config;
318         }
319
320         /**
321          * Tries to load the specified legacy configuration file and returns the config array.
322          *
323          * @param string $filepath
324          *
325          * @return array The configuration array
326          * @throws ConfigFileException
327          * @deprecated since version 2018.12
328          */
329         private function loadINIConfigFile(string $filepath): array
330         {
331                 $contents = include($filepath);
332
333                 $config = parse_ini_string($contents, true, INI_SCANNER_TYPED);
334
335                 if ($config === false) {
336                         throw new ConfigFileException('Error parsing INI config file ' . $filepath);
337                 }
338
339                 return $config;
340         }
341
342         /**
343          * Tries to load the specified configuration file and returns the config array.
344          *
345          * The config format is PHP array and the template for configuration files is the following:
346          *
347          * <?php return [
348          *      'section' => [
349          *          'key' => 'value',
350          *      ],
351          * ];
352          *
353          * @param string $filepath The filepath of the
354          *
355          * @return array The config array0
356          *
357          * @throws ConfigFileException if the config cannot get loaded.
358          */
359         private function loadConfigFile(string $filepath): array
360         {
361                 if (file_exists($filepath)) {
362                         $config = include $filepath;
363
364                         if (!is_array($config)) {
365                                 throw new ConfigFileException('Error loading config file ' . $filepath);
366                         }
367
368                         return $config;
369                 } else {
370                         return [];
371                 }
372         }
373 }