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() { |
||
0 ignored issues
–
show
|
|||
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; |
||
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) { |
||
0 ignored issues
–
show
admin 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...
|
|||
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() { |
||
0 ignored issues
–
show
isHttps uses the super-global variable $_SERVER 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...
|
|||
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() { |
||
0 ignored issues
–
show
getBaseUrl uses the super-global variable $_SERVER 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...
|
|||
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() { |
||
0 ignored issues
–
show
getPostVariables uses the super-global variable $_POST 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...
|
|||
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() { |
||
0 ignored issues
–
show
processRewriteTest uses the super-global variable $_SERVER 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...
|
|||
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 |
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: