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(
54 'drupal', 'wordpress'))) {
55 $errorTitle = "Oops! Unsupported installation mode";
57 errorDisplayPage($errorTitle, $errorMsg);
62 global $installDirPath;
63 global $installURLPath;
65 if ($installType == 'drupal') {
66 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
67 $installDirPath = $installURLPath = '';
69 elseif ($installType == 'wordpress') {
70 $crmPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
;
71 $installDirPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
72 $installURLPath = WP_PLUGIN_URL
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
75 $pkgPath = $crmPath . DIRECTORY_SEPARATOR
. 'packages';
78 $crmPath . PATH_SEPARATOR
.
79 $pkgPath . PATH_SEPARATOR
.
83 require_once $crmPath . '/CRM/Core/ClassLoader.php';
84 CRM_Core_ClassLoader
::singleton()->register();
86 $docLink = CRM_Utils_System
::docURL2('Installation and Upgrades', FALSE, 'Installation Guide',NULL,NULL,"wiki");
88 if ($installType == 'drupal') {
89 // Lets check only /modules/.
90 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR
. 'modules', CIVICRM_DIRECTORY_SEPARATOR
) . '/';
92 if (!preg_match($pattern, str_replace("\\", "/", $_SERVER['SCRIPT_FILENAME']))) {
93 $errorTitle = "Oops! Please Correct Your Install Location";
94 $errorMsg = "Please untar (uncompress) your downloaded copy of CiviCRM in the <strong>" . implode(CIVICRM_DIRECTORY_SEPARATOR
, array(
95 'sites', 'all', 'modules')) . "</strong> directory below your Drupal root directory. Refer to the online " . $docLink . " for more information.";
96 errorDisplayPage($errorTitle, $errorMsg);
100 // Load civicrm database config
101 if (isset($_REQUEST['mysql'])) {
102 $databaseConfig = $_REQUEST['mysql'];
105 $databaseConfig = array(
106 "server" => "localhost",
107 "username" => "civicrm",
109 "database" => "civicrm",
113 if ($installType == 'drupal') {
114 // Load drupal database config
115 if (isset($_REQUEST['drupal'])) {
116 $drupalConfig = $_REQUEST['drupal'];
119 $drupalConfig = array(
120 "server" => "localhost",
121 "username" => "drupal",
123 "database" => "drupal",
129 if (isset($_REQUEST['loadGenerated'])) {
133 require_once dirname(__FILE__
) . CIVICRM_DIRECTORY_SEPARATOR
. 'langs.php';
134 foreach ($langs as $locale => $_) {
135 if ($locale == 'en_US') {
138 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR
, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
139 unset($langs[$locale]);
143 // Set the locale (works with both native gettext and phpgettext)
144 define('CIVICRM_UF', 'Drupal');
145 define('CIVICRM_GETTEXT_NATIVE', 1);
149 $seedLanguage = 'en_US';
151 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
152 $seedLanguage = $_REQUEST['seedLanguage'];
153 $tsLocale = $_REQUEST['seedLanguage'];
156 $config = CRM_Core_Config
::singleton(FALSE);
158 // The translation files are in the parent directory (l10n)
159 $config->gettextResourceDir
= '..' . DIRECTORY_SEPARATOR
. $config->gettextResourceDir
;
160 $i18n = CRM_Core_I18n
::singleton();
163 if ($installType == 'drupal') {
164 //CRM-6840 -don't force to install in sites/all/modules/
165 $object = new CRM_Utils_System_Drupal();
166 $cmsPath = $object->cmsRootPath();
168 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
169 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
170 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
171 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
172 'civicrm.settings.php'
175 elseif ($installType == 'wordpress') {
176 $cmsPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm';
177 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
178 'civicrm.settings.php'
182 // Exit with error if CiviCRM has already been installed.
183 if ($alreadyInstalled) {
184 $errorTitle = "Oops! CiviCRM is Already Installed";
185 if ($installType == 'drupal') {
187 $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(
188 '[your Drupal root directory]', 'sites', $siteDir)) . "</strong>.</li><li>To <strong>upgrade an existing installation</strong>, refer to the online " . $docLink . ".</li></ul>";
190 elseif ($installType == 'wordpress') {
191 $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>";
193 errorDisplayPage($errorTitle, $errorMsg);
196 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'civicrm-version.php';
197 if (file_exists($versionFile)) {
198 require_once ($versionFile);
199 $civicrm_version = civicrmVersion();
202 $civicrm_version = 'unknown';
205 if ($installType == 'drupal') {
206 // Ensure that they have downloaded the correct version of CiviCRM
207 if ($civicrm_version['cms'] != 'Drupal' &&
208 $civicrm_version['cms'] != 'Drupal6'
210 $errorTitle = "Oops! Incorrect CiviCRM Version";
211 $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!";
212 errorDisplayPage($errorTitle, $errorMsg);
215 define('DRUPAL_ROOT', $cmsPath);
216 $drupalVersionFiles = array(
218 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'modules', 'system', 'system.module')),
220 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'includes', 'bootstrap.inc')),
222 foreach ($drupalVersionFiles as $drupalVersionFile) {
223 if (file_exists($drupalVersionFile)) {
224 require_once $drupalVersionFile;
228 if (!defined('VERSION') or version_compare(VERSION
, '6.0') < 0) {
229 $errorTitle = "Oops! Incorrect Drupal Version";
230 $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.";
231 errorDisplayPage($errorTitle, $errorMsg);
234 elseif ($installType == 'wordpress') {
236 $civicrm_version['cms'] = 'WordPress';
238 // Ensure that they have downloaded the correct version of CiviCRM
239 if ($civicrm_version['cms'] != 'WordPress') {
240 $errorTitle = "Oops! Incorrect CiviCRM Version";
241 $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!";
242 errorDisplayPage($errorTitle, $errorMsg);
246 // Check requirements
247 $req = new InstallRequirements();
250 if ($req->hasErrors()) {
251 $hasErrorOtherThanDatabase = TRUE;
254 if ($databaseConfig) {
255 $dbReq = new InstallRequirements();
256 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
257 if ($installType == 'drupal') {
258 $dbReq->checkdatabase($drupalConfig, 'Drupal');
263 if (isset($_REQUEST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
264 // Confirm before reinstalling
265 if (!isset($_REQUEST['force_reinstall']) && $alreadyInstalled) {
266 include ($installDirPath . 'template.html');
269 $inst = new Installer();
270 $inst->install($_REQUEST);
273 // Show the config form
276 include ($installDirPath . 'template.html');
280 * This class checks requirements
281 * Each of the requireXXX functions takes an argument which gives a user description of the test. It's an array
283 * $description[0] - The test catetgory
284 * $description[1] - The test title
285 * $description[2] - The test error to show, if it goes wrong
287 class InstallRequirements
{
288 var $errors, $warnings, $tests;
290 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
291 const MINIMUM_THREAD_STACK
= 192;
294 * Just check that the database configuration is okay
296 function checkdatabase($databaseConfig, $dbName) {
297 if ($this->requireFunction('mysql_connect',
299 ts("PHP Configuration"),
301 ts("MySQL support not included in PHP."),
304 $this->requireMySQLServer($databaseConfig['server'],
306 ts("MySQL %1 Configuration", array(1 => $dbName)),
307 ts("Does the server exist?"),
308 ts("Can't find the a MySQL server on '%1'", array(1 => $databaseConfig['server'])),
309 $databaseConfig['server'],
312 if ($this->requireMysqlConnection($databaseConfig['server'],
313 $databaseConfig['username'],
314 $databaseConfig['password'],
316 ts("MySQL %1 Configuration", array(1 => $dbName)),
317 ts("Are the access credentials correct?"),
318 ts("That username/password doesn't work"),
321 @$this->requireMySQLVersion("5.1",
323 ts("MySQL %1 Configuration", array(1 => $dbName)),
324 ts("MySQL version at least %1", array(1 => '5.1')),
325 "MySQL version 5.1 or higher is required, you only have ",
326 "MySQL " . mysql_get_server_info(),
329 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
330 $databaseConfig['username'],
331 $databaseConfig['password'],
333 "MySQL $dbName Configuration",
334 "Is auto_increment_increment set to 1",
335 "An auto_increment_increment value greater than 1 is not currently supported. Please see issue CRM-7923 for further details and potential workaround.",
338 $this->requireMySQLThreadStack($databaseConfig['server'],
339 $databaseConfig['username'],
340 $databaseConfig['password'],
341 $databaseConfig['database'],
342 self
::MINIMUM_THREAD_STACK
,
344 "MySQL $dbName Configuration",
345 "Does MySQL thread_stack meet minimum (" . self
::MINIMUM_THREAD_STACK
. "k)",
346 "", // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
350 $onlyRequire = ($dbName == 'Drupal') ?
TRUE : FALSE;
351 $this->requireDatabaseOrCreatePermissions(
352 $databaseConfig['server'],
353 $databaseConfig['username'],
354 $databaseConfig['password'],
355 $databaseConfig['database'],
357 "MySQL $dbName Configuration",
358 "Can I access/create the database",
359 "I can't create new databases and the database '$databaseConfig[database]' doesn't exist",
363 if ($dbName != 'Drupal') {
364 $this->requireMySQLInnoDB($databaseConfig['server'],
365 $databaseConfig['username'],
366 $databaseConfig['password'],
367 $databaseConfig['database'],
369 "MySQL $dbName Configuration",
370 "Can I access/create InnoDB tables in the database",
371 "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.",
374 $this->requireMySQLTempTables($databaseConfig['server'],
375 $databaseConfig['username'],
376 $databaseConfig['password'],
377 $databaseConfig['database'],
379 "MySQL $dbName Configuration",
380 'Can I create temporary tables in the database',
381 'Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.',
384 $this->requireMySQLLockTables($databaseConfig['server'],
385 $databaseConfig['username'],
386 $databaseConfig['password'],
387 $databaseConfig['database'],
389 "MySQL $dbName Configuration",
390 'Can I create lock tables in the database',
391 'Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.',
394 $this->requireMySQLTrigger($databaseConfig['server'],
395 $databaseConfig['username'],
396 $databaseConfig['password'],
397 $databaseConfig['database'],
399 "MySQL $dbName Configuration",
400 'Can I create triggers in the database',
401 'Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.',
409 * Check everything except the database
412 global $crmPath, $installType;
414 $this->errors
= NULL;
416 $this->requirePHPVersion('5.3.3', array(ts("PHP Configuration"), ts("PHP5 installed"), NULL, ts("PHP version %1", array(1 => phpversion()))));
418 // Check that we can identify the root folder successfully
419 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'README.txt',
421 ts("File permissions"),
422 ts("Does the webserver know where files are stored?"),
423 ts("The webserver isn't letting me identify where files are stored."),
429 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
430 $this->requireNoPathSeparator(
432 ts('File permissions'),
433 ts('Does the CiviCRM path contain PATH_SEPARATOR?'),
434 ts('The %1 path contains the PATH_SEPARATOR (the %2 character)', array(1 => $this->getBaseDir(), 2 => PATH_SEPARATOR
)),
439 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
440 foreach ($requiredDirectories as $dir) {
441 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. $dir,
443 ts("File permissions"),
444 ts("%1: folder exists", array(1 => $dir)),
445 ts("%1: folder is missing", array(1 => $dir)),
451 $configIDSiniDir = NULL;
453 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
454 if ($installType == 'drupal') {
456 // make sure that we can write to sites/default and files/
457 $writableDirectories = array(
458 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
459 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
460 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
462 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
463 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
467 elseif ($installType == 'wordpress') {
468 // make sure that we can write to plugins/civicrm and plugins/files/
469 $writableDirectories = array(WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'files', $cmsPath);
472 foreach ($writableDirectories as $dir) {
473 $dirName = CIVICRM_WINDOWS ?
$dir : CIVICRM_DIRECTORY_SEPARATOR
. $dir;
474 $this->requireWriteable($dirName,
475 array(ts("File permissions"), ts("Is the %1 folder writeable?", array(1 => $dir)), NULL),
480 //check for Config.IDS.ini, file may exist in re-install
481 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
483 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
484 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR
, $configIDSiniDir);
485 if (file_exists($configIDSiniFile)) {
486 unlink($configIDSiniFile);
490 // Check for rewriting
491 if (isset($_SERVER['SERVER_SOFTWARE'])) {
492 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
494 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
495 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
498 if ($webserver == '') {
499 $webserver = ts("I can't tell what webserver you are running");
502 // Check for $_SERVER configuration
503 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array("Webserver config", "Recognised webserver", "You seem to be using an unsupported webserver. The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."));
505 // Check for MySQL support
506 $this->requireFunction('mysql_connect',
507 array(ts("PHP Configuration"), ts("MySQL support"), ts("MySQL support not included in PHP."))
510 // Check for JSON support
511 $this->requireFunction('json_encode',
512 array(ts("PHP Configuration"), ts("JSON support"), ts("JSON support not included in PHP."))
515 // Check for xcache_isset and emit warning if exists
516 $this->checkXCache(array(
517 ts("PHP Configuration"),
518 "XCache compatibility",
519 "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.",
522 // Check memory allocation
523 $this->requireMemory(32 * 1024 * 1024,
526 ts("PHP Configuration"),
527 ts("Memory allocated (PHP config option 'memory_limit')"),
528 ts("CiviCRM needs a minimum of 32M allocated to PHP, but recommends 64M."),
529 ini_get("memory_limit"),
533 return $this->errors
;
536 function requireMemory($min, $recommended, $testDetails) {
537 $this->testing($testDetails);
538 $mem = $this->getPHPMemory();
540 if ($mem < $min && $mem > 0) {
541 $testDetails[2] .= " " . ts("You only have %1 of memory allocated", array(1 => ini_get("memory_limit")));
542 $this->error($testDetails);
544 elseif ($mem < $recommended && $mem > 0) {
545 $testDetails[2] .= " " . ts("You only have %1 of memory allocated", array(1 => ini_get("memory_limit")));
546 $this->warning($testDetails);
549 $testDetails[2] .= " " . ts("We can't determine how much memory you have allocated. Install only if you're sure you've allocated at least 20 MB.");
550 $this->warning($testDetails);
554 function getPHPMemory() {
555 $memString = ini_get("memory_limit");
557 switch (strtolower(substr($memString, -1))) {
559 return round(substr($memString, 0, -1) * 1024);
562 return round(substr($memString, 0, -1) * 1024 * 1024);
565 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
568 return round($memString);
572 function listErrors() {
574 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
575 foreach ($this->errors
as $error) {
576 echo "<li>" . htmlentities($error) . "</li>";
581 function showTable($section = NULL) {
583 $tests = $this->tests
[$section];
584 echo "<table class=\"testResults\" width=\"100%\">";
585 foreach ($tests as $test => $result) {
586 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
591 foreach ($this->tests
as $section => $tests) {
592 echo "<h3>$section</h3>";
593 echo "<table class=\"testResults\" width=\"100%\">";
595 foreach ($tests as $test => $result) {
596 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
603 function requireFunction($funcName, $testDetails) {
604 $this->testing($testDetails);
606 if (!function_exists($funcName)) {
607 $this->error($testDetails);
615 function checkXCache($testDetails) {
616 if (function_exists('xcache_isset') &&
617 ini_get('xcache.size') > 0
619 $this->testing($testDetails);
620 $this->warning($testDetails);
624 function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
626 $this->testing($testDetails);
628 $phpVersion = phpversion();
629 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
630 $belowMaxVersion = $maxVersion ?
version_compare($phpVersion, $maxVersion) < 0 : TRUE;
632 if ($maxVersion && $aboveMinVersion && $belowMaxVersion) {
635 elseif (!$maxVersion && $aboveMinVersion) {
639 if (!$testDetails[2]) {
640 if (!$aboveMinVersion) {
641 $testDetails[2] = "You need PHP version $minVersion or later, only {$phpVersion} is installed. Please upgrade your server, or ask your web-host to do so.";
644 $testDetails[2] = "PHP version {$phpVersion} is not supported. PHP version earlier than $maxVersion is required. You might want to downgrade your server, or ask your web-host to do so.";
648 $this->error($testDetails);
651 function requireFile($filename, $testDetails, $absolute = FALSE) {
652 $this->testing($testDetails);
654 $filename = $this->getBaseDir() . $filename;
656 if (!file_exists($filename)) {
657 $testDetails[2] .= " (file '$filename' not found)";
658 $this->error($testDetails);
662 function requireNoPathSeparator($testDetails) {
663 $this->testing($testDetails);
664 if (substr_count($this->getBaseDir(), PATH_SEPARATOR
)) {
665 $this->error($testDetails);
669 function requireNoFile($filename, $testDetails) {
670 $this->testing($testDetails);
671 $filename = $this->getBaseDir() . $filename;
672 if (file_exists($filename)) {
673 $testDetails[2] .= " (file '$filename' found)";
674 $this->error($testDetails);
678 function moveFileOutOfTheWay($filename, $testDetails) {
679 $this->testing($testDetails);
680 $filename = $this->getBaseDir() . $filename;
681 if (file_exists($filename)) {
682 if (file_exists("$filename.bak")) {
685 rename($filename, "$filename.bak");
689 function requireWriteable($filename, $testDetails, $absolute = FALSE) {
690 $this->testing($testDetails);
692 $filename = $this->getBaseDir() . $filename;
695 if (!is_writeable($filename)) {
697 if (function_exists('posix_getpwuid')) {
698 $user = posix_getpwuid(posix_geteuid());
699 $name = '- ' . $user['name'] . ' -';
702 if (!isset($testDetails[2])) {
703 $testDetails[2] = NULL;
705 $testDetails[2] .= "The user account used by your web-server $name needs to be granted write access to the following directory in order to configure the CiviCRM settings file:\n$filename";
706 $this->error($testDetails);
710 function requireApacheModule($moduleName, $testDetails) {
711 $this->testing($testDetails);
712 if (!in_array($moduleName, apache_get_modules())) {
713 $this->error($testDetails);
717 function requireMysqlConnection($server, $username, $password, $testDetails) {
718 $this->testing($testDetails);
719 $conn = @mysql_connect
($server, $username, $password);
725 $testDetails[2] .= ": " . mysql_error();
726 $this->error($testDetails);
730 function requireMySQLServer($server, $testDetails) {
731 $this->testing($testDetails);
732 $conn = @mysql_connect
($server, NULL, NULL);
734 if ($conn ||
mysql_errno() < 2000) {
738 $testDetails[2] .= ": " . mysql_error();
739 $this->error($testDetails);
743 function requireMySQLVersion($version, $testDetails) {
744 $this->testing($testDetails);
746 if (!mysql_get_server_info()) {
747 $testDetails[2] = 'Cannot determine the version of MySQL installed. Please ensure at least version 4.1 is installed.';
748 $this->warning($testDetails);
751 list($majorRequested, $minorRequested) = explode('.', $version);
752 list($majorHas, $minorHas) = explode('.', mysql_get_server_info());
754 if (($majorHas > $majorRequested) ||
($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
758 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
759 $this->error($testDetails);
764 function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
765 $this->testing($testDetails);
766 $conn = @mysql_connect
($server, $username, $password);
768 $testDetails[2] .= ' Could not determine if mysql has innodb support. Assuming no';
769 $this->error($testDetails);
773 $innodb_support = FALSE;
774 $result = mysql_query("SHOW ENGINES", $conn);
775 while ($values = mysql_fetch_array($result)) {
776 if ($values['Engine'] == 'InnoDB') {
777 if (strtolower($values['Support']) == 'yes' ||
778 strtolower($values['Support']) == 'default'
780 $innodb_support = TRUE;
784 if ($innodb_support) {
785 $testDetails[3] = 'MySQL server does have innodb support';
788 $testDetails[2] .= ' Could not determine if mysql has innodb support. Assuming no';
792 function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
793 $this->testing($testDetails);
794 $conn = @mysql_connect
($server, $username, $password);
796 $testDetails[2] = 'Could not login to the database.';
797 $this->error($testDetails);
801 if (!@mysql_select_db
($database, $conn)) {
802 $testDetails[2] = 'Could not select the database.';
803 $this->error($testDetails);
807 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
809 $testDetails[2] = 'Could not create a temp table.';
810 $this->error($testDetails);
812 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
815 function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
816 $this->testing($testDetails);
817 $conn = @mysql_connect
($server, $username, $password);
819 $testDetails[2] = 'Could not login to the database.';
820 $this->error($testDetails);
824 if (!@mysql_select_db
($database, $conn)) {
825 $testDetails[2] = 'Could not select the database.';
826 $this->error($testDetails);
830 $result = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
832 $testDetails[2] = 'Could not create a table.';
833 $this->error($testDetails);
836 $result = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
838 mysql_query('DROP TABLE civicrm_install_temp_table_test');
839 $testDetails[2] = 'Could not create a trigger.';
840 $this->error($testDetails);
844 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
845 mysql_query('DROP TABLE civicrm_install_temp_table_test');
849 function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
850 $this->testing($testDetails);
851 $conn = @mysql_connect
($server, $username, $password);
853 $testDetails[2] = 'Could not login to the database.';
854 $this->error($testDetails);
858 if (!@mysql_select_db
($database, $conn)) {
859 $testDetails[2] = 'Could not select the database.';
860 $this->error($testDetails);
864 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
866 $testDetails[2] = 'Could not create a table.';
867 $this->error($testDetails);
871 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
873 $testDetails[2] = 'Could not obtain a write lock for the table.';
874 $this->error($testDetails);
875 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
879 $result = mysql_query('UNLOCK TABLES', $conn);
881 $testDetails[2] = 'Could not release the lock for the table.';
882 $this->error($testDetails);
883 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
887 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
891 function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
892 $this->testing($testDetails);
893 $conn = @mysql_connect
($server, $username, $password);
895 $testDetails[2] = 'Could not connect to the database server.';
896 $this->error($testDetails);
900 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
902 $testDetails[2] = 'Could not query database server variables.';
903 $this->error($testDetails);
907 $values = mysql_fetch_row($result);
908 if ($values[1] == 1) {
909 $testDetails[3] = 'MySQL server auto_increment_increment is 1';
912 $this->error($testDetails);
917 function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
918 $this->testing($testDetails);
919 $conn = @mysql_connect
($server, $username, $password);
921 $testDetails[2] = 'Could not login to the database.';
922 $this->error($testDetails);
926 if (!@mysql_select_db
($database, $conn)) {
927 $testDetails[2] = 'Could not select the database.';
928 $this->error($testDetails);
932 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
934 $testDetails[2] = 'Could not query thread_stack.';
935 $this->error($testDetails);
937 $values = mysql_fetch_row($result);
938 if ($values[1] < (1024*$minValueKB)) {
939 $testDetails[2] = 'MySQL "thread_stack" is ' . ($values[1]/1024) . 'k';
940 $this->error($testDetails);
945 function requireDatabaseOrCreatePermissions($server,
952 $this->testing($testDetails);
953 $conn = @mysql_connect
($server, $username, $password);
956 if (@mysql_select_db
($database)) {
957 $okay = "Database '$database' exists";
959 elseif ($onlyRequire) {
960 $testDetails[2] = "The database: '$database' does not exist";
961 $this->error($testDetails);
965 if (@mysql_query
("CREATE DATABASE $database")) {
966 $okay = "Able to create a new database";
969 $testDetails[2] .= " (user '$username' doesn't have CREATE DATABASE permissions.)";
970 $this->error($testDetails);
976 $testDetails[3] = $okay;
977 $this->testing($testDetails);
981 function requireServerVariables($varNames, $errorMessage) {
982 //$this->testing($testDetails);
983 foreach ($varNames as $varName) {
984 if (!$_SERVER[$varName]) {
985 $missing[] = '$_SERVER[' . $varName . ']';
988 if (!isset($missing)) {
992 $testDetails[2] = " (the following PHP variables are missing: " . implode(", ", $missing) . ")";
993 $this->error($testDetails);
997 function isRunningApache($testDetails) {
998 $this->testing($testDetails);
999 if (function_exists('apache_get_modules') ||
stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1003 $this->warning($testDetails);
1007 function getBaseDir() {
1008 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR
;
1011 function testing($testDetails) {
1012 if (!$testDetails) {
1016 $section = $testDetails[0];
1017 $test = $testDetails[1];
1020 if (isset($testDetails[3])) {
1021 $message .= " ($testDetails[3])";
1024 $this->tests
[$section][$test] = array("good", $message);
1027 function error($testDetails) {
1028 $section = $testDetails[0];
1029 $test = $testDetails[1];
1031 $this->tests
[$section][$test] = array("error", $testDetails[2]);
1032 $this->errors
[] = $testDetails;
1035 function warning($testDetails) {
1036 $section = $testDetails[0];
1037 $test = $testDetails[1];
1040 $this->tests
[$section][$test] = array("warning", $testDetails[2]);
1041 $this->warnings
[] = $testDetails;
1044 function hasErrors() {
1045 return sizeof($this->errors
);
1048 function hasWarnings() {
1049 return sizeof($this->warnings
);
1053 class Installer
extends InstallRequirements
{
1054 function createDatabaseIfNotExists($server, $username, $password, $database) {
1055 $conn = @mysql_connect
($server, $username, $password);
1057 if (@mysql_select_db
($database)) {
1058 // skip if database already present
1062 if (@mysql_query
("CREATE DATABASE $database")) {}
1064 $errorTitle = "Oops! Could not create Database $database";
1065 $errorMsg = "We encountered an error when attempting to create the database. Please check your mysql server permissions and the database name and try again.";
1066 errorDisplayPage($errorTitle, $errorMsg);
1070 function install($config) {
1071 global $installDirPath;
1073 // create database if does not exists
1074 $this->createDatabaseIfNotExists($config['mysql']['server'],
1075 $config['mysql']['username'],
1076 $config['mysql']['password'],
1077 $config['mysql']['database']
1080 global $installDirPath;
1083 require_once $installDirPath . 'civicrm.php';
1084 civicrm_main($config);
1086 if (!$this->errors
) {
1087 global $installType, $installURLPath;
1089 $registerSiteURL = "http://civicrm.org/civicrm/profile/create?reset=1&gid=15";
1090 $commonOutputMessage = "
1091 <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>
1092 <li>We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.</li>
1097 $installType == 'drupal' &&
1098 version_compare(VERSION
, '7.0-rc1') >= 0
1104 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1105 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1106 $output .= '<head>';
1107 $output .= '<title>CiviCRM Installed</title>';
1108 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1109 $output .= '</head>';
1110 $output .= '<body>';
1111 $output .= '<div style="padding: 1em;"><p class="good">CiviCRM has been successfully installed</p>';
1113 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here',NULL,NULL,"wiki");
1114 if (!function_exists('ts')) {
1115 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1117 $drupalURL = civicrm_cms_base();
1118 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1119 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1121 $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>
1122 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1123 {$commonOutputMessage}";
1125 // automatically enable CiviCRM module once it is installed successfully.
1126 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1127 global $cmsPath, $crmPath;
1129 // relative / abosolute paths are not working for drupal, hence using chdir()
1132 include_once "./includes/bootstrap.inc";
1133 include_once "./includes/unicode.inc";
1135 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1137 // prevent session information from being saved.
1138 drupal_save_session(FALSE);
1140 // Force the current user to anonymous.
1141 $original_user = $GLOBALS['user'];
1142 $GLOBALS['user'] = drupal_anonymous_user();
1144 // explicitly setting error reporting, since we cannot handle drupal related notices
1147 // rebuild modules, so that civicrm is added
1148 system_rebuild_module_data();
1150 // now enable civicrm module.
1151 module_enable(array('civicrm', 'civicrmtheme'));
1153 // clear block, page, theme, and hook caches
1154 drupal_flush_all_caches();
1156 //add basic drupal permissions
1157 civicrm_install_set_drupal_perms();
1159 // restore the user.
1160 $GLOBALS['user'] = $original_user;
1161 drupal_save_session(TRUE);
1164 $output .= '</div>';
1165 $output .= '</body>';
1166 $output .= '</html>';
1169 elseif ($installType == 'drupal' && version_compare(VERSION
, '6.0') >= 0) {
1173 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1174 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1175 $output .= '<head>';
1176 $output .= '<title>CiviCRM Installed</title>';
1177 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1178 $output .= '</head>';
1179 $output .= '<body>';
1180 $output .= '<div style="padding: 1em;"><p class="good">CiviCRM has been successfully installed</p>';
1182 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here',NULL,NULL,"wiki");
1183 if (!function_exists('ts')) {
1184 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1186 $drupalURL = civicrm_cms_base();
1187 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1188 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1190 $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>
1191 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1192 {$commonOutputMessage}";
1194 // explicitly setting error reporting, since we cannot handle drupal related notices
1197 // automatically enable CiviCRM module once it is installed successfully.
1198 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1199 global $cmsPath, $crmPath;
1201 // relative / abosolute paths are not working for drupal, hence using chdir()
1204 include_once "./includes/bootstrap.inc";
1205 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1207 // rebuild modules, so that civicrm is added
1208 module_rebuild_cache();
1210 // now enable civicrm module.
1211 module_enable(array('civicrm'));
1213 // clear block, page, theme, and hook caches
1214 drupal_flush_all_caches();
1216 //add basic drupal permissions
1217 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)');
1221 elseif ($installType == 'wordpress') {
1222 echo '<h1>CiviCRM Installed</h1>';
1223 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">CiviCRM has been successfully installed</p>';
1225 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here',NULL,NULL,"wiki");
1226 if (!function_exists('ts')) {
1227 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1230 $cmsURL = civicrm_cms_base();
1231 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1232 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1235 <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>
1236 <li>Use the <a target='_blank' href=\"$cmsURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1237 {$commonOutputMessage}
1245 return $this->errors
;
1249 function civicrm_install_set_drupal_perms() {
1250 if (!function_exists('db_select')) {
1251 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)');
1255 'access all custom data',
1256 'access uploaded files',
1257 'make online contributions',
1261 'register for events',
1263 'view event participants',
1264 'access CiviMail subscribe/unsubscribe pages',
1267 // Adding a permission that has not yet been assigned to a module by
1268 // a hook_permission implementation results in a database error.
1270 $allPerms = array_keys(module_invoke_all('permission'));
1271 foreach (array_diff($perms, $allPerms) as $perm) {
1273 'Cannot grant the %perm permission because it does not yet exist.',
1275 '%perm' => $perm), WATCHDOG_ERROR
1278 $perms = array_intersect($perms, $allPerms);
1279 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID
, $perms);
1280 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID
, $perms);
1284 function getSiteDir($cmsPath, $str) {
1285 static $siteDir = '';
1291 $sites = CIVICRM_DIRECTORY_SEPARATOR
. 'sites' . CIVICRM_DIRECTORY_SEPARATOR
;
1292 $modules = CIVICRM_DIRECTORY_SEPARATOR
. 'modules' . CIVICRM_DIRECTORY_SEPARATOR
;
1293 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR
) .
1294 "([\-a-zA-Z0-9_.]+)" .
1295 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR
) . "/",
1296 $_SERVER['SCRIPT_FILENAME'], $matches
1298 $siteDir = isset($matches[1]) ?
$matches[1] : 'default';
1300 if (strtolower($siteDir) == 'all') {
1301 // For this case - use drupal's way of finding out multi-site directory
1302 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR
, $_SERVER['SCRIPT_FILENAME']);
1303 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1304 for ($i = count($uri) - 1; $i > 0; $i--) {
1305 for ($j = count($server); $j > 0; $j--) {
1306 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1307 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
1308 'sites' . CIVICRM_DIRECTORY_SEPARATOR
. $dir
1315 $siteDir = 'default';
1321 function errorDisplayPage($errorTitle, $errorMsg) {
1322 include ('error.html');