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"))))unset($langs[$locale]);
136 $seedLanguage = 'en_US';
137 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
138 $seedLanguage = $_REQUEST['seedLanguage'];
142 if ($installType == 'drupal') {
143 //CRM-6840 -don't force to install in sites/all/modules/
144 $object = new CRM_Utils_System_Drupal();
145 $cmsPath = $object->cmsRootPath();
147 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
148 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
149 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
150 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
151 'civicrm.settings.php'
154 elseif ($installType == 'wordpress') {
155 $cmsPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm';
156 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
157 'civicrm.settings.php'
161 // Exit with error if CiviCRM has already been installed.
162 if ($alreadyInstalled) {
163 $errorTitle = "Oops! CiviCRM is Already Installed";
164 if ($installType == 'drupal') {
166 $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(
167 '[your Drupal root directory]', 'sites', $siteDir)) . "</strong>.</li><li>To <strong>upgrade an existing installation</strong>, refer to the online " . $docLink . ".</li></ul>";
169 elseif ($installType == 'wordpress') {
170 $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>";
172 errorDisplayPage($errorTitle, $errorMsg);
175 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'civicrm-version.php';
176 if (file_exists($versionFile)) {
177 require_once ($versionFile);
178 $civicrm_version = civicrmVersion();
181 $civicrm_version = 'unknown';
184 if ($installType == 'drupal') {
185 // Ensure that they have downloaded the correct version of CiviCRM
186 if ($civicrm_version['cms'] != 'Drupal' &&
187 $civicrm_version['cms'] != 'Drupal6'
189 $errorTitle = "Oops! Incorrect CiviCRM Version";
190 $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!";
191 errorDisplayPage($errorTitle, $errorMsg);
194 define('DRUPAL_ROOT', $cmsPath);
195 $drupalVersionFiles = array(
197 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'modules', 'system', 'system.module')),
199 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'includes', 'bootstrap.inc')),
201 foreach ($drupalVersionFiles as $drupalVersionFile) {
202 if (file_exists($drupalVersionFile)) {
203 require_once $drupalVersionFile;
207 if (!defined('VERSION') or version_compare(VERSION
, '6.0') < 0) {
208 $errorTitle = "Oops! Incorrect Drupal Version";
209 $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.";
210 errorDisplayPage($errorTitle, $errorMsg);
213 elseif ($installType == 'wordpress') {
215 $civicrm_version['cms'] = 'WordPress';
217 // Ensure that they have downloaded the correct version of CiviCRM
218 if ($civicrm_version['cms'] != 'WordPress') {
219 $errorTitle = "Oops! Incorrect CiviCRM Version";
220 $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!";
221 errorDisplayPage($errorTitle, $errorMsg);
225 // Check requirements
226 $req = new InstallRequirements();
229 if ($req->hasErrors()) {
230 $hasErrorOtherThanDatabase = TRUE;
233 if ($databaseConfig) {
234 $dbReq = new InstallRequirements();
235 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
236 if ($installType == 'drupal') {
237 $dbReq->checkdatabase($drupalConfig, 'Drupal');
242 if (isset($_REQUEST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
243 // Confirm before reinstalling
244 if (!isset($_REQUEST['force_reinstall']) && $alreadyInstalled) {
245 include ($installDirPath . 'template.html');
248 $inst = new Installer();
249 $inst->install($_REQUEST);
252 // Show the config form
255 include ($installDirPath . 'template.html');
259 * This class checks requirements
260 * Each of the requireXXX functions takes an argument which gives a user description of the test. It's an array
262 * $description[0] - The test catetgory
263 * $description[1] - The test title
264 * $description[2] - The test error to show, if it goes wrong
266 class InstallRequirements
{
267 var $errors, $warnings, $tests;
269 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
270 const MINIMUM_THREAD_STACK
= 192;
273 * Just check that the database configuration is okay
275 function checkdatabase($databaseConfig, $dbName) {
276 if ($this->requireFunction('mysql_connect',
280 "MySQL support not included in PHP.",
283 $this->requireMySQLServer($databaseConfig['server'],
285 "MySQL $dbName Configuration",
286 "Does the server exist",
287 "Can't find the a MySQL server on '$databaseConfig[server]'",
288 $databaseConfig['server'],
291 if ($this->requireMysqlConnection($databaseConfig['server'],
292 $databaseConfig['username'],
293 $databaseConfig['password'],
295 "MySQL $dbName Configuration",
296 "Are the access credentials correct",
297 "That username/password doesn't work",
300 @$this->requireMySQLVersion("5.1",
302 "MySQL $dbName Configuration",
303 "MySQL version at least 5.1",
304 "MySQL version 5.1 or higher is required, you only have ",
305 "MySQL " . mysql_get_server_info(),
308 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
309 $databaseConfig['username'],
310 $databaseConfig['password'],
312 "MySQL $dbName Configuration",
313 "Is auto_increment_increment set to 1",
314 "An auto_increment_increment value greater than 1 is not currently supported. Please see issue CRM-7923 for further details and potential workaround.",
317 $this->requireMySQLThreadStack($databaseConfig['server'],
318 $databaseConfig['username'],
319 $databaseConfig['password'],
320 $databaseConfig['database'],
321 self
::MINIMUM_THREAD_STACK
,
323 "MySQL $dbName Configuration",
324 "Does MySQL thread_stack meet minimum (" . self
::MINIMUM_THREAD_STACK
. "k)",
325 "", // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
329 $onlyRequire = ($dbName == 'Drupal') ?
TRUE : FALSE;
330 $this->requireDatabaseOrCreatePermissions(
331 $databaseConfig['server'],
332 $databaseConfig['username'],
333 $databaseConfig['password'],
334 $databaseConfig['database'],
336 "MySQL $dbName Configuration",
337 "Can I access/create the database",
338 "I can't create new databases and the database '$databaseConfig[database]' doesn't exist",
342 if ($dbName != 'Drupal') {
343 $this->requireMySQLInnoDB($databaseConfig['server'],
344 $databaseConfig['username'],
345 $databaseConfig['password'],
346 $databaseConfig['database'],
348 "MySQL $dbName Configuration",
349 "Can I access/create InnoDB tables in the database",
350 "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.",
353 $this->requireMySQLTempTables($databaseConfig['server'],
354 $databaseConfig['username'],
355 $databaseConfig['password'],
356 $databaseConfig['database'],
358 "MySQL $dbName Configuration",
359 'Can I create temporary tables in the database',
360 'Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.',
363 $this->requireMySQLLockTables($databaseConfig['server'],
364 $databaseConfig['username'],
365 $databaseConfig['password'],
366 $databaseConfig['database'],
368 "MySQL $dbName Configuration",
369 'Can I create lock tables in the database',
370 'Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.',
373 $this->requireMySQLTrigger($databaseConfig['server'],
374 $databaseConfig['username'],
375 $databaseConfig['password'],
376 $databaseConfig['database'],
378 "MySQL $dbName Configuration",
379 'Can I create triggers in the database',
380 'Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.',
388 * Check everything except the database
391 global $crmPath, $installType;
393 $this->errors
= NULL;
395 $this->requirePHPVersion('5.3.3', array("PHP Configuration", "PHP5 installed", NULL, "PHP version " . phpversion()));
397 // Check that we can identify the root folder successfully
398 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'README.txt',
401 "Does the webserver know where files are stored?",
402 "The webserver isn't letting me identify where files are stored.",
408 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
409 $this->requireNoPathSeparator(
412 'does the CiviCRM path contain PATH_SEPARATOR?',
413 'the ' . $this->getBaseDir() . ' path contains PATH_SEPARATOR (the ' . PATH_SEPARATOR
. ' character)',
418 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
419 foreach ($requiredDirectories as $dir) {
420 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. $dir,
422 "File permissions", "$dir folder exists", "There is no $dir folder"), TRUE
426 $configIDSiniDir = NULL;
428 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
429 if ($installType == 'drupal') {
431 // make sure that we can write to sites/default and files/
432 $writableDirectories = array(
433 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
434 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
435 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
437 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
438 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
442 elseif ($installType == 'wordpress') {
443 // make sure that we can write to plugins/civicrm and plugins/files/
444 $writableDirectories = array(WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'files', $cmsPath);
447 foreach ($writableDirectories as $dir) {
448 $dirName = CIVICRM_WINDOWS ?
$dir : CIVICRM_DIRECTORY_SEPARATOR
. $dir;
449 $this->requireWriteable($dirName,
450 array("File permissions", "Is the $dir folder writeable?", NULL),
455 //check for Config.IDS.ini, file may exist in re-install
456 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
458 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
459 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR
, $configIDSiniDir);
460 if (file_exists($configIDSiniFile)) {
461 unlink($configIDSiniFile);
465 // Check for rewriting
466 if (isset($_SERVER['SERVER_SOFTWARE'])) {
467 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
469 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
470 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
473 if ($webserver == '') {
474 $webserver = "I can't tell what webserver you are running";
477 // Check for $_SERVER configuration
478 $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."));
480 // Check for MySQL support
481 $this->requireFunction('mysql_connect',
482 array("PHP Configuration", "MySQL support", "MySQL support not included in PHP.")
485 // Check for JSON support
486 $this->requireFunction('json_encode',
487 array("PHP Configuration", "JSON support", "JSON support not included in PHP.")
490 // Check for xcache_isset and emit warning if exists
491 $this->checkXCache(array(
493 "XCache compatibility",
494 "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.",
497 // Check memory allocation
498 $this->requireMemory(32 * 1024 * 1024,
502 "Memory allocated (PHP config option 'memory_limit')",
503 "CiviCRM needs a minimum of 32M allocated to PHP, but recommends 64M.",
504 ini_get("memory_limit"),
508 return $this->errors
;
511 function requireMemory($min, $recommended, $testDetails) {
512 $this->testing($testDetails);
513 $mem = $this->getPHPMemory();
515 if ($mem < $min && $mem > 0) {
516 $testDetails[2] .= " You only have " . ini_get("memory_limit") . " allocated";
517 $this->error($testDetails);
519 elseif ($mem < $recommended && $mem > 0) {
520 $testDetails[2] .= " You only have " . ini_get("memory_limit") . " allocated";
521 $this->warning($testDetails);
524 $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.";
525 $this->warning($testDetails);
529 function getPHPMemory() {
530 $memString = ini_get("memory_limit");
532 switch (strtolower(substr($memString, -1))) {
534 return round(substr($memString, 0, -1) * 1024);
537 return round(substr($memString, 0, -1) * 1024 * 1024);
540 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
543 return round($memString);
547 function listErrors() {
549 echo "<p>The following problems are preventing me from installing CiviCRM:</p>";
550 foreach ($this->errors
as $error) {
551 echo "<li>" . htmlentities($error) . "</li>";
556 function showTable($section = NULL) {
558 $tests = $this->tests
[$section];
559 echo "<table class=\"testResults\" width=\"100%\">";
560 foreach ($tests as $test => $result) {
561 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
566 foreach ($this->tests
as $section => $tests) {
567 echo "<h3>$section</h3>";
568 echo "<table class=\"testResults\" width=\"100%\">";
570 foreach ($tests as $test => $result) {
571 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
578 function requireFunction($funcName, $testDetails) {
579 $this->testing($testDetails);
581 if (!function_exists($funcName)) {
582 $this->error($testDetails);
590 function checkXCache($testDetails) {
591 if (function_exists('xcache_isset') &&
592 ini_get('xcache.size') > 0
594 $this->testing($testDetails);
595 $this->warning($testDetails);
599 function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
601 $this->testing($testDetails);
603 $phpVersion = phpversion();
604 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
605 $belowMaxVersion = $maxVersion ?
version_compare($phpVersion, $maxVersion) < 0 : TRUE;
607 if ($maxVersion && $aboveMinVersion && $belowMaxVersion) {
610 elseif (!$maxVersion && $aboveMinVersion) {
614 if (!$testDetails[2]) {
615 if (!$aboveMinVersion) {
616 $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.";
619 $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.";
623 $this->error($testDetails);
626 function requireFile($filename, $testDetails, $absolute = FALSE) {
627 $this->testing($testDetails);
629 $filename = $this->getBaseDir() . $filename;
631 if (!file_exists($filename)) {
632 $testDetails[2] .= " (file '$filename' not found)";
633 $this->error($testDetails);
637 function requireNoPathSeparator($testDetails) {
638 $this->testing($testDetails);
639 if (substr_count($this->getBaseDir(), PATH_SEPARATOR
)) {
640 $this->error($testDetails);
644 function requireNoFile($filename, $testDetails) {
645 $this->testing($testDetails);
646 $filename = $this->getBaseDir() . $filename;
647 if (file_exists($filename)) {
648 $testDetails[2] .= " (file '$filename' found)";
649 $this->error($testDetails);
653 function moveFileOutOfTheWay($filename, $testDetails) {
654 $this->testing($testDetails);
655 $filename = $this->getBaseDir() . $filename;
656 if (file_exists($filename)) {
657 if (file_exists("$filename.bak")) {
660 rename($filename, "$filename.bak");
664 function requireWriteable($filename, $testDetails, $absolute = FALSE) {
665 $this->testing($testDetails);
667 $filename = $this->getBaseDir() . $filename;
670 if (!is_writeable($filename)) {
672 if (function_exists('posix_getpwuid')) {
673 $user = posix_getpwuid(posix_geteuid());
674 $name = '- ' . $user['name'] . ' -';
677 if (!isset($testDetails[2])) {
678 $testDetails[2] = NULL;
680 $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";
681 $this->error($testDetails);
685 function requireApacheModule($moduleName, $testDetails) {
686 $this->testing($testDetails);
687 if (!in_array($moduleName, apache_get_modules())) {
688 $this->error($testDetails);
692 function requireMysqlConnection($server, $username, $password, $testDetails) {
693 $this->testing($testDetails);
694 $conn = @mysql_connect
($server, $username, $password);
700 $testDetails[2] .= ": " . mysql_error();
701 $this->error($testDetails);
705 function requireMySQLServer($server, $testDetails) {
706 $this->testing($testDetails);
707 $conn = @mysql_connect
($server, NULL, NULL);
709 if ($conn ||
mysql_errno() < 2000) {
713 $testDetails[2] .= ": " . mysql_error();
714 $this->error($testDetails);
718 function requireMySQLVersion($version, $testDetails) {
719 $this->testing($testDetails);
721 if (!mysql_get_server_info()) {
722 $testDetails[2] = 'Cannot determine the version of MySQL installed. Please ensure at least version 4.1 is installed.';
723 $this->warning($testDetails);
726 list($majorRequested, $minorRequested) = explode('.', $version);
727 list($majorHas, $minorHas) = explode('.', mysql_get_server_info());
729 if (($majorHas > $majorRequested) ||
($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
733 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
734 $this->error($testDetails);
739 function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
740 $this->testing($testDetails);
741 $conn = @mysql_connect
($server, $username, $password);
743 $testDetails[2] .= ' Could not determine if mysql has innodb support. Assuming no';
744 $this->error($testDetails);
748 $innodb_support = FALSE;
749 $result = mysql_query("SHOW ENGINES", $conn);
750 while ($values = mysql_fetch_array($result)) {
751 if ($values['Engine'] == 'InnoDB') {
752 if (strtolower($values['Support']) == 'yes' ||
753 strtolower($values['Support']) == 'default'
755 $innodb_support = TRUE;
759 if ($innodb_support) {
760 $testDetails[3] = 'MySQL server does have innodb support';
763 $testDetails[2] .= ' Could not determine if mysql has innodb support. Assuming no';
767 function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
768 $this->testing($testDetails);
769 $conn = @mysql_connect
($server, $username, $password);
771 $testDetails[2] = 'Could not login to the database.';
772 $this->error($testDetails);
776 if (!@mysql_select_db
($database, $conn)) {
777 $testDetails[2] = 'Could not select the database.';
778 $this->error($testDetails);
782 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
784 $testDetails[2] = 'Could not create a temp table.';
785 $this->error($testDetails);
787 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
790 function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
791 $this->testing($testDetails);
792 $conn = @mysql_connect
($server, $username, $password);
794 $testDetails[2] = 'Could not login to the database.';
795 $this->error($testDetails);
799 if (!@mysql_select_db
($database, $conn)) {
800 $testDetails[2] = 'Could not select the database.';
801 $this->error($testDetails);
805 $result = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
807 $testDetails[2] = 'Could not create a table.';
808 $this->error($testDetails);
811 $result = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
813 mysql_query('DROP TABLE civicrm_install_temp_table_test');
814 $testDetails[2] = 'Could not create a trigger.';
815 $this->error($testDetails);
819 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
820 mysql_query('DROP TABLE civicrm_install_temp_table_test');
824 function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
825 $this->testing($testDetails);
826 $conn = @mysql_connect
($server, $username, $password);
828 $testDetails[2] = 'Could not login to the database.';
829 $this->error($testDetails);
833 if (!@mysql_select_db
($database, $conn)) {
834 $testDetails[2] = 'Could not select the database.';
835 $this->error($testDetails);
839 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
841 $testDetails[2] = 'Could not create a table.';
842 $this->error($testDetails);
846 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
848 $testDetails[2] = 'Could not obtain a write lock for the table.';
849 $this->error($testDetails);
850 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
854 $result = mysql_query('UNLOCK TABLES', $conn);
856 $testDetails[2] = 'Could not release the lock for the table.';
857 $this->error($testDetails);
858 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
862 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
866 function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
867 $this->testing($testDetails);
868 $conn = @mysql_connect
($server, $username, $password);
870 $testDetails[2] = 'Could not connect to the database server.';
871 $this->error($testDetails);
875 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
877 $testDetails[2] = 'Could not query database server variables.';
878 $this->error($testDetails);
882 $values = mysql_fetch_row($result);
883 if ($values[1] == 1) {
884 $testDetails[3] = 'MySQL server auto_increment_increment is 1';
887 $this->error($testDetails);
892 function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
893 $this->testing($testDetails);
894 $conn = @mysql_connect
($server, $username, $password);
896 $testDetails[2] = 'Could not login to the database.';
897 $this->error($testDetails);
901 if (!@mysql_select_db
($database, $conn)) {
902 $testDetails[2] = 'Could not select the database.';
903 $this->error($testDetails);
907 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
909 $testDetails[2] = 'Could not query thread_stack.';
910 $this->error($testDetails);
912 $values = mysql_fetch_row($result);
913 if ($values[1] < (1024*$minValueKB)) {
914 $testDetails[2] = 'MySQL "thread_stack" is ' . ($values[1]/1024) . 'k';
915 $this->error($testDetails);
920 function requireDatabaseOrCreatePermissions($server,
927 $this->testing($testDetails);
928 $conn = @mysql_connect
($server, $username, $password);
931 if (@mysql_select_db
($database)) {
932 $okay = "Database '$database' exists";
934 elseif ($onlyRequire) {
935 $testDetails[2] = "The database: '$database' does not exist";
936 $this->error($testDetails);
940 if (@mysql_query
("CREATE DATABASE $database")) {
941 $okay = "Able to create a new database";
944 $testDetails[2] .= " (user '$username' doesn't have CREATE DATABASE permissions.)";
945 $this->error($testDetails);
951 $testDetails[3] = $okay;
952 $this->testing($testDetails);
956 function requireServerVariables($varNames, $errorMessage) {
957 //$this->testing($testDetails);
958 foreach ($varNames as $varName) {
959 if (!$_SERVER[$varName]) {
960 $missing[] = '$_SERVER[' . $varName . ']';
963 if (!isset($missing)) {
967 $testDetails[2] = " (the following PHP variables are missing: " . implode(", ", $missing) . ")";
968 $this->error($testDetails);
972 function isRunningApache($testDetails) {
973 $this->testing($testDetails);
974 if (function_exists('apache_get_modules') ||
stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
978 $this->warning($testDetails);
982 function getBaseDir() {
983 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR
;
986 function testing($testDetails) {
991 $section = $testDetails[0];
992 $test = $testDetails[1];
995 if (isset($testDetails[3])) {
996 $message .= " ($testDetails[3])";
999 $this->tests
[$section][$test] = array("good", $message);
1002 function error($testDetails) {
1003 $section = $testDetails[0];
1004 $test = $testDetails[1];
1006 $this->tests
[$section][$test] = array("error", $testDetails[2]);
1007 $this->errors
[] = $testDetails;
1010 function warning($testDetails) {
1011 $section = $testDetails[0];
1012 $test = $testDetails[1];
1015 $this->tests
[$section][$test] = array("warning", $testDetails[2]);
1016 $this->warnings
[] = $testDetails;
1019 function hasErrors() {
1020 return sizeof($this->errors
);
1023 function hasWarnings() {
1024 return sizeof($this->warnings
);
1028 class Installer
extends InstallRequirements
{
1029 function createDatabaseIfNotExists($server, $username, $password, $database) {
1030 $conn = @mysql_connect
($server, $username, $password);
1032 if (@mysql_select_db
($database)) {
1033 // skip if database already present
1037 if (@mysql_query
("CREATE DATABASE $database")) {}
1039 $errorTitle = "Oops! Could not create Database $database";
1040 $errorMsg = "We encountered an error when attempting to create the database. Please check your mysql server permissions and the database name and try again.";
1041 errorDisplayPage($errorTitle, $errorMsg);
1045 function install($config) {
1046 global $installDirPath;
1048 // create database if does not exists
1049 $this->createDatabaseIfNotExists($config['mysql']['server'],
1050 $config['mysql']['username'],
1051 $config['mysql']['password'],
1052 $config['mysql']['database']
1055 global $installDirPath;
1058 require_once $installDirPath . 'civicrm.php';
1059 civicrm_main($config);
1061 if (!$this->errors
) {
1062 global $installType, $installURLPath;
1064 $registerSiteURL = "http://civicrm.org/civicrm/profile/create?reset=1&gid=15";
1065 $commonOutputMessage = "
1066 <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>
1067 <li>We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.</li>
1072 $installType == 'drupal' &&
1073 version_compare(VERSION
, '7.0-rc1') >= 0
1079 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1080 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1081 $output .= '<head>';
1082 $output .= '<title>CiviCRM Installed</title>';
1083 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1084 $output .= '</head>';
1085 $output .= '<body>';
1086 $output .= '<div style="padding: 1em;"><p class="good">CiviCRM has been successfully installed</p>';
1088 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here',NULL,NULL,"wiki");
1089 if (!function_exists('ts')) {
1090 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1092 $drupalURL = civicrm_cms_base();
1093 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1094 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1096 $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>
1097 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1098 {$commonOutputMessage}";
1100 // automatically enable CiviCRM module once it is installed successfully.
1101 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1102 global $cmsPath, $crmPath;
1104 // relative / abosolute paths are not working for drupal, hence using chdir()
1107 include_once "./includes/bootstrap.inc";
1108 include_once "./includes/unicode.inc";
1110 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1112 // prevent session information from being saved.
1113 drupal_save_session(FALSE);
1115 // Force the current user to anonymous.
1116 $original_user = $GLOBALS['user'];
1117 $GLOBALS['user'] = drupal_anonymous_user();
1119 // explicitly setting error reporting, since we cannot handle drupal related notices
1122 // rebuild modules, so that civicrm is added
1123 system_rebuild_module_data();
1125 // now enable civicrm module.
1126 module_enable(array('civicrm', 'civicrmtheme'));
1128 // clear block, page, theme, and hook caches
1129 drupal_flush_all_caches();
1131 //add basic drupal permissions
1132 civicrm_install_set_drupal_perms();
1134 // restore the user.
1135 $GLOBALS['user'] = $original_user;
1136 drupal_save_session(TRUE);
1139 $output .= '</div>';
1140 $output .= '</body>';
1141 $output .= '</html>';
1144 elseif ($installType == 'drupal' && version_compare(VERSION
, '6.0') >= 0) {
1148 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1149 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1150 $output .= '<head>';
1151 $output .= '<title>CiviCRM Installed</title>';
1152 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1153 $output .= '</head>';
1154 $output .= '<body>';
1155 $output .= '<div style="padding: 1em;"><p class="good">CiviCRM has been successfully installed</p>';
1157 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here',NULL,NULL,"wiki");
1158 if (!function_exists('ts')) {
1159 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1161 $drupalURL = civicrm_cms_base();
1162 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1163 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1165 $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>
1166 <li>Use the <a target='_blank' href=\"$drupalURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1167 {$commonOutputMessage}";
1169 // explicitly setting error reporting, since we cannot handle drupal related notices
1172 // automatically enable CiviCRM module once it is installed successfully.
1173 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1174 global $cmsPath, $crmPath;
1176 // relative / abosolute paths are not working for drupal, hence using chdir()
1179 include_once "./includes/bootstrap.inc";
1180 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1182 // rebuild modules, so that civicrm is added
1183 module_rebuild_cache();
1185 // now enable civicrm module.
1186 module_enable(array('civicrm'));
1188 // clear block, page, theme, and hook caches
1189 drupal_flush_all_caches();
1191 //add basic drupal permissions
1192 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)');
1196 elseif ($installType == 'wordpress') {
1197 echo '<h1>CiviCRM Installed</h1>';
1198 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">CiviCRM has been successfully installed</p>';
1200 $docLinkConfig = CRM_Utils_System
::docURL2('Configuring a New Site', FALSE, 'here',NULL,NULL,"wiki");
1201 if (!function_exists('ts')) {
1202 $docLinkConfig = "<a href=\"{$docLinkConfig}\">here</a>";
1205 $cmsURL = civicrm_cms_base();
1206 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1207 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1210 <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>
1211 <li>Use the <a target='_blank' href=\"$cmsURL\">Configuration Checklist</a> to review and configure settings for your new site</li>
1212 {$commonOutputMessage}
1220 return $this->errors
;
1224 function civicrm_install_set_drupal_perms() {
1225 if (!function_exists('db_select')) {
1226 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)');
1230 'access all custom data',
1231 'access uploaded files',
1232 'make online contributions',
1236 'register for events',
1238 'view event participants',
1239 'access CiviMail subscribe/unsubscribe pages',
1242 // Adding a permission that has not yet been assigned to a module by
1243 // a hook_permission implementation results in a database error.
1245 $allPerms = array_keys(module_invoke_all('permission'));
1246 foreach (array_diff($perms, $allPerms) as $perm) {
1248 'Cannot grant the %perm permission because it does not yet exist.',
1250 '%perm' => $perm), WATCHDOG_ERROR
1253 $perms = array_intersect($perms, $allPerms);
1254 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID
, $perms);
1255 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID
, $perms);
1259 function getSiteDir($cmsPath, $str) {
1260 static $siteDir = '';
1266 $sites = CIVICRM_DIRECTORY_SEPARATOR
. 'sites' . CIVICRM_DIRECTORY_SEPARATOR
;
1267 $modules = CIVICRM_DIRECTORY_SEPARATOR
. 'modules' . CIVICRM_DIRECTORY_SEPARATOR
;
1268 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR
) .
1269 "([\-a-zA-Z0-9_.]+)" .
1270 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR
) . "/",
1271 $_SERVER['SCRIPT_FILENAME'], $matches
1273 $siteDir = isset($matches[1]) ?
$matches[1] : 'default';
1275 if (strtolower($siteDir) == 'all') {
1276 // For this case - use drupal's way of finding out multi-site directory
1277 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR
, $_SERVER['SCRIPT_FILENAME']);
1278 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1279 for ($i = count($uri) - 1; $i > 0; $i--) {
1280 for ($j = count($server); $j > 0; $j--) {
1281 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1282 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
1283 'sites' . CIVICRM_DIRECTORY_SEPARATOR
. $dir
1290 $siteDir = 'default';
1296 function errorDisplayPage($errorTitle, $errorMsg) {
1297 include ('error.html');