Completed
Push — master ( 76d231...c2873c )
by Jeroen
18:44 queued 09:27
created

Config::__unset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
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() {
0 ignored issues
show
Coding Style introduced by
loadSettingsFile uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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
Bug introduced by
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