PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.2.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.2.2
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Config.php
matomo / app / core Last commit date
API 1 year ago Access 1 year ago Application 1 year ago Archive 1 year ago ArchiveProcessor 1 year ago Archiver 2 years ago AssetManager 1 year ago Auth 1 year ago Category 2 years ago Changes 1 year ago CliMulti 1 year ago Columns 1 year ago Concurrency 1 year ago Config 1 year ago Container 1 year ago CronArchive 1 year ago DataAccess 1 year ago DataFiles 2 years ago DataTable 1 year ago Db 1 year ago DeviceDetector 1 year ago Email 2 years ago Exception 1 year ago Http 1 year ago Intl 1 year ago Log 2 years ago Mail 1 year ago Measurable 1 year ago Menu 1 year ago Metrics 1 year ago Notification 1 year ago Period 1 year ago Plugin 1 year ago ProfessionalServices 1 year ago Report 1 year ago ReportRenderer 1 year ago Scheduler 1 year ago Segment 1 year ago Session 1 year ago Settings 1 year ago Tracker 1 year ago Translation 1 year ago Twig 1 year ago UpdateCheck 1 year ago Updater 1 year ago Updates 1 year ago Validators 1 year ago View 1 year ago ViewDataTable 1 year ago Visualization 1 year ago Widget 1 year ago .htaccess 2 years ago Access.php 1 year ago Archive.php 1 year ago ArchiveProcessor.php 1 year ago AssetManager.php 1 year ago Auth.php 2 years ago AuthResult.php 2 years ago BaseFactory.php 2 years ago Cache.php 2 years ago CacheId.php 1 year ago CliMulti.php 1 year ago Common.php 1 year ago Config.php 1 year ago Console.php 1 year ago Context.php 2 years ago Cookie.php 1 year ago CronArchive.php 1 year ago DI.php 1 year ago DataArray.php 1 year ago DataTable.php 1 year ago Date.php 1 year ago Db.php 1 year ago DbHelper.php 1 year ago Development.php 1 year ago ErrorHandler.php 1 year ago EventDispatcher.php 1 year ago ExceptionHandler.php 1 year ago FileIntegrity.php 1 year ago Filechecks.php 1 year ago Filesystem.php 1 year ago FrontController.php 1 year ago Http.php 1 year ago IP.php 1 year ago Log.php 2 years ago LogDeleter.php 1 year ago Mail.php 1 year ago Metrics.php 1 year ago NoAccessException.php 2 years ago Nonce.php 1 year ago Notification.php 1 year ago NumberFormatter.php 1 year ago Option.php 1 year ago Period.php 1 year ago Piwik.php 1 year ago Plugin.php 1 year ago Process.php 1 year ago Profiler.php 1 year ago ProxyHeaders.php 2 years ago ProxyHttp.php 1 year ago QuickForm2.php 1 year ago RankingQuery.php 1 year ago ReportRenderer.php 1 year ago Request.php 1 year ago Segment.php 1 year ago Sequence.php 2 years ago Session.php 1 year ago SettingsPiwik.php 1 year ago SettingsServer.php 1 year ago Singleton.php 2 years ago Site.php 1 year ago SiteContentDetector.php 1 year ago SupportedBrowser.php 2 years ago TCPDF.php 1 year ago Theme.php 1 year ago Timer.php 2 years ago Tracker.php 1 year ago Twig.php 1 year ago Unzip.php 1 year ago UpdateCheck.php 1 year ago Updater.php 1 year ago UpdaterErrorException.php 2 years ago Updates.php 1 year ago Url.php 1 year ago UrlHelper.php 1 year ago Version.php 1 year ago View.php 1 year ago bootstrap.php 1 year ago dispatch.php 2 years ago testMinimumPhpVersion.php 2 years ago
Config.php
430 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 */
9 namespace Piwik;
10
11 use Exception;
12 use Piwik\Application\Kernel\GlobalSettingsProvider;
13 use Piwik\Container\StaticContainer;
14 use Piwik\Exception\MissingFilePermissionException;
15 use Piwik\Plugins\CoreAdminHome\Controller;
16 use Piwik\Plugins\CorePluginsAdmin\CorePluginsAdmin;
17 use Piwik\ProfessionalServices\Advertising;
18 use Piwik\Log\LoggerInterface;
19 /**
20 * Singleton that provides read & write access to Piwik's INI configuration.
21 *
22 * This class reads and writes to the `config/config.ini.php` file. If config
23 * options are missing from that file, this class will look for their default
24 * values in `config/global.ini.php`.
25 *
26 * ### Examples
27 *
28 * **Getting a value:**
29 *
30 * // read the minimum_memory_limit option under the [General] section
31 * $minValue = Config::getInstance()->General['minimum_memory_limit'];
32 *
33 * **Setting a value:**
34 *
35 * // set the minimum_memory_limit option
36 * Config::getInstance()->General['minimum_memory_limit'] = 256;
37 * Config::getInstance()->forceSave();
38 *
39 * **Setting an entire section:**
40 *
41 * Config::getInstance()->MySection = array('myoption' => 1);
42 * Config::getInstance()->forceSave();
43 */
44 class Config
45 {
46 public const DEFAULT_LOCAL_CONFIG_PATH = '/config/config.ini.php';
47 public const DEFAULT_COMMON_CONFIG_PATH = '/config/common.config.ini.php';
48 public const DEFAULT_GLOBAL_CONFIG_PATH = '/config/global.ini.php';
49 /**
50 * @var boolean
51 */
52 protected $doNotWriteConfigInTests = \false;
53 /**
54 * @var GlobalSettingsProvider
55 */
56 protected $settings;
57 /**
58 * @return Config
59 */
60 public static function getInstance()
61 {
62 return StaticContainer::get('Piwik\\Config');
63 }
64 public function __construct(GlobalSettingsProvider $settings)
65 {
66 $this->settings = $settings;
67 }
68 /**
69 * Returns the path to the local config file used by this instance.
70 *
71 * @return string
72 */
73 public function getLocalPath()
74 {
75 return $this->settings->getPathLocal();
76 }
77 /**
78 * Returns the path to the global config file used by this instance.
79 *
80 * @return string
81 */
82 public function getGlobalPath()
83 {
84 return $this->settings->getPathGlobal();
85 }
86 /**
87 * Returns the path to the common config file used by this instance.
88 *
89 * @return string
90 */
91 public function getCommonPath()
92 {
93 return $this->settings->getPathCommon();
94 }
95 /**
96 * Returns absolute path to the global configuration file
97 *
98 * @return string
99 */
100 public static function getGlobalConfigPath()
101 {
102 return PIWIK_DOCUMENT_ROOT . self::DEFAULT_GLOBAL_CONFIG_PATH;
103 }
104 /**
105 * Returns absolute path to the common configuration file.
106 *
107 * @return string
108 */
109 public static function getCommonConfigPath()
110 {
111 return PIWIK_USER_PATH . self::DEFAULT_COMMON_CONFIG_PATH;
112 }
113 /**
114 * Returns default absolute path to the local configuration file.
115 *
116 * @return string
117 */
118 public static function getDefaultLocalConfigPath()
119 {
120 return PIWIK_USER_PATH . self::DEFAULT_LOCAL_CONFIG_PATH;
121 }
122 /**
123 * Returns absolute path to the local configuration file
124 *
125 * @return string
126 */
127 public static function getLocalConfigPath()
128 {
129 if (!empty($GLOBALS['CONFIG_INI_PATH_RESOLVER']) && is_callable($GLOBALS['CONFIG_INI_PATH_RESOLVER'])) {
130 return call_user_func($GLOBALS['CONFIG_INI_PATH_RESOLVER']);
131 }
132 $path = self::getByDomainConfigPath();
133 if ($path) {
134 return $path;
135 }
136 return self::getDefaultLocalConfigPath();
137 }
138 private static function getLocalConfigInfoForHostname($hostname)
139 {
140 if (!$hostname) {
141 return array();
142 }
143 // Remove any port number to get actual hostname
144 $hostname = \Piwik\Url::getHostSanitized($hostname);
145 $standardConfigName = 'config.ini.php';
146 $perHostFilename = $hostname . '.' . $standardConfigName;
147 $pathDomainConfig = PIWIK_USER_PATH . '/config/' . $perHostFilename;
148 $pathDomainMiscUser = PIWIK_USER_PATH . '/misc/user/' . $hostname . '/' . $standardConfigName;
149 $locations = array(array('file' => $perHostFilename, 'path' => $pathDomainConfig), array('file' => $standardConfigName, 'path' => $pathDomainMiscUser));
150 return $locations;
151 }
152 public function getConfigHostnameIfSet()
153 {
154 if ($this->getByDomainConfigPath() === \false) {
155 return \false;
156 }
157 return $this->getHostname();
158 }
159 public function getClientSideOptions()
160 {
161 $general = $this->General;
162 return array('action_url_category_delimiter' => $general['action_url_category_delimiter'], 'action_title_category_delimiter' => $general['action_title_category_delimiter'], 'are_ads_enabled' => Advertising::isAdsEnabledInConfig($general), 'autocomplete_min_sites' => $general['autocomplete_min_sites'], 'datatable_export_range_as_day' => $general['datatable_export_range_as_day'], 'datatable_row_limits' => $this->getDatatableRowLimits(), 'enable_general_settings_admin' => Controller::isGeneralSettingsAdminEnabled(), 'enable_plugins_admin' => CorePluginsAdmin::isPluginsAdminEnabled());
163 }
164 /**
165 * @param $general
166 * @return mixed
167 */
168 private function getDatatableRowLimits()
169 {
170 $limits = $this->General['datatable_row_limits'];
171 $limits = explode(",", $limits);
172 $limits = array_map('trim', $limits);
173 return $limits;
174 }
175 public static function getByDomainConfigPath()
176 {
177 $host = self::getHostname();
178 $hostConfigs = self::getLocalConfigInfoForHostname($host);
179 foreach ($hostConfigs as $hostConfig) {
180 if (\Piwik\Filesystem::isValidFilename($hostConfig['file']) && file_exists($hostConfig['path'])) {
181 return $hostConfig['path'];
182 }
183 }
184 return \false;
185 }
186 /**
187 * Returns the hostname of the current request (without port number)
188 * @param bool $checkIfTrusted Check trusted requires config which is maybe not ready yet,
189 * make sure the config is ready when you call with true
190 *
191 * @return string
192 */
193 public static function getHostname($checkIfTrusted = \false)
194 {
195 $host = \Piwik\Url::getHost($checkIfTrusted);
196 // Remove any port number to get actual hostname
197 $host = \Piwik\Url::getHostSanitized($host);
198 return $host;
199 }
200 /**
201 * If set, Piwik will use the hostname config no matter if it exists or not. Useful for instance if you want to
202 * create a new hostname config:
203 *
204 * $config = Config::getInstance();
205 * $config->forceUsageOfHostnameConfig('piwik.example.com');
206 * $config->save();
207 *
208 * @param string $hostname eg piwik.example.com
209 * @param string $preferredPath If there are different paths for the config that can be used, eg /config/* and /misc/user/*,
210 * and a preferred path is given, then the config path must contain the preferred path.
211 * @return string
212 * @throws \Exception In case the domain contains not allowed characters
213 * @internal
214 */
215 public function forceUsageOfLocalHostnameConfig($hostname, $preferredPath = null)
216 {
217 $hostConfigs = self::getLocalConfigInfoForHostname($hostname);
218 $fileNames = '';
219 foreach ($hostConfigs as $hostConfig) {
220 if (count($hostConfigs) > 1 && $preferredPath && strpos($hostConfig['path'], $preferredPath) === \false) {
221 continue;
222 }
223 $filename = $hostConfig['file'];
224 $fileNames .= $filename . ' ';
225 if (\Piwik\Filesystem::isValidFilename($filename)) {
226 $pathLocal = $hostConfig['path'];
227 try {
228 $this->reload($pathLocal);
229 } catch (Exception $ex) {
230 // pass (not required for local file to exist at this point)
231 }
232 return $pathLocal;
233 }
234 }
235 throw new Exception('Matomo domain is not a valid looking hostname (' . trim($fileNames) . ').');
236 }
237 /**
238 * Returns `true` if the local configuration file is writable.
239 *
240 * @return bool
241 */
242 public function isFileWritable()
243 {
244 return is_writable($this->settings->getPathLocal());
245 }
246 /**
247 * Reloads config data from disk.
248 *
249 * @throws \Exception if the global config file is not found and this is a tracker request, or
250 * if the local config file is not found and this is NOT a tracker request.
251 */
252 protected function reload($pathLocal = null, $pathGlobal = null, $pathCommon = null)
253 {
254 $this->settings->reload($pathGlobal, $pathLocal, $pathCommon);
255 }
256 public function existsLocalConfig()
257 {
258 return is_readable($this->getLocalPath());
259 }
260 public function deleteLocalConfig()
261 {
262 $configLocal = $this->getLocalPath();
263 if (file_exists($configLocal)) {
264 @unlink($configLocal);
265 }
266 }
267 /**
268 * Returns a configuration value or section by name.
269 *
270 * @param string $name The value or section name.
271 * @return string|array The requested value requested. Returned by reference.
272 * @throws Exception If the value requested not found in either `config.ini.php` or
273 * `global.ini.php`.
274 * @api
275 */
276 public function &__get($name)
277 {
278 $section =& $this->settings->getIniFileChain()->get($name);
279 return $section;
280 }
281 /**
282 * @api
283 */
284 public function getFromGlobalConfig($name)
285 {
286 return $this->settings->getIniFileChain()->getFrom($this->getGlobalPath(), $name);
287 }
288 /**
289 * @api
290 */
291 public function getFromCommonConfig($name)
292 {
293 return $this->settings->getIniFileChain()->getFrom($this->getCommonPath(), $name);
294 }
295 /**
296 * @api
297 */
298 public function getFromLocalConfig($name)
299 {
300 return $this->settings->getIniFileChain()->getFrom($this->getLocalPath(), $name);
301 }
302 /**
303 * Sets a configuration value or section.
304 *
305 * @param string $name This section name or value name to set.
306 * @param mixed $value
307 * @api
308 */
309 public function __set($name, $value)
310 {
311 $this->settings->getIniFileChain()->set($name, $value);
312 }
313 /**
314 * Dump config
315 *
316 * @return string|null
317 * @throws \Exception
318 */
319 public function dumpConfig()
320 {
321 $chain = $this->settings->getIniFileChain();
322 $header = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n";
323 $header .= "; file automatically generated or modified by Matomo; you can manually override the default values in global.ini.php by redefining them in this file.\n";
324 return $chain->dumpChanges($header);
325 }
326 /**
327 * Write user configuration file
328 *
329 * @throws \Exception if config file not writable
330 */
331 protected function writeConfig()
332 {
333 $output = $this->dumpConfig();
334 if ($output !== null && $output !== \false) {
335 $localPath = $this->getLocalPath();
336 if ($this->doNotWriteConfigInTests) {
337 // simulate whether it would be successful
338 $success = is_writable($localPath);
339 } else {
340 $success = @file_put_contents($localPath, $output, \LOCK_EX);
341 }
342 if ($success === \false) {
343 throw $this->getConfigNotWritableException();
344 }
345 if (!$this->sanityCheck($localPath, $output)) {
346 // If sanity check fails, try to write the contents once more before logging the issue.
347 if (@file_put_contents($localPath, $output, \LOCK_EX) === \false || !$this->sanityCheck($localPath, $output, \true)) {
348 StaticContainer::get(LoggerInterface::class)->info("The configuration file {$localPath} did not write correctly.");
349 }
350 }
351 $this->settings->getIniFileChain()->deleteConfigCache();
352 /**
353 * Triggered when a INI config file is changed on disk.
354 *
355 * @param string $localPath Absolute path to the changed file on the server.
356 */
357 \Piwik\Piwik::postEvent('Core.configFileChanged', [$localPath]);
358 }
359 }
360 /**
361 * Writes the current configuration to the **config.ini.php** file. Only writes options whose
362 * values are different from the default.
363 *
364 * @api
365 */
366 public function forceSave()
367 {
368 $this->writeConfig();
369 }
370 /**
371 * @throws \Exception
372 */
373 public function getConfigNotWritableException()
374 {
375 $path = "config/" . basename($this->getLocalPath());
376 return new MissingFilePermissionException(\Piwik\Piwik::translate('General_ConfigFileIsNotWritable', array("(" . $path . ")", "")));
377 }
378 /**
379 * @throws MissingFilePermissionException If config file is not writable.
380 */
381 public function checkConfigIsWritable()
382 {
383 if (!$this->isFileWritable()) {
384 throw $this->getConfigNotWritableException();
385 }
386 }
387 /**
388 * Convenience method for setting settings in a single section. Will set them in a new array first
389 * to be compatible with certain PHP versions.
390 *
391 * @param string $sectionName Section name.
392 * @param string $name The setting name.
393 * @param mixed $value The setting value to set.
394 */
395 public static function setSetting($sectionName, $name, $value)
396 {
397 $section = self::getInstance()->{$sectionName};
398 $section[$name] = $value;
399 self::getInstance()->{$sectionName} = $section;
400 }
401 /**
402 * Sanity check a config file by checking contents
403 *
404 * @param string $localPath
405 * @param string $expectedContent
406 * @param bool $notify
407 * @return bool
408 */
409 public function sanityCheck(string $localPath, string $expectedContent, bool $notify = \false) : bool
410 {
411 clearstatcache(\true, $localPath);
412 if (function_exists('opcache_invalidate')) {
413 @opcache_invalidate($localPath, $force = \true);
414 }
415 $content = @file_get_contents($localPath);
416 if (trim($content) !== trim($expectedContent)) {
417 if ($notify) {
418 /**
419 * Triggered when the INI config file was not written correctly with the expected content.
420 *
421 * @param string $localPath Absolute path to the changed file on the server.
422 */
423 \Piwik\Piwik::postEvent('Core.configFileSanityCheckFailed', [$localPath]);
424 }
425 return \false;
426 }
427 return \true;
428 }
429 }
430