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(
58 $errorTitle = "Oops! Unsupported installation mode";
60 errorDisplayPage($errorTitle, $errorMsg);
64 global $installDirPath;
65 global $installURLPath;
66 if ($installType == 'drupal') {
67 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
68 $installDirPath = $installURLPath = '';
70 elseif ($installType == 'wordpress') {
71 $crmPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
;
72 $installDirPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
74 $installURLPath = WP_PLUGIN_URL
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
77 set_include_path(get_include_path() . PATH_SEPARATOR
. $crmPath);
79 require_once $crmPath . '/CRM/Core/ClassLoader.php';
80 CRM_Core_ClassLoader
::singleton()->register();
82 $docLink = CRM_Utils_System
::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
84 if ($installType == 'drupal') {
85 //lets check only /modules/.
86 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR
. 'modules', CIVICRM_DIRECTORY_SEPARATOR
) . '/';
88 if (!preg_match($pattern,
89 str_replace("\\", "/", $_SERVER['SCRIPT_FILENAME'])
92 $errorTitle = "Oops! Please Correct Your Install Location";
93 $errorMsg = "Please untar (uncompress) your downloaded copy of CiviCRM in the <strong>" . implode(CIVICRM_DIRECTORY_SEPARATOR
, array(
97 )) . "</strong> directory below your Drupal root directory. Refer to the online " . $docLink . " for more information.";
98 errorDisplayPage($errorTitle, $errorMsg);
102 // Load civicrm database config
103 if (isset($_REQUEST['mysql'])) {
104 $databaseConfig = $_REQUEST['mysql'];
107 $databaseConfig = array(
108 "server" => "localhost",
109 "username" => "civicrm",
111 "database" => "civicrm",
115 if ($installType == 'drupal') {
116 // Load drupal database config
117 if (isset($_REQUEST['drupal'])) {
118 $drupalConfig = $_REQUEST['drupal'];
121 $drupalConfig = array(
122 "server" => "localhost",
123 "username" => "drupal",
125 "database" => "drupal",
131 if (isset($_REQUEST['loadGenerated'])) {
135 require_once dirname(__FILE__
) . CIVICRM_DIRECTORY_SEPARATOR
. 'langs.php';
136 foreach ($langs as $locale => $_) {
137 if ($locale == 'en_US') {
140 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR
, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
141 unset($langs[$locale]);
145 $seedLanguage = 'en_US';
146 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
147 $seedLanguage = $_REQUEST['seedLanguage'];
151 if ($installType == 'drupal') {
152 //CRM-6840 -don't force to install in sites/all/modules/
153 $object = new CRM_Utils_System_Drupal();
154 $cmsPath = $object->cmsRootPath();
156 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
157 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
158 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
159 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
160 'civicrm.settings.php'
163 elseif ($installType == 'wordpress') {
164 $cmsPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm';
165 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
166 'civicrm.settings.php'
170 // Exit with error if CiviCRM has already been installed.
171 if ($alreadyInstalled) {
172 $errorTitle = "Oops! CiviCRM is Already Installed";
173 if ($installType == 'drupal') {
175 $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(
176 '[your Drupal root directory]',
179 )) . "</strong>.</li><li>To <strong>upgrade an existing installation</strong>, refer to the online " . $docLink . ".</li></ul>";
181 elseif ($installType == 'wordpress') {
182 $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>";
184 errorDisplayPage($errorTitle, $errorMsg);
187 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'civicrm-version.php';
188 if (file_exists($versionFile)) {
189 require_once $versionFile;
190 $civicrm_version = civicrmVersion();
193 $civicrm_version = 'unknown';
196 if ($installType == 'drupal') {
197 // Ensure that they have downloaded the correct version of CiviCRM
198 if ($civicrm_version['cms'] != 'Drupal' &&
199 $civicrm_version['cms'] != 'Drupal6'
201 $errorTitle = "Oops! Incorrect CiviCRM Version";
202 $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!";
203 errorDisplayPage($errorTitle, $errorMsg);
206 define('DRUPAL_ROOT', $cmsPath);
207 $drupalVersionFiles = array(
209 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'modules', 'system', 'system.module')),
211 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'includes', 'bootstrap.inc')),
213 foreach ($drupalVersionFiles as $drupalVersionFile) {
214 if (file_exists($drupalVersionFile)) {
215 require_once $drupalVersionFile;
219 if (!defined('VERSION') or version_compare(VERSION
, '6.0') < 0) {
220 $errorTitle = "Oops! Incorrect Drupal Version";
221 $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.";
222 errorDisplayPage($errorTitle, $errorMsg);
225 elseif ($installType == 'wordpress') {
227 $civicrm_version['cms'] = 'WordPress';
229 // Ensure that they have downloaded the correct version of CiviCRM
230 if ($civicrm_version['cms'] != 'WordPress') {
231 $errorTitle = "Oops! Incorrect CiviCRM Version";
232 $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!";
233 errorDisplayPage($errorTitle, $errorMsg);
237 // Check requirements
238 $req = new InstallRequirements();
241 if ($req->hasErrors()) {
242 $hasErrorOtherThanDatabase = TRUE;
245 if ($databaseConfig) {
246 $dbReq = new InstallRequirements();
247 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
248 if ($installType == 'drupal') {
249 $dbReq->checkdatabase($drupalConfig, 'Drupal');
254 if (isset($_REQUEST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
255 // Confirm before reinstalling
256 if (!isset($_REQUEST['force_reinstall']) && $alreadyInstalled) {
257 include $installDirPath . 'template.html';
260 $inst = new Installer();
261 $inst->install($_REQUEST);
264 // Show the config form
267 include $installDirPath . 'template.html';
271 * This class checks requirements
272 * Each of the requireXXX functions takes an argument which gives a user description of the test. It's an array
274 * $description[0] - The test catetgory
275 * $description[1] - The test title
276 * $description[2] - The test error to show, if it goes wrong
278 class InstallRequirements
{
279 var $errors, $warnings, $tests;
281 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
282 const MINIMUM_THREAD_STACK
= 192;
285 * Just check that the database configuration is okay
286 * @param $databaseConfig
289 function checkdatabase($databaseConfig, $dbName) {
290 if ($this->requireFunction('mysql_connect',
294 "MySQL support not included in PHP.",
298 $this->requireMySQLServer($databaseConfig['server'],
300 "MySQL $dbName Configuration",
301 "Does the server exist",
302 "Can't find the a MySQL server on '$databaseConfig[server]'",
303 $databaseConfig['server'],
306 if ($this->requireMysqlConnection($databaseConfig['server'],
307 $databaseConfig['username'],
308 $databaseConfig['password'],
310 "MySQL $dbName Configuration",
311 "Are the access credentials correct",
312 "That username/password doesn't work",
316 @$this->requireMySQLVersion("5.1",
318 "MySQL $dbName Configuration",
319 "MySQL version at least 5.1",
320 "MySQL version 5.1 or higher is required, you only have ",
321 "MySQL " . mysql_get_server_info(),
324 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
325 $databaseConfig['username'],
326 $databaseConfig['password'],
328 "MySQL $dbName Configuration",
329 "Is auto_increment_increment set to 1",
330 "An auto_increment_increment value greater than 1 is not currently supported. Please see issue CRM-7923 for further details and potential workaround.",
333 $this->requireMySQLThreadStack($databaseConfig['server'],
334 $databaseConfig['username'],
335 $databaseConfig['password'],
336 $databaseConfig['database'],
337 self
::MINIMUM_THREAD_STACK
,
339 "MySQL $dbName Configuration",
340 "Does MySQL thread_stack meet minimum (" . self
::MINIMUM_THREAD_STACK
. "k)",
342 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
346 $onlyRequire = ($dbName == 'Drupal') ?
TRUE : FALSE;
347 $this->requireDatabaseOrCreatePermissions(
348 $databaseConfig['server'],
349 $databaseConfig['username'],
350 $databaseConfig['password'],
351 $databaseConfig['database'],
353 "MySQL $dbName Configuration",
354 "Can I access/create the database",
355 "I can't create new databases and the database '$databaseConfig[database]' doesn't exist",
359 if ($dbName != 'Drupal') {
360 $this->requireMySQLInnoDB($databaseConfig['server'],
361 $databaseConfig['username'],
362 $databaseConfig['password'],
363 $databaseConfig['database'],
365 "MySQL $dbName Configuration",
366 "Can I access/create InnoDB tables in the database",
367 "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.",
370 $this->requireMySQLTempTables($databaseConfig['server'],
371 $databaseConfig['username'],
372 $databaseConfig['password'],
373 $databaseConfig['database'],
375 "MySQL $dbName Configuration",
376 'Can I create temporary tables in the database',
377 'Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.',
380 $this->requireMySQLLockTables($databaseConfig['server'],
381 $databaseConfig['username'],
382 $databaseConfig['password'],
383 $databaseConfig['database'],
385 "MySQL $dbName Configuration",
386 'Can I create lock tables in the database',
387 'Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.',
390 $this->requireMySQLTrigger($databaseConfig['server'],
391 $databaseConfig['username'],
392 $databaseConfig['password'],
393 $databaseConfig['database'],
395 "MySQL $dbName Configuration",
396 'Can I create triggers in the database',
397 'Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.',
405 * Check everything except the database
408 global $crmPath, $installType;
410 $this->errors
= NULL;
412 $this->requirePHPVersion('5.3.3', array(
416 "PHP version " . phpversion()
419 // Check that we can identify the root folder successfully
420 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'README.txt',
423 "Does the webserver know where files are stored?",
424 "The webserver isn't letting me identify where files are stored.",
430 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
431 $this->requireNoPathSeparator(
434 'does the CiviCRM path contain PATH_SEPARATOR?',
435 'the ' . $this->getBaseDir() . ' path contains PATH_SEPARATOR (the ' . PATH_SEPARATOR
. ' character)',
440 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
441 foreach ($requiredDirectories as $dir) {
442 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. $dir,
445 "$dir folder exists",
446 "There is no $dir folder"
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("File permissions", "Is the $dir folder writeable?", 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 = "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(
505 "Recognised webserver",
506 "You seem to be using an unsupported webserver. The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."
509 // Check for MySQL support
510 $this->requireFunction('mysql_connect',
511 array("PHP Configuration", "MySQL support", "MySQL support not included in PHP.")
514 // Check for JSON support
515 $this->requireFunction('json_encode',
516 array("PHP Configuration", "JSON support", "JSON support not included in PHP.")
519 // Check for xcache_isset and emit warning if exists
520 $this->checkXCache(array(
522 "XCache compatibility",
523 "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.",
526 // Check memory allocation
527 $this->requireMemory(32 * 1024 * 1024,
531 "Memory allocated (PHP config option 'memory_limit')",
532 "CiviCRM needs a minimum of 32M allocated to PHP, but recommends 64M.",
533 ini_get("memory_limit"),
537 return $this->errors
;
542 * @param $recommended
543 * @param $testDetails
545 function requireMemory($min, $recommended, $testDetails) {
546 $this->testing($testDetails);
547 $mem = $this->getPHPMemory();
549 if ($mem < $min && $mem > 0) {
550 $testDetails[2] .= " You only have " . ini_get("memory_limit") . " allocated";
551 $this->error($testDetails);
553 elseif ($mem < $recommended && $mem > 0) {
554 $testDetails[2] .= " You only have " . ini_get("memory_limit") . " allocated";
555 $this->warning($testDetails);
558 $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.";
559 $this->warning($testDetails);
566 function getPHPMemory() {
567 $memString = ini_get("memory_limit");
569 switch (strtolower(substr($memString, -1))) {
571 return round(substr($memString, 0, -1) * 1024);
574 return round(substr($memString, 0, -1) * 1024 * 1024);
577 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
580 return round($memString);
584 function listErrors() {
586 echo "<p>The following problems are preventing me from installing CiviCRM:</p>";
587 foreach ($this->errors
as $error) {
588 echo "<li>" . htmlentities($error) . "</li>";
594 * @param null $section
596 function showTable($section = NULL) {
598 $tests = $this->tests
[$section];
599 echo "<table class=\"testResults\" width=\"100%\">";
600 foreach ($tests as $test => $result) {
601 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
606 foreach ($this->tests
as $section => $tests) {
607 echo "<h3>$section</h3>";
608 echo "<table class=\"testResults\" width=\"100%\">";
610 foreach ($tests as $test => $result) {
611 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
619 * @param string $funcName
620 * @param $testDetails
624 function requireFunction($funcName, $testDetails) {
625 $this->testing($testDetails);
627 if (!function_exists($funcName)) {
628 $this->error($testDetails);
637 * @param $testDetails
639 function checkXCache($testDetails) {
640 if (function_exists('xcache_isset') &&
641 ini_get('xcache.size') > 0
643 $this->testing($testDetails);
644 $this->warning($testDetails);
650 * @param $testDetails
651 * @param null $maxVersion
653 function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
655 $this->testing($testDetails);
657 $phpVersion = phpversion();
658 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
659 $belowMaxVersion = $maxVersion ?
version_compare($phpVersion, $maxVersion) < 0 : TRUE;
661 if ($maxVersion && $aboveMinVersion && $belowMaxVersion) {
664 elseif (!$maxVersion && $aboveMinVersion) {
668 if (!$testDetails[2]) {
669 if (!$aboveMinVersion) {
670 $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.";
673 $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.";
677 $this->error($testDetails);
681 * @param string $filename
682 * @param $testDetails
683 * @param bool $absolute
685 function requireFile($filename, $testDetails, $absolute = FALSE) {
686 $this->testing($testDetails);
688 $filename = $this->getBaseDir() . $filename;
690 if (!file_exists($filename)) {
691 $testDetails[2] .= " (file '$filename' not found)";
692 $this->error($testDetails);
697 * @param $testDetails
699 function requireNoPathSeparator($testDetails) {
700 $this->testing($testDetails);
701 if (substr_count($this->getBaseDir(), PATH_SEPARATOR
)) {
702 $this->error($testDetails);
707 * @param string $filename
708 * @param $testDetails
710 function requireNoFile($filename, $testDetails) {
711 $this->testing($testDetails);
712 $filename = $this->getBaseDir() . $filename;
713 if (file_exists($filename)) {
714 $testDetails[2] .= " (file '$filename' found)";
715 $this->error($testDetails);
720 * @param string $filename
721 * @param $testDetails
723 function moveFileOutOfTheWay($filename, $testDetails) {
724 $this->testing($testDetails);
725 $filename = $this->getBaseDir() . $filename;
726 if (file_exists($filename)) {
727 if (file_exists("$filename.bak")) {
730 rename($filename, "$filename.bak");
735 * @param string $filename
736 * @param $testDetails
737 * @param bool $absolute
739 function requireWriteable($filename, $testDetails, $absolute = FALSE) {
740 $this->testing($testDetails);
742 $filename = $this->getBaseDir() . $filename;
745 if (!is_writable($filename)) {
747 if (function_exists('posix_getpwuid')) {
748 $user = posix_getpwuid(posix_geteuid());
749 $name = '- ' . $user['name'] . ' -';
752 if (!isset($testDetails[2])) {
753 $testDetails[2] = NULL;
755 $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";
756 $this->error($testDetails);
761 * @param string $moduleName
762 * @param $testDetails
764 function requireApacheModule($moduleName, $testDetails) {
765 $this->testing($testDetails);
766 if (!in_array($moduleName, apache_get_modules())) {
767 $this->error($testDetails);
773 * @param string $username
775 * @param $testDetails
777 function requireMysqlConnection($server, $username, $password, $testDetails) {
778 $this->testing($testDetails);
779 $conn = @mysql_connect
($server, $username, $password);
785 $testDetails[2] .= ": " . mysql_error();
786 $this->error($testDetails);
792 * @param $testDetails
794 function requireMySQLServer($server, $testDetails) {
795 $this->testing($testDetails);
796 $conn = @mysql_connect
($server, NULL, NULL);
798 if ($conn ||
mysql_errno() < 2000) {
802 $testDetails[2] .= ": " . mysql_error();
803 $this->error($testDetails);
809 * @param $testDetails
811 function requireMySQLVersion($version, $testDetails) {
812 $this->testing($testDetails);
814 if (!mysql_get_server_info()) {
815 $testDetails[2] = 'Cannot determine the version of MySQL installed. Please ensure at least version 4.1 is installed.';
816 $this->warning($testDetails);
819 list($majorRequested, $minorRequested) = explode('.', $version);
820 list($majorHas, $minorHas) = explode('.', mysql_get_server_info());
822 if (($majorHas > $majorRequested) ||
($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
826 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
827 $this->error($testDetails);
834 * @param string $username
837 * @param $testDetails
839 function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
840 $this->testing($testDetails);
841 $conn = @mysql_connect
($server, $username, $password);
843 $testDetails[2] .= ' Could not determine if mysql has innodb support. Assuming no';
844 $this->error($testDetails);
848 $innodb_support = FALSE;
849 $result = mysql_query("SHOW ENGINES", $conn);
850 while ($values = mysql_fetch_array($result)) {
851 if ($values['Engine'] == 'InnoDB') {
852 if (strtolower($values['Support']) == 'yes' ||
853 strtolower($values['Support']) == 'default'
855 $innodb_support = TRUE;
859 if ($innodb_support) {
860 $testDetails[3] = 'MySQL server does have innodb support';
863 $testDetails[2] .= ' Could not determine if mysql has innodb support. Assuming no';
869 * @param string $username
872 * @param $testDetails
874 function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
875 $this->testing($testDetails);
876 $conn = @mysql_connect
($server, $username, $password);
878 $testDetails[2] = 'Could not login to the database.';
879 $this->error($testDetails);
883 if (!@mysql_select_db
($database, $conn)) {
884 $testDetails[2] = 'Could not select the database.';
885 $this->error($testDetails);
889 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
891 $testDetails[2] = 'Could not create a temp table.';
892 $this->error($testDetails);
894 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
899 * @param string $username
902 * @param $testDetails
904 function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
905 $this->testing($testDetails);
906 $conn = @mysql_connect
($server, $username, $password);
908 $testDetails[2] = 'Could not login to the database.';
909 $this->error($testDetails);
913 if (!@mysql_select_db
($database, $conn)) {
914 $testDetails[2] = 'Could not select the database.';
915 $this->error($testDetails);
919 $result = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
921 $testDetails[2] = 'Could not create a table.';
922 $this->error($testDetails);
925 $result = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
927 mysql_query('DROP TABLE civicrm_install_temp_table_test');
928 $testDetails[2] = 'Could not create a trigger.';
929 $this->error($testDetails);
932 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
933 mysql_query('DROP TABLE civicrm_install_temp_table_test');
939 * @param string $username
942 * @param $testDetails
944 function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
945 $this->testing($testDetails);
946 $conn = @mysql_connect
($server, $username, $password);
948 $testDetails[2] = 'Could not login to the database.';
949 $this->error($testDetails);
953 if (!@mysql_select_db
($database, $conn)) {
954 $testDetails[2] = 'Could not select the database.';
955 $this->error($testDetails);
959 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
961 $testDetails[2] = 'Could not create a table.';
962 $this->error($testDetails);
966 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
968 $testDetails[2] = 'Could not obtain a write lock for the table.';
969 $this->error($testDetails);
970 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
974 $result = mysql_query('UNLOCK TABLES', $conn);
976 $testDetails[2] = 'Could not release the lock for the table.';
977 $this->error($testDetails);
978 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
982 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
988 * @param string $username
990 * @param $testDetails
992 function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
993 $this->testing($testDetails);
994 $conn = @mysql_connect
($server, $username, $password);
996 $testDetails[2] = 'Could not connect to the database server.';
997 $this->error($testDetails);
1001 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
1003 $testDetails[2] = 'Could not query database server variables.';
1004 $this->error($testDetails);
1008 $values = mysql_fetch_row($result);
1009 if ($values[1] == 1) {
1010 $testDetails[3] = 'MySQL server auto_increment_increment is 1';
1013 $this->error($testDetails);
1020 * @param string $username
1023 * @param $minValueKB
1024 * @param $testDetails
1026 function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
1027 $this->testing($testDetails);
1028 $conn = @mysql_connect
($server, $username, $password);
1030 $testDetails[2] = 'Could not login to the database.';
1031 $this->error($testDetails);
1035 if (!@mysql_select_db
($database, $conn)) {
1036 $testDetails[2] = 'Could not select the database.';
1037 $this->error($testDetails);
1041 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
1043 $testDetails[2] = 'Could not query thread_stack.';
1044 $this->error($testDetails);
1047 $values = mysql_fetch_row($result);
1048 if ($values[1] < (1024 * $minValueKB)) {
1049 $testDetails[2] = 'MySQL "thread_stack" is ' . ($values[1] / 1024) . 'k';
1050 $this->error($testDetails);
1057 * @param string $username
1060 * @param $testDetails
1061 * @param bool $onlyRequire
1063 function requireDatabaseOrCreatePermissions(
1069 $onlyRequire = FALSE
1071 $this->testing($testDetails);
1072 $conn = @mysql_connect
($server, $username, $password);
1075 if (@mysql_select_db
($database)) {
1076 $okay = "Database '$database' exists";
1078 elseif ($onlyRequire) {
1079 $testDetails[2] = "The database: '$database' does not exist";
1080 $this->error($testDetails);
1084 if (@mysql_query
("CREATE DATABASE $database")) {
1085 $okay = "Able to create a new database";
1088 $testDetails[2] .= " (user '$username' doesn't have CREATE DATABASE permissions.)";
1089 $this->error($testDetails);
1095 $testDetails[3] = $okay;
1096 $this->testing($testDetails);
1102 * @param $errorMessage
1104 function requireServerVariables($varNames, $errorMessage) {
1105 //$this->testing($testDetails);
1106 foreach ($varNames as $varName) {
1107 if (!$_SERVER[$varName]) {
1108 $missing[] = '$_SERVER[' . $varName . ']';
1111 if (!isset($missing)) {
1115 $testDetails[2] = " (the following PHP variables are missing: " . implode(", ", $missing) . ")";
1116 $this->error($testDetails);
1121 * @param $testDetails
1125 function isRunningApache($testDetails) {
1126 $this->testing($testDetails);
1127 if (function_exists('apache_get_modules') ||
stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1131 $this->warning($testDetails);
1138 function getBaseDir() {
1139 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR
;
1143 * @param $testDetails
1145 function testing($testDetails) {
1146 if (!$testDetails) {
1150 $section = $testDetails[0];
1151 $test = $testDetails[1];
1154 if (isset($testDetails[3])) {
1155 $message .= " ($testDetails[3])";
1158 $this->tests
[$section][$test] = array("good", $message);
1162 * @param $testDetails
1164 function error($testDetails) {
1165 $section = $testDetails[0];
1166 $test = $testDetails[1];
1168 $this->tests
[$section][$test] = array("error", $testDetails[2]);
1169 $this->errors
[] = $testDetails;
1173 * @param $testDetails
1175 function warning($testDetails) {
1176 $section = $testDetails[0];
1177 $test = $testDetails[1];
1179 $this->tests
[$section][$test] = array("warning", $testDetails[2]);
1180 $this->warnings
[] = $testDetails;
1186 function hasErrors() {
1187 return sizeof($this->errors
);
1193 function hasWarnings() {
1194 return sizeof($this->warnings
);
1201 class Installer
extends InstallRequirements
{
1208 function createDatabaseIfNotExists($server, $username, $password, $database) {
1209 $conn = @mysql_connect
($server, $username, $password);
1211 if (@mysql_select_db
($database)) {
1212 // skip if database already present
1216 if (@mysql_query
("CREATE DATABASE $database")) {
1219 $errorTitle = "Oops! Could not create Database $database";
1220 $errorMsg = "We encountered an error when attempting to create the database. Please check your mysql server permissions and the database name and try again.";
1221 errorDisplayPage($errorTitle, $errorMsg);
1230 function install($config) {
1231 global $installDirPath;
1233 // create database if does not exists
1234 $this->createDatabaseIfNotExists($config['mysql']['server'],
1235 $config['mysql']['username'],
1236 $config['mysql']['password'],
1237 $config['mysql']['database']
1240 global $installDirPath;
1243 require_once $installDirPath . 'civicrm.php';
1244 civicrm_main($config);
1246 if (!$this->errors
) {
1247 global $installType, $installURLPath;
1249 $registerSiteURL = "https://civicrm.org/register-site";
1250 $commonOutputMessage = "
1251 <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>
1252 <li>We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.</li>
1257 $installType == 'drupal' &&
1258 version_compare(VERSION
, '7.0-rc1') >= 0
1264 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1265 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1266 $output .= '<head>';
1267 $output .= '<title>CiviCRM Installed</title>';
1268 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1269 $output .= '</head>';
1270 $output .= '<body>';
1271 $output .= '<div style="padding: 1em;"><p class="good">CiviCRM has been successfully installed</p>';
1273 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1274 if (!function_exists('ts')) {
1275 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1277 $drupalURL = civicrm_cms_base();
1278 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1279 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1281 $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>
1282 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1283 {$commonOutputMessage}";
1285 // automatically enable CiviCRM module once it is installed successfully.
1286 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1287 global $cmsPath, $crmPath;
1289 // relative / abosolute paths are not working for drupal, hence using chdir()
1292 include_once "./includes/bootstrap.inc";
1293 include_once "./includes/unicode.inc";
1295 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1297 // prevent session information from being saved.
1298 drupal_save_session(FALSE);
1300 // Force the current user to anonymous.
1301 $original_user = $GLOBALS['user'];
1302 $GLOBALS['user'] = drupal_anonymous_user();
1304 // explicitly setting error reporting, since we cannot handle drupal related notices
1307 // rebuild modules, so that civicrm is added
1308 system_rebuild_module_data();
1310 // now enable civicrm module.
1311 module_enable(array('civicrm', 'civicrmtheme'));
1313 // clear block, page, theme, and hook caches
1314 drupal_flush_all_caches();
1316 //add basic drupal permissions
1317 civicrm_install_set_drupal_perms();
1319 // restore the user.
1320 $GLOBALS['user'] = $original_user;
1321 drupal_save_session(TRUE);
1324 $output .= '</div>';
1325 $output .= '</body>';
1326 $output .= '</html>';
1329 elseif ($installType == 'drupal' && version_compare(VERSION
, '6.0') >= 0) {
1333 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1334 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1335 $output .= '<head>';
1336 $output .= '<title>CiviCRM Installed</title>';
1337 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1338 $output .= '</head>';
1339 $output .= '<body>';
1340 $output .= '<div style="padding: 1em;"><p class="good">CiviCRM has been successfully installed</p>';
1342 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1343 if (!function_exists('ts')) {
1344 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1346 $drupalURL = civicrm_cms_base();
1347 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1348 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1350 $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>
1351 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1352 {$commonOutputMessage}";
1354 // explicitly setting error reporting, since we cannot handle drupal related notices
1357 // automatically enable CiviCRM module once it is installed successfully.
1358 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1359 global $cmsPath, $crmPath;
1361 // relative / abosolute paths are not working for drupal, hence using chdir()
1364 include_once "./includes/bootstrap.inc";
1365 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1367 // rebuild modules, so that civicrm is added
1368 module_rebuild_cache();
1370 // now enable civicrm module.
1371 module_enable(array('civicrm'));
1373 // clear block, page, theme, and hook caches
1374 drupal_flush_all_caches();
1376 //add basic drupal permissions
1377 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)');
1381 elseif ($installType == 'wordpress') {
1382 echo '<h1>CiviCRM Installed</h1>';
1383 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">CiviCRM has been successfully installed</p>';
1385 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here', NULL, NULL, "wiki");
1386 if (!function_exists('ts')) {
1387 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1390 $cmsURL = civicrm_cms_base();
1391 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1392 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1395 <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>
1396 <li>Use the <a target='_blank' href=\"$cmsURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1397 {$commonOutputMessage}
1405 return $this->errors
;
1409 function civicrm_install_set_drupal_perms() {
1410 if (!function_exists('db_select')) {
1411 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)');
1415 'access all custom data',
1416 'access uploaded files',
1417 'make online contributions',
1421 'register for events',
1423 'view event participants',
1424 'access CiviMail subscribe/unsubscribe pages',
1427 // Adding a permission that has not yet been assigned to a module by
1428 // a hook_permission implementation results in a database error.
1430 $allPerms = array_keys(module_invoke_all('permission'));
1431 foreach (array_diff($perms, $allPerms) as $perm) {
1433 'Cannot grant the %perm permission because it does not yet exist.',
1439 $perms = array_intersect($perms, $allPerms);
1440 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID
, $perms);
1441 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID
, $perms);
1451 function getSiteDir($cmsPath, $str) {
1452 static $siteDir = '';
1458 $sites = CIVICRM_DIRECTORY_SEPARATOR
. 'sites' . CIVICRM_DIRECTORY_SEPARATOR
;
1459 $modules = CIVICRM_DIRECTORY_SEPARATOR
. 'modules' . CIVICRM_DIRECTORY_SEPARATOR
;
1460 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR
) .
1461 "([\-a-zA-Z0-9_.]+)" .
1462 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR
) . "/",
1463 $_SERVER['SCRIPT_FILENAME'], $matches
1465 $siteDir = isset($matches[1]) ?
$matches[1] : 'default';
1467 if (strtolower($siteDir) == 'all') {
1468 // For this case - use drupal's way of finding out multi-site directory
1469 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR
, $_SERVER['SCRIPT_FILENAME']);
1470 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1471 for ($i = count($uri) - 1; $i > 0; $i--) {
1472 for ($j = count($server); $j > 0; $j--) {
1473 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1474 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
1475 'sites' . CIVICRM_DIRECTORY_SEPARATOR
. $dir
1482 $siteDir = 'default';
1489 * @param $errorTitle
1492 function errorDisplayPage($errorTitle, $errorMsg) {
1493 include 'error.html';