Test Failed
Push — master ( 8c47c2...3acf9f )
by Steve
12:37
created

engine/classes/Elgg/Config.php (1 issue)

a variable is defined regardless of execution path.

Bug Major

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Elgg;
3
4
use Elgg\Config\DatarootSettingMigrator;
5
use Elgg\Config\SettingsMigrator;
6
use Elgg\Config\WwwrootSettingMigrator;
7
use Elgg\Filesystem\Directory;
8
use Elgg\Database\ConfigTable;
9
10
/**
11
 * Access to configuration values
12
 *
13
 * @since 1.10.0
14
 *
15
 * @property int           $action_time_limit
16
 * @property int           $action_token_timeout
17
 * @property bool          $allow_registration
18
 * @property string        $allow_user_default_access
19
 * @property bool          $auto_disable_plugins
20
 * @property int           $batch_run_time_in_secs
21
 * @property bool          $boot_complete
22
 * @property int           $boot_cache_ttl
23
 * @property array         $breadcrumbs
24
 * @property string        $cacheroot         Path of cache storage with trailing "/"
25
 * @property string        $dataroot          Path of data storage with trailing "/"
26
 * @property bool          $data_dir_override
27
 * @property array         $db
28
 * @property string        $dbencoding
29
 * @property string        $dbname
30
 * @property string        $dbuser
31
 * @property string        $dbhost
32
 * @property string        $dbpass
33
 * @property string        $dbprefix
34
 * @property string        $debug
35
 * @property int           $default_access
36
 * @property int           $default_limit
37
 * @property array         $default_widget_info
38
 * @property bool          $elgg_config_locks The application will lock some settings (default true)
39
 * @property string[]      $elgg_cron_periods
40
 * @property bool          $elgg_load_sync_code
41
 * @property bool          $elgg_maintenance_mode
42
 * @property string        $elgg_settings_file
43 196
 * @property bool          $enable_profiling
44 196
 * @property mixed         $embed_tab
45
 * @property string        $exception_include
46
 * @property string[]      $group
47 196
 * @property array         $group_tool_options
48 196
 * @property bool          $i18n_loaded_from_cache
49
 * @property array         $icon_sizes
50 196
 * @property string        $installed
51
 * @property bool          $installer_running
52
 * @property string        $language     Site language code
53
 * @property int           $lastcache
54
 * @property \ElggLogCache $log_cache
55
 * @property array         $libraries
56
 * @property bool          $memcache
57
 * @property array         $memcache_servers
58
 * @property array         $menus
59
 * @property int           $min_password_length
60
 * @property string[]      $pages
61
 * @property-read string   $path         Path of composer install with trailing "/"
62
 * @property-read string   $pluginspath  Alias of plugins_path
63
 * @property-read string   $plugins_path Path of project "mod/" directory
64 196
 * @property array         $profile_custom_fields
65 196
 * @property array         $profile_fields
66
 * @property string        $profiling_minimum_percentage
67 196
 * @property bool          $profiling_sql
68
 * @property array         $processed_upgrades
69
 * @property string[]      $registered_entities
70
 * @property bool          $security_disable_password_autocomplete
71
 * @property bool          $security_email_require_password
72 461
 * @property bool          $security_notify_admins
73 461
 * @property bool          $security_notify_user_admin
74
 * @property bool          $security_notify_user_ban
75
 * @property bool          $security_protect_cron
76
 * @property bool          $security_protect_upgrade
77
 * @property int           $simplecache_enabled
78
 * @property int           $simplecache_lastupdate
79
 * @property bool          $simplecache_minify_css
80
 * @property bool          $simplecache_minify_js
81
 * @property \ElggSite     $site
82
 * @property string        $sitedescription
83
 * @property string        $sitename
84
 * @property string[]      $site_custom_menu_items
85
 * @property string[]      $site_featured_menu_names
86
 * @property-read int      $site_guid
87
 * @property bool          $system_cache_enabled
88 353
 * @property bool          $system_cache_loaded
89 353
 * @property string        $url          Alias of "wwwroot"
90
 * @property int           $version
91 353
 * @property string        $view         Default viewtype (usually not set)
92 157
 * @property bool          $walled_garden
93
 * @property string        $wwwroot      Site URL
94
 * @property bool          $_boot_cache_hit
95 196
 * @property bool          $_elgg_autofeed
96
 */
97
class Config implements Services\Config {
98 196
	/**
99
	 * Configuration storage. Is usually reference to global $CONFIG
100
	 *
101 196
	 * @var \stdClass
102
	 */
103
	private $config;
104 196
105 196
	/**
106 196
	 * @var bool
107 196
	 */
108
	private $settings_loaded = false;
109
110 196
	/**
111 196
	 * @var bool
112 196
	 */
113
	private $cookies_configured = false;
114 196
115
	/**
116 196
	 * @var ConfigTable Do not use directly. Use getConfigTable().
117
	 */
118
	private $config_table;
119
120
	/**
121
	 * Constructor
122 18
	 *
123 18
	 * @internal Access this object via Elgg\Application::$config
124 18
	 *
125
	 * @param \stdClass $config     Elgg's $CONFIG object
126
	 * @param bool      $set_global Copy the config object to global $CONFIG
127
	 */
128
	public function __construct(\stdClass $config = null, $set_global = true) {
129
		if (!$config) {
130 2
			$config = new \stdClass();
131 2
		}
132 2
		$this->config = $config;
133
		$this->config->path = Directory\Local::root()->getPath('/');
134
135
		if ($set_global) {
136
			/**
137
			 * Configuration values.
138 409
			 *
139 409
			 * The $CONFIG global contains configuration values required
140
			 * for running Elgg as defined in the settings.php file.
141 409
			 *
142 309
			 * Plugin authors are encouraged to use elgg_get_config() instead of accessing
143
			 * the global directly.
144
			 *
145 255
			 * @see elgg_get_config()
146 255
			 * @see engine/settings.php
147
			 * @global \stdClass $CONFIG
148
			 */
149
			global $CONFIG;
150
			$CONFIG = $config;
151
		}
152
	}
153
154
	/**
155
	 * {@inheritdoc}
156
	 */
157
	public function getSiteUrl() {
158
		return $this->config->wwwroot;
159
	}
160
161
	/**
162
	 * {@inheritdoc}
163 211
	 */
164 211
	public function getPluginsPath() {
165
		return $this->config->pluginspath;
166
	}
167
168
	/**
169
	 * Set up and return the cookie configuration array resolved from settings.php
170 270
	 *
171 270
	 * @return array
172 270
	 */
173 270
	public function getCookieConfig() {
174
		$c = $this->config;
175
176
		if ($this->cookies_configured) {
177
			return $c->cookies;
178
		}
179
180
		$this->loadSettingsFile();
181
182
		// set cookie values for session and remember me
183
		if (!isset($c->cookies)) {
184
			$c->cookies = [];
185
		}
186
		if (!isset($c->cookies['session'])) {
187
			$c->cookies['session'] = [];
188
		}
189
		$session_defaults = session_get_cookie_params();
190
		$session_defaults['name'] = 'Elgg';
191
		$c->cookies['session'] = array_merge($session_defaults, $c->cookies['session']);
192
		if (!isset($c->cookies['remember_me'])) {
193
			$c->cookies['remember_me'] = [];
194
		}
195
		$session_defaults['name'] = 'elggperm';
196
		$session_defaults['expire'] = strtotime("+30 days");
197
		$c->cookies['remember_me'] = array_merge($session_defaults, $c->cookies['remember_me']);
198
199
		$this->cookies_configured = true;
200
201
		return $c->cookies;
202
	}
203
204
	/**
205
	 * {@inheritdoc}
206
	 */
207
	public function getDataPath() {
208
		$this->loadSettingsFile();
209
		return $this->config->dataroot;
210
	}
211
212
	/**
213
	 * {@inheritdoc}
214
	 */
215
	public function getCachePath() {
216
		$this->loadSettingsFile();
217
		return $this->config->cacheroot;
218
	}
219
220
	/**
221
	 * {@inheritdoc}
222
	 */
223 216
	public function get($name, $default = null) {
224 216
		$name = trim($name);
225 216
	
226
		if (isset($this->config->$name)) {
227
			return $this->config->$name;
228 196
		}
229 196
230 196
		if (!empty($this->config->site_config_loaded)) {
231 196
			return $default;
232
		}
233
		
234
		$value = $this->getConfigTable()->get($name);
235
236
		if ($value === null) {
237
			return $default;
238
		}
239
	
240
		$this->config->$name = $value;
241
		
242
		return $value;
243
	}
244
245
	/**
246
	 * Use get() to read a property
247
	 *
248
	 * @param string $name Name
249
	 * @return mixed
250
	 */
251
	public function __get($name) {
252
		return $this->get($name);
253
	}
254
255
	/**
256
	 * {@inheritdoc}
257
	 */
258
	public function getVolatile($name) {
259
		return isset($this->config->{$name}) ? $this->config->{$name} : null;
260
	}
261
262
	/**
263
	 * {@inheritdoc}
264
	 */
265
	public function set($name, $value) {
266
		$name = trim($name);
267
		$this->config->$name = $value;
268
	}
269
270
	/**
271
	 * Set an Elgg configuration value
272
	 *
273
	 * @warning This does not persist the configuration setting. Use elgg_save_config()
274
	 *
275
	 * @param string $name  Name
276
	 * @param mixed  $value Value
277
	 * @return void
278
	 */
279
	public function __set($name, $value) {
280
		$this->set($name, $value);
281
	}
282
283
	/**
284
	 * Handle isset()
285
	 *
286
	 * @param string $name Name
287
	 * @return bool
288
	 */
289
	public function __isset($name) {
290
		return $this->get($name) !== null;
291
	}
292
293
	/**
294
	 * Handle unset()
295
	 *
296
	 * @param string $name Name
297
	 * @return void
298
	 */
299
	public function __unset($name) {
300
		unset($this->config->{$name});
301
	}
302 200
303 200
	/**
304
	 * {@inheritdoc}
305
	 */
306
	public function save($name, $value) {
307
		$name = trim($name);
308
	
309
		if (strlen($name) > 255) {
310
			_elgg_services()->logger->error("The name length for configuration variables cannot be greater than 255");
311
			return false;
312
		}
313
314
		$result = $this->getConfigTable()->set($name, $value);
315
316
		$this->set($name, $value);
317 196
	
318 196
		return $result;
319 196
	}
320
321
	/**
322
	 * {@inheritdoc}
323
	 */
324
	public function remove($name) {
325
		$name = trim($name);
326
327
		$result = $this->getConfigTable()->remove($name);
328
329
		unset($this->config->$name);
330
	
331
		return $result;
332
	}
333
334
	/**
335
	 * Get expected settings file paths
336
	 *
337
	 * @return string[]
338
	 * @array private
339
	 */
340
	public function getSettingsPaths() {
341
		$root = Directory\Local::root();
342
		return [
343
			$root->getPath('engine/settings.php'),
344
			$root->getPath('elgg-config/settings.php'),
345
		];
346
	}
347
348
	/**
349
	 * {@inheritdoc}
350
	 */
351
	public function loadSettingsFile() {
352
		if ($this->settings_loaded) {
353
			return;
354
		}
355
356
		if (isset($this->config->Config_file)) {
357
			if ($this->config->Config_file === false) {
358
				$this->settings_loaded = true;
359
				return;
360
			}
361
			$path = $this->config->Config_file;
362
		} else {
363
			foreach ($this->getSettingsPaths() as $path) {
364
				if (is_file($path)) {
365
					break;
366
				}
367
			}
368
		}
369
370
		// No settings means a fresh install
371
		if (!is_file($path)) {
0 ignored issues
show
The variable $path does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
372
			if ($this->getVolatile('installer_running')) {
373
				$this->settings_loaded = true;
374
				return;
375
			}
376
377
			header("Location: install.php");
378
			exit;
379
		}
380
381
		if (!is_readable($path)) {
382
			throw new \RuntimeException("The Elgg settings file exists but the web server doesn't have read permission to it.");
383
		}
384
385
		// we assume settings is going to write to CONFIG, but we may need to copy its values
386
		// into our local config
387
		global $CONFIG;
388
		$global_is_bound = (isset($CONFIG) && $CONFIG === $this->config);
389
390
		require_once $path;
391
392
		$get_db = function() use ($CONFIG) {
393
			// try to migrate settings to the file
394
			$db_conf = new \Elgg\Database\Config($CONFIG);
395
			return new Database($db_conf);
396
		};
397
398
		if (empty($CONFIG->dataroot)) {
399
			$dataroot = (new DatarootSettingMigrator($get_db(), $path))->migrate();
400
			if (isset($dataroot)) {
401
				$CONFIG->dataroot = $dataroot;
402
			} else {
403
				throw new \RuntimeException('The Elgg settings file is missing $CONFIG->dataroot.');
404
			}
405
		}
406
407
		// normalize commonly needed values
408
		$CONFIG->dataroot = rtrim($CONFIG->dataroot, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
409
410
		if (!isset($CONFIG->wwwroot)) {
411
			$wwwroot = (new WwwrootSettingMigrator($get_db(), $path))->migrate();
412
			if (isset($wwwroot)) {
413
				$CONFIG->wwwroot = $wwwroot;
414
			}
415
		}
416
417
		$GLOBALS['_ELGG']->simplecache_enabled_in_settings = isset($CONFIG->simplecache_enabled);
418
419
		if (empty($CONFIG->cacheroot)) {
420
			$CONFIG->cacheroot = $CONFIG->dataroot;
421
		} else {
422
			$CONFIG->cacheroot = rtrim($CONFIG->cacheroot, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
423
		}
424
425
		if (!$global_is_bound) {
426
			// must manually copy settings into our storage
427
			foreach ($CONFIG as $key => $value) {
428
				$this->config->{$key} = $value;
429
			}
430
		}
431
432
		$this->settings_loaded = true;
433
	}
434
435
	/**
436
	 * Get the raw \stdClass object used for storage.
437
	 *
438
	 * We need this, for now, to construct some services.
439
	 *
440
	 * @internal Do not use this plugins or new core code!
441
	 * @todo Get rid of this.
442
	 *
443
	 * @return \stdClass
444
	 * @access private
445
	 */
446
	public function getStorageObject() {
447
		return $this->config;
448
	}
449
450
	/**
451
	 * Set the config table service (must be set)
452
	 *
453
	 * This is a necessary evil until we refactor so that the service provider has no dependencies.
454
	 *
455
	 * @param ConfigTable $table
456
	 * @return void
457
	 *
458
	 * @access private
459
	 * @internal
460
	 */
461
	public function setConfigTable(ConfigTable $table) {
462
		$this->config_table = $table;
463
	}
464
465
	/**
466
	 * Get the config table API
467
	 *
468
	 * @return ConfigTable
469
	 */
470
	private function getConfigTable() {
471
		if (!$this->config_table) {
472
			if (!function_exists('_elgg_services')) {
473
				throw new \RuntimeException('setConfigTable() must be called before using API that' .
474
					' uses the database.');
475
			}
476
477
			$this->config_table = _elgg_services()->configTable;
478
		}
479
480
		return $this->config_table;
481
	}
482
}
483