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 | use ConfigurationException; |
||
10 | use Elgg\Project\Paths; |
||
11 | |||
12 | /** |
||
13 | * Access to configuration values |
||
14 | * |
||
15 | * @since 1.10.0 |
||
16 | * |
||
17 | * @property int $action_time_limit |
||
18 | * @property int $action_token_timeout |
||
19 | * @property bool $allow_registration |
||
20 | * @property string $allow_user_default_access |
||
21 | * @property bool $auto_disable_plugins |
||
22 | * @property int $batch_run_time_in_secs |
||
23 | * @property bool $boot_complete |
||
24 | * @property int $boot_cache_ttl |
||
25 | * @property array $breadcrumbs |
||
26 | * @property string $cacheroot Path of cache storage with trailing "/" |
||
27 | * @property string $dataroot Path of data storage with trailing "/" |
||
28 | * @property bool $data_dir_override |
||
29 | * @property array $db |
||
30 | * @property string $dbencoding |
||
31 | * @property string $dbname |
||
32 | * @property string $dbuser |
||
33 | * @property string $dbhost |
||
34 | * @property string $dbpass |
||
35 | * @property string $dbprefix |
||
36 | * @property string $debug |
||
37 | * @property int $default_access |
||
38 | * @property int $default_limit |
||
39 | * @property array $default_widget_info |
||
40 | * @property bool $elgg_config_locks The application will lock some settings (default true) |
||
41 | * @property string[] $elgg_cron_periods |
||
42 | * @property array $elgg_lazy_hover_menus |
||
43 | 196 | * @property bool $elgg_load_sync_code |
|
44 | 196 | * @property bool $elgg_maintenance_mode |
|
45 | * @property string $elgg_settings_file |
||
46 | * @property bool $elgg_config_set_secret |
||
47 | 196 | * @property bool $enable_profiling |
|
48 | 196 | * @property mixed $embed_tab |
|
49 | * @property string $exception_include |
||
50 | 196 | * @property string[] $group |
|
51 | * @property array $group_tool_options |
||
52 | * @property bool $i18n_loaded_from_cache |
||
53 | * @property array $icon_sizes |
||
54 | * @property string $installed |
||
55 | * @property bool $installer_running |
||
56 | * @property string $language Site language code |
||
57 | * @property int $lastcache |
||
58 | * @property \ElggLogCache $log_cache |
||
59 | * @property array $libraries |
||
60 | * @property bool $memcache |
||
61 | * @property array $memcache_servers |
||
62 | * @property array $menus |
||
63 | * @property int $min_password_length |
||
64 | 196 | * @property string[] $pages |
|
65 | 196 | * @property-read string $path Path of composer install with trailing "/" |
|
66 | * @property-read string $pluginspath Alias of plugins_path |
||
67 | 196 | * @property-read string $plugins_path Path of project "mod/" directory |
|
68 | * @property array $profile_custom_fields |
||
69 | * @property array $profile_fields |
||
70 | * @property string $profiling_minimum_percentage |
||
71 | * @property bool $profiling_sql |
||
72 | 461 | * @property array $processed_upgrades |
|
73 | 461 | * @property string[] $registered_entities |
|
74 | * @property bool $security_disable_password_autocomplete |
||
75 | * @property bool $security_email_require_password |
||
76 | * @property bool $security_notify_admins |
||
77 | * @property bool $security_notify_user_admin |
||
78 | * @property bool $security_notify_user_ban |
||
79 | * @property bool $security_protect_cron |
||
80 | * @property bool $security_protect_upgrade |
||
81 | * @property int $simplecache_enabled |
||
82 | * @property int $simplecache_lastupdate |
||
83 | * @property bool $simplecache_minify_css |
||
84 | * @property bool $simplecache_minify_js |
||
85 | * @property \ElggSite $site |
||
86 | * @property string $sitedescription |
||
87 | * @property string $sitename |
||
88 | 353 | * @property string[] $site_custom_menu_items |
|
89 | 353 | * @property string[] $site_featured_menu_names |
|
90 | * @property-read int $site_guid |
||
91 | 353 | * @property bool $system_cache_enabled |
|
92 | 157 | * @property bool $system_cache_loaded |
|
93 | * @property string $url Alias of "wwwroot" |
||
94 | * @property int $version |
||
95 | 196 | * @property string $view Default viewtype (usually not set) |
|
96 | * @property bool $walled_garden |
||
97 | * @property string $wwwroot Site URL |
||
98 | 196 | * @property string $x_sendfile_type |
|
99 | * @property string $x_accel_mapping |
||
100 | * @property bool $_boot_cache_hit |
||
101 | 196 | * @property bool $_elgg_autofeed |
|
102 | */ |
||
103 | class Config { |
||
104 | 196 | use Loggable; |
|
105 | 196 | ||
106 | 196 | /** |
|
107 | 196 | * @var array Configuration storage |
|
108 | */ |
||
109 | private $values; |
||
110 | 196 | ||
111 | 196 | /** |
|
112 | 196 | * @var array |
|
113 | */ |
||
114 | 196 | private $initial_values; |
|
115 | |||
116 | 196 | /** |
|
117 | * @var bool |
||
118 | */ |
||
119 | private $cookies_configured = false; |
||
120 | |||
121 | /** |
||
122 | 18 | * @var ConfigTable Do not use directly. Use getConfigTable(). |
|
123 | 18 | */ |
|
124 | 18 | private $config_table; |
|
125 | |||
126 | /** |
||
127 | * @var array |
||
128 | */ |
||
129 | private $locked = []; |
||
130 | 2 | ||
131 | 2 | /** |
|
132 | 2 | * Constructor |
|
133 | * |
||
134 | * @param array $values Initial config values from Env/settings file |
||
135 | * @internal Do not use |
||
136 | * @access private |
||
137 | */ |
||
138 | 409 | public function __construct(array $values = []) { |
|
139 | 409 | $this->values = $values; |
|
140 | |||
141 | 409 | // Don't keep copies of these in case config gets dumped |
|
142 | 309 | $sensitive_props = [ |
|
143 | '__site_secret__', |
||
144 | 'db', |
||
145 | 255 | 'dbhost', |
|
146 | 255 | 'dbuser', |
|
147 | 'dbpass', |
||
148 | 'dbname', |
||
149 | 'profiler_secret_get_var' |
||
150 | ]; |
||
151 | foreach ($sensitive_props as $name) { |
||
152 | unset($values[$name]); |
||
153 | } |
||
154 | $this->initial_values = $values; |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Build a config from default settings locations |
||
159 | * |
||
160 | * @param string $settings_path Path of settings file |
||
161 | * @param bool $try_env If path not given, try $_ENV['ELGG_SETTINGS_FILE'] |
||
162 | * @return Config |
||
163 | 211 | * |
|
164 | 211 | * @throws ConfigurationException |
|
165 | */ |
||
166 | public static function factory($settings_path = '', $try_env = true) { |
||
0 ignored issues
–
show
|
|||
167 | $reason1 = ''; |
||
168 | $reason2 = ''; |
||
169 | |||
170 | 270 | if ($try_env && !empty($_ENV['ELGG_SETTINGS_FILE'])) { |
|
171 | 270 | $settings_path = $_ENV['ELGG_SETTINGS_FILE']; |
|
172 | 270 | } |
|
173 | 270 | ||
174 | if ($settings_path) { |
||
175 | $config = self::fromFile($settings_path, $reason1); |
||
176 | } else { |
||
177 | $config = self::fromFile(Paths::settingsFile(Paths::SETTINGS_PHP), $reason1); |
||
178 | } |
||
179 | |||
180 | if (!$config) { |
||
181 | $msg = __METHOD__ . ": Reading configs failed: $reason1 $reason2"; |
||
182 | throw new ConfigurationException($msg); |
||
183 | } |
||
184 | |||
185 | return $config; |
||
186 | } |
||
187 | |||
188 | /** |
||
189 | * Build a config from a file |
||
190 | * |
||
191 | * @param string $path Path of settings.php |
||
192 | * @param string $reason Returned reason for failure |
||
193 | * |
||
194 | * @return bool|Config false on failure |
||
195 | */ |
||
196 | public static function fromFile($path, &$reason = '') { |
||
0 ignored issues
–
show
fromFile 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...
|
|||
197 | if (!is_file($path)) { |
||
198 | $reason = "File $path not present."; |
||
199 | return false; |
||
200 | } |
||
201 | |||
202 | if (!is_readable($path)) { |
||
203 | $reason = "File $path not readable."; |
||
204 | return false; |
||
205 | } |
||
206 | |||
207 | // legacy loading. If $CONFIG doesn't exist, remove it after the |
||
208 | // settings file is read. |
||
209 | $global_is_set = isset($GLOBALS['CONFIG']); |
||
210 | |||
211 | Includer::requireFile($path); |
||
212 | |||
213 | $get_db = function() { |
||
214 | // try to migrate settings to the file |
||
215 | $db_conf = new \Elgg\Database\DbConfig($GLOBALS['CONFIG']); |
||
216 | return new Database($db_conf); |
||
217 | }; |
||
218 | |||
219 | if (empty($GLOBALS['CONFIG']->dataroot)) { |
||
220 | $dataroot = (new DatarootSettingMigrator($get_db(), $path))->migrate(); |
||
221 | if (!isset($dataroot)) { |
||
222 | $reason = 'The Elgg settings file is missing $CONFIG->dataroot.'; |
||
223 | 216 | return false; |
|
224 | 216 | } |
|
225 | 216 | ||
226 | $GLOBALS['CONFIG']->dataroot = $dataroot; |
||
227 | |||
228 | 196 | // just try this one time to migrate wwwroot |
|
229 | 196 | if (!isset($GLOBALS['CONFIG']->wwwroot)) { |
|
230 | 196 | $wwwroot = (new WwwrootSettingMigrator($get_db(), $path))->migrate(); |
|
231 | 196 | if (isset($wwwroot)) { |
|
232 | $GLOBALS['CONFIG']->wwwroot = $wwwroot; |
||
233 | } |
||
234 | } |
||
235 | } |
||
236 | |||
237 | $config = new self(get_object_vars($GLOBALS['CONFIG'])); |
||
238 | |||
239 | if (!$global_is_set) { |
||
240 | unset($GLOBALS['CONFIG']); |
||
241 | } |
||
242 | |||
243 | if ($config->{'X-Sendfile-Type'}) { |
||
244 | $config->{'x_sendfile_type'} = $config->{'X-Sendfile-Type'}; |
||
245 | unset($config->{'X-Sendfile-Type'}); |
||
246 | } |
||
247 | if ($config->{'X-Accel-Mapping'}) { |
||
248 | $config->{'x_accel_mapping'} = $config->{'X-Accel-Mapping'}; |
||
249 | unset($config->{'X-Accel-Mapping'}); |
||
250 | } |
||
251 | |||
252 | $config->elgg_settings_file = $path; |
||
253 | $config->lock('elgg_settings_file'); |
||
254 | |||
255 | return $config; |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * Set an array of values |
||
260 | * |
||
261 | * @param array $values Values |
||
262 | * @return void |
||
263 | */ |
||
264 | public function mergeValues(array $values) { |
||
265 | foreach ($values as $name => $value) { |
||
266 | $this->__set($name, $value); |
||
267 | } |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * Get all values |
||
272 | * |
||
273 | * @return array |
||
274 | */ |
||
275 | public function getValues() { |
||
276 | return $this->values; |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * Set up and return the cookie configuration array resolved from settings |
||
281 | * |
||
282 | * @return array |
||
283 | */ |
||
284 | public function getCookieConfig() { |
||
285 | if ($this->cookies_configured) { |
||
286 | return $this->cookies; |
||
0 ignored issues
–
show
The property
cookies does not seem to exist. Did you mean cookies_configured ?
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.
Loading history...
|
|||
287 | } |
||
288 | |||
289 | $cookies = $this->cookies; |
||
0 ignored issues
–
show
The property
cookies does not seem to exist. Did you mean cookies_configured ?
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.
Loading history...
|
|||
290 | if (!is_array($cookies)) { |
||
291 | $cookies = []; |
||
292 | } |
||
293 | |||
294 | if (!isset($cookies['session'])) { |
||
295 | $cookies['session'] = []; |
||
296 | } |
||
297 | $session_defaults = session_get_cookie_params(); |
||
298 | $session_defaults['name'] = 'Elgg'; |
||
299 | $cookies['session'] = array_merge($session_defaults, $cookies['session']); |
||
300 | if (!isset($cookies['remember_me'])) { |
||
301 | $cookies['remember_me'] = []; |
||
302 | 200 | } |
|
303 | 200 | $session_defaults['name'] = 'elggperm'; |
|
304 | $session_defaults['expire'] = strtotime("+30 days"); |
||
305 | $cookies['remember_me'] = array_merge($session_defaults, $cookies['remember_me']); |
||
306 | |||
307 | $this->cookies = $cookies; |
||
0 ignored issues
–
show
The property
cookies does not seem to exist. Did you mean cookies_configured ?
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.
Loading history...
|
|||
308 | $this->cookies_configured = true; |
||
309 | |||
310 | return $cookies; |
||
311 | } |
||
312 | |||
313 | /** |
||
314 | * Get an Elgg configuration value if it's been set or loaded during the boot process. |
||
315 | * |
||
316 | * Before \Elgg\BootService::boot, values from the database will not be present. |
||
317 | 196 | * |
|
318 | 196 | * @param string $name Name |
|
319 | 196 | * |
|
320 | * @return mixed null if does not exist |
||
321 | */ |
||
322 | public function __get($name) { |
||
323 | if (isset($this->values[$name])) { |
||
324 | return $this->values[$name]; |
||
325 | } |
||
326 | |||
327 | return null; |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * Get a value set at construction time |
||
332 | * |
||
333 | * @param string $name Name |
||
334 | * @return mixed null = not set |
||
335 | */ |
||
336 | public function getInitialValue($name) { |
||
337 | return isset($this->initial_values[$name]) ? $this->initial_values[$name] : null; |
||
338 | } |
||
339 | |||
340 | /** |
||
341 | * Was a value available at construction time? (From settings.php) |
||
342 | * |
||
343 | * @param string $name Name |
||
344 | * |
||
345 | * @return bool |
||
346 | */ |
||
347 | public function hasInitialValue($name) { |
||
348 | return isset($this->initial_values[$name]); |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * Make a value read-only |
||
353 | * |
||
354 | * @param string $name Name |
||
355 | * @return void |
||
356 | */ |
||
357 | public function lock($name) { |
||
358 | $this->locked[$name] = true; |
||
359 | } |
||
360 | |||
361 | /** |
||
362 | * Is this value locked? |
||
363 | * |
||
364 | * @param string $name Name |
||
365 | * |
||
366 | * @return bool |
||
367 | */ |
||
368 | public function isLocked($name) { |
||
369 | return isset($this->locked[$name]); |
||
370 | } |
||
371 | |||
372 | /** |
||
373 | * Set an Elgg configuration value |
||
374 | * |
||
375 | * @warning This does not persist the configuration setting. Use elgg_save_config() |
||
376 | * |
||
377 | * @param string $name Name |
||
378 | * @param mixed $value Value |
||
379 | * @return void |
||
380 | */ |
||
381 | public function __set($name, $value) { |
||
382 | if ($this->wasWarnedLocked($name)) { |
||
383 | return; |
||
384 | } |
||
385 | |||
386 | $this->values[$name] = $value; |
||
387 | } |
||
388 | |||
389 | /** |
||
390 | * Handle isset() |
||
391 | * |
||
392 | * @param string $name Name |
||
393 | * @return bool |
||
394 | */ |
||
395 | public function __isset($name) { |
||
396 | return $this->__get($name) !== null; |
||
397 | } |
||
398 | |||
399 | /** |
||
400 | * Handle unset() |
||
401 | * |
||
402 | * @param string $name Name |
||
403 | * @return void |
||
404 | */ |
||
405 | public function __unset($name) { |
||
406 | if ($this->wasWarnedLocked($name)) { |
||
407 | return; |
||
408 | } |
||
409 | |||
410 | unset($this->values[$name]); |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * Save a configuration setting to the database |
||
415 | * |
||
416 | * @param string $name Name (cannot be greater than 255 characters) |
||
417 | * @param mixed $value Value |
||
418 | * |
||
419 | * @return bool |
||
420 | */ |
||
421 | public function save($name, $value) { |
||
422 | if ($this->wasWarnedLocked($name)) { |
||
423 | return false; |
||
424 | } |
||
425 | |||
426 | if (strlen($name) > 255) { |
||
427 | if ($this->logger) { |
||
428 | $this->logger->error("The name length for configuration variables cannot be greater than 255"); |
||
429 | } |
||
430 | return false; |
||
431 | } |
||
432 | |||
433 | $result = $this->getConfigTable()->set($name, $value); |
||
434 | |||
435 | $this->__set($name, $value); |
||
436 | |||
437 | return $result; |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * Removes a configuration setting from the database |
||
442 | * |
||
443 | * @param string $name Configuration name |
||
444 | * |
||
445 | * @return bool |
||
446 | */ |
||
447 | public function remove($name) { |
||
448 | if ($this->wasWarnedLocked($name)) { |
||
449 | return false; |
||
450 | } |
||
451 | |||
452 | $result = $this->getConfigTable()->remove($name); |
||
453 | |||
454 | unset($this->values[$name]); |
||
455 | |||
456 | return $result; |
||
457 | } |
||
458 | |||
459 | /** |
||
460 | * Log a read-only warning if the name is read-only |
||
461 | * |
||
462 | * @param string $name Name |
||
463 | * @return bool |
||
464 | */ |
||
465 | private function wasWarnedLocked($name) { |
||
466 | if (!isset($this->locked[$name])) { |
||
467 | return false; |
||
468 | } |
||
469 | |||
470 | if ($this->logger) { |
||
471 | $this->logger->warn("The property $name is read-only."); |
||
472 | } |
||
473 | return true; |
||
474 | } |
||
475 | |||
476 | /** |
||
477 | * Set the config table service (must be set) |
||
478 | * |
||
479 | * This is a necessary evil until we refactor so that the service provider has no dependencies. |
||
480 | * |
||
481 | * @param ConfigTable $table |
||
482 | * @return void |
||
483 | * |
||
484 | * @access private |
||
485 | * @internal |
||
486 | */ |
||
487 | public function setConfigTable(ConfigTable $table) { |
||
488 | $this->config_table = $table; |
||
489 | } |
||
490 | |||
491 | /** |
||
492 | * Get the core entity types |
||
493 | * |
||
494 | * @return string[] |
||
495 | */ |
||
496 | public static function getEntityTypes() { |
||
497 | return ['group', 'object', 'site', 'user']; |
||
498 | } |
||
499 | |||
500 | /** |
||
501 | * Get the config table API |
||
502 | * |
||
503 | * @return ConfigTable |
||
504 | */ |
||
505 | private function getConfigTable() { |
||
506 | if (!$this->config_table) { |
||
507 | if (!function_exists('_elgg_services')) { |
||
508 | throw new \RuntimeException('setConfigTable() must be called before using API that' . |
||
509 | ' uses the database.'); |
||
510 | } |
||
511 | |||
512 | $this->config_table = _elgg_services()->configTable; |
||
513 | } |
||
514 | |||
515 | return $this->config_table; |
||
516 | } |
||
517 | } |
||
518 |
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: