These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | use Elgg\Filesystem\Directory; |
||
4 | |||
5 | /** |
||
6 | * Elgg Installer. |
||
7 | * Controller for installing Elgg. Supports both web-based on CLI installation. |
||
8 | * |
||
9 | * This controller steps the user through the install process. The method for |
||
10 | * each step handles both the GET and POST requests. There is no XSS/CSRF protection |
||
11 | * on the POST processing since the installer is only run once by the administrator. |
||
12 | * |
||
13 | * The installation process can be resumed by hitting the first page. The installer |
||
14 | * will try to figure out where to pick up again. |
||
15 | * |
||
16 | * All the logic for the installation process is in this class, but it depends on |
||
17 | * the core libraries. To do this, we selectively load a subset of the core libraries |
||
18 | * for the first few steps and then load the entire engine once the database and |
||
19 | * site settings are configured. In addition, this controller does its own session |
||
20 | * handling until the database is setup. |
||
21 | * |
||
22 | * There is an aborted attempt in the code at creating the data directory for |
||
23 | * users as a subdirectory of Elgg's root. The idea was to protect this directory |
||
24 | * through a .htaccess file. The problem is that a malicious user can upload a |
||
25 | * .htaccess of his own that overrides the protection for his user directory. The |
||
26 | * best solution is server level configuration that turns off AllowOverride for the |
||
27 | * data directory. See ticket #3453 for discussion on this. |
||
28 | * |
||
29 | * @package Elgg.Core |
||
30 | * @subpackage Installer |
||
31 | */ |
||
32 | class ElggInstaller { |
||
33 | |||
34 | protected $steps = [ |
||
35 | 'welcome', |
||
36 | 'requirements', |
||
37 | 'database', |
||
38 | 'settings', |
||
39 | 'admin', |
||
40 | 'complete', |
||
41 | ]; |
||
42 | |||
43 | protected $status = [ |
||
44 | 'config' => false, |
||
45 | 'database' => false, |
||
46 | 'settings' => false, |
||
47 | 'admin' => false, |
||
48 | ]; |
||
49 | |||
50 | protected $isAction = false; |
||
51 | |||
52 | protected $autoLogin = true; |
||
53 | |||
54 | private $view_path = ''; |
||
55 | |||
56 | /** |
||
57 | * Global Elgg configuration |
||
58 | * |
||
59 | * @var \stdClass |
||
60 | */ |
||
61 | private $CONFIG; |
||
62 | |||
63 | /** |
||
64 | * Constructor bootstraps the Elgg engine |
||
65 | */ |
||
66 | public function __construct() { |
||
67 | global $CONFIG; |
||
68 | if (!isset($CONFIG)) { |
||
69 | $CONFIG = new stdClass; |
||
70 | } |
||
71 | |||
72 | global $_ELGG; |
||
73 | if (!isset($_ELGG)) { |
||
74 | $_ELGG = new stdClass; |
||
75 | } |
||
76 | |||
77 | $this->CONFIG = $CONFIG; |
||
78 | |||
79 | $this->isAction = isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST'; |
||
80 | |||
81 | $this->bootstrapConfig(); |
||
82 | |||
83 | $this->bootstrapEngine(); |
||
84 | |||
85 | _elgg_services()->views->view_path = $this->view_path; |
||
0 ignored issues
–
show
|
|||
86 | |||
87 | _elgg_services()->setValue('session', \ElggSession::getMock()); |
||
88 | |||
89 | elgg_set_viewtype('installation'); |
||
90 | |||
91 | set_error_handler('_elgg_php_error_handler'); |
||
92 | set_exception_handler('_elgg_php_exception_handler'); |
||
93 | |||
94 | _elgg_services()->config->set('simplecache_enabled', false); |
||
95 | _elgg_services()->translator->registerTranslations(\Elgg\Application::elggDir()->getPath("/install/languages/"), true); |
||
96 | _elgg_services()->views->registerPluginViews(\Elgg\Application::elggDir()->getPath("/")); |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * Dispatches a request to one of the step controllers |
||
101 | * |
||
102 | * @param string $step The installation step to run |
||
103 | * |
||
104 | * @return void |
||
105 | * @throws InstallationException |
||
106 | */ |
||
107 | public function run($step) { |
||
108 | global $CONFIG; |
||
109 | |||
110 | // language needs to be set before the first call to elgg_echo() |
||
111 | $CONFIG->language = 'en'; |
||
112 | |||
113 | // check if this is a URL rewrite test coming in |
||
114 | $this->processRewriteTest(); |
||
115 | |||
116 | if (!in_array($step, $this->getSteps())) { |
||
117 | $msg = _elgg_services()->translator->translate('InstallationException:UnknownStep', [$step]); |
||
118 | throw new InstallationException($msg); |
||
119 | } |
||
120 | |||
121 | $this->setInstallStatus(); |
||
122 | |||
123 | $this->checkInstallCompletion($step); |
||
124 | |||
125 | // check if this is an install being resumed |
||
126 | $this->resumeInstall($step); |
||
127 | |||
128 | $this->finishBootstrapping($step); |
||
129 | |||
130 | $params = $this->getPostVariables(); |
||
131 | |||
132 | $this->$step($params); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Set the auto login flag |
||
137 | * |
||
138 | * @param bool $flag Auto login |
||
139 | * |
||
140 | * @return void |
||
141 | */ |
||
142 | public function setAutoLogin($flag) { |
||
143 | $this->autoLogin = (bool) $flag; |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * A batch install of Elgg |
||
148 | * |
||
149 | * All required parameters must be passed in as an associative array. See |
||
150 | * $requiredParams for a list of them. This creates the necessary files, |
||
151 | * loads the database, configures the site settings, and creates the admin |
||
152 | * account. If it fails, an exception is thrown. It does not check any of |
||
153 | * the requirements as the multiple step web installer does. |
||
154 | * |
||
155 | * If the settings.php file exists, it will use that rather than the parameters |
||
156 | * passed to this function. |
||
157 | * |
||
158 | * @param array $params Array of key value pairs |
||
159 | * @param bool $createHtaccess Should .htaccess be created |
||
160 | * |
||
161 | * @return void |
||
162 | * @throws InstallationException |
||
163 | */ |
||
164 | public function batchInstall(array $params, $createHtaccess = false) { |
||
165 | |||
166 | |||
167 | restore_error_handler(); |
||
168 | restore_exception_handler(); |
||
169 | |||
170 | $defaults = [ |
||
171 | 'dbhost' => 'localhost', |
||
172 | 'dbprefix' => 'elgg_', |
||
173 | 'language' => 'en', |
||
174 | 'siteaccess' => ACCESS_PUBLIC, |
||
175 | 'site_guid' => 1, |
||
176 | ]; |
||
177 | $params = array_merge($defaults, $params); |
||
178 | |||
179 | $requiredParams = [ |
||
180 | 'dbuser', |
||
181 | 'dbpassword', |
||
182 | 'dbname', |
||
183 | 'sitename', |
||
184 | 'wwwroot', |
||
185 | 'dataroot', |
||
186 | 'displayname', |
||
187 | 'email', |
||
188 | 'username', |
||
189 | 'password', |
||
190 | ]; |
||
191 | foreach ($requiredParams as $key) { |
||
192 | if (empty($params[$key])) { |
||
193 | $msg = _elgg_services()->translator->translate('install:error:requiredfield', [$key]); |
||
194 | throw new InstallationException($msg); |
||
195 | } |
||
196 | } |
||
197 | |||
198 | // password is passed in once |
||
199 | $params['password1'] = $params['password2'] = $params['password']; |
||
200 | |||
201 | if ($createHtaccess) { |
||
202 | $rewriteTester = new ElggRewriteTester(); |
||
203 | if (!$rewriteTester->createHtaccess($params['wwwroot'], Directory\Local::root()->getPath())) { |
||
204 | throw new InstallationException(_elgg_services()->translator->translate('install:error:htaccess')); |
||
205 | } |
||
206 | } |
||
207 | |||
208 | $this->setInstallStatus(); |
||
209 | |||
210 | View Code Duplication | if (!$this->status['config']) { |
|
211 | if (!$this->createSettingsFile($params)) { |
||
212 | throw new InstallationException(_elgg_services()->translator->translate('install:error:settings')); |
||
213 | } |
||
214 | } |
||
215 | |||
216 | if (!$this->connectToDatabase()) { |
||
217 | throw new InstallationException(_elgg_services()->translator->translate('install:error:databasesettings')); |
||
218 | } |
||
219 | |||
220 | View Code Duplication | if (!$this->status['database']) { |
|
221 | if (!$this->installDatabase()) { |
||
222 | throw new InstallationException(_elgg_services()->translator->translate('install:error:cannotloadtables')); |
||
223 | } |
||
224 | } |
||
225 | |||
226 | // load remaining core libraries |
||
227 | $this->finishBootstrapping('settings'); |
||
228 | |||
229 | if (!$this->saveSiteSettings($params)) { |
||
230 | throw new InstallationException(_elgg_services()->translator->translate('install:error:savesitesettings')); |
||
231 | } |
||
232 | |||
233 | if (!$this->createAdminAccount($params)) { |
||
234 | throw new InstallationException(_elgg_services()->translator->translate('install:admin:cannot_create')); |
||
235 | } |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * Renders the data passed by a controller |
||
240 | * |
||
241 | * @param string $step The current step |
||
242 | * @param array $vars Array of vars to pass to the view |
||
243 | * |
||
244 | * @return void |
||
245 | */ |
||
246 | protected function render($step, $vars = []) { |
||
247 | $vars['next_step'] = $this->getNextStep($step); |
||
248 | |||
249 | $title = _elgg_services()->translator->translate("install:$step"); |
||
250 | $body = elgg_view("install/pages/$step", $vars); |
||
251 | |||
252 | echo elgg_view_page( |
||
253 | $title, |
||
254 | $body, |
||
255 | 'default', |
||
256 | [ |
||
257 | 'step' => $step, |
||
258 | 'steps' => $this->getSteps(), |
||
259 | ] |
||
260 | ); |
||
261 | exit; |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Step controllers |
||
266 | */ |
||
267 | |||
268 | /** |
||
269 | * Welcome controller |
||
270 | * |
||
271 | * @param array $vars Not used |
||
272 | * |
||
273 | * @return void |
||
274 | */ |
||
275 | protected function welcome($vars) { |
||
276 | $this->render('welcome'); |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * Requirements controller |
||
281 | * |
||
282 | * Checks version of php, libraries, permissions, and rewrite rules |
||
283 | * |
||
284 | * @param array $vars Vars |
||
285 | * |
||
286 | * @return void |
||
287 | */ |
||
288 | protected function requirements($vars) { |
||
289 | |||
290 | $report = []; |
||
291 | |||
292 | // check PHP parameters and libraries |
||
293 | $this->checkPHP($report); |
||
294 | |||
295 | // check URL rewriting |
||
296 | $this->checkRewriteRules($report); |
||
297 | |||
298 | // check for existence of settings file |
||
299 | if ($this->checkSettingsFile($report) != true) { |
||
300 | // no file, so check permissions on engine directory |
||
301 | $this->isInstallDirWritable($report); |
||
302 | } |
||
303 | |||
304 | // check the database later |
||
305 | $report['database'] = [[ |
||
306 | 'severity' => 'info', |
||
307 | 'message' => _elgg_services()->translator->translate('install:check:database') |
||
308 | ]]; |
||
309 | |||
310 | // any failures? |
||
311 | $numFailures = $this->countNumConditions($report, 'failure'); |
||
312 | |||
313 | // any warnings |
||
314 | $numWarnings = $this->countNumConditions($report, 'warning'); |
||
315 | |||
316 | |||
317 | $params = [ |
||
318 | 'report' => $report, |
||
319 | 'num_failures' => $numFailures, |
||
320 | 'num_warnings' => $numWarnings, |
||
321 | ]; |
||
322 | |||
323 | $this->render('requirements', $params); |
||
324 | } |
||
325 | |||
326 | /** |
||
327 | * Database set up controller |
||
328 | * |
||
329 | * Creates the settings.php file and creates the database tables |
||
330 | * |
||
331 | * @param array $submissionVars Submitted form variables |
||
332 | * |
||
333 | * @return void |
||
334 | */ |
||
335 | protected function database($submissionVars) { |
||
336 | |||
337 | $formVars = [ |
||
338 | 'dbuser' => [ |
||
339 | 'type' => 'text', |
||
340 | 'value' => '', |
||
341 | 'required' => true, |
||
342 | ], |
||
343 | 'dbpassword' => [ |
||
344 | 'type' => 'password', |
||
345 | 'value' => '', |
||
346 | 'required' => false, |
||
347 | ], |
||
348 | 'dbname' => [ |
||
349 | 'type' => 'text', |
||
350 | 'value' => '', |
||
351 | 'required' => true, |
||
352 | ], |
||
353 | 'dbhost' => [ |
||
354 | 'type' => 'text', |
||
355 | 'value' => 'localhost', |
||
356 | 'required' => true, |
||
357 | ], |
||
358 | 'dbprefix' => [ |
||
359 | 'type' => 'text', |
||
360 | 'value' => 'elgg_', |
||
361 | 'required' => true, |
||
362 | ], |
||
363 | 'dataroot' => [ |
||
364 | 'type' => 'text', |
||
365 | 'value' => '', |
||
366 | 'required' => true, |
||
367 | ], |
||
368 | 'wwwroot' => [ |
||
369 | 'type' => 'url', |
||
370 | 'value' => _elgg_services()->config->wwwroot, |
||
371 | 'required' => true, |
||
372 | ], |
||
373 | 'timezone' => [ |
||
374 | 'type' => 'dropdown', |
||
375 | 'value' => 'UTC', |
||
376 | 'options' => \DateTimeZone::listIdentifiers(), |
||
377 | 'required' => true |
||
378 | ] |
||
379 | ]; |
||
380 | |||
381 | if ($this->checkSettingsFile()) { |
||
382 | // user manually created settings file so we fake out action test |
||
383 | $this->isAction = true; |
||
384 | } |
||
385 | |||
386 | if ($this->isAction) { |
||
387 | do { |
||
388 | // only create settings file if it doesn't exist |
||
389 | if (!$this->checkSettingsFile()) { |
||
390 | if (!$this->validateDatabaseVars($submissionVars, $formVars)) { |
||
391 | // error so we break out of action and serve same page |
||
392 | break; |
||
393 | } |
||
394 | |||
395 | if (!$this->createSettingsFile($submissionVars)) { |
||
396 | break; |
||
397 | } |
||
398 | } |
||
399 | |||
400 | // check db version and connect |
||
401 | if (!$this->connectToDatabase()) { |
||
402 | break; |
||
403 | } |
||
404 | |||
405 | if (!$this->installDatabase()) { |
||
406 | break; |
||
407 | } |
||
408 | |||
409 | system_message(_elgg_services()->translator->translate('install:success:database')); |
||
410 | |||
411 | $this->continueToNextStep('database'); |
||
412 | } while (false); // PHP doesn't support breaking out of if statements |
||
413 | } |
||
414 | |||
415 | $formVars = $this->makeFormSticky($formVars, $submissionVars); |
||
416 | |||
417 | $params = ['variables' => $formVars,]; |
||
418 | |||
419 | if ($this->checkSettingsFile()) { |
||
420 | // settings file exists and we're here so failed to create database |
||
421 | $params['failure'] = true; |
||
422 | } |
||
423 | |||
424 | $this->render('database', $params); |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Site settings controller |
||
429 | * |
||
430 | * Sets the site name, URL, data directory, etc. |
||
431 | * |
||
432 | * @param array $submissionVars Submitted vars |
||
433 | * |
||
434 | * @return void |
||
435 | */ |
||
436 | protected function settings($submissionVars) { |
||
437 | $formVars = [ |
||
438 | 'sitename' => [ |
||
439 | 'type' => 'text', |
||
440 | 'value' => 'My New Community', |
||
441 | 'required' => true, |
||
442 | ], |
||
443 | 'siteemail' => [ |
||
444 | 'type' => 'email', |
||
445 | 'value' => '', |
||
446 | 'required' => false, |
||
447 | ], |
||
448 | 'siteaccess' => [ |
||
449 | 'type' => 'access', |
||
450 | 'value' => ACCESS_PUBLIC, |
||
451 | 'required' => true, |
||
452 | ], |
||
453 | ]; |
||
454 | |||
455 | // if Apache, we give user option of having Elgg create data directory |
||
456 | //if (ElggRewriteTester::guessWebServer() == 'apache') { |
||
457 | // $formVars['dataroot']['type'] = 'combo'; |
||
458 | // $GLOBALS['_ELGG']->translations['en']['install:settings:help:dataroot'] = |
||
459 | // $GLOBALS['_ELGG']->translations['en']['install:settings:help:dataroot:apache']; |
||
460 | //} |
||
461 | |||
462 | if ($this->isAction) { |
||
463 | do { |
||
464 | //if (!$this->createDataDirectory($submissionVars, $formVars)) { |
||
465 | // break; |
||
466 | //} |
||
467 | |||
468 | if (!$this->validateSettingsVars($submissionVars, $formVars)) { |
||
469 | break; |
||
470 | } |
||
471 | |||
472 | if (!$this->saveSiteSettings($submissionVars)) { |
||
473 | break; |
||
474 | } |
||
475 | |||
476 | system_message(_elgg_services()->translator->translate('install:success:settings')); |
||
477 | |||
478 | $this->continueToNextStep('settings'); |
||
479 | } while (false); // PHP doesn't support breaking out of if statements |
||
480 | } |
||
481 | |||
482 | $formVars = $this->makeFormSticky($formVars, $submissionVars); |
||
483 | |||
484 | $this->render('settings', ['variables' => $formVars]); |
||
485 | } |
||
486 | |||
487 | /** |
||
488 | * Admin account controller |
||
489 | * |
||
490 | * Creates an admin user account |
||
491 | * |
||
492 | * @param array $submissionVars Submitted vars |
||
493 | * |
||
494 | * @return void |
||
495 | */ |
||
496 | protected function admin($submissionVars) { |
||
497 | $formVars = [ |
||
498 | 'displayname' => [ |
||
499 | 'type' => 'text', |
||
500 | 'value' => '', |
||
501 | 'required' => true, |
||
502 | ], |
||
503 | 'email' => [ |
||
504 | 'type' => 'email', |
||
505 | 'value' => '', |
||
506 | 'required' => true, |
||
507 | ], |
||
508 | 'username' => [ |
||
509 | 'type' => 'text', |
||
510 | 'value' => '', |
||
511 | 'required' => true, |
||
512 | ], |
||
513 | 'password1' => [ |
||
514 | 'type' => 'password', |
||
515 | 'value' => '', |
||
516 | 'required' => true, |
||
517 | 'pattern' => '.{6,}', |
||
518 | ], |
||
519 | 'password2' => [ |
||
520 | 'type' => 'password', |
||
521 | 'value' => '', |
||
522 | 'required' => true, |
||
523 | ], |
||
524 | ]; |
||
525 | |||
526 | if ($this->isAction) { |
||
527 | call_user_func(function () use ($submissionVars, $formVars) { |
||
528 | if (!$this->validateAdminVars($submissionVars, $formVars)) { |
||
529 | return; |
||
530 | } |
||
531 | |||
532 | if (!$this->createAdminAccount($submissionVars, $this->autoLogin)) { |
||
533 | return; |
||
534 | } |
||
535 | |||
536 | system_message(_elgg_services()->translator->translate('install:success:admin')); |
||
537 | |||
538 | $this->continueToNextStep('admin'); |
||
539 | }); |
||
540 | } |
||
541 | |||
542 | // bit of a hack to get the password help to show right number of characters |
||
543 | |||
544 | $lang = _elgg_services()->translator->getCurrentLanguage(); |
||
545 | $GLOBALS['_ELGG']->translations[$lang]['install:admin:help:password1'] = |
||
546 | sprintf($GLOBALS['_ELGG']->translations[$lang]['install:admin:help:password1'], |
||
547 | $this->CONFIG->min_password_length); |
||
548 | |||
549 | $formVars = $this->makeFormSticky($formVars, $submissionVars); |
||
550 | |||
551 | $this->render('admin', ['variables' => $formVars]); |
||
552 | } |
||
553 | |||
554 | /** |
||
555 | * Controller for last step |
||
556 | * |
||
557 | * @return void |
||
558 | */ |
||
559 | protected function complete() { |
||
560 | |||
561 | // nudge to check out settings |
||
562 | $link = elgg_format_element([ |
||
563 | '#tag_name' => 'a', |
||
564 | '#text' => _elgg_services()->translator->translate('install:complete:admin_notice:link_text'), |
||
565 | 'href' => elgg_normalize_url('admin/settings/basic'), |
||
566 | ]); |
||
567 | $notice = _elgg_services()->translator->translate('install:complete:admin_notice', [$link]); |
||
568 | elgg_add_admin_notice('fresh_install', $notice); |
||
569 | |||
570 | $this->render('complete'); |
||
571 | } |
||
572 | |||
573 | /** |
||
574 | * Step management |
||
575 | */ |
||
576 | |||
577 | /** |
||
578 | * Get an array of steps |
||
579 | * |
||
580 | * @return array |
||
581 | */ |
||
582 | protected function getSteps() { |
||
583 | return $this->steps; |
||
584 | } |
||
585 | |||
586 | /** |
||
587 | * Forwards the browser to the next step |
||
588 | * |
||
589 | * @param string $currentStep Current installation step |
||
590 | * |
||
591 | * @return void |
||
592 | */ |
||
593 | protected function continueToNextStep($currentStep) { |
||
594 | $this->isAction = false; |
||
595 | forward($this->getNextStepUrl($currentStep)); |
||
596 | } |
||
597 | |||
598 | /** |
||
599 | * Get the next step as a string |
||
600 | * |
||
601 | * @param string $currentStep Current installation step |
||
602 | * |
||
603 | * @return string |
||
604 | */ |
||
605 | protected function getNextStep($currentStep) { |
||
606 | $index = 1 + array_search($currentStep, $this->steps); |
||
607 | if (isset($this->steps[$index])) { |
||
608 | return $this->steps[$index]; |
||
609 | } else { |
||
610 | return null; |
||
611 | } |
||
612 | } |
||
613 | |||
614 | /** |
||
615 | * Get the URL of the next step |
||
616 | * |
||
617 | * @param string $currentStep Current installation step |
||
618 | * |
||
619 | * @return string |
||
620 | */ |
||
621 | protected function getNextStepUrl($currentStep) { |
||
622 | $nextStep = $this->getNextStep($currentStep); |
||
623 | return _elgg_services()->config->wwwroot . "install.php?step=$nextStep"; |
||
624 | } |
||
625 | |||
626 | /** |
||
627 | * Check the different install steps for completion |
||
628 | * |
||
629 | * @return void |
||
630 | * @throws InstallationException |
||
631 | */ |
||
632 | protected function setInstallStatus() { |
||
633 | $settings_found = false; |
||
634 | foreach (_elgg_services()->config->getSettingsPaths() as $path) { |
||
635 | if (is_file($path) && is_readable($path)) { |
||
636 | $settings_found = true; |
||
637 | break; |
||
638 | } |
||
639 | } |
||
640 | |||
641 | if (!$settings_found) { |
||
642 | return; |
||
643 | } |
||
644 | |||
645 | $this->loadSettingsFile(); |
||
646 | |||
647 | $this->status['config'] = true; |
||
648 | |||
649 | // must be able to connect to database to jump install steps |
||
650 | $dbSettingsPass = $this->checkDatabaseSettings( |
||
651 | $this->CONFIG->dbuser, |
||
652 | $this->CONFIG->dbpass, |
||
653 | $this->CONFIG->dbname, |
||
654 | $this->CONFIG->dbhost |
||
655 | ); |
||
656 | |||
657 | if ($dbSettingsPass == false) { |
||
0 ignored issues
–
show
|
|||
658 | return; |
||
659 | } |
||
660 | |||
661 | if (!include_once(\Elgg\Application::elggDir()->getPath("engine/lib/database.php"))) { |
||
662 | throw new InstallationException(_elgg_services()->translator->translate('InstallationException:MissingLibrary', ['database.php'])); |
||
663 | } |
||
664 | |||
665 | // check that the config table has been created |
||
666 | $query = "show tables"; |
||
667 | $result = _elgg_services()->db->getData($query); |
||
668 | if ($result) { |
||
669 | foreach ($result as $table) { |
||
670 | $table = (array) $table; |
||
671 | if (in_array("{$this->CONFIG->dbprefix}config", $table)) { |
||
672 | $this->status['database'] = true; |
||
673 | } |
||
674 | } |
||
675 | if ($this->status['database'] == false) { |
||
0 ignored issues
–
show
|
|||
676 | return; |
||
677 | } |
||
678 | } else { |
||
679 | // no tables |
||
680 | return; |
||
681 | } |
||
682 | |||
683 | // check that the config table has entries |
||
684 | $query = "SELECT COUNT(*) AS total FROM {$this->CONFIG->dbprefix}config"; |
||
685 | $result = _elgg_services()->db->getData($query); |
||
686 | if ($result && $result[0]->total > 0) { |
||
687 | $this->status['settings'] = true; |
||
688 | } else { |
||
689 | return; |
||
690 | } |
||
691 | |||
692 | // check that the users entity table has an entry |
||
693 | $query = "SELECT COUNT(*) AS total FROM {$this->CONFIG->dbprefix}users_entity"; |
||
694 | $result = _elgg_services()->db->getData($query); |
||
695 | if ($result && $result[0]->total > 0) { |
||
696 | $this->status['admin'] = true; |
||
697 | } else { |
||
698 | return; |
||
699 | } |
||
700 | } |
||
701 | |||
702 | /** |
||
703 | * Security check to ensure the installer cannot be run after installation |
||
704 | * has finished. If this is detected, the viewer is sent to the front page. |
||
705 | * |
||
706 | * @param string $step Installation step to check against |
||
707 | * |
||
708 | * @return void |
||
709 | */ |
||
710 | protected function checkInstallCompletion($step) { |
||
711 | if ($step != 'complete') { |
||
712 | if (!in_array(false, $this->status)) { |
||
713 | // install complete but someone is trying to view an install page |
||
714 | forward(); |
||
715 | } |
||
716 | } |
||
717 | } |
||
718 | |||
719 | /** |
||
720 | * Check if this is a case of a install being resumed and figure |
||
721 | * out where to continue from. Returns the best guess on the step. |
||
722 | * |
||
723 | * @param string $step Installation step to resume from |
||
724 | * |
||
725 | * @return string |
||
726 | */ |
||
727 | protected function resumeInstall($step) { |
||
728 | // only do a resume from the first step |
||
729 | if ($step !== 'welcome') { |
||
730 | return; |
||
731 | } |
||
732 | |||
733 | if ($this->status['database'] == false) { |
||
734 | return; |
||
735 | } |
||
736 | |||
737 | if ($this->status['settings'] == false) { |
||
738 | forward("install.php?step=settings"); |
||
739 | } |
||
740 | |||
741 | if ($this->status['admin'] == false) { |
||
742 | forward("install.php?step=admin"); |
||
743 | } |
||
744 | |||
745 | // everything appears to be set up |
||
746 | forward("install.php?step=complete"); |
||
747 | } |
||
748 | |||
749 | /** |
||
750 | * Bootstraping |
||
751 | */ |
||
752 | |||
753 | /** |
||
754 | * Load the essential libraries of the engine |
||
755 | * |
||
756 | * @return void |
||
757 | */ |
||
758 | protected function bootstrapEngine() { |
||
759 | $config = new \Elgg\Config($this->CONFIG); |
||
760 | $services = new \Elgg\Di\ServiceProvider($config); |
||
761 | (new \Elgg\Application($services))->loadCore(); |
||
762 | } |
||
763 | |||
764 | /** |
||
765 | * Load remaining engine libraries and complete bootstrapping |
||
766 | * |
||
767 | * @param string $step Which step to boot strap for. Required because |
||
768 | * boot strapping is different until the DB is populated. |
||
769 | * |
||
770 | * @return void |
||
771 | * @throws InstallationException |
||
772 | */ |
||
773 | protected function finishBootstrapping($step) { |
||
774 | |||
775 | $dbIndex = array_search('database', $this->getSteps()); |
||
776 | $settingsIndex = array_search('settings', $this->getSteps()); |
||
777 | $adminIndex = array_search('admin', $this->getSteps()); |
||
778 | $completeIndex = array_search('complete', $this->getSteps()); |
||
779 | $stepIndex = array_search($step, $this->getSteps()); |
||
780 | |||
781 | // To log in the user, we need to use the Elgg core session handling. |
||
782 | // Otherwise, use default php session handling |
||
783 | $useElggSession = ($stepIndex == $adminIndex && $this->isAction) || |
||
784 | $stepIndex == $completeIndex; |
||
785 | if (!$useElggSession) { |
||
786 | session_name('Elgg_install'); |
||
787 | session_start(); |
||
788 | } |
||
789 | |||
790 | if ($stepIndex > $dbIndex) { |
||
791 | // once the database has been created, load rest of engine |
||
792 | |||
793 | $lib_dir = \Elgg\Application::elggDir()->chroot('/engine/lib/'); |
||
794 | |||
795 | $this->loadSettingsFile(); |
||
796 | |||
797 | $lib_files = [ |
||
798 | // these want to be loaded first apparently? |
||
799 | 'autoloader.php', |
||
800 | 'database.php', |
||
801 | 'actions.php', |
||
802 | |||
803 | 'admin.php', |
||
804 | 'annotations.php', |
||
805 | 'cron.php', |
||
806 | 'entities.php', |
||
807 | 'filestore.php', |
||
808 | 'group.php', |
||
809 | 'mb_wrapper.php', |
||
810 | 'memcache.php', |
||
811 | 'metadata.php', |
||
812 | 'metastrings.php', |
||
813 | 'navigation.php', |
||
814 | 'notification.php', |
||
815 | 'objects.php', |
||
816 | 'pagehandler.php', |
||
817 | 'pam.php', |
||
818 | 'plugins.php', |
||
819 | 'private_settings.php', |
||
820 | 'relationships.php', |
||
821 | 'river.php', |
||
822 | 'sites.php', |
||
823 | 'statistics.php', |
||
824 | 'tags.php', |
||
825 | 'user_settings.php', |
||
826 | 'users.php', |
||
827 | 'upgrade.php', |
||
828 | 'widgets.php', |
||
829 | ]; |
||
830 | |||
831 | foreach ($lib_files as $file) { |
||
832 | if (!include_once($lib_dir->getPath($file))) { |
||
833 | throw new InstallationException('InstallationException:MissingLibrary', [$file]); |
||
834 | } |
||
835 | } |
||
836 | |||
837 | _elgg_services()->db->setupConnections(); |
||
838 | _elgg_services()->translator->registerTranslations(\Elgg\Application::elggDir()->getPath("/languages/")); |
||
839 | $this->CONFIG->language = 'en'; |
||
840 | |||
841 | if ($stepIndex > $settingsIndex) { |
||
842 | $this->CONFIG->site_guid = 1; |
||
843 | $this->CONFIG->site = get_entity(1); |
||
844 | _elgg_services()->config->getCookieConfig(); |
||
845 | _elgg_session_boot(); |
||
846 | } |
||
847 | |||
848 | _elgg_services()->events->trigger('init', 'system'); |
||
849 | } |
||
850 | } |
||
851 | |||
852 | /** |
||
853 | * Set up configuration variables |
||
854 | * |
||
855 | * @return void |
||
856 | */ |
||
857 | protected function bootstrapConfig() { |
||
858 | $this->CONFIG->installer_running = true; |
||
859 | |||
860 | if (empty($this->CONFIG->dbencoding)) { |
||
861 | $this->CONFIG->dbencoding = 'utf8mb4'; |
||
862 | } |
||
863 | $this->CONFIG->wwwroot = $this->getBaseUrl(); |
||
864 | $this->CONFIG->url = $this->CONFIG->wwwroot; |
||
865 | $this->CONFIG->path = Directory\Local::root()->getPath('/'); |
||
866 | $this->view_path = $this->CONFIG->path . 'views/'; |
||
867 | $this->CONFIG->pluginspath = $this->CONFIG->path . 'mod/'; |
||
868 | $this->CONFIG->context = []; |
||
869 | $this->CONFIG->entity_types = ['group', 'object', 'site', 'user']; |
||
870 | |||
871 | // required by elgg_view_page() |
||
872 | $this->CONFIG->sitename = ''; |
||
873 | $this->CONFIG->sitedescription = ''; |
||
874 | |||
875 | // required by Elgg\Config::get |
||
876 | $this->CONFIG->site_guid = 1; |
||
877 | } |
||
878 | |||
879 | /** |
||
880 | * @return bool Whether the install process is encrypted. |
||
881 | */ |
||
882 | private function isHttps() { |
||
883 | return (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") || |
||
884 | (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443); |
||
885 | } |
||
886 | |||
887 | /** |
||
888 | * Get the best guess at the base URL |
||
889 | * |
||
890 | * @note Cannot use current_page_url() because it depends on $this->CONFIG->wwwroot |
||
891 | * @todo Should this be a core function? |
||
892 | * |
||
893 | * @return string |
||
894 | */ |
||
895 | protected function getBaseUrl() { |
||
896 | $protocol = $this->isHttps() ? 'https' : 'http'; |
||
897 | |||
898 | if (isset($_SERVER["SERVER_PORT"])) { |
||
899 | $port = ':' . $_SERVER["SERVER_PORT"]; |
||
900 | } else { |
||
901 | $port = ''; |
||
902 | } |
||
903 | if ($port == ':80' || $port == ':443') { |
||
904 | $port = ''; |
||
905 | } |
||
906 | $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; |
||
907 | $cutoff = strpos($uri, 'install.php'); |
||
908 | $uri = substr($uri, 0, $cutoff); |
||
909 | $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''; |
||
910 | |||
911 | return "$protocol://{$serverName}$port{$uri}"; |
||
912 | } |
||
913 | |||
914 | /** |
||
915 | * Load settings.php |
||
916 | * |
||
917 | * @return void |
||
918 | * @throws InstallationException |
||
919 | */ |
||
920 | protected function loadSettingsFile() { |
||
921 | try { |
||
922 | _elgg_services()->config->loadSettingsFile(); |
||
923 | } catch (\Exception $e) { |
||
924 | $msg = _elgg_services()->translator->translate('InstallationException:CannotLoadSettings'); |
||
925 | throw new InstallationException($msg, 0, $e); |
||
926 | } |
||
927 | } |
||
928 | |||
929 | /** |
||
930 | * Action handling methods |
||
931 | */ |
||
932 | |||
933 | /** |
||
934 | * Return an associative array of post variables |
||
935 | * (could be selective based on expected variables) |
||
936 | * |
||
937 | * Does not filter as person installing the site should not be attempting |
||
938 | * XSS attacks. If filtering is added, it should not be done for passwords. |
||
939 | * |
||
940 | * @return array |
||
941 | */ |
||
942 | protected function getPostVariables() { |
||
943 | $vars = []; |
||
944 | foreach ($_POST as $k => $v) { |
||
945 | $vars[$k] = $v; |
||
946 | } |
||
947 | return $vars; |
||
948 | } |
||
949 | |||
950 | /** |
||
951 | * If form is reshown, remember previously submitted variables |
||
952 | * |
||
953 | * @param array $formVars Vars int he form |
||
954 | * @param array $submissionVars Submitted vars |
||
955 | * |
||
956 | * @return array |
||
957 | */ |
||
958 | protected function makeFormSticky($formVars, $submissionVars) { |
||
959 | foreach ($submissionVars as $field => $value) { |
||
960 | $formVars[$field]['value'] = $value; |
||
961 | } |
||
962 | return $formVars; |
||
963 | } |
||
964 | |||
965 | /* Requirement checks support methods */ |
||
966 | |||
967 | /** |
||
968 | * Indicates whether the webserver can add settings.php on its own or not. |
||
969 | * |
||
970 | * @param array $report The requirements report object |
||
971 | * |
||
972 | * @return bool |
||
973 | */ |
||
974 | protected function isInstallDirWritable(&$report) { |
||
975 | $root = Directory\Local::root()->getPath(); |
||
976 | $abs_path = \Elgg\Application::elggDir()->getPath('elgg-config'); |
||
977 | |||
978 | if (0 === strpos($abs_path, $root)) { |
||
979 | $relative_path = substr($abs_path, strlen($root)); |
||
980 | } else { |
||
981 | $relative_path = $abs_path; |
||
982 | } |
||
983 | $relative_path = rtrim($relative_path, '/\\'); |
||
984 | |||
985 | $writable = is_writable(Directory\Local::root()->getPath('elgg-config')); |
||
986 | if (!$writable) { |
||
987 | $report['settings'] = [ |
||
988 | [ |
||
989 | 'severity' => 'failure', |
||
990 | 'message' => _elgg_services()->translator->translate('install:check:installdir', [$relative_path]), |
||
991 | ] |
||
992 | ]; |
||
993 | return false; |
||
994 | } |
||
995 | |||
996 | return true; |
||
997 | } |
||
998 | |||
999 | /** |
||
1000 | * Check that the settings file exists |
||
1001 | * |
||
1002 | * @param array $report The requirements report array |
||
1003 | * |
||
1004 | * @return bool |
||
1005 | */ |
||
1006 | protected function checkSettingsFile(&$report = []) { |
||
1007 | if (!is_file($this->getSettingsPath())) { |
||
1008 | return false; |
||
1009 | } |
||
1010 | |||
1011 | if (!is_readable($this->getSettingsPath())) { |
||
1012 | $report['settings'] = [ |
||
1013 | [ |
||
1014 | 'severity' => 'failure', |
||
1015 | 'message' => _elgg_services()->translator->translate('install:check:readsettings'), |
||
1016 | ] |
||
1017 | ]; |
||
1018 | } |
||
1019 | |||
1020 | return true; |
||
1021 | } |
||
1022 | |||
1023 | /** |
||
1024 | * Returns the path to the root settings.php file. |
||
1025 | * |
||
1026 | * @return string |
||
1027 | */ |
||
1028 | private function getSettingsPath() { |
||
1029 | return Directory\Local::root()->getPath("elgg-config/settings.php"); |
||
1030 | } |
||
1031 | |||
1032 | /** |
||
1033 | * Check version of PHP, extensions, and variables |
||
1034 | * |
||
1035 | * @param array $report The requirements report array |
||
1036 | * |
||
1037 | * @return void |
||
1038 | */ |
||
1039 | protected function checkPHP(&$report) { |
||
1040 | $phpReport = []; |
||
1041 | |||
1042 | $min_php_version = '5.6.0'; |
||
1043 | if (version_compare(PHP_VERSION, $min_php_version, '<')) { |
||
1044 | $phpReport[] = [ |
||
1045 | 'severity' => 'failure', |
||
1046 | 'message' => _elgg_services()->translator->translate('install:check:php:version', [$min_php_version, PHP_VERSION]) |
||
1047 | ]; |
||
1048 | } |
||
1049 | |||
1050 | $this->checkPhpExtensions($phpReport); |
||
1051 | |||
1052 | $this->checkPhpDirectives($phpReport); |
||
1053 | |||
1054 | if (count($phpReport) == 0) { |
||
1055 | $phpReport[] = [ |
||
1056 | 'severity' => 'pass', |
||
1057 | 'message' => _elgg_services()->translator->translate('install:check:php:success') |
||
1058 | ]; |
||
1059 | } |
||
1060 | |||
1061 | $report['php'] = $phpReport; |
||
1062 | } |
||
1063 | |||
1064 | /** |
||
1065 | * Check the server's PHP extensions |
||
1066 | * |
||
1067 | * @param array $phpReport The PHP requirements report array |
||
1068 | * |
||
1069 | * @return void |
||
1070 | */ |
||
1071 | protected function checkPhpExtensions(&$phpReport) { |
||
1072 | $extensions = get_loaded_extensions(); |
||
1073 | $requiredExtensions = [ |
||
1074 | 'pdo_mysql', |
||
1075 | 'json', |
||
1076 | 'xml', |
||
1077 | 'gd', |
||
1078 | ]; |
||
1079 | View Code Duplication | foreach ($requiredExtensions as $extension) { |
|
1080 | if (!in_array($extension, $extensions)) { |
||
1081 | $phpReport[] = [ |
||
1082 | 'severity' => 'failure', |
||
1083 | 'message' => _elgg_services()->translator->translate('install:check:php:extension', [$extension]) |
||
1084 | ]; |
||
1085 | } |
||
1086 | } |
||
1087 | |||
1088 | $recommendedExtensions = [ |
||
1089 | 'mbstring', |
||
1090 | ]; |
||
1091 | View Code Duplication | foreach ($recommendedExtensions as $extension) { |
|
1092 | if (!in_array($extension, $extensions)) { |
||
1093 | $phpReport[] = [ |
||
1094 | 'severity' => 'warning', |
||
1095 | 'message' => _elgg_services()->translator->translate('install:check:php:extension:recommend', [$extension]) |
||
1096 | ]; |
||
1097 | } |
||
1098 | } |
||
1099 | } |
||
1100 | |||
1101 | /** |
||
1102 | * Check PHP parameters |
||
1103 | * |
||
1104 | * @param array $phpReport The PHP requirements report array |
||
1105 | * |
||
1106 | * @return void |
||
1107 | */ |
||
1108 | protected function checkPhpDirectives(&$phpReport) { |
||
1109 | if (ini_get('open_basedir')) { |
||
1110 | $phpReport[] = [ |
||
1111 | 'severity' => 'warning', |
||
1112 | 'message' => _elgg_services()->translator->translate("install:check:php:open_basedir") |
||
1113 | ]; |
||
1114 | } |
||
1115 | |||
1116 | if (ini_get('safe_mode')) { |
||
1117 | $phpReport[] = [ |
||
1118 | 'severity' => 'warning', |
||
1119 | 'message' => _elgg_services()->translator->translate("install:check:php:safe_mode") |
||
1120 | ]; |
||
1121 | } |
||
1122 | |||
1123 | if (ini_get('arg_separator.output') !== '&') { |
||
1124 | $separator = htmlspecialchars(ini_get('arg_separator.output')); |
||
1125 | $msg = _elgg_services()->translator->translate("install:check:php:arg_separator", [$separator]); |
||
1126 | $phpReport[] = [ |
||
1127 | 'severity' => 'failure', |
||
1128 | 'message' => $msg, |
||
1129 | ]; |
||
1130 | } |
||
1131 | |||
1132 | if (ini_get('register_globals')) { |
||
1133 | $phpReport[] = [ |
||
1134 | 'severity' => 'failure', |
||
1135 | 'message' => _elgg_services()->translator->translate("install:check:php:register_globals") |
||
1136 | ]; |
||
1137 | } |
||
1138 | |||
1139 | if (ini_get('session.auto_start')) { |
||
1140 | $phpReport[] = [ |
||
1141 | 'severity' => 'failure', |
||
1142 | 'message' => _elgg_services()->translator->translate("install:check:php:session.auto_start") |
||
1143 | ]; |
||
1144 | } |
||
1145 | } |
||
1146 | |||
1147 | /** |
||
1148 | * Confirm that the rewrite rules are firing |
||
1149 | * |
||
1150 | * @param array $report The requirements report array |
||
1151 | * |
||
1152 | * @return void |
||
1153 | */ |
||
1154 | protected function checkRewriteRules(&$report) { |
||
1155 | $tester = new ElggRewriteTester(); |
||
1156 | $url = _elgg_services()->config->wwwroot . "rewrite.php"; |
||
1157 | $report['rewrite'] = [$tester->run($url, Directory\Local::root()->getPath())]; |
||
1158 | } |
||
1159 | |||
1160 | /** |
||
1161 | * Check if the request is coming from the URL rewrite test on the |
||
1162 | * requirements page. |
||
1163 | * |
||
1164 | * @return void |
||
1165 | */ |
||
1166 | protected function processRewriteTest() { |
||
1167 | if (strpos($_SERVER['REQUEST_URI'], 'rewrite.php') !== false) { |
||
1168 | echo \Elgg\Application::REWRITE_TEST_OUTPUT; |
||
1169 | exit; |
||
1170 | } |
||
1171 | } |
||
1172 | |||
1173 | /** |
||
1174 | * Count the number of failures in the requirements report |
||
1175 | * |
||
1176 | * @param array $report The requirements report array |
||
1177 | * @param string $condition 'failure' or 'warning' |
||
1178 | * |
||
1179 | * @return int |
||
1180 | */ |
||
1181 | protected function countNumConditions($report, $condition) { |
||
1182 | $count = 0; |
||
1183 | foreach ($report as $category => $checks) { |
||
1184 | foreach ($checks as $check) { |
||
1185 | if ($check['severity'] === $condition) { |
||
1186 | $count++; |
||
1187 | } |
||
1188 | } |
||
1189 | } |
||
1190 | |||
1191 | return $count; |
||
1192 | } |
||
1193 | |||
1194 | |||
1195 | /** |
||
1196 | * Database support methods |
||
1197 | */ |
||
1198 | |||
1199 | /** |
||
1200 | * Validate the variables for the database step |
||
1201 | * |
||
1202 | * @param array $submissionVars Submitted vars |
||
1203 | * @param array $formVars Vars in the form |
||
1204 | * |
||
1205 | * @return bool |
||
1206 | */ |
||
1207 | protected function validateDatabaseVars($submissionVars, $formVars) { |
||
1208 | |||
1209 | View Code Duplication | foreach ($formVars as $field => $info) { |
|
1210 | if ($info['required'] == true && !$submissionVars[$field]) { |
||
1211 | $name = _elgg_services()->translator->translate("install:database:label:$field"); |
||
1212 | register_error(_elgg_services()->translator->translate('install:error:requiredfield', [$name])); |
||
1213 | return false; |
||
1214 | } |
||
1215 | } |
||
1216 | |||
1217 | // check that data root is absolute path |
||
1218 | if (stripos(PHP_OS, 'win') === 0) { |
||
1219 | View Code Duplication | if (strpos($submissionVars['dataroot'], ':') !== 1) { |
|
1220 | $msg = _elgg_services()->translator->translate('install:error:relative_path', [$submissionVars['dataroot']]); |
||
1221 | register_error($msg); |
||
1222 | return false; |
||
1223 | } |
||
1224 | View Code Duplication | } else { |
|
1225 | if (strpos($submissionVars['dataroot'], '/') !== 0) { |
||
1226 | $msg = _elgg_services()->translator->translate('install:error:relative_path', [$submissionVars['dataroot']]); |
||
1227 | register_error($msg); |
||
1228 | return false; |
||
1229 | } |
||
1230 | } |
||
1231 | |||
1232 | // check that data root exists |
||
1233 | View Code Duplication | if (!is_dir($submissionVars['dataroot'])) { |
|
1234 | $msg = _elgg_services()->translator->translate('install:error:datadirectoryexists', [$submissionVars['dataroot']]); |
||
1235 | register_error($msg); |
||
1236 | return false; |
||
1237 | } |
||
1238 | |||
1239 | // check that data root is writable |
||
1240 | View Code Duplication | if (!is_writable($submissionVars['dataroot'])) { |
|
1241 | $msg = _elgg_services()->translator->translate('install:error:writedatadirectory', [$submissionVars['dataroot']]); |
||
1242 | register_error($msg); |
||
1243 | return false; |
||
1244 | } |
||
1245 | |||
1246 | if (!isset($this->CONFIG->data_dir_override) || !$this->CONFIG->data_dir_override) { |
||
1247 | // check that data root is not subdirectory of Elgg root |
||
1248 | if (stripos($submissionVars['dataroot'], $this->CONFIG->path) === 0) { |
||
1249 | $msg = _elgg_services()->translator->translate('install:error:locationdatadirectory', [$submissionVars['dataroot']]); |
||
1250 | register_error($msg); |
||
1251 | return false; |
||
1252 | } |
||
1253 | } |
||
1254 | |||
1255 | // according to postgres documentation: SQL identifiers and key words must |
||
1256 | // begin with a letter (a-z, but also letters with diacritical marks and |
||
1257 | // non-Latin letters) or an underscore (_). Subsequent characters in an |
||
1258 | // identifier or key word can be letters, underscores, digits (0-9), or dollar signs ($). |
||
1259 | // Refs #4994 |
||
1260 | if (!preg_match("/^[a-zA-Z_][\w]*$/", $submissionVars['dbprefix'])) { |
||
1261 | register_error(_elgg_services()->translator->translate('install:error:database_prefix')); |
||
1262 | return false; |
||
1263 | } |
||
1264 | |||
1265 | return $this->checkDatabaseSettings( |
||
1266 | $submissionVars['dbuser'], |
||
1267 | $submissionVars['dbpassword'], |
||
1268 | $submissionVars['dbname'], |
||
1269 | $submissionVars['dbhost'] |
||
1270 | ); |
||
1271 | } |
||
1272 | |||
1273 | /** |
||
1274 | * Confirm the settings for the database |
||
1275 | * |
||
1276 | * @param string $user Username |
||
1277 | * @param string $password Password |
||
1278 | * @param string $dbname Database name |
||
1279 | * @param string $host Host |
||
1280 | * |
||
1281 | * @return bool |
||
1282 | */ |
||
1283 | protected function checkDatabaseSettings($user, $password, $dbname, $host) { |
||
1284 | $config = new \Elgg\Database\Config((object) [ |
||
1285 | 'dbhost' => $host, |
||
1286 | 'dbuser' => $user, |
||
1287 | 'dbpass' => $password, |
||
1288 | 'dbname' => $dbname, |
||
1289 | 'dbencoding' => 'utf8mb4', |
||
1290 | ]); |
||
1291 | $db = new \Elgg\Database($config); |
||
1292 | |||
1293 | try { |
||
1294 | $db->getDataRow("SELECT 1"); |
||
1295 | } catch (DatabaseException $e) { |
||
1296 | if (0 === strpos($e->getMessage(), "Elgg couldn't connect")) { |
||
1297 | register_error(_elgg_services()->translator->translate('install:error:databasesettings')); |
||
1298 | } else { |
||
1299 | register_error(_elgg_services()->translator->translate('install:error:nodatabase', [$dbname])); |
||
1300 | } |
||
1301 | return false; |
||
1302 | } |
||
1303 | |||
1304 | // check MySQL version |
||
1305 | $version = $db->getServerVersion(\Elgg\Database\Config::READ_WRITE); |
||
1306 | if (version_compare($version, '5.5.3', '<')) { |
||
1307 | register_error(_elgg_services()->translator->translate('install:error:oldmysql2', [$version])); |
||
1308 | return false; |
||
1309 | } |
||
1310 | |||
1311 | return true; |
||
1312 | } |
||
1313 | |||
1314 | /** |
||
1315 | * Writes the settings file to the engine directory |
||
1316 | * |
||
1317 | * @param array $params Array of inputted params from the user |
||
1318 | * |
||
1319 | * @return bool |
||
1320 | */ |
||
1321 | protected function createSettingsFile($params) { |
||
1322 | $template = \Elgg\Application::elggDir()->getContents("elgg-config/settings.example.php"); |
||
1323 | if (!$template) { |
||
1324 | register_error(_elgg_services()->translator->translate('install:error:readsettingsphp')); |
||
1325 | return false; |
||
1326 | } |
||
1327 | |||
1328 | foreach ($params as $k => $v) { |
||
1329 | $template = str_replace("{{" . $k . "}}", $v, $template); |
||
1330 | } |
||
1331 | |||
1332 | $result = file_put_contents($this->getSettingsPath(), $template); |
||
1333 | if (!$result) { |
||
1334 | register_error(_elgg_services()->translator->translate('install:error:writesettingphp')); |
||
1335 | return false; |
||
1336 | } |
||
1337 | |||
1338 | return true; |
||
1339 | } |
||
1340 | |||
1341 | /** |
||
1342 | * Bootstrap database connection before entire engine is available |
||
1343 | * |
||
1344 | * @return bool |
||
1345 | */ |
||
1346 | protected function connectToDatabase() { |
||
1347 | if (!include_once($this->getSettingsPath())) { |
||
1348 | register_error('Elgg could not load the settings file. It does not exist or there is a file permissions issue.'); |
||
1349 | return false; |
||
1350 | } |
||
1351 | |||
1352 | if (!include_once(\Elgg\Application::elggDir()->getPath("engine/lib/database.php"))) { |
||
1353 | register_error('Could not load database.php'); |
||
1354 | return false; |
||
1355 | } |
||
1356 | |||
1357 | try { |
||
1358 | _elgg_services()->db->setupConnections(); |
||
1359 | } catch (DatabaseException $e) { |
||
1360 | register_error($e->getMessage()); |
||
1361 | return false; |
||
1362 | } |
||
1363 | |||
1364 | return true; |
||
1365 | } |
||
1366 | |||
1367 | /** |
||
1368 | * Create the database tables |
||
1369 | * |
||
1370 | * @return bool |
||
1371 | */ |
||
1372 | protected function installDatabase() { |
||
1373 | try { |
||
1374 | _elgg_services()->db->runSqlScript(\Elgg\Application::elggDir()->getPath("/engine/schema/mysql.sql")); |
||
1375 | } catch (Exception $e) { |
||
1376 | $msg = $e->getMessage(); |
||
1377 | if (strpos($msg, 'already exists')) { |
||
1378 | $msg = _elgg_services()->translator->translate('install:error:tables_exist'); |
||
1379 | } |
||
1380 | register_error($msg); |
||
1381 | return false; |
||
1382 | } |
||
1383 | |||
1384 | return true; |
||
1385 | } |
||
1386 | |||
1387 | /** |
||
1388 | * Site settings support methods |
||
1389 | */ |
||
1390 | |||
1391 | /** |
||
1392 | * Create the data directory if requested |
||
1393 | * |
||
1394 | * @param array $submissionVars Submitted vars |
||
1395 | * @param array $formVars Variables in the form |
||
1396 | * |
||
1397 | * @return bool |
||
1398 | */ |
||
1399 | protected function createDataDirectory(&$submissionVars, $formVars) { |
||
1400 | // did the user have option of Elgg creating the data directory |
||
1401 | if ($formVars['dataroot']['type'] != 'combo') { |
||
1402 | return true; |
||
1403 | } |
||
1404 | |||
1405 | // did the user select the option |
||
1406 | if ($submissionVars['dataroot'] != 'dataroot-checkbox') { |
||
1407 | return true; |
||
1408 | } |
||
1409 | |||
1410 | $dir = sanitise_filepath($submissionVars['path']) . 'data'; |
||
1411 | if (file_exists($dir) || mkdir($dir, 0700)) { |
||
1412 | $submissionVars['dataroot'] = $dir; |
||
1413 | if (!file_exists("$dir/.htaccess")) { |
||
1414 | $htaccess = "Order Deny,Allow\nDeny from All\n"; |
||
1415 | if (!file_put_contents("$dir/.htaccess", $htaccess)) { |
||
1416 | return false; |
||
1417 | } |
||
1418 | } |
||
1419 | return true; |
||
1420 | } |
||
1421 | |||
1422 | return false; |
||
1423 | } |
||
1424 | |||
1425 | /** |
||
1426 | * Validate the site settings form variables |
||
1427 | * |
||
1428 | * @param array $submissionVars Submitted vars |
||
1429 | * @param array $formVars Vars in the form |
||
1430 | * |
||
1431 | * @return bool |
||
1432 | */ |
||
1433 | protected function validateSettingsVars($submissionVars, $formVars) { |
||
1434 | foreach ($formVars as $field => $info) { |
||
1435 | $submissionVars[$field] = trim($submissionVars[$field]); |
||
1436 | if ($info['required'] == true && $submissionVars[$field] === '') { |
||
1437 | $name = _elgg_services()->translator->translate("install:settings:label:$field"); |
||
1438 | register_error(_elgg_services()->translator->translate('install:error:requiredfield', [$name])); |
||
1439 | return false; |
||
1440 | } |
||
1441 | } |
||
1442 | |||
1443 | // check that email address is email address |
||
1444 | View Code Duplication | if ($submissionVars['siteemail'] && !is_email_address($submissionVars['siteemail'])) { |
|
1445 | $msg = _elgg_services()->translator->translate('install:error:emailaddress', [$submissionVars['siteemail']]); |
||
1446 | register_error($msg); |
||
1447 | return false; |
||
1448 | } |
||
1449 | |||
1450 | // @todo check that url is a url |
||
1451 | // @note filter_var cannot be used because it doesn't work on international urls |
||
1452 | |||
1453 | return true; |
||
1454 | } |
||
1455 | |||
1456 | /** |
||
1457 | * Initialize the site including site entity, plugins, and configuration |
||
1458 | * |
||
1459 | * @param array $submissionVars Submitted vars |
||
1460 | * |
||
1461 | * @return bool |
||
1462 | */ |
||
1463 | protected function saveSiteSettings($submissionVars) { |
||
1464 | $site = new ElggSite(); |
||
1465 | $site->name = strip_tags($submissionVars['sitename']); |
||
1466 | $site->access_id = ACCESS_PUBLIC; |
||
1467 | $site->email = $submissionVars['siteemail']; |
||
1468 | $guid = $site->save(); |
||
1469 | |||
1470 | if ($guid !== 1) { |
||
1471 | register_error(_elgg_services()->translator->translate('install:error:createsite')); |
||
1472 | return false; |
||
1473 | } |
||
1474 | |||
1475 | // bootstrap site info |
||
1476 | $this->CONFIG->site_guid = 1; |
||
1477 | $this->CONFIG->site = $site; |
||
1478 | |||
1479 | _elgg_services()->configTable->set('installed', time()); |
||
1480 | _elgg_services()->configTable->set('version', elgg_get_version()); |
||
1481 | _elgg_services()->configTable->set('simplecache_enabled', 1); |
||
1482 | _elgg_services()->configTable->set('system_cache_enabled', 1); |
||
1483 | _elgg_services()->configTable->set('simplecache_lastupdate', time()); |
||
1484 | |||
1485 | // new installations have run all the upgrades |
||
1486 | $upgrades = elgg_get_upgrade_files(\Elgg\Application::elggDir()->getPath("/engine/lib/upgrades/")); |
||
1487 | _elgg_services()->configTable->set('processed_upgrades', $upgrades); |
||
1488 | |||
1489 | _elgg_services()->configTable->set('view', 'default'); |
||
1490 | _elgg_services()->configTable->set('language', 'en'); |
||
1491 | _elgg_services()->configTable->set('default_access', $submissionVars['siteaccess']); |
||
1492 | _elgg_services()->configTable->set('allow_registration', false); |
||
1493 | _elgg_services()->configTable->set('walled_garden', false); |
||
1494 | _elgg_services()->configTable->set('allow_user_default_access', ''); |
||
1495 | _elgg_services()->configTable->set('default_limit', 10); |
||
1496 | _elgg_services()->configTable->set('security_protect_upgrade', true); |
||
1497 | _elgg_services()->configTable->set('security_notify_admins', true); |
||
1498 | _elgg_services()->configTable->set('security_notify_user_password', true); |
||
1499 | _elgg_services()->configTable->set('security_email_require_password', true); |
||
1500 | |||
1501 | $this->setSubtypeClasses(); |
||
1502 | |||
1503 | $this->enablePlugins(); |
||
1504 | |||
1505 | return true; |
||
1506 | } |
||
1507 | |||
1508 | /** |
||
1509 | * Register classes for core objects |
||
1510 | * |
||
1511 | * @return void |
||
1512 | */ |
||
1513 | protected function setSubtypeClasses() { |
||
1514 | add_subtype("object", "plugin", "ElggPlugin"); |
||
1515 | add_subtype("object", "file", "ElggFile"); |
||
1516 | add_subtype("object", "widget", "ElggWidget"); |
||
1517 | add_subtype("object", "comment", "ElggComment"); |
||
1518 | add_subtype("object", "elgg_upgrade", 'ElggUpgrade'); |
||
1519 | } |
||
1520 | |||
1521 | /** |
||
1522 | * Enable a set of default plugins |
||
1523 | * |
||
1524 | * @return void |
||
1525 | */ |
||
1526 | protected function enablePlugins() { |
||
1527 | _elgg_generate_plugin_entities(); |
||
1528 | $plugins = elgg_get_plugins('any'); |
||
1529 | foreach ($plugins as $plugin) { |
||
1530 | if ($plugin->getManifest()) { |
||
1531 | if ($plugin->getManifest()->getActivateOnInstall()) { |
||
1532 | $plugin->activate(); |
||
1533 | } |
||
1534 | if (in_array('theme', $plugin->getManifest()->getCategories())) { |
||
1535 | $plugin->setPriority('last'); |
||
1536 | } |
||
1537 | } |
||
1538 | } |
||
1539 | } |
||
1540 | |||
1541 | /** |
||
1542 | * Admin account support methods |
||
1543 | */ |
||
1544 | |||
1545 | /** |
||
1546 | * Validate account form variables |
||
1547 | * |
||
1548 | * @param array $submissionVars Submitted vars |
||
1549 | * @param array $formVars Form vars |
||
1550 | * |
||
1551 | * @return bool |
||
1552 | */ |
||
1553 | protected function validateAdminVars($submissionVars, $formVars) { |
||
1554 | |||
1555 | View Code Duplication | foreach ($formVars as $field => $info) { |
|
1556 | if ($info['required'] == true && !$submissionVars[$field]) { |
||
1557 | $name = _elgg_services()->translator->translate("install:admin:label:$field"); |
||
1558 | register_error(_elgg_services()->translator->translate('install:error:requiredfield', [$name])); |
||
1559 | return false; |
||
1560 | } |
||
1561 | } |
||
1562 | |||
1563 | if ($submissionVars['password1'] !== $submissionVars['password2']) { |
||
1564 | register_error(_elgg_services()->translator->translate('install:admin:password:mismatch')); |
||
1565 | return false; |
||
1566 | } |
||
1567 | |||
1568 | if (trim($submissionVars['password1']) == "") { |
||
1569 | register_error(_elgg_services()->translator->translate('install:admin:password:empty')); |
||
1570 | return false; |
||
1571 | } |
||
1572 | |||
1573 | $minLength = _elgg_services()->configTable->get('min_password_length'); |
||
1574 | if (strlen($submissionVars['password1']) < $minLength) { |
||
1575 | register_error(_elgg_services()->translator->translate('install:admin:password:tooshort')); |
||
1576 | return false; |
||
1577 | } |
||
1578 | |||
1579 | // check that email address is email address |
||
1580 | View Code Duplication | if ($submissionVars['email'] && !is_email_address($submissionVars['email'])) { |
|
1581 | $msg = _elgg_services()->translator->translate('install:error:emailaddress', [$submissionVars['email']]); |
||
1582 | register_error($msg); |
||
1583 | return false; |
||
1584 | } |
||
1585 | |||
1586 | return true; |
||
1587 | } |
||
1588 | |||
1589 | /** |
||
1590 | * Create a user account for the admin |
||
1591 | * |
||
1592 | * @param array $submissionVars Submitted vars |
||
1593 | * @param bool $login Login in the admin user? |
||
1594 | * |
||
1595 | * @return bool |
||
1596 | */ |
||
1597 | protected function createAdminAccount($submissionVars, $login = false) { |
||
1598 | try { |
||
1599 | $guid = register_user( |
||
1600 | $submissionVars['username'], |
||
1601 | $submissionVars['password1'], |
||
1602 | $submissionVars['displayname'], |
||
1603 | $submissionVars['email'] |
||
1604 | ); |
||
1605 | } catch (Exception $e) { |
||
1606 | register_error($e->getMessage()); |
||
1607 | return false; |
||
1608 | } |
||
1609 | |||
1610 | if (!$guid) { |
||
1611 | register_error(_elgg_services()->translator->translate('install:admin:cannot_create')); |
||
1612 | return false; |
||
1613 | } |
||
1614 | |||
1615 | $user = get_entity($guid); |
||
1616 | if (!$user instanceof ElggUser) { |
||
1617 | register_error(_elgg_services()->translator->translate('install:error:loadadmin')); |
||
1618 | return false; |
||
1619 | } |
||
1620 | |||
1621 | elgg_set_ignore_access(true); |
||
1622 | if ($user->makeAdmin() == false) { |
||
1623 | register_error(_elgg_services()->translator->translate('install:error:adminaccess')); |
||
1624 | } else { |
||
1625 | _elgg_services()->configTable->set('admin_registered', 1); |
||
1626 | } |
||
1627 | elgg_set_ignore_access(false); |
||
1628 | |||
1629 | // add validation data to satisfy user validation plugins |
||
1630 | $user->validated = 1; |
||
1631 | $user->validated_method = 'admin_user'; |
||
1632 | |||
1633 | if ($login) { |
||
1634 | $handler = new Elgg\Http\DatabaseSessionHandler(_elgg_services()->db); |
||
1635 | |||
1636 | // session.cache_limiter is unfortunately set to "" by the NativeSessionStorage constructor, |
||
1637 | // so we must capture and inject it directly. |
||
1638 | $options = [ |
||
1639 | 'cache_limiter' => session_cache_limiter(), |
||
1640 | ]; |
||
1641 | $storage = new Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage($options, $handler); |
||
1642 | |||
1643 | $session = new ElggSession(new Symfony\Component\HttpFoundation\Session\Session($storage)); |
||
1644 | $session->setName('Elgg'); |
||
1645 | _elgg_services()->setValue('session', $session); |
||
1646 | if (login($user) == false) { |
||
0 ignored issues
–
show
|
|||
1647 | register_error(_elgg_services()->translator->translate('install:error:adminlogin')); |
||
1648 | } |
||
1649 | } |
||
1650 | |||
1651 | return true; |
||
1652 | } |
||
1653 | } |
||
1654 |
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.