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);
61 global $installDirPath;
62 global $installURLPath;
63 if ($installType == 'drupal') {
64 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
65 $installDirPath = $installURLPath = '';
67 elseif ($installType == 'wordpress') {
68 $crmPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
;
69 $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 set_include_path(get_include_path() . PATH_SEPARATOR
. $crmPath);
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'])
88 $errorTitle = "Oops! Please Correct Your Install Location";
89 $errorMsg = "Please untar (uncompress) your downloaded copy of CiviCRM in the <strong>" . implode(CIVICRM_DIRECTORY_SEPARATOR
, array(
90 'sites', 'all', 'modules')) . "</strong> directory below your Drupal root directory. Refer to the online " . $docLink . " for more information.";
91 errorDisplayPage($errorTitle, $errorMsg);
95 // Load civicrm database config
96 if (isset($_REQUEST['mysql'])) {
97 $databaseConfig = $_REQUEST['mysql'];
100 $databaseConfig = array(
101 "server" => "localhost",
102 "username" => "civicrm",
104 "database" => "civicrm",
108 if ($installType == 'drupal') {
109 // Load drupal database config
110 if (isset($_REQUEST['drupal'])) {
111 $drupalConfig = $_REQUEST['drupal'];
114 $drupalConfig = array(
115 "server" => "localhost",
116 "username" => "drupal",
118 "database" => "drupal",
124 if (isset($_REQUEST['loadGenerated'])) {
128 require_once dirname(__FILE__
) . CIVICRM_DIRECTORY_SEPARATOR
. 'langs.php';
129 foreach ($langs as $locale => $_) {
130 if ($locale == 'en_US') {
133 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR
, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
134 unset($langs[$locale]);
138 $seedLanguage = 'en_US';
139 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
140 $seedLanguage = $_REQUEST['seedLanguage'];
144 if ($installType == 'drupal') {
145 //CRM-6840 -don't force to install in sites/all/modules/
146 $object = new CRM_Utils_System_Drupal();
147 $cmsPath = $object->cmsRootPath();
149 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
150 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
151 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
152 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
153 'civicrm.settings.php'
156 elseif ($installType == 'wordpress') {
157 $cmsPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm';
158 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
159 'civicrm.settings.php'
163 // Exit with error if CiviCRM has already been installed.
164 if ($alreadyInstalled) {
165 $errorTitle = "Oops! CiviCRM is Already Installed";
166 if ($installType == 'drupal') {
168 $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(
169 '[your Drupal root directory]', 'sites', $siteDir)) . "</strong>.</li><li>To <strong>upgrade an existing installation</strong>, refer to the online " . $docLink . ".</li></ul>";
171 elseif ($installType == 'wordpress') {
172 $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>";
174 errorDisplayPage($errorTitle, $errorMsg);
177 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'civicrm-version.php';
178 if (file_exists($versionFile)) {
179 require_once $versionFile;
180 $civicrm_version = civicrmVersion();
183 $civicrm_version = 'unknown';
186 if ($installType == 'drupal') {
187 // Ensure that they have downloaded the correct version of CiviCRM
188 if ($civicrm_version['cms'] != 'Drupal' &&
189 $civicrm_version['cms'] != 'Drupal6'
191 $errorTitle = "Oops! Incorrect CiviCRM Version";
192 $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!";
193 errorDisplayPage($errorTitle, $errorMsg);
196 define('DRUPAL_ROOT', $cmsPath);
197 $drupalVersionFiles = array(
199 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'modules', 'system', 'system.module')),
201 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'includes', 'bootstrap.inc')),
203 foreach ($drupalVersionFiles as $drupalVersionFile) {
204 if (file_exists($drupalVersionFile)) {
205 require_once $drupalVersionFile;
209 if (!defined('VERSION') or version_compare(VERSION
, '6.0') < 0) {
210 $errorTitle = "Oops! Incorrect Drupal Version";
211 $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.";
212 errorDisplayPage($errorTitle, $errorMsg);
215 elseif ($installType == 'wordpress') {
217 $civicrm_version['cms'] = 'WordPress';
219 // Ensure that they have downloaded the correct version of CiviCRM
220 if ($civicrm_version['cms'] != 'WordPress') {
221 $errorTitle = "Oops! Incorrect CiviCRM Version";
222 $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!";
223 errorDisplayPage($errorTitle, $errorMsg);
227 // Check requirements
228 $req = new InstallRequirements();
231 if ($req->hasErrors()) {
232 $hasErrorOtherThanDatabase = TRUE;
235 if ($databaseConfig) {
236 $dbReq = new InstallRequirements();
237 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
238 if ($installType == 'drupal') {
239 $dbReq->checkdatabase($drupalConfig, 'Drupal');
244 if (isset($_REQUEST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
245 // Confirm before reinstalling
246 if (!isset($_REQUEST['force_reinstall']) && $alreadyInstalled) {
247 include $installDirPath . 'template.html';
250 $inst = new Installer();
251 $inst->install($_REQUEST);
254 // Show the config form
257 include $installDirPath . 'template.html';
261 * This class checks requirements
262 * Each of the requireXXX functions takes an argument which gives a user description of the test. It's an array
264 * $description[0] - The test catetgory
265 * $description[1] - The test title
266 * $description[2] - The test error to show, if it goes wrong
268 class InstallRequirements
{
269 var $errors, $warnings, $tests;
271 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
272 const MINIMUM_THREAD_STACK
= 192;
275 * Just check that the database configuration is okay
277 function checkdatabase($databaseConfig, $dbName) {
278 if ($this->requireFunction('mysql_connect',
282 "MySQL support not included in PHP.",
285 $this->requireMySQLServer($databaseConfig['server'],
287 "MySQL $dbName Configuration",
288 "Does the server exist",
289 "Can't find the a MySQL server on '$databaseConfig[server]'",
290 $databaseConfig['server'],
293 if ($this->requireMysqlConnection($databaseConfig['server'],
294 $databaseConfig['username'],
295 $databaseConfig['password'],
297 "MySQL $dbName Configuration",
298 "Are the access credentials correct",
299 "That username/password doesn't work",
302 @$this->requireMySQLVersion("5.1",
304 "MySQL $dbName Configuration",
305 "MySQL version at least 5.1",
306 "MySQL version 5.1 or higher is required, you only have ",
307 "MySQL " . mysql_get_server_info(),
310 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
311 $databaseConfig['username'],
312 $databaseConfig['password'],
314 "MySQL $dbName Configuration",
315 "Is auto_increment_increment set to 1",
316 "An auto_increment_increment value greater than 1 is not currently supported. Please see issue CRM-7923 for further details and potential workaround.",
319 $this->requireMySQLThreadStack($databaseConfig['server'],
320 $databaseConfig['username'],
321 $databaseConfig['password'],
322 $databaseConfig['database'],
323 self
::MINIMUM_THREAD_STACK
,
325 "MySQL $dbName Configuration",
326 "Does MySQL thread_stack meet minimum (" . self
::MINIMUM_THREAD_STACK
. "k)",
327 "", // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
331 $onlyRequire = ($dbName == 'Drupal') ?
TRUE : FALSE;
332 $this->requireDatabaseOrCreatePermissions(
333 $databaseConfig['server'],
334 $databaseConfig['username'],
335 $databaseConfig['password'],
336 $databaseConfig['database'],
338 "MySQL $dbName Configuration",
339 "Can I access/create the database",
340 "I can't create new databases and the database '$databaseConfig[database]' doesn't exist",
344 if ($dbName != 'Drupal') {
345 $this->requireMySQLInnoDB($databaseConfig['server'],
346 $databaseConfig['username'],
347 $databaseConfig['password'],
348 $databaseConfig['database'],
350 "MySQL $dbName Configuration",
351 "Can I access/create InnoDB tables in the database",
352 "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.",
355 $this->requireMySQLTempTables($databaseConfig['server'],
356 $databaseConfig['username'],
357 $databaseConfig['password'],
358 $databaseConfig['database'],
360 "MySQL $dbName Configuration",
361 'Can I create temporary tables in the database',
362 'Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.',
365 $this->requireMySQLLockTables($databaseConfig['server'],
366 $databaseConfig['username'],
367 $databaseConfig['password'],
368 $databaseConfig['database'],
370 "MySQL $dbName Configuration",
371 'Can I create lock tables in the database',
372 'Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.',
375 $this->requireMySQLTrigger($databaseConfig['server'],
376 $databaseConfig['username'],
377 $databaseConfig['password'],
378 $databaseConfig['database'],
380 "MySQL $dbName Configuration",
381 'Can I create triggers in the database',
382 'Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.',
390 * Check everything except the database
393 global $crmPath, $installType;
395 $this->errors
= NULL;
397 $this->requirePHPVersion('5.3.3', array("PHP Configuration", "PHP5 installed", NULL, "PHP version " . phpversion()));
399 // Check that we can identify the root folder successfully
400 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'README.txt',
403 "Does the webserver know where files are stored?",
404 "The webserver isn't letting me identify where files are stored.",
410 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
411 $this->requireNoPathSeparator(
414 'does the CiviCRM path contain PATH_SEPARATOR?',
415 'the ' . $this->getBaseDir() . ' path contains PATH_SEPARATOR (the ' . PATH_SEPARATOR
. ' character)',
420 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
421 foreach ($requiredDirectories as $dir) {
422 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. $dir,
424 "File permissions", "$dir folder exists", "There is no $dir folder"), TRUE
428 $configIDSiniDir = NULL;
430 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
431 if ($installType == 'drupal') {
433 // make sure that we can write to sites/default and files/
434 $writableDirectories = array(
435 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
436 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
437 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
439 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
440 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
444 elseif ($installType == 'wordpress') {
445 // make sure that we can write to plugins/civicrm and plugins/files/
446 $writableDirectories = array(WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'files', $cmsPath);
449 foreach ($writableDirectories as $dir) {
450 $dirName = CIVICRM_WINDOWS ?
$dir : CIVICRM_DIRECTORY_SEPARATOR
. $dir;
451 $this->requireWriteable($dirName,
452 array("File permissions", "Is the $dir folder writeable?", NULL),
457 //check for Config.IDS.ini, file may exist in re-install
458 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
460 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
461 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR
, $configIDSiniDir);
462 if (file_exists($configIDSiniFile)) {
463 unlink($configIDSiniFile);
467 // Check for rewriting
468 if (isset($_SERVER['SERVER_SOFTWARE'])) {
469 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
471 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
472 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
475 if ($webserver == '') {
476 $webserver = "I can't tell what webserver you are running";
479 // Check for $_SERVER configuration
480 $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."));
482 // Check for MySQL support
483 $this->requireFunction('mysql_connect',
484 array("PHP Configuration", "MySQL support", "MySQL support not included in PHP.")
487 // Check for JSON support
488 $this->requireFunction('json_encode',
489 array("PHP Configuration", "JSON support", "JSON support not included in PHP.")
492 // Check for xcache_isset and emit warning if exists
493 $this->checkXCache(array(
495 "XCache compatibility",
496 "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.",
499 // Check memory allocation
500 $this->requireMemory(32 * 1024 * 1024,
504 "Memory allocated (PHP config option 'memory_limit')",
505 "CiviCRM needs a minimum of 32M allocated to PHP, but recommends 64M.",
506 ini_get("memory_limit"),
510 return $this->errors
;
515 * @param $recommended
516 * @param $testDetails
518 function requireMemory($min, $recommended, $testDetails) {
519 $this->testing($testDetails);
520 $mem = $this->getPHPMemory();
522 if ($mem < $min && $mem > 0) {
523 $testDetails[2] .= " You only have " . ini_get("memory_limit") . " allocated";
524 $this->error($testDetails);
526 elseif ($mem < $recommended && $mem > 0) {
527 $testDetails[2] .= " You only have " . ini_get("memory_limit") . " allocated";
528 $this->warning($testDetails);
531 $testDetails[2] .= " We can't determine how much memory you have allocated. Install only if you're sure you've allocated at least 20 MB.";
532 $this->warning($testDetails);
539 function getPHPMemory() {
540 $memString = ini_get("memory_limit");
542 switch (strtolower(substr($memString, -1))) {
544 return round(substr($memString, 0, -1) * 1024);
547 return round(substr($memString, 0, -1) * 1024 * 1024);
550 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
553 return round($memString);
557 function listErrors() {
559 echo "<p>The following problems are preventing me from installing CiviCRM:</p>";
560 foreach ($this->errors
as $error) {
561 echo "<li>" . htmlentities($error) . "</li>";
567 * @param null $section
569 function showTable($section = NULL) {
571 $tests = $this->tests
[$section];
572 echo "<table class=\"testResults\" width=\"100%\">";
573 foreach ($tests as $test => $result) {
574 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
579 foreach ($this->tests
as $section => $tests) {
580 echo "<h3>$section</h3>";
581 echo "<table class=\"testResults\" width=\"100%\">";
583 foreach ($tests as $test => $result) {
584 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
592 * @param string $funcName
593 * @param $testDetails
597 function requireFunction($funcName, $testDetails) {
598 $this->testing($testDetails);
600 if (!function_exists($funcName)) {
601 $this->error($testDetails);
610 * @param $testDetails
612 function checkXCache($testDetails) {
613 if (function_exists('xcache_isset') &&
614 ini_get('xcache.size') > 0
616 $this->testing($testDetails);
617 $this->warning($testDetails);
623 * @param $testDetails
624 * @param null $maxVersion
626 function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
628 $this->testing($testDetails);
630 $phpVersion = phpversion();
631 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
632 $belowMaxVersion = $maxVersion ?
version_compare($phpVersion, $maxVersion) < 0 : TRUE;
634 if ($maxVersion && $aboveMinVersion && $belowMaxVersion) {
637 elseif (!$maxVersion && $aboveMinVersion) {
641 if (!$testDetails[2]) {
642 if (!$aboveMinVersion) {
643 $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.";
646 $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.";
650 $this->error($testDetails);
654 * @param string $filename
655 * @param $testDetails
656 * @param bool $absolute
658 function requireFile($filename, $testDetails, $absolute = FALSE) {
659 $this->testing($testDetails);
661 $filename = $this->getBaseDir() . $filename;
663 if (!file_exists($filename)) {
664 $testDetails[2] .= " (file '$filename' not found)";
665 $this->error($testDetails);
670 * @param $testDetails
672 function requireNoPathSeparator($testDetails) {
673 $this->testing($testDetails);
674 if (substr_count($this->getBaseDir(), PATH_SEPARATOR
)) {
675 $this->error($testDetails);
680 * @param string $filename
681 * @param $testDetails
683 function requireNoFile($filename, $testDetails) {
684 $this->testing($testDetails);
685 $filename = $this->getBaseDir() . $filename;
686 if (file_exists($filename)) {
687 $testDetails[2] .= " (file '$filename' found)";
688 $this->error($testDetails);
693 * @param string $filename
694 * @param $testDetails
696 function moveFileOutOfTheWay($filename, $testDetails) {
697 $this->testing($testDetails);
698 $filename = $this->getBaseDir() . $filename;
699 if (file_exists($filename)) {
700 if (file_exists("$filename.bak")) {
703 rename($filename, "$filename.bak");
708 * @param string $filename
709 * @param $testDetails
710 * @param bool $absolute
712 function requireWriteable($filename, $testDetails, $absolute = FALSE) {
713 $this->testing($testDetails);
715 $filename = $this->getBaseDir() . $filename;
718 if (!is_writable($filename)) {
720 if (function_exists('posix_getpwuid')) {
721 $user = posix_getpwuid(posix_geteuid());
722 $name = '- ' . $user['name'] . ' -';
725 if (!isset($testDetails[2])) {
726 $testDetails[2] = NULL;
728 $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";
729 $this->error($testDetails);
734 * @param string $moduleName
735 * @param $testDetails
737 function requireApacheModule($moduleName, $testDetails) {
738 $this->testing($testDetails);
739 if (!in_array($moduleName, apache_get_modules())) {
740 $this->error($testDetails);
746 * @param string $username
748 * @param $testDetails
750 function requireMysqlConnection($server, $username, $password, $testDetails) {
751 $this->testing($testDetails);
752 $conn = @mysql_connect
($server, $username, $password);
758 $testDetails[2] .= ": " . mysql_error();
759 $this->error($testDetails);
765 * @param $testDetails
767 function requireMySQLServer($server, $testDetails) {
768 $this->testing($testDetails);
769 $conn = @mysql_connect
($server, NULL, NULL);
771 if ($conn ||
mysql_errno() < 2000) {
775 $testDetails[2] .= ": " . mysql_error();
776 $this->error($testDetails);
782 * @param $testDetails
784 function requireMySQLVersion($version, $testDetails) {
785 $this->testing($testDetails);
787 if (!mysql_get_server_info()) {
788 $testDetails[2] = 'Cannot determine the version of MySQL installed. Please ensure at least version 4.1 is installed.';
789 $this->warning($testDetails);
792 list($majorRequested, $minorRequested) = explode('.', $version);
793 list($majorHas, $minorHas) = explode('.', mysql_get_server_info());
795 if (($majorHas > $majorRequested) ||
($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
799 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
800 $this->error($testDetails);
807 * @param string $username
810 * @param $testDetails
812 function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
813 $this->testing($testDetails);
814 $conn = @mysql_connect
($server, $username, $password);
816 $testDetails[2] .= ' Could not determine if mysql has innodb support. Assuming no';
817 $this->error($testDetails);
821 $innodb_support = FALSE;
822 $result = mysql_query("SHOW ENGINES", $conn);
823 while ($values = mysql_fetch_array($result)) {
824 if ($values['Engine'] == 'InnoDB') {
825 if (strtolower($values['Support']) == 'yes' ||
826 strtolower($values['Support']) == 'default'
828 $innodb_support = TRUE;
832 if ($innodb_support) {
833 $testDetails[3] = 'MySQL server does have innodb support';
836 $testDetails[2] .= ' Could not determine if mysql has innodb support. Assuming no';
842 * @param string $username
845 * @param $testDetails
847 function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
848 $this->testing($testDetails);
849 $conn = @mysql_connect
($server, $username, $password);
851 $testDetails[2] = 'Could not login to the database.';
852 $this->error($testDetails);
856 if (!@mysql_select_db
($database, $conn)) {
857 $testDetails[2] = 'Could not select the database.';
858 $this->error($testDetails);
862 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
864 $testDetails[2] = 'Could not create a temp table.';
865 $this->error($testDetails);
867 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
872 * @param string $username
875 * @param $testDetails
877 function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
878 $this->testing($testDetails);
879 $conn = @mysql_connect
($server, $username, $password);
881 $testDetails[2] = 'Could not login to the database.';
882 $this->error($testDetails);
886 if (!@mysql_select_db
($database, $conn)) {
887 $testDetails[2] = 'Could not select the database.';
888 $this->error($testDetails);
892 $result = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
894 $testDetails[2] = 'Could not create a table.';
895 $this->error($testDetails);
898 $result = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
900 mysql_query('DROP TABLE civicrm_install_temp_table_test');
901 $testDetails[2] = 'Could not create a trigger.';
902 $this->error($testDetails);
905 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
906 mysql_query('DROP TABLE civicrm_install_temp_table_test');
912 * @param string $username
915 * @param $testDetails
917 function requireMySQLLockTables($server, $username, $password, $database, $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('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
934 $testDetails[2] = 'Could not create a table.';
935 $this->error($testDetails);
939 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
941 $testDetails[2] = 'Could not obtain a write lock for the table.';
942 $this->error($testDetails);
943 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
947 $result = mysql_query('UNLOCK TABLES', $conn);
949 $testDetails[2] = 'Could not release the lock for the table.';
950 $this->error($testDetails);
951 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
955 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
961 * @param string $username
963 * @param $testDetails
965 function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
966 $this->testing($testDetails);
967 $conn = @mysql_connect
($server, $username, $password);
969 $testDetails[2] = 'Could not connect to the database server.';
970 $this->error($testDetails);
974 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
976 $testDetails[2] = 'Could not query database server variables.';
977 $this->error($testDetails);
981 $values = mysql_fetch_row($result);
982 if ($values[1] == 1) {
983 $testDetails[3] = 'MySQL server auto_increment_increment is 1';
986 $this->error($testDetails);
993 * @param string $username
997 * @param $testDetails
999 function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
1000 $this->testing($testDetails);
1001 $conn = @mysql_connect
($server, $username, $password);
1003 $testDetails[2] = 'Could not login to the database.';
1004 $this->error($testDetails);
1008 if (!@mysql_select_db
($database, $conn)) {
1009 $testDetails[2] = 'Could not select the database.';
1010 $this->error($testDetails);
1014 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
1016 $testDetails[2] = 'Could not query thread_stack.';
1017 $this->error($testDetails);
1020 $values = mysql_fetch_row($result);
1021 if ($values[1] < (1024 * $minValueKB)) {
1022 $testDetails[2] = 'MySQL "thread_stack" is ' . ($values[1] / 1024) . 'k';
1023 $this->error($testDetails);
1030 * @param string $username
1033 * @param $testDetails
1034 * @param bool $onlyRequire
1036 function requireDatabaseOrCreatePermissions($server,
1041 $onlyRequire = FALSE
1043 $this->testing($testDetails);
1044 $conn = @mysql_connect
($server, $username, $password);
1047 if (@mysql_select_db
($database)) {
1048 $okay = "Database '$database' exists";
1050 elseif ($onlyRequire) {
1051 $testDetails[2] = "The database: '$database' does not exist";
1052 $this->error($testDetails);
1056 if (@mysql_query
("CREATE DATABASE $database")) {
1057 $okay = "Able to create a new database";
1060 $testDetails[2] .= " (user '$username' doesn't have CREATE DATABASE permissions.)";
1061 $this->error($testDetails);
1067 $testDetails[3] = $okay;
1068 $this->testing($testDetails);
1074 * @param $errorMessage
1076 function requireServerVariables($varNames, $errorMessage) {
1077 //$this->testing($testDetails);
1078 foreach ($varNames as $varName) {
1079 if (!$_SERVER[$varName]) {
1080 $missing[] = '$_SERVER[' . $varName . ']';
1083 if (!isset($missing)) {
1087 $testDetails[2] = " (the following PHP variables are missing: " . implode(", ", $missing) . ")";
1088 $this->error($testDetails);
1093 * @param $testDetails
1097 function isRunningApache($testDetails) {
1098 $this->testing($testDetails);
1099 if (function_exists('apache_get_modules') ||
stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1103 $this->warning($testDetails);
1110 function getBaseDir() {
1111 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR
;
1115 * @param $testDetails
1117 function testing($testDetails) {
1118 if (!$testDetails) {
1122 $section = $testDetails[0];
1123 $test = $testDetails[1];
1126 if (isset($testDetails[3])) {
1127 $message .= " ($testDetails[3])";
1130 $this->tests
[$section][$test] = array("good", $message);
1134 * @param $testDetails
1136 function error($testDetails) {
1137 $section = $testDetails[0];
1138 $test = $testDetails[1];
1140 $this->tests
[$section][$test] = array("error", $testDetails[2]);
1141 $this->errors
[] = $testDetails;
1145 * @param $testDetails
1147 function warning($testDetails) {
1148 $section = $testDetails[0];
1149 $test = $testDetails[1];
1151 $this->tests
[$section][$test] = array("warning", $testDetails[2]);
1152 $this->warnings
[] = $testDetails;
1158 function hasErrors() {
1159 return sizeof($this->errors
);
1165 function hasWarnings() {
1166 return sizeof($this->warnings
);
1173 class Installer
extends InstallRequirements
{
1180 function createDatabaseIfNotExists($server, $username, $password, $database) {
1181 $conn = @mysql_connect
($server, $username, $password);
1183 if (@mysql_select_db
($database)) {
1184 // skip if database already present
1188 if (@mysql_query
("CREATE DATABASE $database")) {}
1190 $errorTitle = "Oops! Could not create Database $database";
1191 $errorMsg = "We encountered an error when attempting to create the database. Please check your mysql server permissions and the database name and try again.";
1192 errorDisplayPage($errorTitle, $errorMsg);
1201 function install($config) {
1202 global $installDirPath;
1204 // create database if does not exists
1205 $this->createDatabaseIfNotExists($config['mysql']['server'],
1206 $config['mysql']['username'],
1207 $config['mysql']['password'],
1208 $config['mysql']['database']
1211 global $installDirPath;
1214 require_once $installDirPath . 'civicrm.php';
1215 civicrm_main($config);
1217 if (!$this->errors
) {
1218 global $installType, $installURLPath;
1220 $registerSiteURL = "https://civicrm.org/register-site";
1221 $commonOutputMessage = "
1222 <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>
1223 <li>We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.</li>
1228 $installType == 'drupal' &&
1229 version_compare(VERSION
, '7.0-rc1') >= 0
1235 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1236 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1237 $output .= '<head>';
1238 $output .= '<title>CiviCRM Installed</title>';
1239 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1240 $output .= '</head>';
1241 $output .= '<body>';
1242 $output .= '<div style="padding: 1em;"><p class="good">CiviCRM has been successfully installed</p>';
1244 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1245 if (!function_exists('ts')) {
1246 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1248 $drupalURL = civicrm_cms_base();
1249 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1250 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1252 $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>
1253 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1254 {$commonOutputMessage}";
1256 // automatically enable CiviCRM module once it is installed successfully.
1257 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1258 global $cmsPath, $crmPath;
1260 // relative / abosolute paths are not working for drupal, hence using chdir()
1263 include_once "./includes/bootstrap.inc";
1264 include_once "./includes/unicode.inc";
1266 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1268 // prevent session information from being saved.
1269 drupal_save_session(FALSE);
1271 // Force the current user to anonymous.
1272 $original_user = $GLOBALS['user'];
1273 $GLOBALS['user'] = drupal_anonymous_user();
1275 // explicitly setting error reporting, since we cannot handle drupal related notices
1278 // rebuild modules, so that civicrm is added
1279 system_rebuild_module_data();
1281 // now enable civicrm module.
1282 module_enable(array('civicrm', 'civicrmtheme'));
1284 // clear block, page, theme, and hook caches
1285 drupal_flush_all_caches();
1287 //add basic drupal permissions
1288 civicrm_install_set_drupal_perms();
1290 // restore the user.
1291 $GLOBALS['user'] = $original_user;
1292 drupal_save_session(TRUE);
1295 $output .= '</div>';
1296 $output .= '</body>';
1297 $output .= '</html>';
1300 elseif ($installType == 'drupal' && version_compare(VERSION
, '6.0') >= 0) {
1304 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1305 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1306 $output .= '<head>';
1307 $output .= '<title>CiviCRM Installed</title>';
1308 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1309 $output .= '</head>';
1310 $output .= '<body>';
1311 $output .= '<div style="padding: 1em;"><p class="good">CiviCRM has been successfully installed</p>';
1313 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1314 if (!function_exists('ts')) {
1315 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1317 $drupalURL = civicrm_cms_base();
1318 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1319 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1321 $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>
1322 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1323 {$commonOutputMessage}";
1325 // explicitly setting error reporting, since we cannot handle drupal related notices
1328 // automatically enable CiviCRM module once it is installed successfully.
1329 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1330 global $cmsPath, $crmPath;
1332 // relative / abosolute paths are not working for drupal, hence using chdir()
1335 include_once "./includes/bootstrap.inc";
1336 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1338 // rebuild modules, so that civicrm is added
1339 module_rebuild_cache();
1341 // now enable civicrm module.
1342 module_enable(array('civicrm'));
1344 // clear block, page, theme, and hook caches
1345 drupal_flush_all_caches();
1347 //add basic drupal permissions
1348 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)');
1352 elseif ($installType == 'wordpress') {
1353 echo '<h1>CiviCRM Installed</h1>';
1354 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">CiviCRM has been successfully installed</p>';
1356 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1357 if (!function_exists('ts')) {
1358 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1361 $cmsURL = civicrm_cms_base();
1362 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1363 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1366 <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>
1367 <li>Use the <a target='_blank' href=\"$cmsURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1368 {$commonOutputMessage}
1376 return $this->errors
;
1380 function civicrm_install_set_drupal_perms() {
1381 if (!function_exists('db_select')) {
1382 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)');
1386 'access all custom data',
1387 'access uploaded files',
1388 'make online contributions',
1392 'register for events',
1394 'view event participants',
1395 'access CiviMail subscribe/unsubscribe pages',
1398 // Adding a permission that has not yet been assigned to a module by
1399 // a hook_permission implementation results in a database error.
1401 $allPerms = array_keys(module_invoke_all('permission'));
1402 foreach (array_diff($perms, $allPerms) as $perm) {
1404 'Cannot grant the %perm permission because it does not yet exist.',
1406 '%perm' => $perm), WATCHDOG_ERROR
1409 $perms = array_intersect($perms, $allPerms);
1410 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID
, $perms);
1411 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID
, $perms);
1421 function getSiteDir($cmsPath, $str) {
1422 static $siteDir = '';
1428 $sites = CIVICRM_DIRECTORY_SEPARATOR
. 'sites' . CIVICRM_DIRECTORY_SEPARATOR
;
1429 $modules = CIVICRM_DIRECTORY_SEPARATOR
. 'modules' . CIVICRM_DIRECTORY_SEPARATOR
;
1430 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR
) .
1431 "([\-a-zA-Z0-9_.]+)" .
1432 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR
) . "/",
1433 $_SERVER['SCRIPT_FILENAME'], $matches
1435 $siteDir = isset($matches[1]) ?
$matches[1] : 'default';
1437 if (strtolower($siteDir) == 'all') {
1438 // For this case - use drupal's way of finding out multi-site directory
1439 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR
, $_SERVER['SCRIPT_FILENAME']);
1440 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1441 for ($i = count($uri) - 1; $i > 0; $i--) {
1442 for ($j = count($server); $j > 0; $j--) {
1443 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1444 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
1445 'sites' . CIVICRM_DIRECTORY_SEPARATOR
. $dir
1452 $siteDir = 'default';
1459 * @param $errorTitle
1462 function errorDisplayPage($errorTitle, $errorMsg) {
1463 include 'error.html';