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-2015 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";
53 global $installDirPath;
54 global $installURLPath;
56 $installType = strtolower($_SESSION['civicrm_install_type']);
58 if ($installType == 'drupal') {
59 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
60 $installDirPath = $installURLPath = '';
62 elseif ($installType == 'wordpress') {
63 $crmPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
;
64 $installDirPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
65 $installURLPath = WP_PLUGIN_URL
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
68 $errorTitle = "Oops! Unsupported installation mode";
69 $errorMsg = sprintf('%s: unknown installation mode. Please refer to the online documentation for more information.', $installType);
70 errorDisplayPage($errorTitle, $errorMsg, FALSE);
73 $pkgPath = $crmPath . DIRECTORY_SEPARATOR
. 'packages';
75 require_once $crmPath . '/CRM/Core/ClassLoader.php';
76 CRM_Core_ClassLoader
::singleton()->register();
78 // Load civicrm database config
79 if (isset($_POST['mysql'])) {
80 $databaseConfig = $_POST['mysql'];
83 $databaseConfig = array(
84 "server" => "localhost",
85 "username" => "civicrm",
87 "database" => "civicrm",
91 if ($installType == 'drupal') {
92 // Load drupal database config
93 if (isset($_POST['drupal'])) {
94 $drupalConfig = $_POST['drupal'];
97 $drupalConfig = array(
98 "server" => "localhost",
99 "username" => "drupal",
101 "database" => "drupal",
107 if (isset($_POST['loadGenerated'])) {
111 require_once dirname(__FILE__
) . CIVICRM_DIRECTORY_SEPARATOR
. 'langs.php';
112 foreach ($langs as $locale => $_) {
113 if ($locale == 'en_US') {
116 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR
, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
117 unset($langs[$locale]);
121 // Set the locale (required by CRM_Core_Config)
122 // This is mostly sympbolic, since nothing we do during the install
123 // really requires CIVICRM_UF to be defined.
124 $installTypeToUF = array(
125 'wordpress' => 'WordPress',
126 'drupal' => 'Drupal',
129 $uf = (isset($installTypeToUF[$installType]) ?
$installTypeToUF[$installType] : 'Drupal');
130 define('CIVICRM_UF', $uf);
135 $seedLanguage = 'en_US';
137 // CRM-16801 This validates that seedLanguage is valid by looking in $langs.
138 // NB: the variable is initial a $_REQUEST for the initial page reload,
139 // then becomes a $_POST when the installation form is submitted.
140 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
141 $seedLanguage = $_REQUEST['seedLanguage'];
142 $tsLocale = $_REQUEST['seedLanguage'];
145 $config = CRM_Core_Config
::singleton(FALSE);
146 $GLOBALS['civicrm_default_error_scope'] = NULL;
148 // The translation files are in the parent directory (l10n)
149 $config->gettextResourceDir
= '..' . DIRECTORY_SEPARATOR
. $config->gettextResourceDir
;
150 $i18n = CRM_Core_I18n
::singleton();
153 if ($installType == 'drupal') {
154 //CRM-6840 -don't force to install in sites/all/modules/
155 $object = new CRM_Utils_System_Drupal();
156 $cmsPath = $object->cmsRootPath();
158 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
159 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
160 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
161 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
162 'civicrm.settings.php'
165 elseif ($installType == 'wordpress') {
166 $cmsPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm';
167 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
168 'civicrm.settings.php'
172 if ($installType == 'drupal') {
173 // Lets check only /modules/.
174 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR
. 'modules', CIVICRM_DIRECTORY_SEPARATOR
) . '/';
176 if (!preg_match($pattern, str_replace("\\", "/", $_SERVER['SCRIPT_FILENAME']))) {
177 $directory = implode(CIVICRM_DIRECTORY_SEPARATOR
, array('sites', 'all', 'modules'));
178 $errorTitle = ts("Oops! Please correct your install location");
179 $errorMsg = ts("Please untar (uncompress) your downloaded copy of CiviCRM in the <strong>%1</strong> directory below your Drupal root directory.", array(1 => $directory));
180 errorDisplayPage($errorTitle, $errorMsg);
184 // Exit with error if CiviCRM has already been installed.
185 if ($alreadyInstalled) {
186 $errorTitle = ts("Oops! CiviCRM is already installed");
187 $settings_directory = $cmsPath;
189 if ($installType == 'drupal') {
190 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR
, array(
191 ts('[your Drupal root directory]'),
197 $docLink = CRM_Utils_System
::docURL2('Installation and Upgrades', FALSE, ts('Installation Guide'), NULL, NULL, "wiki");
198 $errorMsg = ts("CiviCRM has already been installed. <ul><li>To <strong>start over</strong>, you must delete or rename the existing CiviCRM settings file - <strong>civicrm.settings.php</strong> - from <strong>%1</strong>.</li><li>To <strong>upgrade an existing installation</strong>, <a href='%2'>refer to the online documentation</a>.</li></ul>", array(1 => $settings_directory, 2 => $docLink));
199 errorDisplayPage($errorTitle, $errorMsg, FALSE);
202 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'civicrm-version.php';
203 if (file_exists($versionFile)) {
204 require_once $versionFile;
205 $civicrm_version = civicrmVersion();
208 $civicrm_version = 'unknown';
211 if ($installType == 'drupal') {
212 // Ensure that they have downloaded the correct version of CiviCRM
213 if ($civicrm_version['cms'] != 'Drupal' && $civicrm_version['cms'] != 'Drupal6') {
214 $errorTitle = ts("Oops! Incorrect CiviCRM version");
215 $errorMsg = ts("This installer can only be used for the Drupal version of CiviCRM.");
216 errorDisplayPage($errorTitle, $errorMsg);
219 define('DRUPAL_ROOT', $cmsPath);
220 $drupalVersionFiles = array(
222 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'modules', 'system', 'system.module')),
224 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'includes', 'bootstrap.inc')),
226 foreach ($drupalVersionFiles as $drupalVersionFile) {
227 if (file_exists($drupalVersionFile)) {
228 require_once $drupalVersionFile;
232 if (!defined('VERSION') or version_compare(VERSION
, '6.0') < 0) {
233 $errorTitle = ts("Oops! Incorrect Drupal version");
234 $errorMsg = ts("This version of CiviCRM can only be used with Drupal 6.x or 7.x. Please ensure that '%1' exists if you are running Drupal 7.0 and over.", array(1 => implode("' or '", $drupalVersionFiles)));
235 errorDisplayPage($errorTitle, $errorMsg);
238 elseif ($installType == 'wordpress') {
240 $civicrm_version['cms'] = 'WordPress';
242 // Ensure that they have downloaded the correct version of CiviCRM
243 if ($civicrm_version['cms'] != 'WordPress') {
244 $errorTitle = ts("Oops! Incorrect CiviCRM version");
245 $errorMsg = ts("This installer can only be used for the WordPress version of CiviCRM.");
246 errorDisplayPage($errorTitle, $errorMsg);
250 // Check requirements
251 $req = new InstallRequirements();
254 if ($req->hasErrors()) {
255 $hasErrorOtherThanDatabase = TRUE;
258 if ($databaseConfig) {
259 $dbReq = new InstallRequirements();
260 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
261 if ($installType == 'drupal') {
262 $dbReq->checkdatabase($drupalConfig, 'Drupal');
267 if (isset($_POST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
268 // Confirm before reinstalling
269 if (!isset($_POST['force_reinstall']) && $alreadyInstalled) {
270 include $installDirPath . 'template.html';
273 $inst = new Installer();
274 $inst->install($_POST);
277 // Show the config form
280 include $installDirPath . 'template.html';
284 * This class checks requirements
285 * Each of the requireXXX functions takes an argument which gives a user description of the test. It's an array
287 * $description[0] - The test category
288 * $description[1] - The test title
289 * $description[2] - The test error to show, if it goes wrong
291 class InstallRequirements
{
292 var $errors, $warnings, $tests;
294 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
295 const MINIMUM_THREAD_STACK
= 192;
298 * Just check that the database configuration is okay.
299 * @param $databaseConfig
302 public function checkdatabase($databaseConfig, $dbName) {
303 if ($this->requireFunction('mysql_connect',
305 ts("PHP Configuration"),
307 ts("MySQL support not included in PHP."),
311 $this->requireMySQLServer($databaseConfig['server'],
313 ts("MySQL %1 Configuration", array(1 => $dbName)),
314 ts("Does the server exist?"),
315 ts("Can't find the a MySQL server on '%1'.", array(1 => $databaseConfig['server'])),
316 $databaseConfig['server'],
319 if ($this->requireMysqlConnection($databaseConfig['server'],
320 $databaseConfig['username'],
321 $databaseConfig['password'],
323 ts("MySQL %1 Configuration", array(1 => $dbName)),
324 ts("Are the access credentials correct?"),
325 ts("That username/password doesn't work"),
329 @$this->requireMySQLVersion("5.1",
331 ts("MySQL %1 Configuration", array(1 => $dbName)),
332 ts("MySQL version at least %1", array(1 => '5.1')),
333 ts("MySQL version %1 or higher is required, you are running MySQL %2.", array(1 => '5.1', 2 => mysql_get_server_info())),
334 ts("MySQL %1", array(1 => mysql_get_server_info())),
337 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
338 $databaseConfig['username'],
339 $databaseConfig['password'],
341 ts("MySQL %1 Configuration", array(1 => $dbName)),
342 ts("Is auto_increment_increment set to 1"),
343 ts("An auto_increment_increment value greater than 1 is not currently supported. Please see issue CRM-7923 for further details and potential workaround."),
346 $testDetails = array(
347 ts("MySQL %1 Configuration", array(1 => $dbName)),
348 ts("Is the provided database name valid?"),
349 ts("The database name provided is not valid. Please use only 0-9, a-z, A-Z and _ as characters in the name."),
351 if (!CRM_Core_DAO
::requireValidDBName($databaseConfig['database'])) {
352 $this->error($testDetails);
356 $this->testing($testDetails);
358 $this->requireMySQLThreadStack($databaseConfig['server'],
359 $databaseConfig['username'],
360 $databaseConfig['password'],
361 $databaseConfig['database'],
362 self
::MINIMUM_THREAD_STACK
,
364 ts("MySQL %1 Configuration", array(1 => $dbName)),
365 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self
::MINIMUM_THREAD_STACK
)),
367 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
371 $onlyRequire = ($dbName == 'Drupal') ?
TRUE : FALSE;
372 $this->requireDatabaseOrCreatePermissions(
373 $databaseConfig['server'],
374 $databaseConfig['username'],
375 $databaseConfig['password'],
376 $databaseConfig['database'],
378 ts("MySQL %1 Configuration", array(1 => $dbName)),
379 ts("Can I access/create the database?"),
380 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
384 if ($dbName != 'Drupal') {
385 $this->requireMySQLInnoDB($databaseConfig['server'],
386 $databaseConfig['username'],
387 $databaseConfig['password'],
388 $databaseConfig['database'],
390 ts("MySQL %1 Configuration", array(1 => $dbName)),
391 ts("Can I access/create InnoDB tables in the database?"),
392 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."),
395 $this->requireMySQLTempTables($databaseConfig['server'],
396 $databaseConfig['username'],
397 $databaseConfig['password'],
398 $databaseConfig['database'],
400 ts("MySQL %1 Configuration", array(1 => $dbName)),
401 ts('Can I create temporary tables in the database?'),
402 ts('Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.'),
405 $this->requireMySQLLockTables($databaseConfig['server'],
406 $databaseConfig['username'],
407 $databaseConfig['password'],
408 $databaseConfig['database'],
410 ts("MySQL %1 Configuration", array(1 => $dbName)),
411 ts('Can I create lock tables in the database?'),
412 ts('Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.'),
415 $this->requireMySQLTrigger($databaseConfig['server'],
416 $databaseConfig['username'],
417 $databaseConfig['password'],
418 $databaseConfig['database'],
420 ts("MySQL %1 Configuration", array(1 => $dbName)),
421 ts('Can I create triggers in the database?'),
422 ts('Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.'),
430 * Check everything except the database.
432 public function check() {
433 global $crmPath, $installType;
435 $this->errors
= NULL;
437 $this->requirePHPVersion('5.3.3', array(
438 ts("PHP Configuration"),
439 ts("PHP5 installed"),
441 ts("PHP version %1", array(1 => phpversion())),
444 // Check that we can identify the root folder successfully
445 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'README.txt',
447 ts("File permissions"),
448 ts("Does the webserver know where files are stored?"),
449 ts("The webserver isn't letting me identify where files are stored."),
455 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
456 $this->requireNoPathSeparator(
458 ts("File permissions"),
459 ts('Does the CiviCRM path contain PATH_SEPARATOR?'),
460 ts('The path %1 contains PATH_SEPARATOR (the %2 character).', array(1 => $this->getBaseDir(), 2 => PATH_SEPARATOR
)),
465 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
466 foreach ($requiredDirectories as $dir) {
467 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. $dir,
469 ts("File permissions"),
470 ts("Folder '%1' exists?", array(1 => $dir)),
471 ts("There is no '%1' folder.", array(1 => $dir)),
476 $configIDSiniDir = NULL;
478 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
479 if ($installType == 'drupal') {
481 // make sure that we can write to sites/default and files/
482 $writableDirectories = array(
483 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
484 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
485 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
487 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
488 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
492 elseif ($installType == 'wordpress') {
493 // make sure that we can write to plugins/civicrm and plugins/files/
494 $writableDirectories = array(WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'files', $cmsPath);
497 foreach ($writableDirectories as $dir) {
498 $dirName = CIVICRM_WINDOWS ?
$dir : CIVICRM_DIRECTORY_SEPARATOR
. $dir;
499 $testDetails = array(
500 ts("File permissions"),
501 ts("Is the %1 folder writeable?", array(1 => $dir)),
504 $this->requireWriteable($dirName, $testDetails, TRUE);
507 //check for Config.IDS.ini, file may exist in re-install
508 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
510 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
511 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR
, $configIDSiniDir);
512 if (file_exists($configIDSiniFile)) {
513 unlink($configIDSiniFile);
517 // Check for rewriting
518 if (isset($_SERVER['SERVER_SOFTWARE'])) {
519 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
521 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
522 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
525 if ($webserver == '') {
526 $webserver = ts("I can't tell what webserver you are running");
529 // Check for $_SERVER configuration
530 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
531 ts("Webserver config"),
532 ts("Recognised webserver"),
533 ts("You seem to be using an unsupported webserver. The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."),
536 // Check for MySQL support
537 $this->requireFunction('mysql_connect', array(
538 ts("PHP Configuration"),
540 ts("MySQL support not included in PHP."),
543 // Check for JSON support
544 $this->requireFunction('json_encode', array(
545 ts("PHP Configuration"),
547 ts("JSON support not included in PHP."),
550 // Check for xcache_isset and emit warning if exists
551 $this->checkXCache(array(
552 ts("PHP Configuration"),
553 ts("XCache compatibility"),
554 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."),
557 // Check memory allocation
558 $this->requireMemory(32 * 1024 * 1024,
561 ts("PHP Configuration"),
562 ts("Memory allocated (PHP config option 'memory_limit')"),
563 ts("CiviCRM needs a minimum of %1 MB allocated to PHP, but recommends %2 MB.", array(1 => 32, 2 => 64)),
564 ini_get("memory_limit"),
568 return $this->errors
;
573 * @param $recommended
574 * @param $testDetails
576 public function requireMemory($min, $recommended, $testDetails) {
577 $this->testing($testDetails);
578 $mem = $this->getPHPMemory();
580 if ($mem < $min && $mem > 0) {
581 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
582 $this->error($testDetails);
584 elseif ($mem < $recommended && $mem > 0) {
585 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
586 $this->warning($testDetails);
589 $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));
590 $this->warning($testDetails);
597 public function getPHPMemory() {
598 $memString = ini_get("memory_limit");
600 switch (strtolower(substr($memString, -1))) {
602 return round(substr($memString, 0, -1) * 1024);
605 return round(substr($memString, 0, -1) * 1024 * 1024);
608 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
611 return round($memString);
615 public function listErrors() {
617 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
618 foreach ($this->errors
as $error) {
619 echo "<li>" . htmlentities($error) . "</li>";
625 * @param null $section
627 public function showTable($section = NULL) {
629 $tests = $this->tests
[$section];
630 echo "<table class=\"testResults\" width=\"100%\">";
631 foreach ($tests as $test => $result) {
632 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
637 foreach ($this->tests
as $section => $tests) {
638 echo "<h3>$section</h3>";
639 echo "<table class=\"testResults\" width=\"100%\">";
641 foreach ($tests as $test => $result) {
642 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
650 * @param string $funcName
651 * @param $testDetails
655 public function requireFunction($funcName, $testDetails) {
656 $this->testing($testDetails);
658 if (!function_exists($funcName)) {
659 $this->error($testDetails);
668 * @param $testDetails
670 public function checkXCache($testDetails) {
671 if (function_exists('xcache_isset') &&
672 ini_get('xcache.size') > 0
674 $this->testing($testDetails);
675 $this->warning($testDetails);
681 * @param $testDetails
682 * @param null $maxVersion
684 public function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
686 $this->testing($testDetails);
688 $phpVersion = phpversion();
689 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
690 $belowMaxVersion = $maxVersion ?
version_compare($phpVersion, $maxVersion) < 0 : TRUE;
692 if ($maxVersion && $aboveMinVersion && $belowMaxVersion) {
695 elseif (!$maxVersion && $aboveMinVersion) {
699 if (!$testDetails[2]) {
700 if (!$aboveMinVersion) {
701 $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));
704 $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));
708 $this->error($testDetails);
712 * @param string $filename
713 * @param $testDetails
714 * @param bool $absolute
716 public function requireFile($filename, $testDetails, $absolute = FALSE) {
717 $this->testing($testDetails);
719 $filename = $this->getBaseDir() . $filename;
721 if (!file_exists($filename)) {
722 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
723 $this->error($testDetails);
728 * @param $testDetails
730 public function requireNoPathSeparator($testDetails) {
731 $this->testing($testDetails);
732 if (substr_count($this->getBaseDir(), PATH_SEPARATOR
)) {
733 $this->error($testDetails);
738 * @param string $filename
739 * @param $testDetails
741 public function requireNoFile($filename, $testDetails) {
742 $this->testing($testDetails);
743 $filename = $this->getBaseDir() . $filename;
744 if (file_exists($filename)) {
745 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
746 $this->error($testDetails);
751 * @param string $filename
752 * @param $testDetails
754 public function moveFileOutOfTheWay($filename, $testDetails) {
755 $this->testing($testDetails);
756 $filename = $this->getBaseDir() . $filename;
757 if (file_exists($filename)) {
758 if (file_exists("$filename.bak")) {
761 rename($filename, "$filename.bak");
766 * @param string $filename
767 * @param $testDetails
768 * @param bool $absolute
770 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
771 $this->testing($testDetails);
773 $filename = $this->getBaseDir() . $filename;
776 if (!is_writable($filename)) {
778 if (function_exists('posix_getpwuid')) {
779 $user = posix_getpwuid(posix_geteuid());
780 $name = '- ' . $user['name'] . ' -';
783 if (!isset($testDetails[2])) {
784 $testDetails[2] = NULL;
786 $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";
787 $this->error($testDetails);
792 * @param string $moduleName
793 * @param $testDetails
795 public function requireApacheModule($moduleName, $testDetails) {
796 $this->testing($testDetails);
797 if (!in_array($moduleName, apache_get_modules())) {
798 $this->error($testDetails);
804 * @param string $username
806 * @param $testDetails
808 public function requireMysqlConnection($server, $username, $password, $testDetails) {
809 $this->testing($testDetails);
810 $conn = @mysql_connect
($server, $username, $password);
816 $testDetails[2] .= ": " . mysql_error();
817 $this->error($testDetails);
823 * @param $testDetails
825 public function requireMySQLServer($server, $testDetails) {
826 $this->testing($testDetails);
827 $conn = @mysql_connect
($server, NULL, NULL);
829 if ($conn ||
mysql_errno() < 2000) {
833 $testDetails[2] .= ": " . mysql_error();
834 $this->error($testDetails);
840 * @param $testDetails
842 public function requireMySQLVersion($version, $testDetails) {
843 $this->testing($testDetails);
845 if (!mysql_get_server_info()) {
846 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
847 $this->warning($testDetails);
850 list($majorRequested, $minorRequested) = explode('.', $version);
851 list($majorHas, $minorHas) = explode('.', mysql_get_server_info());
853 if (($majorHas > $majorRequested) ||
($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
857 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
858 $this->error($testDetails);
865 * @param string $username
868 * @param $testDetails
870 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
871 $this->testing($testDetails);
872 $conn = @mysql_connect
($server, $username, $password);
874 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
875 $this->error($testDetails);
879 $innodb_support = FALSE;
880 $result = mysql_query("SHOW ENGINES", $conn);
881 while ($values = mysql_fetch_array($result)) {
882 if ($values['Engine'] == 'InnoDB') {
883 if (strtolower($values['Support']) == 'yes' ||
884 strtolower($values['Support']) == 'default'
886 $innodb_support = TRUE;
890 if ($innodb_support) {
891 $testDetails[3] = ts('MySQL server does have InnoDB support');
894 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
900 * @param string $username
903 * @param $testDetails
905 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
906 $this->testing($testDetails);
907 $conn = @mysql_connect
($server, $username, $password);
909 $testDetails[2] = ts('Could not login to the database.');
910 $this->error($testDetails);
914 if (!@mysql_select_db
($database, $conn)) {
915 $testDetails[2] = ts('Could not select the database.');
916 $this->error($testDetails);
920 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
922 $testDetails[2] = ts('Could not create a temp table.');
923 $this->error($testDetails);
925 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
930 * @param string $username
933 * @param $testDetails
935 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
936 $this->testing($testDetails);
937 $conn = @mysql_connect
($server, $username, $password);
939 $testDetails[2] = ts('Could not login to the database.');
940 $this->error($testDetails);
944 if (!@mysql_select_db
($database, $conn)) {
945 $testDetails[2] = ts('Could not select the database.');
946 $this->error($testDetails);
950 $result = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
952 $testDetails[2] = ts('Could not create a table in the database.');
953 $this->error($testDetails);
956 $result = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
958 mysql_query('DROP TABLE civicrm_install_temp_table_test');
959 $testDetails[2] = ts('Could not create a database trigger.');
960 $this->error($testDetails);
963 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
964 mysql_query('DROP TABLE civicrm_install_temp_table_test');
970 * @param string $username
973 * @param $testDetails
975 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
976 $this->testing($testDetails);
977 $conn = @mysql_connect
($server, $username, $password);
979 $testDetails[2] = ts('Could not connect to the database server.');
980 $this->error($testDetails);
984 if (!@mysql_select_db
($database, $conn)) {
985 $testDetails[2] = ts('Could not select the database.');
986 $this->error($testDetails);
990 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
992 $testDetails[2] = ts('Could not create a table in the database.');
993 $this->error($testDetails);
997 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
999 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
1000 $this->error($testDetails);
1001 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1005 $result = mysql_query('UNLOCK TABLES', $conn);
1007 $testDetails[2] = ts('Could not release the lock for the database table.');
1008 $this->error($testDetails);
1009 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1013 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1018 * @param string $username
1020 * @param $testDetails
1022 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
1023 $this->testing($testDetails);
1024 $conn = @mysql_connect
($server, $username, $password);
1026 $testDetails[2] = ts('Could not connect to the database server.');
1027 $this->error($testDetails);
1031 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
1033 $testDetails[2] = ts('Could not query database server variables.');
1034 $this->error($testDetails);
1038 $values = mysql_fetch_row($result);
1039 if ($values[1] == 1) {
1040 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
1043 $this->error($testDetails);
1050 * @param string $username
1053 * @param $minValueKB
1054 * @param $testDetails
1056 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
1057 $this->testing($testDetails);
1058 $conn = @mysql_connect
($server, $username, $password);
1060 $testDetails[2] = ts('Could not connect to the database server.');
1061 $this->error($testDetails);
1065 if (!@mysql_select_db
($database, $conn)) {
1066 $testDetails[2] = ts('Could not select the database.');
1067 $this->error($testDetails);
1071 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
1073 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
1074 $this->error($testDetails);
1077 $values = mysql_fetch_row($result);
1078 if ($values[1] < (1024 * $minValueKB)) {
1079 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
1080 $this->error($testDetails);
1087 * @param string $username
1090 * @param $testDetails
1091 * @param bool $onlyRequire
1093 public function requireDatabaseOrCreatePermissions(
1099 $onlyRequire = FALSE
1101 $this->testing($testDetails);
1102 $conn = @mysql_connect
($server, $username, $password);
1105 if (@mysql_select_db
($database)) {
1106 $okay = "Database '$database' exists";
1108 elseif ($onlyRequire) {
1109 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
1110 $this->error($testDetails);
1114 $query = sprintf("CREATE DATABASE %s", mysql_real_escape_string($database));
1115 if (@mysql_query
($query)) {
1116 $okay = ts("Able to create a new database.");
1119 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
1120 $this->error($testDetails);
1126 $testDetails[3] = $okay;
1127 $this->testing($testDetails);
1133 * @param $errorMessage
1135 public function requireServerVariables($varNames, $errorMessage) {
1136 //$this->testing($testDetails);
1137 foreach ($varNames as $varName) {
1138 if (!$_SERVER[$varName]) {
1139 $missing[] = '$_SERVER[' . $varName . ']';
1142 if (!isset($missing)) {
1146 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
1147 $this->error($testDetails);
1152 * @param $testDetails
1156 public function isRunningApache($testDetails) {
1157 $this->testing($testDetails);
1158 if (function_exists('apache_get_modules') ||
stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1162 $this->warning($testDetails);
1169 public function getBaseDir() {
1170 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR
;
1174 * @param $testDetails
1176 public function testing($testDetails) {
1177 if (!$testDetails) {
1181 $section = $testDetails[0];
1182 $test = $testDetails[1];
1184 $message = ts("OK");
1185 if (isset($testDetails[3])) {
1186 $message .= " ($testDetails[3])";
1189 $this->tests
[$section][$test] = array("good", $message);
1193 * @param $testDetails
1195 public function error($testDetails) {
1196 $section = $testDetails[0];
1197 $test = $testDetails[1];
1199 $this->tests
[$section][$test] = array("error", $testDetails[2]);
1200 $this->errors
[] = $testDetails;
1204 * @param $testDetails
1206 public function warning($testDetails) {
1207 $section = $testDetails[0];
1208 $test = $testDetails[1];
1210 $this->tests
[$section][$test] = array("warning", $testDetails[2]);
1211 $this->warnings
[] = $testDetails;
1217 public function hasErrors() {
1218 return count($this->errors
);
1224 public function hasWarnings() {
1225 return count($this->warnings
);
1233 class Installer
extends InstallRequirements
{
1240 public function createDatabaseIfNotExists($server, $username, $password, $database) {
1241 $conn = @mysql_connect
($server, $username, $password);
1243 if (@mysql_select_db
($database)) {
1244 // skip if database already present
1247 $query = sprintf("CREATE DATABASE %s", mysql_real_escape_string($database));
1248 if (@mysql_query
($query)) {
1251 $errorTitle = ts("Oops! Could not create database %1", array(1 => $database));
1252 $errorMsg = ts("We encountered an error when attempting to create the database. Please check your MySQL server permissions and the database name and try again.");
1253 errorDisplayPage($errorTitle, $errorMsg);
1262 public function install($config) {
1263 global $installDirPath;
1265 // create database if does not exists
1266 $this->createDatabaseIfNotExists($config['mysql']['server'],
1267 $config['mysql']['username'],
1268 $config['mysql']['password'],
1269 $config['mysql']['database']
1272 global $installDirPath;
1275 require_once $installDirPath . 'civicrm.php';
1276 civicrm_main($config);
1278 if (!$this->errors
) {
1279 global $installType, $installURLPath;
1281 $registerSiteURL = "https://civicrm.org/register-site";
1282 $commonOutputMessage
1283 = "<li>" . ts("Have you registered this site at CiviCRM.org? If not, please help strengthen the CiviCRM ecosystem by taking a few minutes to <a %1>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).", array(1 => "href='$registerSiteURL' target='_blank'")) . "</li>"
1284 . "<li>" . ts("We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.") . "</li>";
1289 $installType == 'drupal' &&
1290 version_compare(VERSION
, '7.0-rc1') >= 0
1296 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1297 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1298 $output .= '<head>';
1299 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1300 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1301 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1302 $output .= '</head>';
1303 $output .= '<body>';
1304 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1307 $drupalURL = civicrm_cms_base();
1308 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1309 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1311 $output .= "<li>" . ts("Drupal user permissions have been automatically set - giving anonymous and authenticated users access to public CiviCRM forms and features. We recommend that you <a %1>review these permissions</a> to ensure that they are appropriate for your requirements (<a %2>learn more...</a>)", array(1 => "target='_blank' href='{$drupalPermissionsURL}'", 2 => "target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'")) . "</li>";
1312 $output .= "<li>" . ts("Use the <a %1>Configuration Checklist</a> to review and configure settings for your new site", array(1 => "target='_blank' href='$drupalURL'")) . "</li>";
1313 $output .= $commonOutputMessage;
1315 // automatically enable CiviCRM module once it is installed successfully.
1316 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1317 global $cmsPath, $crmPath;
1319 // relative / abosolute paths are not working for drupal, hence using chdir()
1322 // Force the re-initialisation of the config singleton on the next call
1323 // since so far, we had used the Config object without loading the DB.
1324 $c = CRM_Core_Config
::singleton(FALSE);
1327 include_once "./includes/bootstrap.inc";
1328 include_once "./includes/unicode.inc";
1330 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1332 // prevent session information from being saved.
1333 drupal_save_session(FALSE);
1335 // Force the current user to anonymous.
1336 $original_user = $GLOBALS['user'];
1337 $GLOBALS['user'] = drupal_anonymous_user();
1339 // explicitly setting error reporting, since we cannot handle drupal related notices
1342 // rebuild modules, so that civicrm is added
1343 system_rebuild_module_data();
1345 // now enable civicrm module.
1346 module_enable(array('civicrm', 'civicrmtheme'));
1348 // clear block, page, theme, and hook caches
1349 drupal_flush_all_caches();
1351 //add basic drupal permissions
1352 civicrm_install_set_drupal_perms();
1354 // restore the user.
1355 $GLOBALS['user'] = $original_user;
1356 drupal_save_session(TRUE);
1358 //change the default language to one chosen
1359 if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
1360 // This ensures that defaults get set, otherwise the user will login
1361 // and most configurations will be empty, not set to en_US defaults.
1362 civicrm_api3('Setting', 'revert');
1364 civicrm_api3('Setting', 'create', array(
1365 'domain_id' => 'current_domain',
1366 'lcMessages' => $config['seedLanguage'],
1372 $output .= '</div>';
1373 $output .= '</body>';
1374 $output .= '</html>';
1377 elseif ($installType == 'drupal' && version_compare(VERSION
, '6.0') >= 0) {
1381 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1382 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1383 $output .= '<head>';
1384 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1385 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1386 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1387 $output .= '</head>';
1388 $output .= '<body>';
1389 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
1392 $drupalURL = civicrm_cms_base();
1393 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1394 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1396 $output .= "<li>" . ts("Drupal user permissions have been automatically set - giving anonymous and authenticated users access to public CiviCRM forms and features. We recommend that you <a %1>review these permissions</a> to ensure that they are appropriate for your requirements (<a %2>learn more...</a>)", array(1 => "target='_blank' href='{$drupalPermissionsURL}'", 2 => "target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'")) . "</li>";
1397 $output .= "<li>" . ts("Use the <a %1>Configuration Checklist</a> to review and configure settings for your new site", array(1 => "target='_blank' href='$drupalURL'")) . "</li>";
1398 $output .= $commonOutputMessage;
1400 // explicitly setting error reporting, since we cannot handle drupal related notices
1403 // automatically enable CiviCRM module once it is installed successfully.
1404 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1405 global $cmsPath, $crmPath;
1407 // relative / abosolute paths are not working for drupal, hence using chdir()
1410 // Force the re-initialisation of the config singleton on the next call
1411 // since so far, we had used the Config object without loading the DB.
1412 $c = CRM_Core_Config
::singleton(FALSE);
1415 include_once "./includes/bootstrap.inc";
1416 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1418 // rebuild modules, so that civicrm is added
1419 module_rebuild_cache();
1421 // now enable civicrm module.
1422 module_enable(array('civicrm'));
1424 // clear block, page, theme, and hook caches
1425 drupal_flush_all_caches();
1427 //add basic drupal permissions
1428 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)');
1432 elseif ($installType == 'wordpress') {
1433 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
1434 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
1437 $cmsURL = civicrm_cms_base();
1438 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1439 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1441 $output .= "<li>" . ts("WordPress user permissions have been automatically set - giving Anonymous and Subscribers access to public CiviCRM forms and features. We recommend that you <a %1>review these permissions</a> to ensure that they are appropriate for your requirements (<a %2>learn more...</a>)", array(1 => "target='_blank' href='{$wpPermissionsURL}'", 2 => "target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'")) . "</li>";
1442 $output .= "<li>" . ts("Use the <a %1>Configuration Checklist</a> to review and configure settings for your new site", array(1 => "target='_blank' href='$cmsURL'")) . "</li>";
1443 $output .= $commonOutputMessage;
1448 $c = CRM_Core_Config
::singleton(FALSE);
1453 return $this->errors
;
1458 function civicrm_install_set_drupal_perms() {
1459 if (!function_exists('db_select')) {
1460 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)');
1464 'access all custom data',
1465 'access uploaded files',
1466 'make online contributions',
1470 'register for events',
1472 'view event participants',
1473 'access CiviMail subscribe/unsubscribe pages',
1476 // Adding a permission that has not yet been assigned to a module by
1477 // a hook_permission implementation results in a database error.
1479 $allPerms = array_keys(module_invoke_all('permission'));
1480 foreach (array_diff($perms, $allPerms) as $perm) {
1482 'Cannot grant the %perm permission because it does not yet exist.',
1483 array('%perm' => $perm),
1487 $perms = array_intersect($perms, $allPerms);
1488 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID
, $perms);
1489 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID
, $perms);
1499 function getSiteDir($cmsPath, $str) {
1500 static $siteDir = '';
1506 $sites = CIVICRM_DIRECTORY_SEPARATOR
. 'sites' . CIVICRM_DIRECTORY_SEPARATOR
;
1507 $modules = CIVICRM_DIRECTORY_SEPARATOR
. 'modules' . CIVICRM_DIRECTORY_SEPARATOR
;
1508 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR
) .
1509 "([\-a-zA-Z0-9_.]+)" .
1510 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR
) . "/",
1511 $_SERVER['SCRIPT_FILENAME'], $matches
1513 $siteDir = isset($matches[1]) ?
$matches[1] : 'default';
1515 if (strtolower($siteDir) == 'all') {
1516 // For this case - use drupal's way of finding out multi-site directory
1517 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR
, $_SERVER['SCRIPT_FILENAME']);
1518 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1519 for ($i = count($uri) - 1; $i > 0; $i--) {
1520 for ($j = count($server); $j > 0; $j--) {
1521 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1522 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
1523 'sites' . CIVICRM_DIRECTORY_SEPARATOR
. $dir
1530 $siteDir = 'default';
1537 * @param $errorTitle
1541 function errorDisplayPage($errorTitle, $errorMsg, $showRefer = TRUE) {
1543 $docLink = CRM_Utils_System
::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
1545 if (function_exists('ts')) {
1546 $errorMsg .= '<p>' . ts("<a %1>Refer to the online documentation for more information</a>", array(1 => "href='$docLink'")) . '</p>';
1549 $errorMsg .= '<p>' . sprintf("<a %s>Refer to the online documentation for more information</a>", "href='$docLink'") . '</p>';
1553 include 'error.html';