Elgg  Version 2.3
ElggInstaller.php
Go to the documentation of this file.
1 <?php
2 
4 
33 
34  protected $steps = array(
35  'welcome',
36  'requirements',
37  'database',
38  'settings',
39  'admin',
40  'complete',
41  );
42 
43  protected $status = array(
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 
61  private $CONFIG;
62 
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;
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 
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', array($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->finishBootstraping($step);
129 
130  $params = $this->getPostVariables();
131 
132  $this->$step($params);
133  }
134 
142  public function setAutoLogin($flag) {
143  $this->autoLogin = (bool) $flag;
144  }
145 
164  public function batchInstall(array $params, $createHtaccess = FALSE) {
165 
166 
167  restore_error_handler();
168  restore_exception_handler();
169 
170  $defaults = array(
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 = array(
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', array($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  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  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->finishBootstraping('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 
246  protected function render($step, $vars = array()) {
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  array(
257  'step' => $step,
258  'steps' => $this->getSteps(),
259  )
260  );
261  exit;
262  }
263 
275  protected function welcome($vars) {
276  $this->render('welcome');
277  }
278 
288  protected function requirements($vars) {
289 
290  $report = array();
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
302  }
303 
304  // check the database later
305  $report['database'] = array(array(
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 = array(
318  'report' => $report,
319  'num_failures' => $numFailures,
320  'num_warnings' => $numWarnings,
321  );
322 
323  $this->render('requirements', $params);
324  }
325 
335  protected function database($submissionVars) {
336 
337  $formVars = array(
338  'dbuser' => array(
339  'type' => 'text',
340  'value' => '',
341  'required' => TRUE,
342  ),
343  'dbpassword' => array(
344  'type' => 'password',
345  'value' => '',
346  'required' => FALSE,
347  ),
348  'dbname' => array(
349  'type' => 'text',
350  'value' => '',
351  'required' => TRUE,
352  ),
353  'dbhost' => array(
354  'type' => 'text',
355  'value' => 'localhost',
356  'required' => TRUE,
357  ),
358  'dbprefix' => array(
359  'type' => 'text',
360  'value' => 'elgg_',
361  'required' => TRUE,
362  ),
363  'timezone' => array(
364  'type' => 'dropdown',
365  'value' => 'UTC',
366  'options' => \DateTimeZone::listIdentifiers(),
367  'required' => TRUE
368  )
369  );
370 
371  if ($this->checkSettingsFile()) {
372  // user manually created settings file so we fake out action test
373  $this->isAction = TRUE;
374  }
375 
376  if ($this->isAction) {
377  do {
378  // only create settings file if it doesn't exist
379  if (!$this->checkSettingsFile()) {
380  if (!$this->validateDatabaseVars($submissionVars, $formVars)) {
381  // error so we break out of action and serve same page
382  break;
383  }
384 
385  if (!$this->createSettingsFile($submissionVars)) {
386  break;
387  }
388  }
389 
390  // check db version and connect
391  if (!$this->connectToDatabase()) {
392  break;
393  }
394 
395  if (!$this->installDatabase()) {
396  break;
397  }
398 
399  system_message(_elgg_services()->translator->translate('install:success:database'));
400 
401  $this->continueToNextStep('database');
402  } while (FALSE); // PHP doesn't support breaking out of if statements
403  }
404 
405  $formVars = $this->makeFormSticky($formVars, $submissionVars);
406 
407  $params = array('variables' => $formVars,);
408 
409  if ($this->checkSettingsFile()) {
410  // settings file exists and we're here so failed to create database
411  $params['failure'] = TRUE;
412  }
413 
414  $this->render('database', $params);
415  }
416 
426  protected function settings($submissionVars) {
427 
428 
429  $formVars = array(
430  'sitename' => array(
431  'type' => 'text',
432  'value' => 'My New Community',
433  'required' => TRUE,
434  ),
435  'siteemail' => array(
436  'type' => 'email',
437  'value' => '',
438  'required' => FALSE,
439  ),
440  'wwwroot' => array(
441  'type' => 'url',
442  'value' => _elgg_services()->config->getSiteUrl(),
443  'required' => TRUE,
444  ),
445  'dataroot' => array(
446  'type' => 'text',
447  'value' => '',
448  'required' => TRUE,
449  ),
450  'siteaccess' => array(
451  'type' => 'access',
452  'value' => ACCESS_PUBLIC,
453  'required' => TRUE,
454  ),
455  );
456 
457  // if Apache, we give user option of having Elgg create data directory
458  //if (ElggRewriteTester::guessWebServer() == 'apache') {
459  // $formVars['dataroot']['type'] = 'combo';
460  // $GLOBALS['_ELGG']->translations['en']['install:settings:help:dataroot'] =
461  // $GLOBALS['_ELGG']->translations['en']['install:settings:help:dataroot:apache'];
462  //}
463 
464  if ($this->isAction) {
465  do {
466  //if (!$this->createDataDirectory($submissionVars, $formVars)) {
467  // break;
468  //}
469 
470  if (!$this->validateSettingsVars($submissionVars, $formVars)) {
471  break;
472  }
473 
474  if (!$this->saveSiteSettings($submissionVars)) {
475  break;
476  }
477 
478  system_message(_elgg_services()->translator->translate('install:success:settings'));
479 
480  $this->continueToNextStep('settings');
481 
482  } while (FALSE); // PHP doesn't support breaking out of if statements
483  }
484 
485  $formVars = $this->makeFormSticky($formVars, $submissionVars);
486 
487  $this->render('settings', array('variables' => $formVars));
488  }
489 
499  protected function admin($submissionVars) {
500  $formVars = array(
501  'displayname' => array(
502  'type' => 'text',
503  'value' => '',
504  'required' => TRUE,
505  ),
506  'email' => array(
507  'type' => 'email',
508  'value' => '',
509  'required' => TRUE,
510  ),
511  'username' => array(
512  'type' => 'text',
513  'value' => '',
514  'required' => TRUE,
515  ),
516  'password1' => array(
517  'type' => 'password',
518  'value' => '',
519  'required' => TRUE,
520  'pattern' => '.{6,}',
521  ),
522  'password2' => array(
523  'type' => 'password',
524  'value' => '',
525  'required' => TRUE,
526  ),
527  );
528 
529  if ($this->isAction) {
530  do {
531  if (!$this->validateAdminVars($submissionVars, $formVars)) {
532  break;
533  }
534 
535  if (!$this->createAdminAccount($submissionVars, $this->autoLogin)) {
536  break;
537  }
538 
539  system_message(_elgg_services()->translator->translate('install:success:admin'));
540 
541  $this->continueToNextStep('admin');
542 
543  } while (FALSE); // PHP doesn't support breaking out of if statements
544  }
545 
546  // bit of a hack to get the password help to show right number of characters
547 
548  $lang = _elgg_services()->translator->getCurrentLanguage();
549  $GLOBALS['_ELGG']->translations[$lang]['install:admin:help:password1'] =
550  sprintf($GLOBALS['_ELGG']->translations[$lang]['install:admin:help:password1'],
551  $this->CONFIG->min_password_length);
552 
553  $formVars = $this->makeFormSticky($formVars, $submissionVars);
554 
555  $this->render('admin', array('variables' => $formVars));
556  }
557 
563  protected function complete() {
564 
565  $params = array();
566  if ($this->autoLogin) {
567  $params['destination'] = 'admin';
568  } else {
569  $params['destination'] = 'index.php';
570  }
571 
572  $this->render('complete', $params);
573  }
574 
584  protected function getSteps() {
585  return $this->steps;
586  }
587 
595  protected function continueToNextStep($currentStep) {
596  $this->isAction = FALSE;
597  forward($this->getNextStepUrl($currentStep));
598  }
599 
607  protected function getNextStep($currentStep) {
608  $index = 1 + array_search($currentStep, $this->steps);
609  if (isset($this->steps[$index])) {
610  return $this->steps[$index];
611  } else {
612  return null;
613  }
614  }
615 
623  protected function getNextStepUrl($currentStep) {
624  $nextStep = $this->getNextStep($currentStep);
625  return _elgg_services()->config->getSiteUrl() . "install.php?step=$nextStep";
626  }
627 
634  protected function setInstallStatus() {
635  $settings_found = false;
636  foreach (_elgg_services()->config->getSettingsPaths() as $path) {
637  if (is_file($path) && is_readable($path)) {
638  $settings_found = true;
639  break;
640  }
641  }
642 
643  if (!$settings_found) {
644  return;
645  }
646 
647  $this->loadSettingsFile();
648 
649  $this->status['config'] = TRUE;
650 
651  // must be able to connect to database to jump install steps
652  $dbSettingsPass = $this->checkDatabaseSettings(
653  $this->CONFIG->dbuser,
654  $this->CONFIG->dbpass,
655  $this->CONFIG->dbname,
656  $this->CONFIG->dbhost
657  );
658 
659  if ($dbSettingsPass == FALSE) {
660  return;
661  }
662 
663  if (!include_once(\Elgg\Application::elggDir()->getPath("engine/lib/database.php"))) {
664  throw new InstallationException(_elgg_services()->translator->translate('InstallationException:MissingLibrary', array('database.php')));
665  }
666 
667  // check that the config table has been created
668  $query = "show tables";
669  $result = _elgg_services()->db->getData($query);
670  if ($result) {
671  foreach ($result as $table) {
672  $table = (array) $table;
673  if (in_array("{$this->CONFIG->dbprefix}config", $table)) {
674  $this->status['database'] = TRUE;
675  }
676  }
677  if ($this->status['database'] == FALSE) {
678  return;
679  }
680  } else {
681  // no tables
682  return;
683  }
684 
685  // check that the config table has entries
686  $query = "SELECT COUNT(*) AS total FROM {$this->CONFIG->dbprefix}config";
687  $result = _elgg_services()->db->getData($query);
688  if ($result && $result[0]->total > 0) {
689  $this->status['settings'] = TRUE;
690  } else {
691  return;
692  }
693 
694  // check that the users entity table has an entry
695  $query = "SELECT COUNT(*) AS total FROM {$this->CONFIG->dbprefix}users_entity";
696  $result = _elgg_services()->db->getData($query);
697  if ($result && $result[0]->total > 0) {
698  $this->status['admin'] = TRUE;
699  } else {
700  return;
701  }
702  }
703 
712  protected function checkInstallCompletion($step) {
713  if ($step != 'complete') {
714  if (!in_array(FALSE, $this->status)) {
715  // install complete but someone is trying to view an install page
716  forward();
717  }
718  }
719  }
720 
729  protected function resumeInstall($step) {
730  // only do a resume from the first step
731  if ($step !== 'welcome') {
732  return;
733  }
734 
735  if ($this->status['database'] == FALSE) {
736  return;
737  }
738 
739  if ($this->status['settings'] == FALSE) {
740  forward("install.php?step=settings");
741  }
742 
743  if ($this->status['admin'] == FALSE) {
744  forward("install.php?step=admin");
745  }
746 
747  // everything appears to be set up
748  forward("install.php?step=complete");
749  }
750 
760  protected function bootstrapEngine() {
761  $config = new \Elgg\Config($this->CONFIG);
762  $services = new \Elgg\Di\ServiceProvider($config);
763  (new \Elgg\Application($services))->loadCore();
764  }
765 
775  protected function finishBootstraping($step) {
776 
777  $dbIndex = array_search('database', $this->getSteps());
778  $settingsIndex = array_search('settings', $this->getSteps());
779  $adminIndex = array_search('admin', $this->getSteps());
780  $completeIndex = array_search('complete', $this->getSteps());
781  $stepIndex = array_search($step, $this->getSteps());
782 
783  // To log in the user, we need to use the Elgg core session handling.
784  // Otherwise, use default php session handling
785  $useElggSession = ($stepIndex == $adminIndex && $this->isAction) ||
786  $stepIndex == $completeIndex;
787  if (!$useElggSession) {
788  session_name('Elgg_install');
789  session_start();
790  _elgg_services()->events->unregisterHandler('boot', 'system', 'session_init');
791  }
792 
793  if ($stepIndex > $dbIndex) {
794  // once the database has been created, load rest of engine
795 
796  $lib_dir = \Elgg\Application::elggDir()->chroot('/engine/lib/');
797 
798  $this->loadSettingsFile();
799 
800  $lib_files = array(
801  // these want to be loaded first apparently?
802  'autoloader.php',
803  'database.php',
804  'actions.php',
805 
806  'admin.php',
807  'annotations.php',
808  'cron.php',
809  'entities.php',
810  'extender.php',
811  'filestore.php',
812  'group.php',
813  'mb_wrapper.php',
814  'memcache.php',
815  'metadata.php',
816  'metastrings.php',
817  'navigation.php',
818  'notification.php',
819  'objects.php',
820  'pagehandler.php',
821  'pam.php',
822  'plugins.php',
823  'private_settings.php',
824  'relationships.php',
825  'river.php',
826  'sites.php',
827  'statistics.php',
828  'tags.php',
829  'user_settings.php',
830  'users.php',
831  'upgrade.php',
832  'widgets.php',
833  'deprecated-1.9.php',
834  );
835 
836  foreach ($lib_files as $file) {
837  if (!include_once($lib_dir->getPath($file))) {
838  throw new InstallationException('InstallationException:MissingLibrary', array($file));
839  }
840  }
841 
842  _elgg_services()->db->setupConnections();
843  _elgg_services()->translator->registerTranslations(\Elgg\Application::elggDir()->getPath("/languages/"));
844  $this->CONFIG->language = 'en';
845 
846  if ($stepIndex > $settingsIndex) {
847  $this->CONFIG->site_guid = (int) _elgg_services()->datalist->get('default_site');
848  $this->CONFIG->site_id = $this->CONFIG->site_guid;
849  $this->CONFIG->site = get_entity($this->CONFIG->site_guid);
850  $this->CONFIG->dataroot = _elgg_services()->datalist->get('dataroot');
851  _elgg_services()->config->getCookieConfig();
853  }
854 
855  _elgg_services()->events->trigger('init', 'system');
856  }
857  }
858 
864  protected function bootstrapConfig() {
865  $this->CONFIG->installer_running = true;
866 
867  $this->CONFIG->wwwroot = $this->getBaseUrl();
868  $this->CONFIG->url = $this->CONFIG->wwwroot;
869  $this->CONFIG->path = \Elgg\Application::elggDir()->getPath() . "/";
870  $this->view_path = $this->CONFIG->path . 'views/';
871  $this->CONFIG->pluginspath = $this->CONFIG->path . 'mod/';
872  $this->CONFIG->context = array();
873  $this->CONFIG->entity_types = array('group', 'object', 'site', 'user');
874 
875  // required by elgg_view_page()
876  $this->CONFIG->sitename = '';
877  $this->CONFIG->sitedescription = '';
878 
879  // required by Elgg\Config::get
880  $this->CONFIG->site_guid = 1;
881  }
882 
886  private function isHttps() {
887  return (!empty($_SERVER["HTTPS"]) && strtolower($_SERVER["HTTPS"]) !== "off") ||
888  (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443);
889  }
890 
899  protected function getBaseUrl() {
900  $protocol = $this->isHttps() ? 'https' : 'http';
901 
902  if (isset($_SERVER["SERVER_PORT"])) {
903  $port = ':' . $_SERVER["SERVER_PORT"];
904  } else {
905  $port = '';
906  }
907  if ($port == ':80' || $port == ':443') {
908  $port = '';
909  }
910  $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
911  $cutoff = strpos($uri, 'install.php');
912  $uri = substr($uri, 0, $cutoff);
913  $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
914 
915  return "$protocol://{$serverName}$port{$uri}";
916  }
917 
924  protected function loadSettingsFile() {
925  try {
926  _elgg_services()->config->loadSettingsFile();
927  } catch (\Exception $e) {
928  $msg = _elgg_services()->translator->translate('InstallationException:CannotLoadSettings');
929  throw new InstallationException($msg, 0, $e);
930  }
931  }
932 
946  protected function getPostVariables() {
947  $vars = array();
948  foreach ($_POST as $k => $v) {
949  $vars[$k] = $v;
950  }
951  return $vars;
952  }
953 
962  protected function makeFormSticky($formVars, $submissionVars) {
963  foreach ($submissionVars as $field => $value) {
964  $formVars[$field]['value'] = $value;
965  }
966  return $formVars;
967  }
968 
980  protected function isInstallDirWritable(&$report) {
981  $root = Directory\Local::root()->getPath();
982  $abs_path = \Elgg\Application::elggDir()->getPath('elgg-config');
983 
984  if (0 === strpos($abs_path, $root)) {
985  $relative_path = substr($abs_path, strlen($root));
986  } else {
987  $relative_path = $abs_path;
988  }
989  $relative_path = rtrim($relative_path, '/\\');
990 
991  $writable = is_writable(Directory\Local::root()->getPath('elgg-config'));
992  if (!$writable) {
993  $report['settings'] = array(
994  array(
995  'severity' => 'failure',
996  'message' => _elgg_services()->translator->translate('install:check:installdir', [$relative_path]),
997  )
998  );
999  return FALSE;
1000  }
1001 
1002  return TRUE;
1003  }
1004 
1012  protected function checkSettingsFile(&$report = array()) {
1013  if (!is_file($this->getSettingsPath())) {
1014  return FALSE;
1015  }
1016 
1017  if (!is_readable($this->getSettingsPath())) {
1018  $report['settings'] = array(
1019  array(
1020  'severity' => 'failure',
1021  'message' => _elgg_services()->translator->translate('install:check:readsettings'),
1022  )
1023  );
1024  }
1025 
1026  return TRUE;
1027  }
1028 
1034  private function getSettingsPath() {
1035  return Directory\Local::root()->getPath("elgg-config/settings.php");
1036  }
1037 
1045  protected function checkPHP(&$report) {
1046  $phpReport = array();
1047 
1048  $min_php_version = '5.6.0';
1049  if (version_compare(PHP_VERSION, $min_php_version, '<')) {
1050  $phpReport[] = array(
1051  'severity' => 'failure',
1052  'message' => _elgg_services()->translator->translate('install:check:php:version', array($min_php_version, PHP_VERSION))
1053  );
1054  }
1055 
1056  $this->checkPhpExtensions($phpReport);
1057 
1058  $this->checkPhpDirectives($phpReport);
1059 
1060  if (count($phpReport) == 0) {
1061  $phpReport[] = array(
1062  'severity' => 'pass',
1063  'message' => _elgg_services()->translator->translate('install:check:php:success')
1064  );
1065  }
1066 
1067  $report['php'] = $phpReport;
1068  }
1069 
1077  protected function checkPhpExtensions(&$phpReport) {
1078  $extensions = get_loaded_extensions();
1079  $requiredExtensions = array(
1080  'pdo_mysql',
1081  'json',
1082  'xml',
1083  'gd',
1084  );
1085  foreach ($requiredExtensions as $extension) {
1086  if (!in_array($extension, $extensions)) {
1087  $phpReport[] = array(
1088  'severity' => 'failure',
1089  'message' => _elgg_services()->translator->translate('install:check:php:extension', array($extension))
1090  );
1091  }
1092  }
1093 
1094  $recommendedExtensions = array(
1095  'mbstring',
1096  );
1097  foreach ($recommendedExtensions as $extension) {
1098  if (!in_array($extension, $extensions)) {
1099  $phpReport[] = array(
1100  'severity' => 'warning',
1101  'message' => _elgg_services()->translator->translate('install:check:php:extension:recommend', array($extension))
1102  );
1103  }
1104  }
1105  }
1106 
1114  protected function checkPhpDirectives(&$phpReport) {
1115  if (ini_get('open_basedir')) {
1116  $phpReport[] = array(
1117  'severity' => 'warning',
1118  'message' => _elgg_services()->translator->translate("install:check:php:open_basedir")
1119  );
1120  }
1121 
1122  if (ini_get('safe_mode')) {
1123  $phpReport[] = array(
1124  'severity' => 'warning',
1125  'message' => _elgg_services()->translator->translate("install:check:php:safe_mode")
1126  );
1127  }
1128 
1129  if (ini_get('arg_separator.output') !== '&') {
1130  $separator = htmlspecialchars(ini_get('arg_separator.output'));
1131  $msg = _elgg_services()->translator->translate("install:check:php:arg_separator", array($separator));
1132  $phpReport[] = array(
1133  'severity' => 'failure',
1134  'message' => $msg,
1135  );
1136  }
1137 
1138  if (ini_get('register_globals')) {
1139  $phpReport[] = array(
1140  'severity' => 'failure',
1141  'message' => _elgg_services()->translator->translate("install:check:php:register_globals")
1142  );
1143  }
1144 
1145  if (ini_get('session.auto_start')) {
1146  $phpReport[] = array(
1147  'severity' => 'failure',
1148  'message' => _elgg_services()->translator->translate("install:check:php:session.auto_start")
1149  );
1150  }
1151  }
1152 
1160  protected function checkRewriteRules(&$report) {
1161 
1162 
1163  $tester = new ElggRewriteTester();
1164  $url = _elgg_services()->config->getSiteUrl() . "rewrite.php";
1165  $report['rewrite'] = array($tester->run($url, Directory\Local::root()->getPath()));
1166  }
1167 
1174  protected function processRewriteTest() {
1175  if (strpos($_SERVER['REQUEST_URI'], 'rewrite.php') !== FALSE) {
1176  echo \Elgg\Application::REWRITE_TEST_OUTPUT;
1177  exit;
1178  }
1179  }
1180 
1189  protected function countNumConditions($report, $condition) {
1190  $count = 0;
1191  foreach ($report as $category => $checks) {
1192  foreach ($checks as $check) {
1193  if ($check['severity'] === $condition) {
1194  $count++;
1195  }
1196  }
1197  }
1198 
1199  return $count;
1200  }
1201 
1202 
1215  protected function validateDatabaseVars($submissionVars, $formVars) {
1216 
1217  foreach ($formVars as $field => $info) {
1218  if ($info['required'] == TRUE && !$submissionVars[$field]) {
1219  $name = _elgg_services()->translator->translate("install:database:label:$field");
1220  register_error(_elgg_services()->translator->translate('install:error:requiredfield', array($name)));
1221  return FALSE;
1222  }
1223  }
1224 
1225  // according to postgres documentation: SQL identifiers and key words must
1226  // begin with a letter (a-z, but also letters with diacritical marks and
1227  // non-Latin letters) or an underscore (_). Subsequent characters in an
1228  // identifier or key word can be letters, underscores, digits (0-9), or dollar signs ($).
1229  // Refs #4994
1230  if (!preg_match("/^[a-zA-Z_][\w]*$/", $submissionVars['dbprefix'])) {
1231  register_error(_elgg_services()->translator->translate('install:error:database_prefix'));
1232  return FALSE;
1233  }
1234 
1235  return $this->checkDatabaseSettings(
1236  $submissionVars['dbuser'],
1237  $submissionVars['dbpassword'],
1238  $submissionVars['dbname'],
1239  $submissionVars['dbhost']
1240  );
1241  }
1242 
1253  protected function checkDatabaseSettings($user, $password, $dbname, $host) {
1254  $config = new \Elgg\Database\Config((object)[
1255  'dbhost' => $host,
1256  'dbuser' => $user,
1257  'dbpass' => $password,
1258  'dbname' => $dbname,
1259  ]);
1260  $db = new \Elgg\Database($config);
1261 
1262  try {
1263  $db->getDataRow("SELECT 1");
1264  } catch (DatabaseException $e) {
1265  if (0 === strpos($e->getMessage(), "Elgg couldn't connect")) {
1266  register_error(_elgg_services()->translator->translate('install:error:databasesettings'));
1267  } else {
1268  register_error(_elgg_services()->translator->translate('install:error:nodatabase', array($dbname)));
1269  }
1270  return FALSE;
1271  }
1272 
1273  // check MySQL version - must be 5.0 or >
1274  $version = $db->getServerVersion(\Elgg\Database\Config::READ_WRITE);
1275  $required_version = 5.0;
1276  $points = explode('.', $version);
1277  if ($points[0] < $required_version) {
1278  register_error(_elgg_services()->translator->translate('install:error:oldmysql', array($version)));
1279  return FALSE;
1280  }
1281 
1282  return TRUE;
1283  }
1284 
1292  protected function createSettingsFile($params) {
1293  $template = \Elgg\Application::elggDir()->getContents("elgg-config/settings.example.php");
1294  if (!$template) {
1295  register_error(_elgg_services()->translator->translate('install:error:readsettingsphp'));
1296  return FALSE;
1297  }
1298 
1299  foreach ($params as $k => $v) {
1300  $template = str_replace("{{" . $k . "}}", $v, $template);
1301  }
1302 
1303  $result = file_put_contents($this->getSettingsPath(), $template);
1304  if (!$result) {
1305  register_error(_elgg_services()->translator->translate('install:error:writesettingphp'));
1306  return FALSE;
1307  }
1308 
1309  return TRUE;
1310  }
1311 
1317  protected function connectToDatabase() {
1318  if (!include_once($this->getSettingsPath())) {
1319  register_error('Elgg could not load the settings file. It does not exist or there is a file permissions issue.');
1320  return FALSE;
1321  }
1322 
1323  if (!include_once(\Elgg\Application::elggDir()->getPath("engine/lib/database.php"))) {
1324  register_error('Could not load database.php');
1325  return FALSE;
1326  }
1327 
1328  try {
1329  _elgg_services()->db->setupConnections();
1330  } catch (DatabaseException $e) {
1331  register_error($e->getMessage());
1332  return FALSE;
1333  }
1334 
1335  return TRUE;
1336  }
1337 
1343  protected function installDatabase() {
1344 
1345 
1346  try {
1347  _elgg_services()->db->runSqlScript(\Elgg\Application::elggDir()->getPath("/engine/schema/mysql.sql"));
1348  } catch (Exception $e) {
1349  $msg = $e->getMessage();
1350  if (strpos($msg, 'already exists')) {
1351  $msg = _elgg_services()->translator->translate('install:error:tables_exist');
1352  }
1353  register_error($msg);
1354  return FALSE;
1355  }
1356 
1357  return TRUE;
1358  }
1359 
1372  protected function createDataDirectory(&$submissionVars, $formVars) {
1373  // did the user have option of Elgg creating the data directory
1374  if ($formVars['dataroot']['type'] != 'combo') {
1375  return TRUE;
1376  }
1377 
1378  // did the user select the option
1379  if ($submissionVars['dataroot'] != 'dataroot-checkbox') {
1380  return TRUE;
1381  }
1382 
1383  $dir = sanitise_filepath($submissionVars['path']) . 'data';
1384  if (file_exists($dir) || mkdir($dir, 0700)) {
1385  $submissionVars['dataroot'] = $dir;
1386  if (!file_exists("$dir/.htaccess")) {
1387  $htaccess = "Order Deny,Allow\nDeny from All\n";
1388  if (!file_put_contents("$dir/.htaccess", $htaccess)) {
1389  return FALSE;
1390  }
1391  }
1392  return TRUE;
1393  }
1394 
1395  return FALSE;
1396  }
1397 
1406  protected function validateSettingsVars($submissionVars, $formVars) {
1407 
1408 
1409  foreach ($formVars as $field => $info) {
1410  $submissionVars[$field] = trim($submissionVars[$field]);
1411  if ($info['required'] == TRUE && $submissionVars[$field] === '') {
1412  $name = _elgg_services()->translator->translate("install:settings:label:$field");
1413  register_error(_elgg_services()->translator->translate('install:error:requiredfield', array($name)));
1414  return FALSE;
1415  }
1416  }
1417 
1418  // check that data root is absolute path
1419  if (stripos(PHP_OS, 'win') === 0) {
1420  if (strpos($submissionVars['dataroot'], ':') !== 1) {
1421  $msg = _elgg_services()->translator->translate('install:error:relative_path', array($submissionVars['dataroot']));
1422  register_error($msg);
1423  return FALSE;
1424  }
1425  } else {
1426  if (strpos($submissionVars['dataroot'], '/') !== 0) {
1427  $msg = _elgg_services()->translator->translate('install:error:relative_path', array($submissionVars['dataroot']));
1428  register_error($msg);
1429  return FALSE;
1430  }
1431  }
1432 
1433  // check that data root exists
1434  if (!file_exists($submissionVars['dataroot'])) {
1435  $msg = _elgg_services()->translator->translate('install:error:datadirectoryexists', array($submissionVars['dataroot']));
1436  register_error($msg);
1437  return FALSE;
1438  }
1439 
1440  // check that data root is writable
1441  if (!is_writable($submissionVars['dataroot'])) {
1442  $msg = _elgg_services()->translator->translate('install:error:writedatadirectory', array($submissionVars['dataroot']));
1443  register_error($msg);
1444  return FALSE;
1445  }
1446 
1447  if (!isset($this->CONFIG->data_dir_override) || !$this->CONFIG->data_dir_override) {
1448  // check that data root is not subdirectory of Elgg root
1449  if (stripos($submissionVars['dataroot'], $submissionVars['path']) === 0) {
1450  $msg = _elgg_services()->translator->translate('install:error:locationdatadirectory', array($submissionVars['dataroot']));
1451  register_error($msg);
1452  return FALSE;
1453  }
1454  }
1455 
1456  // check that email address is email address
1457  if ($submissionVars['siteemail'] && !is_email_address($submissionVars['siteemail'])) {
1458  $msg = _elgg_services()->translator->translate('install:error:emailaddress', array($submissionVars['siteemail']));
1459  register_error($msg);
1460  return FALSE;
1461  }
1462 
1463  // @todo check that url is a url
1464  // @note filter_var cannot be used because it doesn't work on international urls
1465 
1466  return TRUE;
1467  }
1468 
1476  protected function saveSiteSettings($submissionVars) {
1477 
1478 
1479  // ensure that file path, data path, and www root end in /
1480  $submissionVars['dataroot'] = sanitise_filepath($submissionVars['dataroot']);
1481  $submissionVars['wwwroot'] = sanitise_filepath($submissionVars['wwwroot']);
1482 
1483  $site = new ElggSite();
1484  $site->name = strip_tags($submissionVars['sitename']);
1485  $site->url = $submissionVars['wwwroot'];
1486  $site->access_id = ACCESS_PUBLIC;
1487  $site->email = $submissionVars['siteemail'];
1488  $guid = $site->save();
1489 
1490  if (!$guid) {
1491  register_error(_elgg_services()->translator->translate('install:error:createsite'));
1492  return FALSE;
1493  }
1494 
1495  // bootstrap site info
1496  $this->CONFIG->site_guid = $guid;
1497  $this->CONFIG->site_id = $guid;
1498  $this->CONFIG->site = $site;
1499 
1500  _elgg_services()->datalist->set('installed', time());
1501  _elgg_services()->datalist->set('dataroot', $submissionVars['dataroot']);
1502  _elgg_services()->datalist->set('default_site', $site->getGUID());
1503  _elgg_services()->datalist->set('version', elgg_get_version());
1504  _elgg_services()->datalist->set('simplecache_enabled', 1);
1505  _elgg_services()->datalist->set('system_cache_enabled', 1);
1506  _elgg_services()->datalist->set('simplecache_lastupdate', time());
1507 
1508  // new installations have run all the upgrades
1509  $upgrades = elgg_get_upgrade_files(\Elgg\Application::elggDir()->getPath("/engine/lib/upgrades/"));
1510  _elgg_services()->datalist->set('processed_upgrades', serialize($upgrades));
1511 
1512  _elgg_services()->configTable->set('view', 'default', $site->getGUID());
1513  _elgg_services()->configTable->set('language', 'en', $site->getGUID());
1514  _elgg_services()->configTable->set('default_access', $submissionVars['siteaccess'], $site->getGUID());
1515  _elgg_services()->configTable->set('allow_registration', TRUE, $site->getGUID());
1516  _elgg_services()->configTable->set('walled_garden', FALSE, $site->getGUID());
1517  _elgg_services()->configTable->set('allow_user_default_access', '', $site->getGUID());
1518  _elgg_services()->configTable->set('default_limit', 10, $site->getGUID());
1519 
1520  $this->setSubtypeClasses();
1521 
1522  $this->enablePlugins();
1523 
1524  return TRUE;
1525  }
1526 
1532  protected function setSubtypeClasses() {
1533  add_subtype("object", "plugin", "ElggPlugin");
1534  add_subtype("object", "file", "ElggFile");
1535  add_subtype("object", "widget", "ElggWidget");
1536  add_subtype("object", "comment", "ElggComment");
1537  add_subtype("object", "elgg_upgrade", 'ElggUpgrade');
1538  }
1539 
1545  protected function enablePlugins() {
1547  $plugins = elgg_get_plugins('any');
1548  foreach ($plugins as $plugin) {
1549  if ($plugin->getManifest()) {
1550  if ($plugin->getManifest()->getActivateOnInstall()) {
1551  $plugin->activate();
1552  }
1553  if (in_array('theme', $plugin->getManifest()->getCategories())) {
1554  $plugin->setPriority('last');
1555  }
1556  }
1557  }
1558  }
1559 
1572  protected function validateAdminVars($submissionVars, $formVars) {
1573 
1574  foreach ($formVars as $field => $info) {
1575  if ($info['required'] == TRUE && !$submissionVars[$field]) {
1576  $name = _elgg_services()->translator->translate("install:admin:label:$field");
1577  register_error(_elgg_services()->translator->translate('install:error:requiredfield', array($name)));
1578  return FALSE;
1579  }
1580  }
1581 
1582  if ($submissionVars['password1'] !== $submissionVars['password2']) {
1583  register_error(_elgg_services()->translator->translate('install:admin:password:mismatch'));
1584  return FALSE;
1585  }
1586 
1587  if (trim($submissionVars['password1']) == "") {
1588  register_error(_elgg_services()->translator->translate('install:admin:password:empty'));
1589  return FALSE;
1590  }
1591 
1592  $minLength = _elgg_services()->configTable->get('min_password_length');
1593  if (strlen($submissionVars['password1']) < $minLength) {
1594  register_error(_elgg_services()->translator->translate('install:admin:password:tooshort'));
1595  return FALSE;
1596  }
1597 
1598  // check that email address is email address
1599  if ($submissionVars['email'] && !is_email_address($submissionVars['email'])) {
1600  $msg = _elgg_services()->translator->translate('install:error:emailaddress', array($submissionVars['email']));
1601  register_error($msg);
1602  return FALSE;
1603  }
1604 
1605  return TRUE;
1606  }
1607 
1616  protected function createAdminAccount($submissionVars, $login = FALSE) {
1617  try {
1618  $guid = register_user(
1619  $submissionVars['username'],
1620  $submissionVars['password1'],
1621  $submissionVars['displayname'],
1622  $submissionVars['email']
1623  );
1624  } catch (Exception $e) {
1625  register_error($e->getMessage());
1626  return false;
1627  }
1628 
1629  if (!$guid) {
1630  register_error(_elgg_services()->translator->translate('install:admin:cannot_create'));
1631  return false;
1632  }
1633 
1634  $user = get_entity($guid);
1635  if (!$user instanceof ElggUser) {
1636  register_error(_elgg_services()->translator->translate('install:error:loadadmin'));
1637  return false;
1638  }
1639 
1640  elgg_set_ignore_access(TRUE);
1641  if ($user->makeAdmin() == FALSE) {
1642  register_error(_elgg_services()->translator->translate('install:error:adminaccess'));
1643  } else {
1644  _elgg_services()->datalist->set('admin_registered', 1);
1645  }
1646  elgg_set_ignore_access(false);
1647 
1648  // add validation data to satisfy user validation plugins
1649  create_metadata($guid, 'validated', TRUE, '', 0, ACCESS_PUBLIC);
1650  create_metadata($guid, 'validated_method', 'admin_user', '', 0, ACCESS_PUBLIC);
1651 
1652  if ($login) {
1654 
1655  // session.cache_limiter is unfortunately set to "" by the NativeSessionStorage constructor,
1656  // so we must capture and inject it directly.
1657  $options = [
1658  'cache_limiter' => session_cache_limiter(),
1659  ];
1660  $storage = new Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage($options, $handler);
1661 
1662  $session = new ElggSession(new Symfony\Component\HttpFoundation\Session\Session($storage));
1663  $session->setName('Elgg');
1664  _elgg_services()->setValue('session', $session);
1665  if (login($user) == FALSE) {
1666  register_error(_elgg_services()->translator->translate('install:error:adminlogin'));
1667  }
1668  }
1669 
1670  return TRUE;
1671  }
1672 }
$password
Definition: login.php:25
$session
Definition: login.php:9
$params
Definition: login.php:72
$handler
Definition: add.php:10
$title
Definition: save.php:22
$options
Elgg admin footer.
Definition: footer.php:6
if($guid==elgg_get_logged_in_user_guid()) $name
Definition: delete.php:21
$defaults
exit
Definition: autoloader.php:34
$user
Definition: ban.php:13
$version
checkDatabaseSettings($user, $password, $dbname, $host)
Confirm the settings for the database.
continueToNextStep($currentStep)
Forwards the browser to the next step.
makeFormSticky($formVars, $submissionVars)
If form is reshown, remember previously submitted variables.
checkPhpExtensions(&$phpReport)
Check the server's PHP extensions.
validateDatabaseVars($submissionVars, $formVars)
Database support methods.
setAutoLogin($flag)
Set the auto login flag.
getPostVariables()
Action handling methods.
getBaseUrl()
Get the best guess at the base URL.
isInstallDirWritable(&$report)
Requirement checks support methods.
checkInstallCompletion($step)
Security check to ensure the installer cannot be run after installation has finished.
welcome($vars)
Step controllers.
createDataDirectory(&$submissionVars, $formVars)
Site settings support methods.
render($step, $vars=array())
Renders the data passed by a controller.
finishBootstraping($step)
Load remaining engine libraries and complete bootstraping (see start.php)
saveSiteSettings($submissionVars)
Initialize the site including site entity, plugins, and configuration.
getSteps()
Step management.
setSubtypeClasses()
Register classes for core objects.
checkSettingsFile(&$report=array())
Check that the settings file exists.
checkPhpDirectives(&$phpReport)
Check PHP parameters.
checkPHP(&$report)
Check version of PHP, extensions, and variables.
validateSettingsVars($submissionVars, $formVars)
Validate the site settings form variables.
processRewriteTest()
Check if the request is coming from the URL rewrite test on the requirements page.
bootstrapConfig()
Set up configuration variables.
countNumConditions($report, $condition)
Count the number of failures in the requirements report.
batchInstall(array $params, $createHtaccess=FALSE)
A batch install of Elgg.
validateAdminVars($submissionVars, $formVars)
Admin account support methods.
__construct()
Constructor bootstraps the Elgg engine.
setInstallStatus()
Check the different install steps for completion.
resumeInstall($step)
Check if this is a case of a install being resumed and figure out where to continue from.
getNextStep($currentStep)
Get the next step as a string.
createSettingsFile($params)
Writes the settings file to the engine directory.
requirements($vars)
Requirements controller.
createAdminAccount($submissionVars, $login=FALSE)
Create a user account for the admin.
settings($submissionVars)
Site settings controller.
bootstrapEngine()
Bootstraping.
admin($submissionVars)
Admin account controller.
connectToDatabase()
Bootstrap database connection before entire engine is available.
database($submissionVars)
Database set up controller.
complete()
Controller for last step.
getNextStepUrl($currentStep)
Get the URL of the next step.
loadSettingsFile()
Load settings.php.
checkRewriteRules(&$report)
Confirm that the rewrite rules are firing.
enablePlugins()
Enable a set of default plugins.
installDatabase()
Create the database tables.
run($step)
Dispatches a request to one of the step controllers.
static getMock()
Get an isolated ElggSession that does not persist between requests.
static elggDir()
Returns a directory that points to the root of Elgg, but not necessarily the install root.
$_ELGG translations
String translations for the current language.
Definition: config.php:333
$index
Definition: gallery.php:49
$guid
Removes an admin notice.
$path
Definition: details.php:88
if($screenshots) $info
Definition: details.php:58
register_error($error)
Display an error on next page load.
Definition: elgglib.php:464
sanitise_filepath($path, $append_slash=true)
Sanitise file paths ensuring that they begin and end with slashes etc.
Definition: elgglib.php:411
system_message($message)
Display a system message on next page load.
Definition: elgglib.php:450
elgg_get_version($human_readable=false)
Get the current Elgg version information.
Definition: elgglib.php:1071
const ACCESS_PUBLIC
Definition: elgglib.php:2084
forward($location="", $reason='system')
Forward to $location.
Definition: elgglib.php:94
elgg_set_ignore_access($ignore=true)
Set if Elgg's access system should be ignored.
Definition: access.php:43
_elgg_services(\Elgg\Di\ServiceProvider $services=null)
Get the global service provider.
Definition: autoloader.php:17
is_email_address($address)
Validates an email address.
Definition: input.php:88
create_metadata($entity_guid, $name, $value, $value_type='', $owner_guid=0, $access_id=null, $allow_multiple=false)
Create a new metadata object, or update an existing one.
Definition: metadata.php:66
elgg_get_plugins($status='active', $site_guid=null)
Returns an ordered list of plugins.
Definition: plugins.php:132
_elgg_generate_plugin_entities()
Discovers plugins in the plugins_path setting and creates \ElggPlugin entities for them if they don't...
Definition: plugins.php:60
elgg_get_upgrade_files($upgrade_path=null)
Returns a list of upgrade files relative to the $upgrade_path dir.
Definition: upgrade.php:52
get_entity($guid)
Loads and returns an entity object from a guid.
Definition: entities.php:204
add_subtype($type, $subtype, $class="")
Register \ElggEntities with a certain type and subtype to be loaded as a specific class.
Definition: entities.php:95
$url
Definition: exceptions.php:24
if(elgg_extract('required', $vars)) $field
Definition: field.php:25
$lang
Definition: html.php:12
$value
Definition: longtext.php:42
A simple directory abstraction.
Definition: Directory.php:13
getPath($path='')
Get the absolute path to the given directory-relative path.
elgg_view_page($title, $body, $page_shell='default', $vars=array())
Assembles and outputs a full page.
Definition: views.php:447
elgg_view($view, $vars=array(), $ignore1=false, $ignore2=false, $viewtype='')
Return a parsed view.
Definition: views.php:336
elgg_set_viewtype($viewtype="")
Manually set the viewtype.
Definition: views.php:74
Save menu items.
$extensions
Definition: summary.php:41
if(elgg_in_context('widget')) $count
Definition: pagination.php:21
$vars['entity']
if(!array_key_exists($filename, $text_files)) $file
$report
$key
Definition: summary.php:34
$extension
Definition: default.php:23
login(\ElggUser $user, $persistent=false)
Logs in a specified \ElggUser.
Definition: sessions.php:320
_elgg_session_boot()
Initializes the session and checks for the remember me cookie.
Definition: sessions.php:401
$plugin
global $CONFIG
elgg subtext time
$upgrades
Lists pending upgrades.
Definition: upgrades.php:6
register_user($username, $password, $name, $email, $allow_multiple_emails=false)
Registers a user, returning false if the username already exists.
Definition: users.php:316
$table
Definition: cron.php:34
$e
Definition: metadata.php:12