PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
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 month ago Access 3 months ago Application 1 month ago Archive 1 month ago ArchiveProcessor 1 month ago Archiver 2 years ago AssetManager 1 month ago Auth 6 months ago Category 6 months ago Changes 1 month ago CliMulti 1 year ago Columns 1 month ago Concurrency 1 month ago Config 1 month ago Container 1 month ago CronArchive 3 months ago DataAccess 1 month ago DataFiles 2 years ago DataTable 2 weeks ago Db 2 weeks ago DeviceDetector 1 year ago Email 2 years ago Exception 4 months ago Http 4 months ago Intl 3 months ago Log 2 years ago Mail 1 year ago Measurable 6 months ago Menu 1 month ago Metrics 3 months ago Notification 6 months ago Period 1 month ago Plugin 2 weeks ago Policy 1 month ago ProfessionalServices 1 year ago Report 1 year ago ReportRenderer 3 months ago Request 3 months ago Scheduler 1 month ago Segment 1 month ago Session 2 weeks ago Settings 1 month ago Tracker 2 weeks ago Translation 1 month ago Twig 1 year ago UpdateCheck 3 months ago Updater 1 month ago Updates 2 days ago Validators 1 year ago View 1 month ago ViewDataTable 2 weeks ago Visualization 1 year ago Widget 1 month ago .htaccess 2 years ago Access.php 1 month ago Archive.php 1 month ago ArchiveProcessor.php 1 month ago AssetManager.php 1 month ago Auth.php 6 months ago AuthResult.php 6 months ago BaseFactory.php 2 years ago Cache.php 2 years ago CacheId.php 4 months ago CliMulti.php 1 month ago Common.php 2 weeks ago Config.php 1 month ago Console.php 3 months ago Context.php 2 years ago Cookie.php 1 year ago CronArchive.php 1 month ago DI.php 3 months ago DataArray.php 1 month ago DataTable.php 1 month ago Date.php 1 month ago Db.php 1 month ago DbHelper.php 1 month ago Development.php 1 year ago ErrorHandler.php 6 months ago EventDispatcher.php 1 month ago ExceptionHandler.php 4 months ago FileIntegrity.php 1 month ago Filechecks.php 1 year ago Filesystem.php 1 month ago FrontController.php 4 months ago Http.php 1 month ago IP.php 1 year ago Log.php 3 months ago LogDeleter.php 1 year ago Mail.php 1 year ago Metrics.php 1 month ago NoAccessException.php 2 years ago Nonce.php 6 months ago Notification.php 1 month ago NumberFormatter.php 5 months ago Option.php 5 months ago Period.php 1 month ago Piwik.php 1 month ago Plugin.php 1 month ago Process.php 1 month ago Profiler.php 6 months ago ProxyHeaders.php 4 months ago ProxyHttp.php 5 months ago QuickForm2.php 3 months ago RankingQuery.php 1 month ago ReportRenderer.php 1 month ago Request.php 1 month ago Segment.php 1 month ago Sequence.php 6 months ago Session.php 2 weeks ago SettingsPiwik.php 1 month ago SettingsServer.php 1 year ago Singleton.php 2 years ago Site.php 1 month ago SiteContentDetector.php 1 month ago SupportedBrowser.php 2 years ago TCPDF.php 1 year ago Theme.php 1 year ago Timer.php 1 month ago Tracker.php 1 month ago Twig.php 1 month ago Unzip.php 1 year ago UpdateCheck.php 1 month ago Updater.php 1 month ago UpdaterErrorException.php 2 years ago Updates.php 3 months ago Url.php 3 months ago UrlHelper.php 1 month ago Version.php 2 days ago View.php 1 month ago bootstrap.php 1 year ago dispatch.php 2 years ago testMinimumPhpVersion.php 6 months ago
Config.php
425 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'], 'data_comparison_segment_limit' => $general['data_comparison_segment_limit'], '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 public function sanityCheck(string $localPath, string $expectedContent, bool $notify = \false) : bool
405 {
406 clearstatcache(\true, $localPath);
407 if (function_exists('opcache_invalidate')) {
408 @opcache_invalidate($localPath, $force = \true);
409 }
410 $content = @file_get_contents($localPath);
411 if (trim($content) !== trim($expectedContent)) {
412 if ($notify) {
413 /**
414 * Triggered when the INI config file was not written correctly with the expected content.
415 *
416 * @param string $localPath Absolute path to the changed file on the server.
417 */
418 \Piwik\Piwik::postEvent('Core.configFileSanityCheckFailed', [$localPath]);
419 }
420 return \false;
421 }
422 return \true;
423 }
424 }
425