Elgg  Version 2.2
 All Classes Namespaces Files Functions Variables Pages
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 
59  private $CONFIG;
60 
64  public function __construct() {
65  global $CONFIG;
66  if (!isset($CONFIG)) {
67  $CONFIG = new stdClass;
68  }
69 
70  global $_ELGG;
71  if (!isset($_ELGG)) {
72  $_ELGG = new stdClass;
73  }
74 
75  $this->CONFIG = $CONFIG;
76 
77  $this->isAction = isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST';
78 
79  $this->bootstrapConfig();
80 
81  $this->bootstrapEngine();
82 
83  _elgg_services()->setValue('session', \ElggSession::getMock());
84 
85  elgg_set_viewtype('installation');
86 
87  set_error_handler('_elgg_php_error_handler');
88  set_exception_handler('_elgg_php_exception_handler');
89 
90  _elgg_services()->config->set('simplecache_enabled', false);
91  _elgg_services()->translator->registerTranslations(\Elgg\Application::elggDir()->getPath("/install/languages/"), TRUE);
92  _elgg_services()->views->registerPluginViews(\Elgg\Application::elggDir()->getPath("/"));
93  }
94 
103  public function run($step) {
104  global $CONFIG;
105 
106  // language needs to be set before the first call to elgg_echo()
107  $CONFIG->language = 'en';
108 
109  // check if this is a URL rewrite test coming in
110  $this->processRewriteTest();
111 
112  if (!in_array($step, $this->getSteps())) {
113  $msg = _elgg_services()->translator->translate('InstallationException:UnknownStep', array($step));
114  throw new InstallationException($msg);
115  }
116 
117  $this->setInstallStatus();
118 
119  $this->checkInstallCompletion($step);
120 
121  // check if this is an install being resumed
122  $this->resumeInstall($step);
123 
124  $this->finishBootstraping($step);
125 
126  $params = $this->getPostVariables();
127 
128  $this->$step($params);
129  }
130 
138  public function setAutoLogin($flag) {
139  $this->autoLogin = (bool) $flag;
140  }
141 
160  public function batchInstall(array $params, $createHtaccess = FALSE) {
161 
162 
163  restore_error_handler();
164  restore_exception_handler();
165 
166  $defaults = array(
167  'dbhost' => 'localhost',
168  'dbprefix' => 'elgg_',
169  'language' => 'en',
170  'siteaccess' => ACCESS_PUBLIC,
171  'site_guid' => 1,
172  );
173  $params = array_merge($defaults, $params);
174 
175  $requiredParams = array(
176  'dbuser',
177  'dbpassword',
178  'dbname',
179  'sitename',
180  'wwwroot',
181  'dataroot',
182  'displayname',
183  'email',
184  'username',
185  'password',
186  );
187  foreach ($requiredParams as $key) {
188  if (empty($params[$key])) {
189  $msg = _elgg_services()->translator->translate('install:error:requiredfield', array($key));
190  throw new InstallationException($msg);
191  }
192  }
193 
194  // password is passed in once
195  $params['password1'] = $params['password2'] = $params['password'];
196 
197  if ($createHtaccess) {
198  $rewriteTester = new ElggRewriteTester();
199  if (!$rewriteTester->createHtaccess($params['wwwroot'], Directory\Local::root()->getPath())) {
200  throw new InstallationException(_elgg_services()->translator->translate('install:error:htaccess'));
201  }
202  }
203 
204  $this->setInstallStatus();
205 
206  if (!$this->status['config']) {
207  if (!$this->createSettingsFile($params)) {
208  throw new InstallationException(_elgg_services()->translator->translate('install:error:settings'));
209  }
210  }
211 
212  if (!$this->connectToDatabase()) {
213  throw new InstallationException(_elgg_services()->translator->translate('install:error:databasesettings'));
214  }
215 
216  if (!$this->status['database']) {
217  if (!$this->installDatabase()) {
218  throw new InstallationException(_elgg_services()->translator->translate('install:error:cannotloadtables'));
219  }
220  }
221 
222  // load remaining core libraries
223  $this->finishBootstraping('settings');
224 
225  if (!$this->saveSiteSettings($params)) {
226  throw new InstallationException(_elgg_services()->translator->translate('install:error:savesitesettings'));
227  }
228 
229  if (!$this->createAdminAccount($params)) {
230  throw new InstallationException(_elgg_services()->translator->translate('install:admin:cannot_create'));
231  }
232  }
233 
242  protected function render($step, $vars = array()) {
243  $vars['next_step'] = $this->getNextStep($step);
244 
245  $title = _elgg_services()->translator->translate("install:$step");
246  $body = elgg_view("install/pages/$step", $vars);
247 
248  echo elgg_view_page(
249  $title,
250  $body,
251  'default',
252  array(
253  'step' => $step,
254  'steps' => $this->getSteps(),
255  )
256  );
257  exit;
258  }
259 
271  protected function welcome($vars) {
272  $this->render('welcome');
273  }
274 
284  protected function requirements($vars) {
285 
286  $report = array();
287 
288  // check PHP parameters and libraries
289  $this->checkPHP($report);
290 
291  // check URL rewriting
292  $this->checkRewriteRules($report);
293 
294  // check for existence of settings file
295  if ($this->checkSettingsFile($report) != TRUE) {
296  // no file, so check permissions on engine directory
298  }
299 
300  // check the database later
301  $report['database'] = array(array(
302  'severity' => 'info',
303  'message' => _elgg_services()->translator->translate('install:check:database')
304  ));
305 
306  // any failures?
307  $numFailures = $this->countNumConditions($report, 'failure');
308 
309  // any warnings
310  $numWarnings = $this->countNumConditions($report, 'warning');
311 
312 
313  $params = array(
314  'report' => $report,
315  'num_failures' => $numFailures,
316  'num_warnings' => $numWarnings,
317  );
318 
319  $this->render('requirements', $params);
320  }
321 
331  protected function database($submissionVars) {
332 
333  $formVars = array(
334  'dbuser' => array(
335  'type' => 'text',
336  'value' => '',
337  'required' => TRUE,
338  ),
339  'dbpassword' => array(
340  'type' => 'password',
341  'value' => '',
342  'required' => FALSE,
343  ),
344  'dbname' => array(
345  'type' => 'text',
346  'value' => '',
347  'required' => TRUE,
348  ),
349  'dbhost' => array(
350  'type' => 'text',
351  'value' => 'localhost',
352  'required' => TRUE,
353  ),
354  'dbprefix' => array(
355  'type' => 'text',
356  'value' => 'elgg_',
357  'required' => TRUE,
358  ),
359  'timezone' => array(
360  'type' => 'dropdown',
361  'value' => 'UTC',
362  'options' => \DateTimeZone::listIdentifiers(),
363  'required' => TRUE
364  )
365  );
366 
367  if ($this->checkSettingsFile()) {
368  // user manually created settings file so we fake out action test
369  $this->isAction = TRUE;
370  }
371 
372  if ($this->isAction) {
373  do {
374  // only create settings file if it doesn't exist
375  if (!$this->checkSettingsFile()) {
376  if (!$this->validateDatabaseVars($submissionVars, $formVars)) {
377  // error so we break out of action and serve same page
378  break;
379  }
380 
381  if (!$this->createSettingsFile($submissionVars)) {
382  break;
383  }
384  }
385 
386  // check db version and connect
387  if (!$this->connectToDatabase()) {
388  break;
389  }
390 
391  if (!$this->installDatabase()) {
392  break;
393  }
394 
395  system_message(_elgg_services()->translator->translate('install:success:database'));
396 
397  $this->continueToNextStep('database');
398  } while (FALSE); // PHP doesn't support breaking out of if statements
399  }
400 
401  $formVars = $this->makeFormSticky($formVars, $submissionVars);
402 
403  $params = array('variables' => $formVars,);
404 
405  if ($this->checkSettingsFile()) {
406  // settings file exists and we're here so failed to create database
407  $params['failure'] = TRUE;
408  }
409 
410  $this->render('database', $params);
411  }
412 
422  protected function settings($submissionVars) {
423 
424 
425  $formVars = array(
426  'sitename' => array(
427  'type' => 'text',
428  'value' => 'My New Community',
429  'required' => TRUE,
430  ),
431  'siteemail' => array(
432  'type' => 'email',
433  'value' => '',
434  'required' => FALSE,
435  ),
436  'wwwroot' => array(
437  'type' => 'url',
438  'value' => _elgg_services()->config->getSiteUrl(),
439  'required' => TRUE,
440  ),
441  'dataroot' => array(
442  'type' => 'text',
443  'value' => '',
444  'required' => TRUE,
445  ),
446  'siteaccess' => array(
447  'type' => 'access',
448  'value' => ACCESS_PUBLIC,
449  'required' => TRUE,
450  ),
451  );
452 
453  // if Apache, we give user option of having Elgg create data directory
454  //if (ElggRewriteTester::guessWebServer() == 'apache') {
455  // $formVars['dataroot']['type'] = 'combo';
456  // $GLOBALS['_ELGG']->translations['en']['install:settings:help:dataroot'] =
457  // $GLOBALS['_ELGG']->translations['en']['install:settings:help:dataroot:apache'];
458  //}
459 
460  if ($this->isAction) {
461  do {
462  //if (!$this->createDataDirectory($submissionVars, $formVars)) {
463  // break;
464  //}
465 
466  if (!$this->validateSettingsVars($submissionVars, $formVars)) {
467  break;
468  }
469 
470  if (!$this->saveSiteSettings($submissionVars)) {
471  break;
472  }
473 
474  system_message(_elgg_services()->translator->translate('install:success:settings'));
475 
476  $this->continueToNextStep('settings');
477 
478  } while (FALSE); // PHP doesn't support breaking out of if statements
479  }
480 
481  $formVars = $this->makeFormSticky($formVars, $submissionVars);
482 
483  $this->render('settings', array('variables' => $formVars));
484  }
485 
495  protected function admin($submissionVars) {
496  $formVars = array(
497  'displayname' => array(
498  'type' => 'text',
499  'value' => '',
500  'required' => TRUE,
501  ),
502  'email' => array(
503  'type' => 'email',
504  'value' => '',
505  'required' => TRUE,
506  ),
507  'username' => array(
508  'type' => 'text',
509  'value' => '',
510  'required' => TRUE,
511  ),
512  'password1' => array(
513  'type' => 'password',
514  'value' => '',
515  'required' => TRUE,
516  'pattern' => '.{6,}',
517  ),
518  'password2' => array(
519  'type' => 'password',
520  'value' => '',
521  'required' => TRUE,
522  ),
523  );
524 
525  if ($this->isAction) {
526  do {
527  if (!$this->validateAdminVars($submissionVars, $formVars)) {
528  break;
529  }
530 
531  if (!$this->createAdminAccount($submissionVars, $this->autoLogin)) {
532  break;
533  }
534 
535  system_message(_elgg_services()->translator->translate('install:success:admin'));
536 
537  $this->continueToNextStep('admin');
538 
539  } while (FALSE); // PHP doesn't support breaking out of if statements
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', array('variables' => $formVars));
552  }
553 
559  protected function complete() {
560 
561  $params = array();
562  if ($this->autoLogin) {
563  $params['destination'] = 'admin';
564  } else {
565  $params['destination'] = 'index.php';
566  }
567 
568  $this->render('complete', $params);
569  }
570 
580  protected function getSteps() {
581  return $this->steps;
582  }
583 
591  protected function continueToNextStep($currentStep) {
592  $this->isAction = FALSE;
593  forward($this->getNextStepUrl($currentStep));
594  }
595 
603  protected function getNextStep($currentStep) {
604  $index = 1 + array_search($currentStep, $this->steps);
605  if (isset($this->steps[$index])) {
606  return $this->steps[$index];
607  } else {
608  return null;
609  }
610  }
611 
619  protected function getNextStepUrl($currentStep) {
620  $nextStep = $this->getNextStep($currentStep);
621  return _elgg_services()->config->getSiteUrl() . "install.php?step=$nextStep";
622  }
623 
630  protected function setInstallStatus() {
631  if (!is_readable($this->getSettingsPath())) {
632  return;
633  }
634 
635  $this->loadSettingsFile();
636 
637  $this->status['config'] = TRUE;
638 
639  // must be able to connect to database to jump install steps
640  $dbSettingsPass = $this->checkDatabaseSettings(
641  $this->CONFIG->dbuser,
642  $this->CONFIG->dbpass,
643  $this->CONFIG->dbname,
644  $this->CONFIG->dbhost
645  );
646 
647  if ($dbSettingsPass == FALSE) {
648  return;
649  }
650 
651  if (!include_once(\Elgg\Application::elggDir()->getPath("engine/lib/database.php"))) {
652  throw new InstallationException(_elgg_services()->translator->translate('InstallationException:MissingLibrary', array('database.php')));
653  }
654 
655  // check that the config table has been created
656  $query = "show tables";
657  $result = _elgg_services()->db->getData($query);
658  if ($result) {
659  foreach ($result as $table) {
660  $table = (array) $table;
661  if (in_array("{$this->CONFIG->dbprefix}config", $table)) {
662  $this->status['database'] = TRUE;
663  }
664  }
665  if ($this->status['database'] == FALSE) {
666  return;
667  }
668  } else {
669  // no tables
670  return;
671  }
672 
673  // check that the config table has entries
674  $query = "SELECT COUNT(*) AS total FROM {$this->CONFIG->dbprefix}config";
675  $result = _elgg_services()->db->getData($query);
676  if ($result && $result[0]->total > 0) {
677  $this->status['settings'] = TRUE;
678  } else {
679  return;
680  }
681 
682  // check that the users entity table has an entry
683  $query = "SELECT COUNT(*) AS total FROM {$this->CONFIG->dbprefix}users_entity";
684  $result = _elgg_services()->db->getData($query);
685  if ($result && $result[0]->total > 0) {
686  $this->status['admin'] = TRUE;
687  } else {
688  return;
689  }
690  }
691 
700  protected function checkInstallCompletion($step) {
701  if ($step != 'complete') {
702  if (!in_array(FALSE, $this->status)) {
703  // install complete but someone is trying to view an install page
704  forward();
705  }
706  }
707  }
708 
717  protected function resumeInstall($step) {
718  // only do a resume from the first step
719  if ($step !== 'welcome') {
720  return;
721  }
722 
723  if ($this->status['database'] == FALSE) {
724  return;
725  }
726 
727  if ($this->status['settings'] == FALSE) {
728  forward("install.php?step=settings");
729  }
730 
731  if ($this->status['admin'] == FALSE) {
732  forward("install.php?step=admin");
733  }
734 
735  // everything appears to be set up
736  forward("install.php?step=complete");
737  }
738 
748  protected function bootstrapEngine() {
749  $config = new \Elgg\Config($this->CONFIG);
750  $services = new \Elgg\Di\ServiceProvider($config);
751  (new \Elgg\Application($services))->loadCore();
752  }
753 
763  protected function finishBootstraping($step) {
764 
765  $dbIndex = array_search('database', $this->getSteps());
766  $settingsIndex = array_search('settings', $this->getSteps());
767  $adminIndex = array_search('admin', $this->getSteps());
768  $completeIndex = array_search('complete', $this->getSteps());
769  $stepIndex = array_search($step, $this->getSteps());
770 
771  // To log in the user, we need to use the Elgg core session handling.
772  // Otherwise, use default php session handling
773  $useElggSession = ($stepIndex == $adminIndex && $this->isAction) ||
774  $stepIndex == $completeIndex;
775  if (!$useElggSession) {
776  session_name('Elgg_install');
777  session_start();
778  _elgg_services()->events->unregisterHandler('boot', 'system', 'session_init');
779  }
780 
781  if ($stepIndex > $dbIndex) {
782  // once the database has been created, load rest of engine
783 
784  $lib_dir = \Elgg\Application::elggDir()->chroot('/engine/lib/');
785 
786  $this->loadSettingsFile();
787 
788  $lib_files = array(
789  // these want to be loaded first apparently?
790  'autoloader.php',
791  'database.php',
792  'actions.php',
793 
794  'admin.php',
795  'annotations.php',
796  'cron.php',
797  'entities.php',
798  'extender.php',
799  'filestore.php',
800  'group.php',
801  'mb_wrapper.php',
802  'memcache.php',
803  'metadata.php',
804  'metastrings.php',
805  'navigation.php',
806  'notification.php',
807  'objects.php',
808  'pagehandler.php',
809  'pam.php',
810  'plugins.php',
811  'private_settings.php',
812  'relationships.php',
813  'river.php',
814  'sites.php',
815  'statistics.php',
816  'tags.php',
817  'user_settings.php',
818  'users.php',
819  'upgrade.php',
820  'widgets.php',
821  'deprecated-1.9.php',
822  );
823 
824  foreach ($lib_files as $file) {
825  if (!include_once($lib_dir->getPath($file))) {
826  throw new InstallationException('InstallationException:MissingLibrary', array($file));
827  }
828  }
829 
830  _elgg_services()->db->setupConnections();
831  _elgg_services()->translator->registerTranslations(\Elgg\Application::elggDir()->getPath("/languages/"));
832  $this->CONFIG->language = 'en';
833 
834  if ($stepIndex > $settingsIndex) {
835  $this->CONFIG->site_guid = (int) _elgg_services()->datalist->get('default_site');
836  $this->CONFIG->site_id = $this->CONFIG->site_guid;
837  $this->CONFIG->site = get_entity($this->CONFIG->site_guid);
838  $this->CONFIG->dataroot = _elgg_services()->datalist->get('dataroot');
839  _elgg_services()->config->getCookieConfig();
841  }
842 
843  _elgg_services()->events->trigger('init', 'system');
844  }
845  }
846 
852  protected function bootstrapConfig() {
853  $this->CONFIG->installer_running = true;
854 
855  $this->CONFIG->wwwroot = $this->getBaseUrl();
856  $this->CONFIG->url = $this->CONFIG->wwwroot;
857  $this->CONFIG->path = \Elgg\Application::elggDir()->getPath() . "/";
858  $GLOBALS['_ELGG']->view_path = $this->CONFIG->path . 'views/';
859  $this->CONFIG->pluginspath = $this->CONFIG->path . 'mod/';
860  $this->CONFIG->context = array();
861  $this->CONFIG->entity_types = array('group', 'object', 'site', 'user');
862 
863  // required by elgg_view_page()
864  $this->CONFIG->sitename = '';
865  $this->CONFIG->sitedescription = '';
866 
867  // required by Elgg\Config::get
868  $this->CONFIG->site_guid = 1;
869  }
870 
874  private function isHttps() {
875  return (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") ||
876  (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443);
877  }
878 
887  protected function getBaseUrl() {
888  $protocol = $this->isHttps() ? 'https' : 'http';
889 
890  if (isset($_SERVER["SERVER_PORT"])) {
891  $port = ':' . $_SERVER["SERVER_PORT"];
892  } else {
893  $port = '';
894  }
895  if ($port == ':80' || $port == ':443') {
896  $port = '';
897  }
898  $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
899  $cutoff = strpos($uri, 'install.php');
900  $uri = substr($uri, 0, $cutoff);
901  $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
902 
903  return "$protocol://{$serverName}$port{$uri}";
904  }
905 
912  protected function loadSettingsFile() {
913  if (!include_once($this->getSettingsPath())) {
914  throw new InstallationException(_elgg_services()->translator->translate('InstallationException:CannotLoadSettings'));
915  }
916  }
917 
931  protected function getPostVariables() {
932  $vars = array();
933  foreach ($_POST as $k => $v) {
934  $vars[$k] = $v;
935  }
936  return $vars;
937  }
938 
947  protected function makeFormSticky($formVars, $submissionVars) {
948  foreach ($submissionVars as $field => $value) {
949  $formVars[$field]['value'] = $value;
950  }
951  return $formVars;
952  }
953 
965  protected function isInstallDirWritable(&$report) {
966  $root = Directory\Local::root()->getPath();
967  $abs_path = \Elgg\Application::elggDir()->getPath('elgg-config');
968 
969  if (0 === strpos($abs_path, $root)) {
970  $relative_path = substr($abs_path, strlen($root));
971  } else {
972  $relative_path = $abs_path;
973  }
974  $relative_path = rtrim($relative_path, '/\\');
975 
976  $writable = is_writable(Directory\Local::root()->getPath('elgg-config'));
977  if (!$writable) {
978  $report['settings'] = array(
979  array(
980  'severity' => 'failure',
981  'message' => _elgg_services()->translator->translate('install:check:installdir', [$relative_path]),
982  )
983  );
984  return FALSE;
985  }
986 
987  return TRUE;
988  }
989 
997  protected function checkSettingsFile(&$report = array()) {
998 
999 
1000  if (!file_exists($this->getSettingsPath())) {
1001  return FALSE;
1002  }
1003 
1004  if (!is_readable($this->getSettingsPath())) {
1005  $report['settings'] = array(
1006  array(
1007  'severity' => 'failure',
1008  'message' => _elgg_services()->translator->translate('install:check:readsettings'),
1009  )
1010  );
1011  }
1012 
1013  return TRUE;
1014  }
1015 
1021  private function getSettingsPath() {
1022  return Directory\Local::root()->getPath("elgg-config/settings.php");
1023  }
1024 
1032  protected function checkPHP(&$report) {
1033  $phpReport = array();
1034 
1035  $min_php_version = '5.5.0';
1036  if (version_compare(PHP_VERSION, $min_php_version, '<')) {
1037  $phpReport[] = array(
1038  'severity' => 'failure',
1039  'message' => _elgg_services()->translator->translate('install:check:php:version', array($min_php_version, PHP_VERSION))
1040  );
1041  }
1042 
1043  $this->checkPhpExtensions($phpReport);
1044 
1045  $this->checkPhpDirectives($phpReport);
1046 
1047  if (count($phpReport) == 0) {
1048  $phpReport[] = array(
1049  'severity' => 'pass',
1050  'message' => _elgg_services()->translator->translate('install:check:php:success')
1051  );
1052  }
1053 
1054  $report['php'] = $phpReport;
1055  }
1056 
1064  protected function checkPhpExtensions(&$phpReport) {
1065  $extensions = get_loaded_extensions();
1066  $requiredExtensions = array(
1067  'pdo_mysql',
1068  'json',
1069  'xml',
1070  'gd',
1071  );
1072  foreach ($requiredExtensions as $extension) {
1073  if (!in_array($extension, $extensions)) {
1074  $phpReport[] = array(
1075  'severity' => 'failure',
1076  'message' => _elgg_services()->translator->translate('install:check:php:extension', array($extension))
1077  );
1078  }
1079  }
1080 
1081  $recommendedExtensions = array(
1082  'mbstring',
1083  );
1084  foreach ($recommendedExtensions as $extension) {
1085  if (!in_array($extension, $extensions)) {
1086  $phpReport[] = array(
1087  'severity' => 'warning',
1088  'message' => _elgg_services()->translator->translate('install:check:php:extension:recommend', array($extension))
1089  );
1090  }
1091  }
1092  }
1093 
1101  protected function checkPhpDirectives(&$phpReport) {
1102  if (ini_get('open_basedir')) {
1103  $phpReport[] = array(
1104  'severity' => 'warning',
1105  'message' => _elgg_services()->translator->translate("install:check:php:open_basedir")
1106  );
1107  }
1108 
1109  if (ini_get('safe_mode')) {
1110  $phpReport[] = array(
1111  'severity' => 'warning',
1112  'message' => _elgg_services()->translator->translate("install:check:php:safe_mode")
1113  );
1114  }
1115 
1116  if (ini_get('arg_separator.output') !== '&') {
1117  $separator = htmlspecialchars(ini_get('arg_separator.output'));
1118  $msg = _elgg_services()->translator->translate("install:check:php:arg_separator", array($separator));
1119  $phpReport[] = array(
1120  'severity' => 'failure',
1121  'message' => $msg,
1122  );
1123  }
1124 
1125  if (ini_get('register_globals')) {
1126  $phpReport[] = array(
1127  'severity' => 'failure',
1128  'message' => _elgg_services()->translator->translate("install:check:php:register_globals")
1129  );
1130  }
1131 
1132  if (ini_get('session.auto_start')) {
1133  $phpReport[] = array(
1134  'severity' => 'failure',
1135  'message' => _elgg_services()->translator->translate("install:check:php:session.auto_start")
1136  );
1137  }
1138  }
1139 
1147  protected function checkRewriteRules(&$report) {
1148 
1149 
1150  $tester = new ElggRewriteTester();
1151  $url = _elgg_services()->config->getSiteUrl() . "rewrite.php";
1152  $report['rewrite'] = array($tester->run($url, Directory\Local::root()->getPath()));
1153  }
1154 
1161  protected function processRewriteTest() {
1162  if (strpos($_SERVER['REQUEST_URI'], 'rewrite.php') !== FALSE) {
1163  echo \Elgg\Application::REWRITE_TEST_OUTPUT;
1164  exit;
1165  }
1166  }
1167 
1176  protected function countNumConditions($report, $condition) {
1177  $count = 0;
1178  foreach ($report as $category => $checks) {
1179  foreach ($checks as $check) {
1180  if ($check['severity'] === $condition) {
1181  $count++;
1182  }
1183  }
1184  }
1185 
1186  return $count;
1187  }
1188 
1189 
1202  protected function validateDatabaseVars($submissionVars, $formVars) {
1203 
1204  foreach ($formVars as $field => $info) {
1205  if ($info['required'] == TRUE && !$submissionVars[$field]) {
1206  $name = _elgg_services()->translator->translate("install:database:label:$field");
1207  register_error(_elgg_services()->translator->translate('install:error:requiredfield', array($name)));
1208  return FALSE;
1209  }
1210  }
1211 
1212  // according to postgres documentation: SQL identifiers and key words must
1213  // begin with a letter (a-z, but also letters with diacritical marks and
1214  // non-Latin letters) or an underscore (_). Subsequent characters in an
1215  // identifier or key word can be letters, underscores, digits (0-9), or dollar signs ($).
1216  // Refs #4994
1217  if (!preg_match("/^[a-zA-Z_][\w]*$/", $submissionVars['dbprefix'])) {
1218  register_error(_elgg_services()->translator->translate('install:error:database_prefix'));
1219  return FALSE;
1220  }
1221 
1222  return $this->checkDatabaseSettings(
1223  $submissionVars['dbuser'],
1224  $submissionVars['dbpassword'],
1225  $submissionVars['dbname'],
1226  $submissionVars['dbhost']
1227  );
1228  }
1229 
1240  protected function checkDatabaseSettings($user, $password, $dbname, $host) {
1241  $config = new \Elgg\Database\Config((object)[
1242  'dbhost' => $host,
1243  'dbuser' => $user,
1244  'dbpass' => $password,
1245  'dbname' => $dbname,
1246  ]);
1247  $db = new \Elgg\Database($config);
1248 
1249  try {
1250  $db->getDataRow("SELECT 1");
1251  } catch (DatabaseException $e) {
1252  if (0 === strpos($e->getMessage(), "Elgg couldn't connect")) {
1253  register_error(_elgg_services()->translator->translate('install:error:databasesettings'));
1254  } else {
1255  register_error(_elgg_services()->translator->translate('install:error:nodatabase', array($dbname)));
1256  }
1257  return FALSE;
1258  }
1259 
1260  // check MySQL version - must be 5.0 or >
1261  $version = $db->getServerVersion(\Elgg\Database\Config::READ_WRITE);
1262  $required_version = 5.0;
1263  $points = explode('.', $version);
1264  if ($points[0] < $required_version) {
1265  register_error(_elgg_services()->translator->translate('install:error:oldmysql', array($version)));
1266  return FALSE;
1267  }
1268 
1269  return TRUE;
1270  }
1271 
1279  protected function createSettingsFile($params) {
1280  $template = \Elgg\Application::elggDir()->getContents("elgg-config/settings.example.php");
1281  if (!$template) {
1282  register_error(_elgg_services()->translator->translate('install:error:readsettingsphp'));
1283  return FALSE;
1284  }
1285 
1286  foreach ($params as $k => $v) {
1287  $template = str_replace("{{" . $k . "}}", $v, $template);
1288  }
1289 
1290  $result = file_put_contents($this->getSettingsPath(), $template);
1291  if (!$result) {
1292  register_error(_elgg_services()->translator->translate('install:error:writesettingphp'));
1293  return FALSE;
1294  }
1295 
1296  return TRUE;
1297  }
1298 
1304  protected function connectToDatabase() {
1305 
1306 
1307  if (!include_once($this->getSettingsPath())) {
1308  register_error('Elgg could not load the settings file. It does not exist or there is a file permissions issue.');
1309  return FALSE;
1310  }
1311 
1312  if (!include_once(\Elgg\Application::elggDir()->getPath("engine/lib/database.php"))) {
1313  register_error('Could not load database.php');
1314  return FALSE;
1315  }
1316 
1317  try {
1318  _elgg_services()->db->setupConnections();
1319  } catch (DatabaseException $e) {
1320  register_error($e->getMessage());
1321  return FALSE;
1322  }
1323 
1324  return TRUE;
1325  }
1326 
1332  protected function installDatabase() {
1333 
1334 
1335  try {
1336  _elgg_services()->db->runSqlScript(\Elgg\Application::elggDir()->getPath("/engine/schema/mysql.sql"));
1337  } catch (Exception $e) {
1338  $msg = $e->getMessage();
1339  if (strpos($msg, 'already exists')) {
1340  $msg = _elgg_services()->translator->translate('install:error:tables_exist');
1341  }
1342  register_error($msg);
1343  return FALSE;
1344  }
1345 
1346  return TRUE;
1347  }
1348 
1361  protected function createDataDirectory(&$submissionVars, $formVars) {
1362  // did the user have option of Elgg creating the data directory
1363  if ($formVars['dataroot']['type'] != 'combo') {
1364  return TRUE;
1365  }
1366 
1367  // did the user select the option
1368  if ($submissionVars['dataroot'] != 'dataroot-checkbox') {
1369  return TRUE;
1370  }
1371 
1372  $dir = sanitise_filepath($submissionVars['path']) . 'data';
1373  if (file_exists($dir) || mkdir($dir, 0700)) {
1374  $submissionVars['dataroot'] = $dir;
1375  if (!file_exists("$dir/.htaccess")) {
1376  $htaccess = "Order Deny,Allow\nDeny from All\n";
1377  if (!file_put_contents("$dir/.htaccess", $htaccess)) {
1378  return FALSE;
1379  }
1380  }
1381  return TRUE;
1382  }
1383 
1384  return FALSE;
1385  }
1386 
1395  protected function validateSettingsVars($submissionVars, $formVars) {
1396 
1397 
1398  foreach ($formVars as $field => $info) {
1399  $submissionVars[$field] = trim($submissionVars[$field]);
1400  if ($info['required'] == TRUE && $submissionVars[$field] === '') {
1401  $name = _elgg_services()->translator->translate("install:settings:label:$field");
1402  register_error(_elgg_services()->translator->translate('install:error:requiredfield', array($name)));
1403  return FALSE;
1404  }
1405  }
1406 
1407  // check that data root is absolute path
1408  if (stripos(PHP_OS, 'win') === 0) {
1409  if (strpos($submissionVars['dataroot'], ':') !== 1) {
1410  $msg = _elgg_services()->translator->translate('install:error:relative_path', array($submissionVars['dataroot']));
1411  register_error($msg);
1412  return FALSE;
1413  }
1414  } else {
1415  if (strpos($submissionVars['dataroot'], '/') !== 0) {
1416  $msg = _elgg_services()->translator->translate('install:error:relative_path', array($submissionVars['dataroot']));
1417  register_error($msg);
1418  return FALSE;
1419  }
1420  }
1421 
1422  // check that data root exists
1423  if (!file_exists($submissionVars['dataroot'])) {
1424  $msg = _elgg_services()->translator->translate('install:error:datadirectoryexists', array($submissionVars['dataroot']));
1425  register_error($msg);
1426  return FALSE;
1427  }
1428 
1429  // check that data root is writable
1430  if (!is_writable($submissionVars['dataroot'])) {
1431  $msg = _elgg_services()->translator->translate('install:error:writedatadirectory', array($submissionVars['dataroot']));
1432  register_error($msg);
1433  return FALSE;
1434  }
1435 
1436  if (!isset($this->CONFIG->data_dir_override) || !$this->CONFIG->data_dir_override) {
1437  // check that data root is not subdirectory of Elgg root
1438  if (stripos($submissionVars['dataroot'], $submissionVars['path']) === 0) {
1439  $msg = _elgg_services()->translator->translate('install:error:locationdatadirectory', array($submissionVars['dataroot']));
1440  register_error($msg);
1441  return FALSE;
1442  }
1443  }
1444 
1445  // check that email address is email address
1446  if ($submissionVars['siteemail'] && !is_email_address($submissionVars['siteemail'])) {
1447  $msg = _elgg_services()->translator->translate('install:error:emailaddress', array($submissionVars['siteemail']));
1448  register_error($msg);
1449  return FALSE;
1450  }
1451 
1452  // @todo check that url is a url
1453  // @note filter_var cannot be used because it doesn't work on international urls
1454 
1455  return TRUE;
1456  }
1457 
1465  protected function saveSiteSettings($submissionVars) {
1466 
1467 
1468  // ensure that file path, data path, and www root end in /
1469  $submissionVars['dataroot'] = sanitise_filepath($submissionVars['dataroot']);
1470  $submissionVars['wwwroot'] = sanitise_filepath($submissionVars['wwwroot']);
1471 
1472  $site = new ElggSite();
1473  $site->name = strip_tags($submissionVars['sitename']);
1474  $site->url = $submissionVars['wwwroot'];
1475  $site->access_id = ACCESS_PUBLIC;
1476  $site->email = $submissionVars['siteemail'];
1477  $guid = $site->save();
1478 
1479  if (!$guid) {
1480  register_error(_elgg_services()->translator->translate('install:error:createsite'));
1481  return FALSE;
1482  }
1483 
1484  // bootstrap site info
1485  $this->CONFIG->site_guid = $guid;
1486  $this->CONFIG->site_id = $guid;
1487  $this->CONFIG->site = $site;
1488 
1489  _elgg_services()->datalist->set('installed', time());
1490  _elgg_services()->datalist->set('dataroot', $submissionVars['dataroot']);
1491  _elgg_services()->datalist->set('default_site', $site->getGUID());
1492  _elgg_services()->datalist->set('version', elgg_get_version());
1493  _elgg_services()->datalist->set('simplecache_enabled', 1);
1494  _elgg_services()->datalist->set('system_cache_enabled', 1);
1495  _elgg_services()->datalist->set('simplecache_lastupdate', time());
1496 
1497  // new installations have run all the upgrades
1498  $upgrades = elgg_get_upgrade_files(\Elgg\Application::elggDir()->getPath("/engine/lib/upgrades/"));
1499  _elgg_services()->datalist->set('processed_upgrades', serialize($upgrades));
1500 
1501  _elgg_services()->configTable->set('view', 'default', $site->getGUID());
1502  _elgg_services()->configTable->set('language', 'en', $site->getGUID());
1503  _elgg_services()->configTable->set('default_access', $submissionVars['siteaccess'], $site->getGUID());
1504  _elgg_services()->configTable->set('allow_registration', TRUE, $site->getGUID());
1505  _elgg_services()->configTable->set('walled_garden', FALSE, $site->getGUID());
1506  _elgg_services()->configTable->set('allow_user_default_access', '', $site->getGUID());
1507  _elgg_services()->configTable->set('default_limit', 10, $site->getGUID());
1508 
1509  $this->setSubtypeClasses();
1510 
1511  $this->enablePlugins();
1512 
1513  return TRUE;
1514  }
1515 
1521  protected function setSubtypeClasses() {
1522  add_subtype("object", "plugin", "ElggPlugin");
1523  add_subtype("object", "file", "ElggFile");
1524  add_subtype("object", "widget", "ElggWidget");
1525  add_subtype("object", "comment", "ElggComment");
1526  add_subtype("object", "elgg_upgrade", 'ElggUpgrade');
1527  }
1528 
1534  protected function enablePlugins() {
1536  $plugins = elgg_get_plugins('any');
1537  foreach ($plugins as $plugin) {
1538  if ($plugin->getManifest()) {
1539  if ($plugin->getManifest()->getActivateOnInstall()) {
1540  $plugin->activate();
1541  }
1542  if (in_array('theme', $plugin->getManifest()->getCategories())) {
1543  $plugin->setPriority('last');
1544  }
1545  }
1546  }
1547  }
1548 
1561  protected function validateAdminVars($submissionVars, $formVars) {
1562 
1563  foreach ($formVars as $field => $info) {
1564  if ($info['required'] == TRUE && !$submissionVars[$field]) {
1565  $name = _elgg_services()->translator->translate("install:admin:label:$field");
1566  register_error(_elgg_services()->translator->translate('install:error:requiredfield', array($name)));
1567  return FALSE;
1568  }
1569  }
1570 
1571  if ($submissionVars['password1'] !== $submissionVars['password2']) {
1572  register_error(_elgg_services()->translator->translate('install:admin:password:mismatch'));
1573  return FALSE;
1574  }
1575 
1576  if (trim($submissionVars['password1']) == "") {
1577  register_error(_elgg_services()->translator->translate('install:admin:password:empty'));
1578  return FALSE;
1579  }
1580 
1581  $minLength = _elgg_services()->configTable->get('min_password_length');
1582  if (strlen($submissionVars['password1']) < $minLength) {
1583  register_error(_elgg_services()->translator->translate('install:admin:password:tooshort'));
1584  return FALSE;
1585  }
1586 
1587  // check that email address is email address
1588  if ($submissionVars['email'] && !is_email_address($submissionVars['email'])) {
1589  $msg = _elgg_services()->translator->translate('install:error:emailaddress', array($submissionVars['email']));
1590  register_error($msg);
1591  return FALSE;
1592  }
1593 
1594  return TRUE;
1595  }
1596 
1605  protected function createAdminAccount($submissionVars, $login = FALSE) {
1606  try {
1607  $guid = register_user(
1608  $submissionVars['username'],
1609  $submissionVars['password1'],
1610  $submissionVars['displayname'],
1611  $submissionVars['email']
1612  );
1613  } catch (Exception $e) {
1614  register_error($e->getMessage());
1615  return false;
1616  }
1617 
1618  if (!$guid) {
1619  register_error(_elgg_services()->translator->translate('install:admin:cannot_create'));
1620  return false;
1621  }
1622 
1623  $user = get_entity($guid);
1624  if (!$user instanceof ElggUser) {
1625  register_error(_elgg_services()->translator->translate('install:error:loadadmin'));
1626  return false;
1627  }
1628 
1629  elgg_set_ignore_access(TRUE);
1630  if ($user->makeAdmin() == FALSE) {
1631  register_error(_elgg_services()->translator->translate('install:error:adminaccess'));
1632  } else {
1633  _elgg_services()->datalist->set('admin_registered', 1);
1634  }
1635  elgg_set_ignore_access(false);
1636 
1637  // add validation data to satisfy user validation plugins
1638  create_metadata($guid, 'validated', TRUE, '', 0, ACCESS_PUBLIC);
1639  create_metadata($guid, 'validated_method', 'admin_user', '', 0, ACCESS_PUBLIC);
1640 
1641  if ($login) {
1643 
1644  // session.cache_limiter is unfortunately set to "" by the NativeSessionStorage constructor,
1645  // so we must capture and inject it directly.
1646  $options = [
1647  'cache_limiter' => session_cache_limiter(),
1648  ];
1649  $storage = new Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage($options, $handler);
1650 
1651  $session = new ElggSession(new Symfony\Component\HttpFoundation\Session\Session($storage));
1652  $session->setName('Elgg');
1653  _elgg_services()->setValue('session', $session);
1654  if (login($user) == FALSE) {
1655  register_error(_elgg_services()->translator->translate('install:error:adminlogin'));
1656  }
1657  }
1658 
1659  return TRUE;
1660  }
1661 }
checkSettingsFile(&$report=array())
Check that the settings file exists.
A simple directory abstraction.
Definition: Directory.php:13
$plugin
elgg_get_upgrade_files($upgrade_path=null)
Returns a list of upgrade files relative to the $upgrade_path dir.
Definition: upgrade.php:52
batchInstall(array $params, $createHtaccess=FALSE)
A batch install of Elgg.
createDataDirectory(&$submissionVars, $formVars)
Site settings support methods.
if(!array_key_exists($filename, $text_files)) $file
setSubtypeClasses()
Register classes for core objects.
bootstrapEngine()
Bootstraping.
$table
Definition: cron.php:34
countNumConditions($report, $condition)
Count the number of failures in the requirements report.
processRewriteTest()
Check if the request is coming from the URL rewrite test on the requirements page.
if($guid==elgg_get_logged_in_user_guid()) $name
Definition: delete.php:21
finishBootstraping($step)
Load remaining engine libraries and complete bootstraping (see start.php)
$e
Definition: metadata.php:12
checkPhpDirectives(&$phpReport)
Check PHP parameters.
$lang
Definition: html.php:12
welcome($vars)
Step controllers.
$defaults
$extensions
sanitise_filepath($path, $append_slash=true)
Sanitise file paths ensuring that they begin and end with slashes etc.
Definition: elgglib.php:399
$_ELGG translations
String translations for the current language.
Definition: config.php:321
$value
Definition: longtext.php:26
setInstallStatus()
Check the different install steps for completion.
installDatabase()
Create the database tables.
checkInstallCompletion($step)
Security check to ensure the installer cannot be run after installation has finished.
getNextStep($currentStep)
Get the next step as a string.
$guid
Removes an admin notice.
requirements($vars)
Requirements controller.
getSteps()
Step management.
$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
$report
if($screenshots) $info
Definition: details.php:58
$url
Definition: exceptions.php:24
$vars['entity']
checkPHP(&$report)
Check version of PHP, extensions, and variables.
$title
Definition: save.php:22
$options
Elgg admin footer.
Definition: footer.php:6
register_error($error)
Display an error on next page load.
Definition: elgglib.php:452
validateSettingsVars($submissionVars, $formVars)
Validate the site settings form variables.
resumeInstall($step)
Check if this is a case of a install being resumed and figure out where to continue from...
$params
Definition: login.php:72
is_email_address($address)
Validates an email address.
Definition: input.php:88
settings($submissionVars)
Site settings controller.
continueToNextStep($currentStep)
Forwards the browser to the next step.
getPath($path= '')
Get the absolute path to the given directory-relative path.
render($step, $vars=array())
Renders the data passed by a controller.
getNextStepUrl($currentStep)
Get the URL of the next step.
add_subtype($type, $subtype, $class="")
Register with a certain type and subtype to be loaded as a specific class.
Definition: entities.php:95
getBaseUrl()
Get the best guess at the base URL.
$key
Definition: summary.php:34
elgg_set_ignore_access($ignore=true)
Set if Elgg's access system should be ignored.
Definition: access.php:43
create_metadata($entity_guid, $name, $value, $value_type= '', $owner_guid=0, $access_id=ACCESS_PRIVATE, $allow_multiple=false)
Create a new metadata object, or update an existing one.
Definition: metadata.php:65
makeFormSticky($formVars, $submissionVars)
If form is reshown, remember previously submitted variables.
$user
Definition: ban.php:13
if(elgg_extract('required', $vars)) $field
Definition: field.php:26
elgg_set_viewtype($viewtype="")
Manually set the viewtype.
Definition: views.php:73
checkPhpExtensions(&$phpReport)
Check the server's PHP extensions.
elgg_view($view, $vars=array(), $ignore1=false, $ignore2=false, $viewtype= '')
Return a parsed view.
Definition: views.php:342
bootstrapConfig()
Set up configuration variables.
_elgg_services(\Elgg\Di\ServiceProvider $services=null)
Get the global service provider.
Definition: autoloader.php:17
checkRewriteRules(&$report)
Confirm that the rewrite rules are firing.
$password
Definition: login.php:25
validateDatabaseVars($submissionVars, $formVars)
Database support methods.
createSettingsFile($params)
Writes the settings file to the engine directory.
enablePlugins()
Enable a set of default plugins.
elgg_get_plugins($status= 'active', $site_guid=null)
Returns an ordered list of plugins.
Definition: plugins.php:132
const ACCESS_PUBLIC
Definition: elgglib.php:1990
forward($location="", $reason= 'system')
Forward to $location.
Definition: elgglib.php:93
elgg_get_version($human_readable=false)
Get the current Elgg version information.
Definition: elgglib.php:1043
complete()
Controller for last step.
isInstallDirWritable(&$report)
Requirement checks support methods.
getPostVariables()
Action handling methods.
loadSettingsFile()
Load settings.php.
__construct()
Constructor bootstraps the Elgg engine.
admin($submissionVars)
Admin account controller.
login(\ElggUser $user, $persistent=false)
Logs in a specified .
Definition: sessions.php:320
checkDatabaseSettings($user, $password, $dbname, $host)
Confirm the settings for the database.
static elggDir()
Returns a directory that points to the root of Elgg, but not necessarily the install root...
if(elgg_in_context('widget')) $count
Definition: pagination.php:21
createAdminAccount($submissionVars, $login=FALSE)
Create a user account for the admin.
static getMock()
Get an isolated ElggSession that does not persist between requests.
connectToDatabase()
Bootstrap database connection before entire engine is available.
setAutoLogin($flag)
Set the auto login flag.
exit
Definition: autoloader.php:34
$handler
Definition: add.php:10
saveSiteSettings($submissionVars)
Initialize the site including site entity, plugins, and configuration.
_elgg_session_boot()
Initializes the session and checks for the remember me cookie.
Definition: sessions.php:408
$session
Definition: login.php:9
database($submissionVars)
Database set up controller.
$version
Definition: version.php:14
system_message($message)
Display a system message on next page load.
Definition: elgglib.php:438
run($step)
Dispatches a request to one of the step controllers.
_elgg_generate_plugin_entities()
Discovers plugins in the plugins_path setting and creates entities for them if they don't exist...
Definition: plugins.php:60
$extension
Definition: default.php:23
get_entity($guid)
Loads and returns an entity object from a guid.
Definition: entities.php:204
elgg_view_page($title, $body, $page_shell= 'default', $vars=array())
Assembles and outputs a full page.
Definition: views.php:437
validateAdminVars($submissionVars, $formVars)
Admin account support methods.