4 * Note that this installer has been based of the SilverStripe installer.
5 * You can get more information from the SilverStripe Website at
6 * http://www.silverstripe.com/. Please check
7 * http://www.silverstripe.com/licensing for licensing details.
9 * Copyright (c) 2006-7, SilverStripe Limited - www.silverstripe.com
10 * All rights reserved.
12 * Changes and modifications (c) 2007-8 by CiviCRM LLC
20 ini_set('max_execution_time', 3000);
22 if (stristr(PHP_OS
, 'WIN')) {
23 define('CIVICRM_DIRECTORY_SEPARATOR', '/');
24 define('CIVICRM_WINDOWS', 1);
27 define('CIVICRM_DIRECTORY_SEPARATOR', DIRECTORY_SEPARATOR
);
28 define('CIVICRM_WINDOWS', 0);
31 // set installation type - drupal
36 // unset civicrm session if any
37 if (array_key_exists('CiviCRM', $_SESSION)) {
38 unset($_SESSION['CiviCRM']);
41 if (isset($_GET['civicrm_install_type'])) {
42 $_SESSION['civicrm_install_type'] = $_GET['civicrm_install_type'];
45 if (!isset($_SESSION['civicrm_install_type'])) {
46 $_SESSION['civicrm_install_type'] = "drupal";
51 $installType = strtolower($_SESSION['civicrm_install_type']);
53 if (!in_array($installType, array('drupal', 'wordpress'))) {
54 $errorTitle = "Oops! Unsupported installation mode";
56 errorDisplayPage($errorTitle, $errorMsg);
61 global $installDirPath;
62 global $installURLPath;
64 if ($installType == 'drupal') {
65 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
66 $installDirPath = $installURLPath = '';
68 elseif ($installType == 'wordpress') {
69 $crmPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
;
70 $installDirPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
71 $installURLPath = WP_PLUGIN_URL
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
74 $pkgPath = $crmPath . DIRECTORY_SEPARATOR
. 'packages';
76 require_once $crmPath . '/CRM/Core/ClassLoader.php';
77 CRM_Core_ClassLoader
::singleton()->register();
79 $docLink = CRM_Utils_System
::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
81 if ($installType == 'drupal') {
82 //lets check only /modules/.
83 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR
. 'modules', CIVICRM_DIRECTORY_SEPARATOR
) . '/';
85 if (!preg_match($pattern,
86 str_replace("\\", "/", $_SERVER['SCRIPT_FILENAME'])
89 $errorTitle = "Oops! Please Correct Your Install Location";
90 $errorMsg = "Please untar (uncompress) your downloaded copy of CiviCRM in the <strong>" . implode(CIVICRM_DIRECTORY_SEPARATOR
, array(
94 )) . "</strong> directory below your Drupal root directory. Refer to the online " . $docLink . " for more information.";
95 errorDisplayPage($errorTitle, $errorMsg);
99 // Load civicrm database config
100 if (isset($_REQUEST['mysql'])) {
101 $databaseConfig = $_REQUEST['mysql'];
104 $databaseConfig = array(
105 "server" => "localhost",
106 "username" => "civicrm",
108 "database" => "civicrm",
112 if ($installType == 'drupal') {
113 // Load drupal database config
114 if (isset($_REQUEST['drupal'])) {
115 $drupalConfig = $_REQUEST['drupal'];
118 $drupalConfig = array(
119 "server" => "localhost",
120 "username" => "drupal",
122 "database" => "drupal",
128 if (isset($_REQUEST['loadGenerated'])) {
132 require_once dirname(__FILE__
) . CIVICRM_DIRECTORY_SEPARATOR
. 'langs.php';
133 foreach ($langs as $locale => $_) {
134 if ($locale == 'en_US') {
137 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR
, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
138 unset($langs[$locale]);
142 // Set the locale (required by CRM_Core_Config)
143 // This is mostly sympbolic, since nothing we do during the install
144 // really requires CIVICRM_UF to be defined.
145 $installTypeToUF = array(
146 'wordpress' => 'WordPress',
147 'drupal' => 'Drupal',
150 $uf = (isset($installTypeToUF[$installType]) ?
$installTypeToUF[$installType] : 'Drupal');
151 define('CIVICRM_UF', $uf);
156 $seedLanguage = 'en_US';
158 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
159 $seedLanguage = $_REQUEST['seedLanguage'];
160 $tsLocale = $_REQUEST['seedLanguage'];
163 $config = CRM_Core_Config
::singleton(FALSE);
164 $GLOBALS['civicrm_default_error_scope'] = NULL;
166 // The translation files are in the parent directory (l10n)
167 $config->gettextResourceDir
= '..' . DIRECTORY_SEPARATOR
. $config->gettextResourceDir
;
168 $i18n = CRM_Core_I18n
::singleton();
171 if ($installType == 'drupal') {
172 //CRM-6840 -don't force to install in sites/all/modules/
173 $object = new CRM_Utils_System_Drupal();
174 $cmsPath = $object->cmsRootPath();
176 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
177 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
178 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
179 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
180 'civicrm.settings.php'
183 elseif ($installType == 'wordpress') {
184 $cmsPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm';
185 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
186 'civicrm.settings.php'
190 // Exit with error if CiviCRM has already been installed.
191 if ($alreadyInstalled) {
192 $errorTitle = "Oops! CiviCRM is Already Installed";
193 if ($installType == 'drupal') {
195 $errorMsg = "CiviCRM has already been installed in this Drupal site. <ul><li>To <strong>start over</strong>, you must delete or rename the existing CiviCRM settings file - <strong>civicrm.settings.php</strong> - from <strong>" . implode(CIVICRM_DIRECTORY_SEPARATOR
, array(
196 '[your Drupal root directory]',
199 )) . "</strong>.</li><li>To <strong>upgrade an existing installation</strong>, refer to the online " . $docLink . ".</li></ul>";
201 elseif ($installType == 'wordpress') {
202 $errorMsg = "CiviCRM has already been installed in this WordPress site. <ul><li>To <strong>start over</strong>, you must delete or rename the existing CiviCRM settings file - <strong>civicrm.settings.php</strong> - from <strong>" . $cmsPath . "</strong>.</li><li>To <strong>upgrade an existing installation</strong>, refer to the online " . $docLink . ".</li></ul>";
204 errorDisplayPage($errorTitle, $errorMsg);
207 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'civicrm-version.php';
208 if (file_exists($versionFile)) {
209 require_once $versionFile;
210 $civicrm_version = civicrmVersion();
213 $civicrm_version = 'unknown';
216 if ($installType == 'drupal') {
217 // Ensure that they have downloaded the correct version of CiviCRM
218 if ($civicrm_version['cms'] != 'Drupal' &&
219 $civicrm_version['cms'] != 'Drupal6'
221 $errorTitle = "Oops! Incorrect CiviCRM Version";
222 $errorMsg = "This installer can only be used for the Drupal version of CiviCRM. Refer to the online " . $docLink . " for information about installing CiviCRM on PHP4 servers OR installing CiviCRM for Joomla!";
223 errorDisplayPage($errorTitle, $errorMsg);
226 define('DRUPAL_ROOT', $cmsPath);
227 $drupalVersionFiles = array(
229 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'modules', 'system', 'system.module')),
231 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'includes', 'bootstrap.inc')),
233 foreach ($drupalVersionFiles as $drupalVersionFile) {
234 if (file_exists($drupalVersionFile)) {
235 require_once $drupalVersionFile;
239 if (!defined('VERSION') or version_compare(VERSION
, '6.0') < 0) {
240 $errorTitle = "Oops! Incorrect Drupal Version";
241 $errorMsg = "This version of CiviCRM can only be used with Drupal 6.x or 7.x. Please ensure that '" . implode("' or '", $drupalVersionFiles) . "' exists if you are running Drupal 7.0 and over. Refer to the online " . $docLink . " for information about installing CiviCRM.";
242 errorDisplayPage($errorTitle, $errorMsg);
245 elseif ($installType == 'wordpress') {
247 $civicrm_version['cms'] = 'WordPress';
249 // Ensure that they have downloaded the correct version of CiviCRM
250 if ($civicrm_version['cms'] != 'WordPress') {
251 $errorTitle = "Oops! Incorrect CiviCRM Version";
252 $errorMsg = "This installer can only be used for the WordPress version of CiviCRM. Refer to the online " . $docLink . " for information about installing CiviCRM for Drupal or Joomla!";
253 errorDisplayPage($errorTitle, $errorMsg);
257 // Check requirements
258 $req = new InstallRequirements();
261 if ($req->hasErrors()) {
262 $hasErrorOtherThanDatabase = TRUE;
265 if ($databaseConfig) {
266 $dbReq = new InstallRequirements();
267 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
268 if ($installType == 'drupal') {
269 $dbReq->checkdatabase($drupalConfig, 'Drupal');
274 if (isset($_REQUEST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
275 // Confirm before reinstalling
276 if (!isset($_REQUEST['force_reinstall']) && $alreadyInstalled) {
277 include $installDirPath . 'template.html';
280 $inst = new Installer();
281 $inst->install($_REQUEST);
284 // Show the config form
287 include $installDirPath . 'template.html';
291 * This class checks requirements
292 * Each of the requireXXX functions takes an argument which gives a user description of the test. It's an array
294 * $description[0] - The test catetgory
295 * $description[1] - The test title
296 * $description[2] - The test error to show, if it goes wrong
298 class InstallRequirements
{
299 var $errors, $warnings, $tests;
301 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
302 const MINIMUM_THREAD_STACK
= 192;
305 * Just check that the database configuration is okay.
306 * @param $databaseConfig
309 public function checkdatabase($databaseConfig, $dbName) {
310 if ($this->requireFunction('mysql_connect',
312 ts("PHP Configuration"),
314 ts("MySQL support not included in PHP."),
318 $this->requireMySQLServer($databaseConfig['server'],
320 ts("MySQL %1 Configuration", array(1 => $dbName)),
321 ts("Does the server exist?"),
322 ts("Can't find the a MySQL server on '%1'.", array(1 => $databaseConfig['server'])),
323 $databaseConfig['server'],
326 if ($this->requireMysqlConnection($databaseConfig['server'],
327 $databaseConfig['username'],
328 $databaseConfig['password'],
330 ts("MySQL %1 Configuration", array(1 => $dbName)),
331 ts("Are the access credentials correct?"),
332 ts("That username/password doesn't work"),
336 @$this->requireMySQLVersion("5.1",
338 ts("MySQL %1 Configuration", array(1 => $dbName)),
339 ts("MySQL version at least %1", array(1 => '5.1')),
340 ts("MySQL version %1 or higher is required, you are running MySQL %2.", array(1 => '5.1', 2 => mysql_get_server_info())),
341 ts("MySQL %1", array(1 => mysql_get_server_info())),
344 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
345 $databaseConfig['username'],
346 $databaseConfig['password'],
348 ts("MySQL %1 Configuration", array(1 => $dbName)),
349 ts("Is auto_increment_increment set to 1"),
350 ts("An auto_increment_increment value greater than 1 is not currently supported. Please see issue CRM-7923 for further details and potential workaround."),
353 $this->requireMySQLThreadStack($databaseConfig['server'],
354 $databaseConfig['username'],
355 $databaseConfig['password'],
356 $databaseConfig['database'],
357 self
::MINIMUM_THREAD_STACK
,
359 ts("MySQL %1 Configuration", array(1 => $dbName)),
360 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self
::MINIMUM_THREAD_STACK
)),
362 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
366 $onlyRequire = ($dbName == 'Drupal') ?
TRUE : FALSE;
367 $this->requireDatabaseOrCreatePermissions(
368 $databaseConfig['server'],
369 $databaseConfig['username'],
370 $databaseConfig['password'],
371 $databaseConfig['database'],
373 ts("MySQL %1 Configuration", array(1 => $dbName)),
374 ts("Can I access/create the database?"),
375 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
379 if ($dbName != 'Drupal') {
380 $this->requireMySQLInnoDB($databaseConfig['server'],
381 $databaseConfig['username'],
382 $databaseConfig['password'],
383 $databaseConfig['database'],
385 ts("MySQL %1 Configuration", array(1 => $dbName)),
386 ts("Can I access/create InnoDB tables in the database?"),
387 ts("Unable to create InnoDB tables. MySQL InnoDB support is required for CiviCRM but is either not available or not enabled in this MySQL database server."),
390 $this->requireMySQLTempTables($databaseConfig['server'],
391 $databaseConfig['username'],
392 $databaseConfig['password'],
393 $databaseConfig['database'],
395 ts("MySQL %1 Configuration", array(1 => $dbName)),
396 ts('Can I create temporary tables in the database?'),
397 ts('Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.'),
400 $this->requireMySQLLockTables($databaseConfig['server'],
401 $databaseConfig['username'],
402 $databaseConfig['password'],
403 $databaseConfig['database'],
405 ts("MySQL %1 Configuration", array(1 => $dbName)),
406 ts('Can I create lock tables in the database?'),
407 ts('Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.'),
410 $this->requireMySQLTrigger($databaseConfig['server'],
411 $databaseConfig['username'],
412 $databaseConfig['password'],
413 $databaseConfig['database'],
415 ts("MySQL %1 Configuration", array(1 => $dbName)),
416 ts('Can I create triggers in the database?'),
417 ts('Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.'),
425 * Check everything except the database.
427 public function check() {
428 global $crmPath, $installType;
430 $this->errors
= NULL;
432 $this->requirePHPVersion('5.3.3', array(
433 ts("PHP Configuration"),
434 ts("PHP5 installed"),
436 ts("PHP version %1", array(1 => phpversion())),
439 // Check that we can identify the root folder successfully
440 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'README.txt',
442 ts("File permissions"),
443 ts("Does the webserver know where files are stored?"),
444 ts("The webserver isn't letting me identify where files are stored."),
450 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
451 $this->requireNoPathSeparator(
453 ts("File permissions"),
454 ts('Does the CiviCRM path contain PATH_SEPARATOR?'),
455 ts('The path %1 contains PATH_SEPARATOR (the %2 character).', array(1 => $this->getBaseDir(), 2 => PATH_SEPARATOR
)),
460 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
461 foreach ($requiredDirectories as $dir) {
462 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. $dir,
464 ts("File permissions"),
465 ts("Folder '%1' exists?", array(1 => $dir)),
466 ts("There is no '%1' folder.", array(1 => $dir)),
471 $configIDSiniDir = NULL;
473 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
474 if ($installType == 'drupal') {
476 // make sure that we can write to sites/default and files/
477 $writableDirectories = array(
478 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
479 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
480 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
482 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
483 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
487 elseif ($installType == 'wordpress') {
488 // make sure that we can write to plugins/civicrm and plugins/files/
489 $writableDirectories = array(WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'files', $cmsPath);
492 foreach ($writableDirectories as $dir) {
493 $dirName = CIVICRM_WINDOWS ?
$dir : CIVICRM_DIRECTORY_SEPARATOR
. $dir;
494 $testDetails = array(
495 ts("File permissions"),
496 ts("Is the %1 folder writeable?", array(1 => $dir)),
499 $this->requireWriteable($dirName, $testDetails, TRUE);
502 //check for Config.IDS.ini, file may exist in re-install
503 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
505 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
506 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR
, $configIDSiniDir);
507 if (file_exists($configIDSiniFile)) {
508 unlink($configIDSiniFile);
512 // Check for rewriting
513 if (isset($_SERVER['SERVER_SOFTWARE'])) {
514 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
516 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
517 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
520 if ($webserver == '') {
521 $webserver = ts("I can't tell what webserver you are running");
524 // Check for $_SERVER configuration
525 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
526 ts("Webserver config"),
527 ts("Recognised webserver"),
528 ts("You seem to be using an unsupported webserver. The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."),
531 // Check for MySQL support
532 $this->requireFunction('mysql_connect', array(
533 ts("PHP Configuration"),
535 ts("MySQL support not included in PHP."),
538 // Check for JSON support
539 $this->requireFunction('json_encode', array(
540 ts("PHP Configuration"),
542 ts("JSON support not included in PHP."),
545 // Check for xcache_isset and emit warning if exists
546 $this->checkXCache(array(
547 ts("PHP Configuration"),
548 ts("XCache compatibility"),
549 ts("XCache is installed and there are known compatibility issues between XCache and CiviCRM. Consider using an alternative PHP caching mechanism or disable PHP caching altogether."),
552 // Check memory allocation
553 $this->requireMemory(32 * 1024 * 1024,
556 ts("PHP Configuration"),
557 ts("Memory allocated (PHP config option 'memory_limit')"),
558 ts("CiviCRM needs a minimum of %1 MB allocated to PHP, but recommends %2 MB.", array(1 => 32, 2 => 64)),
559 ini_get("memory_limit"),
563 return $this->errors
;
568 * @param $recommended
569 * @param $testDetails
571 public function requireMemory($min, $recommended, $testDetails) {
572 $this->testing($testDetails);
573 $mem = $this->getPHPMemory();
575 if ($mem < $min && $mem > 0) {
576 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
577 $this->error($testDetails);
579 elseif ($mem < $recommended && $mem > 0) {
580 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
581 $this->warning($testDetails);
584 $testDetails[2] .= " " . ts("We can't determine how much memory you have allocated. Install only if you're sure you've allocated at least %1 MB.", array(1 => 32));
585 $this->warning($testDetails);
592 public function getPHPMemory() {
593 $memString = ini_get("memory_limit");
595 switch (strtolower(substr($memString, -1))) {
597 return round(substr($memString, 0, -1) * 1024);
600 return round(substr($memString, 0, -1) * 1024 * 1024);
603 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
606 return round($memString);
610 public function listErrors() {
612 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
613 foreach ($this->errors
as $error) {
614 echo "<li>" . htmlentities($error) . "</li>";
620 * @param null $section
622 public function showTable($section = NULL) {
624 $tests = $this->tests
[$section];
625 echo "<table class=\"testResults\" width=\"100%\">";
626 foreach ($tests as $test => $result) {
627 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
632 foreach ($this->tests
as $section => $tests) {
633 echo "<h3>$section</h3>";
634 echo "<table class=\"testResults\" width=\"100%\">";
636 foreach ($tests as $test => $result) {
637 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
645 * @param string $funcName
646 * @param $testDetails
650 public function requireFunction($funcName, $testDetails) {
651 $this->testing($testDetails);
653 if (!function_exists($funcName)) {
654 $this->error($testDetails);
663 * @param $testDetails
665 public function checkXCache($testDetails) {
666 if (function_exists('xcache_isset') &&
667 ini_get('xcache.size') > 0
669 $this->testing($testDetails);
670 $this->warning($testDetails);
676 * @param $testDetails
677 * @param null $maxVersion
679 public function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
681 $this->testing($testDetails);
683 $phpVersion = phpversion();
684 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
685 $belowMaxVersion = $maxVersion ?
version_compare($phpVersion, $maxVersion) < 0 : TRUE;
687 if ($maxVersion && $aboveMinVersion && $belowMaxVersion) {
690 elseif (!$maxVersion && $aboveMinVersion) {
694 if (!$testDetails[2]) {
695 if (!$aboveMinVersion) {
696 $testDetails[2] = ts("You need PHP version %1 or later, only %2 is installed. Please upgrade your server, or ask your web-host to do so.", array(1 => $minVersion, 2 => $phpVersion));
699 $testDetails[2] = ts("PHP version %1 is not supported. PHP version earlier than %2 is required. You might want to downgrade your server, or ask your web-host to do so.", array(1 => $maxVersion, 2 => $phpVersion));
703 $this->error($testDetails);
707 * @param string $filename
708 * @param $testDetails
709 * @param bool $absolute
711 public function requireFile($filename, $testDetails, $absolute = FALSE) {
712 $this->testing($testDetails);
714 $filename = $this->getBaseDir() . $filename;
716 if (!file_exists($filename)) {
717 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
718 $this->error($testDetails);
723 * @param $testDetails
725 public function requireNoPathSeparator($testDetails) {
726 $this->testing($testDetails);
727 if (substr_count($this->getBaseDir(), PATH_SEPARATOR
)) {
728 $this->error($testDetails);
733 * @param string $filename
734 * @param $testDetails
736 public function requireNoFile($filename, $testDetails) {
737 $this->testing($testDetails);
738 $filename = $this->getBaseDir() . $filename;
739 if (file_exists($filename)) {
740 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
741 $this->error($testDetails);
746 * @param string $filename
747 * @param $testDetails
749 public function moveFileOutOfTheWay($filename, $testDetails) {
750 $this->testing($testDetails);
751 $filename = $this->getBaseDir() . $filename;
752 if (file_exists($filename)) {
753 if (file_exists("$filename.bak")) {
756 rename($filename, "$filename.bak");
761 * @param string $filename
762 * @param $testDetails
763 * @param bool $absolute
765 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
766 $this->testing($testDetails);
768 $filename = $this->getBaseDir() . $filename;
771 if (!is_writable($filename)) {
773 if (function_exists('posix_getpwuid')) {
774 $user = posix_getpwuid(posix_geteuid());
775 $name = '- ' . $user['name'] . ' -';
778 if (!isset($testDetails[2])) {
779 $testDetails[2] = NULL;
781 $testDetails[2] .= ts("The user account used by your web-server %1 needs to be granted write access to the following directory in order to configure the CiviCRM settings file:", array(1 => $name)) . "\n$filename";
782 $this->error($testDetails);
787 * @param string $moduleName
788 * @param $testDetails
790 public function requireApacheModule($moduleName, $testDetails) {
791 $this->testing($testDetails);
792 if (!in_array($moduleName, apache_get_modules())) {
793 $this->error($testDetails);
799 * @param string $username
801 * @param $testDetails
803 public function requireMysqlConnection($server, $username, $password, $testDetails) {
804 $this->testing($testDetails);
805 $conn = @mysql_connect
($server, $username, $password);
811 $testDetails[2] .= ": " . mysql_error();
812 $this->error($testDetails);
818 * @param $testDetails
820 public function requireMySQLServer($server, $testDetails) {
821 $this->testing($testDetails);
822 $conn = @mysql_connect
($server, NULL, NULL);
824 if ($conn ||
mysql_errno() < 2000) {
828 $testDetails[2] .= ": " . mysql_error();
829 $this->error($testDetails);
835 * @param $testDetails
837 public function requireMySQLVersion($version, $testDetails) {
838 $this->testing($testDetails);
840 if (!mysql_get_server_info()) {
841 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
842 $this->warning($testDetails);
845 list($majorRequested, $minorRequested) = explode('.', $version);
846 list($majorHas, $minorHas) = explode('.', mysql_get_server_info());
848 if (($majorHas > $majorRequested) ||
($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
852 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
853 $this->error($testDetails);
860 * @param string $username
863 * @param $testDetails
865 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
866 $this->testing($testDetails);
867 $conn = @mysql_connect
($server, $username, $password);
869 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
870 $this->error($testDetails);
874 $innodb_support = FALSE;
875 $result = mysql_query("SHOW ENGINES", $conn);
876 while ($values = mysql_fetch_array($result)) {
877 if ($values['Engine'] == 'InnoDB') {
878 if (strtolower($values['Support']) == 'yes' ||
879 strtolower($values['Support']) == 'default'
881 $innodb_support = TRUE;
885 if ($innodb_support) {
886 $testDetails[3] = ts('MySQL server does have InnoDB support');
889 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
895 * @param string $username
898 * @param $testDetails
900 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
901 $this->testing($testDetails);
902 $conn = @mysql_connect
($server, $username, $password);
904 $testDetails[2] = ts('Could not login to the database.');
905 $this->error($testDetails);
909 if (!@mysql_select_db
($database, $conn)) {
910 $testDetails[2] = ts('Could not select the database.');
911 $this->error($testDetails);
915 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
917 $testDetails[2] = ts('Could not create a temp table.');
918 $this->error($testDetails);
920 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
925 * @param string $username
928 * @param $testDetails
930 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
931 $this->testing($testDetails);
932 $conn = @mysql_connect
($server, $username, $password);
934 $testDetails[2] = ts('Could not login to the database.');
935 $this->error($testDetails);
939 if (!@mysql_select_db
($database, $conn)) {
940 $testDetails[2] = ts('Could not select the database.');
941 $this->error($testDetails);
945 $result = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
947 $testDetails[2] = ts('Could not create a table in the database.');
948 $this->error($testDetails);
951 $result = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
953 mysql_query('DROP TABLE civicrm_install_temp_table_test');
954 $testDetails[2] = ts('Could not create a database trigger.');
955 $this->error($testDetails);
958 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
959 mysql_query('DROP TABLE civicrm_install_temp_table_test');
965 * @param string $username
968 * @param $testDetails
970 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
971 $this->testing($testDetails);
972 $conn = @mysql_connect
($server, $username, $password);
974 $testDetails[2] = ts('Could not connect to the database server.');
975 $this->error($testDetails);
979 if (!@mysql_select_db
($database, $conn)) {
980 $testDetails[2] = ts('Could not select the database.');
981 $this->error($testDetails);
985 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
987 $testDetails[2] = ts('Could not create a table in the database.');
988 $this->error($testDetails);
992 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
994 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
995 $this->error($testDetails);
996 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1000 $result = mysql_query('UNLOCK TABLES', $conn);
1002 $testDetails[2] = ts('Could not release the lock for the database table.');
1003 $this->error($testDetails);
1004 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1008 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1013 * @param string $username
1015 * @param $testDetails
1017 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
1018 $this->testing($testDetails);
1019 $conn = @mysql_connect
($server, $username, $password);
1021 $testDetails[2] = ts('Could not connect to the database server.');
1022 $this->error($testDetails);
1026 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
1028 $testDetails[2] = ts('Could not query database server variables.');
1029 $this->error($testDetails);
1033 $values = mysql_fetch_row($result);
1034 if ($values[1] == 1) {
1035 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
1038 $this->error($testDetails);
1045 * @param string $username
1048 * @param $minValueKB
1049 * @param $testDetails
1051 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
1052 $this->testing($testDetails);
1053 $conn = @mysql_connect
($server, $username, $password);
1055 $testDetails[2] = ts('Could not connect to the database server.');
1056 $this->error($testDetails);
1060 if (!@mysql_select_db
($database, $conn)) {
1061 $testDetails[2] = ts('Could not select the database.');
1062 $this->error($testDetails);
1066 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
1068 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
1069 $this->error($testDetails);
1072 $values = mysql_fetch_row($result);
1073 if ($values[1] < (1024 * $minValueKB)) {
1074 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
1075 $this->error($testDetails);
1082 * @param string $username
1085 * @param $testDetails
1086 * @param bool $onlyRequire
1088 public function requireDatabaseOrCreatePermissions(
1094 $onlyRequire = FALSE
1096 $this->testing($testDetails);
1097 $conn = @mysql_connect
($server, $username, $password);
1100 if (@mysql_select_db
($database)) {
1101 $okay = "Database '$database' exists";
1103 elseif ($onlyRequire) {
1104 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
1105 $this->error($testDetails);
1109 if (@mysql_query
("CREATE DATABASE $database")) {
1110 $okay = ts("Able to create a new database.");
1113 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
1114 $this->error($testDetails);
1120 $testDetails[3] = $okay;
1121 $this->testing($testDetails);
1127 * @param $errorMessage
1129 public function requireServerVariables($varNames, $errorMessage) {
1130 //$this->testing($testDetails);
1131 foreach ($varNames as $varName) {
1132 if (!$_SERVER[$varName]) {
1133 $missing[] = '$_SERVER[' . $varName . ']';
1136 if (!isset($missing)) {
1140 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
1141 $this->error($testDetails);
1146 * @param $testDetails
1150 public function isRunningApache($testDetails) {
1151 $this->testing($testDetails);
1152 if (function_exists('apache_get_modules') ||
stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1156 $this->warning($testDetails);
1163 public function getBaseDir() {
1164 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR
;
1168 * @param $testDetails
1170 public function testing($testDetails) {
1171 if (!$testDetails) {
1175 $section = $testDetails[0];
1176 $test = $testDetails[1];
1178 $message = ts("OK");
1179 if (isset($testDetails[3])) {
1180 $message .= " ($testDetails[3])";
1183 $this->tests
[$section][$test] = array("good", $message);
1187 * @param $testDetails
1189 public function error($testDetails) {
1190 $section = $testDetails[0];
1191 $test = $testDetails[1];
1193 $this->tests
[$section][$test] = array("error", $testDetails[2]);
1194 $this->errors
[] = $testDetails;
1198 * @param $testDetails
1200 public function warning($testDetails) {
1201 $section = $testDetails[0];
1202 $test = $testDetails[1];
1204 $this->tests
[$section][$test] = array("warning", $testDetails[2]);
1205 $this->warnings
[] = $testDetails;
1211 public function hasErrors() {
1212 return count($this->errors
);
1218 public function hasWarnings() {
1219 return count($this->warnings
);
1227 class Installer
extends InstallRequirements
{
1234 public function createDatabaseIfNotExists($server, $username, $password, $database) {
1235 $conn = @mysql_connect
($server, $username, $password);
1237 if (@mysql_select_db
($database)) {
1238 // skip if database already present
1242 if (@mysql_query
("CREATE DATABASE $database")) {
1245 $errorTitle = "Oops! Could not create Database $database";
1246 $errorMsg = "We encountered an error when attempting to create the database. Please check your mysql server permissions and the database name and try again.";
1247 errorDisplayPage($errorTitle, $errorMsg);
1256 public function install($config) {
1257 global $installDirPath;
1259 // create database if does not exists
1260 $this->createDatabaseIfNotExists($config['mysql']['server'],
1261 $config['mysql']['username'],
1262 $config['mysql']['password'],
1263 $config['mysql']['database']
1266 global $installDirPath;
1269 require_once $installDirPath . 'civicrm.php';
1270 civicrm_main($config);
1272 if (!$this->errors
) {
1273 global $installType, $installURLPath;
1275 $registerSiteURL = "https://civicrm.org/register-site";
1276 $commonOutputMessage = "
1277 <li>Have you registered this site at CiviCRM.org? If not, please help strengthen the CiviCRM ecosystem by taking a few minutes to <a href='$registerSiteURL' target='_blank'>fill out the site registration form</a>. The information collected will help us prioritize improvements, target our communications and build the community. If you have a technical role for this site, be sure to check Keep in Touch to receive technical updates (a low volume mailing list).</li>
1278 <li>We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.</li>
1284 $installType == 'drupal' &&
1285 version_compare(VERSION
, '7.0-rc1') >= 0
1291 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1292 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1293 $output .= '<head>';
1294 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1295 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1296 $output .= '</head>';
1297 $output .= '<body>';
1298 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1300 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1301 if (!function_exists('ts')) {
1302 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1304 $drupalURL = civicrm_cms_base();
1305 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1306 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1308 $output .= "<li>Drupal user permissions have been automatically set - giving anonymous and authenticated users access to public CiviCRM forms and features. We recommend that you <a target='_blank' href={$drupalPermissionsURL}>review these permissions</a> to ensure that they are appropriate for your requirements (<a target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'>learn more...</a>)</li>
1309 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1310 {$commonOutputMessage}";
1312 // automatically enable CiviCRM module once it is installed successfully.
1313 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1314 global $cmsPath, $crmPath;
1316 // relative / abosolute paths are not working for drupal, hence using chdir()
1319 // Force the re-initialisation of the config singleton on the next call
1320 // since so far, we had used the Config object without loading the DB.
1321 $c = CRM_Core_Config
::singleton(FALSE);
1324 include_once "./includes/bootstrap.inc";
1325 include_once "./includes/unicode.inc";
1327 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1329 // prevent session information from being saved.
1330 drupal_save_session(FALSE);
1332 // Force the current user to anonymous.
1333 $original_user = $GLOBALS['user'];
1334 $GLOBALS['user'] = drupal_anonymous_user();
1336 // explicitly setting error reporting, since we cannot handle drupal related notices
1339 // rebuild modules, so that civicrm is added
1340 system_rebuild_module_data();
1342 // now enable civicrm module.
1343 module_enable(array('civicrm', 'civicrmtheme'));
1345 // clear block, page, theme, and hook caches
1346 drupal_flush_all_caches();
1348 //add basic drupal permissions
1349 civicrm_install_set_drupal_perms();
1351 // restore the user.
1352 $GLOBALS['user'] = $original_user;
1353 drupal_save_session(TRUE);
1355 //change the default language to one chosen
1356 if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
1357 // This ensures that defaults get set, otherwise the user will login
1358 // and most configurations will be empty, not set to en_US defaults.
1359 civicrm_api3('Setting', 'revert');
1361 civicrm_api3('Setting', 'create', array(
1362 'domain_id' => 'current_domain',
1363 'lcMessages' => $config['seedLanguage'],
1369 $output .= '</div>';
1370 $output .= '</body>';
1371 $output .= '</html>';
1374 elseif ($installType == 'drupal' && version_compare(VERSION
, '6.0') >= 0) {
1378 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1379 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1380 $output .= '<head>';
1381 $output .= '<title>CiviCRM Installed</title>';
1382 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1383 $output .= '</head>';
1384 $output .= '<body>';
1385 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
1387 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1388 if (!function_exists('ts')) {
1389 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1391 $drupalURL = civicrm_cms_base();
1392 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1393 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1395 $output .= "<li>Drupal user permissions have been automatically set - giving anonymous and authenticated users access to public CiviCRM forms and features. We recommend that you <a target='_blank' href={$drupalPermissionsURL}>review these permissions</a> to ensure that they are appropriate for your requirements (<a target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'>learn more...</a>)</li>
1396 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1397 {$commonOutputMessage}";
1399 // explicitly setting error reporting, since we cannot handle drupal related notices
1402 // automatically enable CiviCRM module once it is installed successfully.
1403 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1404 global $cmsPath, $crmPath;
1406 // relative / abosolute paths are not working for drupal, hence using chdir()
1409 // Force the re-initialisation of the config singleton on the next call
1410 // since so far, we had used the Config object without loading the DB.
1411 $c = CRM_Core_Config
::singleton(FALSE);
1414 include_once "./includes/bootstrap.inc";
1415 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1417 // rebuild modules, so that civicrm is added
1418 module_rebuild_cache();
1420 // now enable civicrm module.
1421 module_enable(array('civicrm'));
1423 // clear block, page, theme, and hook caches
1424 drupal_flush_all_caches();
1426 //add basic drupal permissions
1427 db_query('UPDATE {permission} SET perm = CONCAT( perm, \', access CiviMail subscribe/unsubscribe pages, access all custom data, access uploaded files, make online contributions, profile create, profile edit, profile view, register for events, view event info\') WHERE rid IN (1, 2)');
1431 elseif ($installType == 'wordpress') {
1432 echo '<h1>CiviCRM Installed</h1>';
1433 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
1435 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1436 if (!function_exists('ts')) {
1437 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1440 $c = CRM_Core_Config
::singleton(FALSE);
1443 $cmsURL = civicrm_cms_base();
1444 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1445 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1448 <li>WordPress user permissions have been automatically set - giving Anonymous and Subscribers access to public CiviCRM forms and features. We recommend that you <a target='_blank' href={$wpPermissionsURL}>review these permissions</a> to ensure that they are appropriate for your requirements (<a target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'>learn more...</a>)</li>
1449 <li>Use the <a target='_blank' href=\"$cmsURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1450 {$commonOutputMessage}
1458 return $this->errors
;
1463 function civicrm_install_set_drupal_perms() {
1464 if (!function_exists('db_select')) {
1465 db_query('UPDATE {permission} SET perm = CONCAT( perm, \', access CiviMail subscribe/unsubscribe pages, access all custom data, access uploaded files, make online contributions, profile listings and forms, register for events, view event info, view event participants\') WHERE rid IN (1, 2)');
1469 'access all custom data',
1470 'access uploaded files',
1471 'make online contributions',
1475 'register for events',
1477 'view event participants',
1478 'access CiviMail subscribe/unsubscribe pages',
1481 // Adding a permission that has not yet been assigned to a module by
1482 // a hook_permission implementation results in a database error.
1484 $allPerms = array_keys(module_invoke_all('permission'));
1485 foreach (array_diff($perms, $allPerms) as $perm) {
1487 'Cannot grant the %perm permission because it does not yet exist.',
1488 array('%perm' => $perm),
1492 $perms = array_intersect($perms, $allPerms);
1493 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID
, $perms);
1494 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID
, $perms);
1504 function getSiteDir($cmsPath, $str) {
1505 static $siteDir = '';
1511 $sites = CIVICRM_DIRECTORY_SEPARATOR
. 'sites' . CIVICRM_DIRECTORY_SEPARATOR
;
1512 $modules = CIVICRM_DIRECTORY_SEPARATOR
. 'modules' . CIVICRM_DIRECTORY_SEPARATOR
;
1513 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR
) .
1514 "([\-a-zA-Z0-9_.]+)" .
1515 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR
) . "/",
1516 $_SERVER['SCRIPT_FILENAME'], $matches
1518 $siteDir = isset($matches[1]) ?
$matches[1] : 'default';
1520 if (strtolower($siteDir) == 'all') {
1521 // For this case - use drupal's way of finding out multi-site directory
1522 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR
, $_SERVER['SCRIPT_FILENAME']);
1523 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1524 for ($i = count($uri) - 1; $i > 0; $i--) {
1525 for ($j = count($server); $j > 0; $j--) {
1526 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1527 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
1528 'sites' . CIVICRM_DIRECTORY_SEPARATOR
. $dir
1535 $siteDir = 'default';
1542 * @param $errorTitle
1545 function errorDisplayPage($errorTitle, $errorMsg) {
1546 include 'error.html';