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/.
8 * Copyright (c) 2006-7, SilverStripe Limited - www.silverstripe.com
11 * License: BSD-3-clause
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are
16 * Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
19 * Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
23 * Neither the name of SilverStripe nor the names of its contributors may
24 * be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
28 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
30 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
31 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * Changes and modifications (c) 2007-2017 by CiviCRM LLC
46 ini_set('max_execution_time', 3000);
48 if (stristr(PHP_OS
, 'WIN')) {
49 define('CIVICRM_DIRECTORY_SEPARATOR', '/');
50 define('CIVICRM_WINDOWS', 1);
53 define('CIVICRM_DIRECTORY_SEPARATOR', DIRECTORY_SEPARATOR
);
54 define('CIVICRM_WINDOWS', 0);
57 // set installation type - drupal
59 if (defined('PANTHEON_ENVIRONMENT')) {
60 ini_set('session.save_handler', 'files');
65 // unset civicrm session if any
66 if (array_key_exists('CiviCRM', $_SESSION)) {
67 unset($_SESSION['CiviCRM']);
70 if (isset($_GET['civicrm_install_type'])) {
71 $_SESSION['civicrm_install_type'] = $_GET['civicrm_install_type'];
74 if (!isset($_SESSION['civicrm_install_type'])) {
75 $_SESSION['civicrm_install_type'] = "drupal";
82 global $installDirPath;
83 global $installURLPath;
85 $installType = strtolower($_SESSION['civicrm_install_type']);
87 if ($installType == 'drupal' ||
$installType == 'backdrop') {
88 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
89 $installDirPath = $installURLPath = '';
91 elseif ($installType == 'wordpress') {
92 $crmPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
;
93 $installDirPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
94 $installURLPath = WP_PLUGIN_URL
. DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'install' . DIRECTORY_SEPARATOR
;
97 $errorTitle = "Oops! Unsupported installation mode";
98 $errorMsg = sprintf('%s: unknown installation mode. Please refer to the online documentation for more information.', $installType);
99 errorDisplayPage($errorTitle, $errorMsg, FALSE);
102 $pkgPath = $crmPath . DIRECTORY_SEPARATOR
. 'packages';
104 require_once $crmPath . '/CRM/Core/ClassLoader.php';
105 CRM_Core_ClassLoader
::singleton()->register();
107 // Load civicrm database config
108 if (isset($_POST['mysql'])) {
109 $databaseConfig = $_POST['mysql'];
112 $databaseConfig = array(
113 "server" => "localhost",
114 "username" => "civicrm",
116 "database" => "civicrm",
120 if ($installType == 'wordpress') {
121 // Load WP database config
122 if (isset($_POST['mysql'])) {
123 $databaseConfig = $_POST['mysql'];
126 $databaseConfig = array(
128 "username" => DB_USER
,
129 "password" => DB_PASSWORD
,
130 "database" => DB_NAME
,
135 if ($installType == 'drupal') {
136 // Load drupal database config
137 if (isset($_POST['drupal'])) {
138 $drupalConfig = $_POST['drupal'];
141 $drupalConfig = array(
142 "server" => "localhost",
143 "username" => "drupal",
145 "database" => "drupal",
150 if ($installType == 'backdrop') {
151 // Load backdrop database config
152 if (isset($_POST['backdrop'])) {
153 $backdropConfig = $_POST['backdrop'];
156 $backdropConfig = array(
157 "server" => "localhost",
158 "username" => "backdrop",
160 "database" => "backdrop",
166 if (isset($_POST['loadGenerated'])) {
170 require_once dirname(__FILE__
) . CIVICRM_DIRECTORY_SEPARATOR
. 'langs.php';
171 foreach ($langs as $locale => $_) {
172 if ($locale == 'en_US') {
175 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR
, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
176 unset($langs[$locale]);
181 // This is mostly sympbolic, since nothing we do during the install
182 // really requires CIVICRM_UF to be defined.
183 $installTypeToUF = array(
184 'wordpress' => 'WordPress',
185 'drupal' => 'Drupal',
186 'backdrop' => 'Backdrop',
189 $uf = (isset($installTypeToUF[$installType]) ?
$installTypeToUF[$installType] : 'Drupal');
190 define('CIVICRM_UF', $uf);
192 // Set the Locale (required by CRM_Core_Config)
196 $seedLanguage = 'en_US';
198 // CRM-16801 This validates that seedLanguage is valid by looking in $langs.
199 // NB: the variable is initial a $_REQUEST for the initial page reload,
200 // then becomes a $_POST when the installation form is submitted.
201 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
202 $seedLanguage = $_REQUEST['seedLanguage'];
203 $tsLocale = $_REQUEST['seedLanguage'];
206 $config = CRM_Core_Config
::singleton(FALSE);
207 $GLOBALS['civicrm_default_error_scope'] = NULL;
209 // The translation files are in the parent directory (l10n)
210 $i18n = CRM_Core_I18n
::singleton();
212 // Support for Arabic, Hebrew, Farsi, etc.
213 // Used in the template.html
214 $short_lang_code = CRM_Core_I18n_PseudoConstant
::shortForLong($tsLocale);
215 $text_direction = (CRM_Core_I18n
::isLanguageRTL($tsLocale) ?
'rtl' : 'ltr');
218 if ($installType == 'drupal') {
219 //CRM-6840 -don't force to install in sites/all/modules/
220 $object = new CRM_Utils_System_Drupal();
221 $cmsPath = $object->cmsRootPath();
223 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
224 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
225 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
226 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
227 'civicrm.settings.php'
230 elseif ($installType == 'backdrop') {
231 $object = new CRM_Utils_System_Backdrop();
232 $cmsPath = $object->cmsRootPath();
233 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
234 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
. 'civicrm.settings.php');
236 elseif ($installType == 'wordpress') {
237 $cmsPath = WP_PLUGIN_DIR
. DIRECTORY_SEPARATOR
. 'civicrm';
238 $upload_dir = wp_upload_dir();
239 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR
. 'civicrm';
240 $wp_civi_settings = $upload_dir['basedir'] . DIRECTORY_SEPARATOR
. 'civicrm' . DIRECTORY_SEPARATOR
. 'civicrm.settings.php';
241 $wp_civi_settings_deprectated = CIVICRM_PLUGIN_DIR
. 'civicrm.settings.php';
242 if (file_exists($wp_civi_settings_deprectated)) {
243 $alreadyInstalled = $wp_civi_settings_deprectated;
245 elseif (file_exists($wp_civi_settings)) {
246 $alreadyInstalled = $wp_civi_settings;
250 if ($installType == 'drupal') {
251 // Lets check only /modules/.
252 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR
. 'modules', CIVICRM_DIRECTORY_SEPARATOR
) . '/';
254 if (!preg_match($pattern, str_replace("\\", "/", $_SERVER['SCRIPT_FILENAME']))) {
255 $directory = implode(CIVICRM_DIRECTORY_SEPARATOR
, array('sites', 'all', 'modules'));
256 $errorTitle = ts("Oops! Please correct your install location");
257 $errorMsg = ts("Please untar (uncompress) your downloaded copy of CiviCRM in the <strong>%1</strong> directory below your Drupal root directory.", array(1 => $directory));
258 errorDisplayPage($errorTitle, $errorMsg);
262 if ($installType == 'backdrop') {
263 // Lets check only /modules/.
264 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR
. 'modules', CIVICRM_DIRECTORY_SEPARATOR
) . '/';
266 if (!preg_match($pattern, str_replace("\\", "/", $_SERVER['SCRIPT_FILENAME']))) {
267 $directory = 'modules';
268 $errorTitle = ts("Oops! Please correct your install location");
269 $errorMsg = ts("Please untar (uncompress) your downloaded copy of CiviCRM in the <strong>%1</strong> directory below your Drupal root directory.", array(1 => $directory));
270 errorDisplayPage($errorTitle, $errorMsg);
274 // Exit with error if CiviCRM has already been installed.
275 if ($alreadyInstalled) {
276 $errorTitle = ts("Oops! CiviCRM is already installed");
277 $settings_directory = $cmsPath;
279 if ($installType == 'drupal') {
280 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR
, array(
281 ts('[your Drupal root directory]'),
286 if ($installType == 'backdrop') {
287 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR
, array(
288 ts('[your Backdrop root directory]'),
293 $docLink = CRM_Utils_System
::docURL2('Installation and Upgrades', FALSE, ts('Installation Guide'), NULL, NULL, "wiki");
294 $errorMsg = ts("CiviCRM has already been installed. <ul><li>To <strong>start over</strong>, you must delete or rename the existing CiviCRM settings file - <strong>civicrm.settings.php</strong> - from <strong>%1</strong>.</li><li>To <strong>upgrade an existing installation</strong>, <a href='%2'>refer to the online documentation</a>.</li></ul>", array(1 => $settings_directory, 2 => $docLink));
295 errorDisplayPage($errorTitle, $errorMsg, FALSE);
298 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'civicrm-version.php';
299 if (file_exists($versionFile)) {
300 require_once $versionFile;
301 $civicrm_version = civicrmVersion();
304 $civicrm_version = 'unknown';
307 if ($installType == 'drupal') {
308 // Ensure that they have downloaded the correct version of CiviCRM
309 if ($civicrm_version['cms'] != 'Drupal' && $civicrm_version['cms'] != 'Drupal6') {
310 $errorTitle = ts("Oops! Incorrect CiviCRM version");
311 $errorMsg = ts("This installer can only be used for the Drupal version of CiviCRM.");
312 errorDisplayPage($errorTitle, $errorMsg);
315 define('DRUPAL_ROOT', $cmsPath);
316 $drupalVersionFiles = array(
318 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'modules', 'system', 'system.module')),
320 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'includes', 'bootstrap.inc')),
322 foreach ($drupalVersionFiles as $drupalVersionFile) {
323 if (file_exists($drupalVersionFile)) {
324 require_once $drupalVersionFile;
328 if (!defined('VERSION') or version_compare(VERSION
, '6.0') < 0) {
329 $errorTitle = ts("Oops! Incorrect Drupal version");
330 $errorMsg = ts("This version of CiviCRM can only be used with Drupal 6.x or 7.x. Please ensure that '%1' exists if you are running Drupal 7.0 and over.", array(1 => implode("' or '", $drupalVersionFiles)));
331 errorDisplayPage($errorTitle, $errorMsg);
334 elseif ($installType == 'backdrop') {
335 // Ensure that they have downloaded the correct version of CiviCRM
336 if ($civicrm_version['cms'] != 'Backdrop') {
337 $errorTitle = ts("Oops! Incorrect CiviCRM version");
338 $errorMsg = ts("This installer can only be used for the Backdrop version of CiviCRM.");
339 errorDisplayPage($errorTitle, $errorMsg);
342 define('BACKDROP_ROOT', $cmsPath);
344 $backdropVersionFiles = array(
346 implode(CIVICRM_DIRECTORY_SEPARATOR
, array($cmsPath, 'core', 'includes', 'bootstrap.inc')),
348 foreach ($backdropVersionFiles as $backdropVersionFile) {
349 if (file_exists($backdropVersionFile)) {
350 require_once $backdropVersionFile;
353 if (!defined('BACKDROP_VERSION') or version_compare(BACKDROP_VERSION
, '1.0') < 0) {
354 $errorTitle = ts("Oops! Incorrect Backdrop version");
355 $errorMsg = ts("This version of CiviCRM can only be used with Backdrop 1.x. Please ensure that '%1' exists if you are running Backdrop 1.0 and over.", array(1 => implode("' or '", $backdropVersionFiles)));
356 errorDisplayPage($errorTitle, $errorMsg);
359 elseif ($installType == 'wordpress') {
361 $civicrm_version['cms'] = 'WordPress';
363 // Ensure that they have downloaded the correct version of CiviCRM
364 if ($civicrm_version['cms'] != 'WordPress') {
365 $errorTitle = ts("Oops! Incorrect CiviCRM version");
366 $errorMsg = ts("This installer can only be used for the WordPress version of CiviCRM.");
367 errorDisplayPage($errorTitle, $errorMsg);
371 // Check requirements
372 $req = new InstallRequirements();
375 if ($req->hasErrors()) {
376 $hasErrorOtherThanDatabase = TRUE;
379 if ($databaseConfig) {
380 $dbReq = new InstallRequirements();
381 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
382 if ($installType == 'drupal') {
383 $dbReq->checkdatabase($drupalConfig, 'Drupal');
385 if ($installType == 'backdrop') {
386 $dbReq->checkdatabase($backdropConfig, 'Backdrop');
391 if (isset($_POST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
392 // Confirm before reinstalling
393 if (!isset($_POST['force_reinstall']) && $alreadyInstalled) {
394 include $installDirPath . 'template.html';
397 $inst = new Installer();
398 $inst->install($_POST);
401 // Show the config form
404 include $installDirPath . 'template.html';
408 * This class checks requirements
409 * Each of the requireXXX functions takes an argument which gives a user description of the test. It's an array
411 * $description[0] - The test category
412 * $description[1] - The test title
413 * $description[2] - The test error to show, if it goes wrong
415 class InstallRequirements
{
416 var $errors, $warnings, $tests, $conn;
418 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
419 const MINIMUM_THREAD_STACK
= 192;
422 * Just check that the database configuration is okay.
423 * @param $databaseConfig
426 public function checkdatabase($databaseConfig, $dbName) {
427 if ($this->requireFunction('mysqli_connect',
429 ts("PHP Configuration"),
431 ts("MySQL support not included in PHP."),
435 $this->requireMySQLServer($databaseConfig['server'],
437 ts("MySQL %1 Configuration", array(1 => $dbName)),
438 ts("Does the server exist?"),
439 ts("Can't find the a MySQL server on '%1'.", array(1 => $databaseConfig['server'])),
440 $databaseConfig['server'],
443 if ($this->requireMysqlConnection($databaseConfig['server'],
444 $databaseConfig['username'],
445 $databaseConfig['password'],
447 ts("MySQL %1 Configuration", array(1 => $dbName)),
448 ts("Are the access credentials correct?"),
449 ts("That username/password doesn't work"),
453 @$this->requireMySQLVersion("5.1",
455 ts("MySQL %1 Configuration", array(1 => $dbName)),
456 ts("MySQL version at least %1", array(1 => '5.1')),
457 ts("MySQL version %1 or higher is required, you are running MySQL %2.", array(1 => '5.1', 2 => mysqli_get_server_info($this->conn
))),
458 ts("MySQL %1", array(1 => mysqli_get_server_info($this->conn
))),
461 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
462 $databaseConfig['username'],
463 $databaseConfig['password'],
465 ts("MySQL %1 Configuration", array(1 => $dbName)),
466 ts("Is auto_increment_increment set to 1"),
467 ts("An auto_increment_increment value greater than 1 is not currently supported. Please see issue CRM-7923 for further details and potential workaround."),
470 $testDetails = array(
471 ts("MySQL %1 Configuration", array(1 => $dbName)),
472 ts("Is the provided database name valid?"),
473 ts("The database name provided is not valid. Please use only 0-9, a-z, A-Z, _ and - as characters in the name."),
475 if (!CRM_Core_DAO
::requireSafeDBName($databaseConfig['database'])) {
476 $this->error($testDetails);
480 $this->testing($testDetails);
482 $this->requireMySQLThreadStack($databaseConfig['server'],
483 $databaseConfig['username'],
484 $databaseConfig['password'],
485 $databaseConfig['database'],
486 self
::MINIMUM_THREAD_STACK
,
488 ts("MySQL %1 Configuration", array(1 => $dbName)),
489 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self
::MINIMUM_THREAD_STACK
)),
491 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
495 $onlyRequire = ($dbName == 'Drupal' ||
$dbName == 'Backdrop') ?
TRUE : FALSE;
496 $this->requireDatabaseOrCreatePermissions(
497 $databaseConfig['server'],
498 $databaseConfig['username'],
499 $databaseConfig['password'],
500 $databaseConfig['database'],
502 ts("MySQL %1 Configuration", array(1 => $dbName)),
503 ts("Can I access/create the database?"),
504 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
508 if ($dbName != 'Drupal' && $dbName != 'Backdrop') {
509 $this->requireMySQLInnoDB($databaseConfig['server'],
510 $databaseConfig['username'],
511 $databaseConfig['password'],
512 $databaseConfig['database'],
514 ts("MySQL %1 Configuration", array(1 => $dbName)),
515 ts("Can I access/create InnoDB tables in the database?"),
516 ts("Unable to create InnoDB tables. MySQL InnoDB support is required for CiviCRM but is either not available or not enabled in this MySQL database server."),
519 $this->requireMySQLTempTables($databaseConfig['server'],
520 $databaseConfig['username'],
521 $databaseConfig['password'],
522 $databaseConfig['database'],
524 ts("MySQL %1 Configuration", array(1 => $dbName)),
525 ts('Can I create temporary tables in the database?'),
526 ts('Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.'),
529 $this->requireMySQLLockTables($databaseConfig['server'],
530 $databaseConfig['username'],
531 $databaseConfig['password'],
532 $databaseConfig['database'],
534 ts("MySQL %1 Configuration", array(1 => $dbName)),
535 ts('Can I create lock tables in the database?'),
536 ts('Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.'),
539 $this->requireMySQLTrigger($databaseConfig['server'],
540 $databaseConfig['username'],
541 $databaseConfig['password'],
542 $databaseConfig['database'],
544 ts("MySQL %1 Configuration", array(1 => $dbName)),
545 ts('Can I create triggers in the database?'),
546 ts('Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.'),
554 * Connect via mysqli.
556 * This is exactly the same as mysqli_connect(), except that it accepts
557 * the port as part of the `$host`.
559 * @param string $host
560 * Ex: 'localhost', 'localhost:3307', '127.0.0.1:3307', '[::1]', '[::1]:3307'.
561 * @param string $username
562 * @param string $password
563 * @param string $database
566 protected function connect($host, $username, $password, $database = '') {
567 $hostParts = explode(':', $host);
568 if (count($hostParts) > 1 && strrpos($host, ']') !== strlen($host) - 1) {
569 $port = array_pop($hostParts);
570 $host = implode(':', $hostParts);
575 $conn = @mysqli_connect
($host, $username, $password, $database, $port);
580 * Check everything except the database.
582 public function check() {
583 global $crmPath, $installType;
585 $this->errors
= NULL;
587 // See also: CRM_Upgrade_Incremental_General::MIN_INSTALL_PHP_VER
588 $this->requirePHPVersion('5.3.4', array(
589 ts("PHP Configuration"),
590 ts("PHP5 installed"),
592 ts("PHP version %1", array(1 => phpversion())),
595 // Check that we can identify the root folder successfully
596 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. 'README.md',
598 ts("File permissions"),
599 ts("Does the webserver know where files are stored?"),
600 ts("The webserver isn't letting me identify where files are stored."),
606 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
607 $this->requireNoPathSeparator(
609 ts("File permissions"),
610 ts('Does the CiviCRM path contain PATH_SEPARATOR?'),
611 ts('The path %1 contains PATH_SEPARATOR (the %2 character).', array(1 => $this->getBaseDir(), 2 => PATH_SEPARATOR
)),
616 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
617 foreach ($requiredDirectories as $dir) {
618 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR
. $dir,
620 ts("File permissions"),
621 ts("Folder '%1' exists?", array(1 => $dir)),
622 ts("There is no '%1' folder.", array(1 => $dir)),
627 $configIDSiniDir = NULL;
629 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
630 if ($installType == 'drupal') {
632 // make sure that we can write to sites/default and files/
633 $writableDirectories = array(
634 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
635 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
636 $siteDir . CIVICRM_DIRECTORY_SEPARATOR
.
638 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
639 'sites' . CIVICRM_DIRECTORY_SEPARATOR
.
643 elseif ($installType == 'backdrop') {
645 // make sure that we can write to sites/default and files/
646 $writableDirectories = array(
647 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
652 elseif ($installType == 'wordpress') {
653 // make sure that we can write to uploads/civicrm/
654 $upload_dir = wp_upload_dir();
655 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR
. 'civicrm';
656 if (!file_exists($files_dirname)) {
657 wp_mkdir_p($files_dirname);
659 $writableDirectories = array($files_dirname);
662 foreach ($writableDirectories as $dir) {
663 $dirName = CIVICRM_WINDOWS ?
$dir : CIVICRM_DIRECTORY_SEPARATOR
. $dir;
664 $testDetails = array(
665 ts("File permissions"),
666 ts("Is the %1 folder writeable?", array(1 => $dir)),
669 $this->requireWriteable($dirName, $testDetails, TRUE);
672 //check for Config.IDS.ini, file may exist in re-install
673 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
675 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
676 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR
, $configIDSiniDir);
677 if (file_exists($configIDSiniFile)) {
678 unlink($configIDSiniFile);
682 // Check for rewriting
683 if (isset($_SERVER['SERVER_SOFTWARE'])) {
684 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
686 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
687 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
690 if ($webserver == '') {
691 $webserver = ts("I can't tell what webserver you are running");
694 // Check for $_SERVER configuration
695 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
696 ts("Webserver config"),
697 ts("Recognised webserver"),
698 ts("You seem to be using an unsupported webserver. The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."),
701 // Check for MySQL support
702 $this->requireFunction('mysqli_connect', array(
703 ts("PHP Configuration"),
705 ts("MySQL support not included in PHP."),
708 // Check for XML support
709 $this->requireFunction('simplexml_load_file', array(
710 ts("PHP Configuration"),
711 ts("SimpleXML support"),
712 ts("SimpleXML support not included in PHP."),
715 // Check for JSON support
716 $this->requireFunction('json_encode', array(
717 ts("PHP Configuration"),
719 ts("JSON support not included in PHP."),
722 // Check for xcache_isset and emit warning if exists
723 $this->checkXCache(array(
724 ts("PHP Configuration"),
725 ts("XCache compatibility"),
726 ts("XCache is installed and there are known compatibility issues between XCache and CiviCRM. Consider using an alternative PHP caching mechanism or disable PHP caching altogether."),
729 // Check memory allocation
730 $this->requireMemory(32 * 1024 * 1024,
733 ts("PHP Configuration"),
734 ts("Memory allocated (PHP config option 'memory_limit')"),
735 ts("CiviCRM needs a minimum of %1 MB allocated to PHP, but recommends %2 MB.", array(1 => 32, 2 => 64)),
736 ini_get("memory_limit"),
740 return $this->errors
;
745 * @param $recommended
746 * @param $testDetails
748 public function requireMemory($min, $recommended, $testDetails) {
749 $this->testing($testDetails);
750 $mem = $this->getPHPMemory();
752 if ($mem < $min && $mem > 0) {
753 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
754 $this->error($testDetails);
756 elseif ($mem < $recommended && $mem > 0) {
757 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
758 $this->warning($testDetails);
761 $testDetails[2] .= " " . ts("We can't determine how much memory you have allocated. Install only if you're sure you've allocated at least %1 MB.", array(1 => 32));
762 $this->warning($testDetails);
769 public function getPHPMemory() {
770 $memString = ini_get("memory_limit");
772 switch (strtolower(substr($memString, -1))) {
774 return round(substr($memString, 0, -1) * 1024);
777 return round(substr($memString, 0, -1) * 1024 * 1024);
780 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
783 return round($memString);
787 public function listErrors() {
789 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
790 foreach ($this->errors
as $error) {
791 echo "<li>" . htmlentities($error) . "</li>";
797 * @param null $section
799 public function showTable($section = NULL) {
801 $tests = $this->tests
[$section];
802 echo "<table class=\"testResults\" width=\"100%\">";
803 foreach ($tests as $test => $result) {
804 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
809 foreach ($this->tests
as $section => $tests) {
810 echo "<h3>$section</h3>";
811 echo "<table class=\"testResults\" width=\"100%\">";
813 foreach ($tests as $test => $result) {
814 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
822 * @param string $funcName
823 * @param $testDetails
827 public function requireFunction($funcName, $testDetails) {
828 $this->testing($testDetails);
830 if (!function_exists($funcName)) {
831 $this->error($testDetails);
840 * @param $testDetails
842 public function checkXCache($testDetails) {
843 if (function_exists('xcache_isset') &&
844 ini_get('xcache.size') > 0
846 $this->testing($testDetails);
847 $this->warning($testDetails);
853 * @param $testDetails
854 * @param null $maxVersion
856 public function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
858 $this->testing($testDetails);
860 $phpVersion = phpversion();
861 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
862 $belowMaxVersion = $maxVersion ?
version_compare($phpVersion, $maxVersion) < 0 : TRUE;
864 if ($aboveMinVersion && $belowMaxVersion) {
865 if (version_compare(phpversion(), CRM_Upgrade_Incremental_General
::MIN_RECOMMENDED_PHP_VER
) < 0) {
866 $testDetails[2] = ts('This webserver is running an outdated version of PHP (%1). It is strongly recommended to upgrade to PHP %2 or later, as older versions can present a security risk.', array(
868 2 => CRM_Upgrade_Incremental_General
::MIN_RECOMMENDED_PHP_VER
,
870 $this->warning($testDetails);
875 if (!$testDetails[2]) {
876 if (!$aboveMinVersion) {
877 $testDetails[2] = ts("You need PHP version %1 or later, only %2 is installed. Please upgrade your server, or ask your web-host to do so.", array(1 => $minVersion, 2 => $phpVersion));
880 $testDetails[2] = ts("PHP version %1 is not supported. PHP version earlier than %2 is required. You might want to downgrade your server, or ask your web-host to do so.", array(1 => $maxVersion, 2 => $phpVersion));
884 $this->error($testDetails);
888 * @param string $filename
889 * @param $testDetails
890 * @param bool $absolute
892 public function requireFile($filename, $testDetails, $absolute = FALSE) {
893 $this->testing($testDetails);
895 $filename = $this->getBaseDir() . $filename;
897 if (!file_exists($filename)) {
898 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
899 $this->error($testDetails);
904 * @param $testDetails
906 public function requireNoPathSeparator($testDetails) {
907 $this->testing($testDetails);
908 if (substr_count($this->getBaseDir(), PATH_SEPARATOR
)) {
909 $this->error($testDetails);
914 * @param string $filename
915 * @param $testDetails
917 public function requireNoFile($filename, $testDetails) {
918 $this->testing($testDetails);
919 $filename = $this->getBaseDir() . $filename;
920 if (file_exists($filename)) {
921 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
922 $this->error($testDetails);
927 * @param string $filename
928 * @param $testDetails
930 public function moveFileOutOfTheWay($filename, $testDetails) {
931 $this->testing($testDetails);
932 $filename = $this->getBaseDir() . $filename;
933 if (file_exists($filename)) {
934 if (file_exists("$filename.bak")) {
937 rename($filename, "$filename.bak");
942 * @param string $filename
943 * @param $testDetails
944 * @param bool $absolute
946 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
947 $this->testing($testDetails);
949 $filename = $this->getBaseDir() . $filename;
952 if (!is_writable($filename)) {
954 if (function_exists('posix_getpwuid')) {
955 $user = posix_getpwuid(posix_geteuid());
956 $name = '- ' . $user['name'] . ' -';
959 if (!isset($testDetails[2])) {
960 $testDetails[2] = NULL;
962 $testDetails[2] .= ts("The user account used by your web-server %1 needs to be granted write access to the following directory in order to configure the CiviCRM settings file:", array(1 => $name)) . "\n$filename";
963 $this->error($testDetails);
968 * @param string $moduleName
969 * @param $testDetails
971 public function requireApacheModule($moduleName, $testDetails) {
972 $this->testing($testDetails);
973 if (!in_array($moduleName, apache_get_modules())) {
974 $this->error($testDetails);
980 * @param string $username
982 * @param $testDetails
984 public function requireMysqlConnection($server, $username, $password, $testDetails) {
985 $this->testing($testDetails);
986 $this->conn
= $this->connect($server, $username, $password);
992 $testDetails[2] .= ": " . mysqli_connect_error();
993 $this->error($testDetails);
999 * @param $testDetails
1001 public function requireMySQLServer($server, $testDetails) {
1002 $this->testing($testDetails);
1003 $conn = $this->connect($server, NULL, NULL);
1005 if ($conn ||
mysqli_connect_errno() < 2000) {
1009 $testDetails[2] .= ": " . mysqli_connect_error();
1010 $this->error($testDetails);
1016 * @param $testDetails
1018 public function requireMySQLVersion($version, $testDetails) {
1019 $this->testing($testDetails);
1021 if (!mysqli_get_server_info($this->conn
)) {
1022 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
1023 $this->warning($testDetails);
1026 list($majorRequested, $minorRequested) = explode('.', $version);
1027 list($majorHas, $minorHas) = explode('.', mysqli_get_server_info($this->conn
));
1029 if (($majorHas > $majorRequested) ||
($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
1033 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
1034 $this->error($testDetails);
1041 * @param string $username
1044 * @param $testDetails
1046 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
1047 $this->testing($testDetails);
1048 $conn = $this->connect($server, $username, $password);
1050 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
1051 $this->error($testDetails);
1055 $innodb_support = FALSE;
1056 $result = mysqli_query($conn, "SHOW ENGINES");
1057 while ($values = mysqli_fetch_array($result)) {
1058 if ($values['Engine'] == 'InnoDB') {
1059 if (strtolower($values['Support']) == 'yes' ||
1060 strtolower($values['Support']) == 'default'
1062 $innodb_support = TRUE;
1066 if ($innodb_support) {
1067 $testDetails[3] = ts('MySQL server does have InnoDB support');
1070 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
1076 * @param string $username
1079 * @param $testDetails
1081 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
1082 $this->testing($testDetails);
1083 $conn = $this->connect($server, $username, $password);
1085 $testDetails[2] = ts('Could not login to the database.');
1086 $this->error($testDetails);
1090 if (!@mysqli_select_db
($conn, $database)) {
1091 $testDetails[2] = ts('Could not select the database.');
1092 $this->error($testDetails);
1096 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
1098 $testDetails[2] = ts('Could not create a temp table.');
1099 $this->error($testDetails);
1101 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1106 * @param string $username
1109 * @param $testDetails
1111 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
1112 $this->testing($testDetails);
1113 $conn = $this->connect($server, $username, $password);
1115 $testDetails[2] = ts('Could not login to the database.');
1116 $this->error($testDetails);
1120 if (!@mysqli_select_db
($conn, $database)) {
1121 $testDetails[2] = ts('Could not select the database.');
1122 $this->error($testDetails);
1126 $result = mysqli_query($conn, 'CREATE TABLE civicrm_install_temp_table_test (test text)');
1128 $testDetails[2] = ts('Could not create a table in the database.');
1129 $this->error($testDetails);
1132 $result = mysqli_query($conn, 'CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
1134 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
1135 $testDetails[2] = ts('Could not create a database trigger.');
1136 $this->error($testDetails);
1139 mysqli_query($conn, 'DROP TRIGGER civicrm_install_temp_table_test_trigger');
1140 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
1146 * @param string $username
1149 * @param $testDetails
1151 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
1152 $this->testing($testDetails);
1153 $conn = $this->connect($server, $username, $password);
1155 $testDetails[2] = ts('Could not connect to the database server.');
1156 $this->error($testDetails);
1160 if (!@mysqli_select_db
($conn, $database)) {
1161 $testDetails[2] = ts('Could not select the database.');
1162 $this->error($testDetails);
1166 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
1168 $testDetails[2] = ts('Could not create a table in the database.');
1169 $this->error($testDetails);
1173 $result = mysqli_query($conn, 'LOCK TABLES civicrm_install_temp_table_test WRITE');
1175 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
1176 $this->error($testDetails);
1177 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1181 $result = mysqli_query($conn, 'UNLOCK TABLES');
1183 $testDetails[2] = ts('Could not release the lock for the database table.');
1184 $this->error($testDetails);
1185 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1189 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1194 * @param string $username
1196 * @param $testDetails
1198 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
1199 $this->testing($testDetails);
1200 $conn = $this->connect($server, $username, $password);
1202 $testDetails[2] = ts('Could not connect to the database server.');
1203 $this->error($testDetails);
1207 $result = mysqli_query($conn, "SHOW variables like 'auto_increment_increment'");
1209 $testDetails[2] = ts('Could not query database server variables.');
1210 $this->error($testDetails);
1214 $values = mysqli_fetch_row($result);
1215 if ($values[1] == 1) {
1216 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
1219 $this->error($testDetails);
1226 * @param string $username
1229 * @param $minValueKB
1230 * @param $testDetails
1232 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
1233 $this->testing($testDetails);
1234 $conn = $this->connect($server, $username, $password);
1236 $testDetails[2] = ts('Could not connect to the database server.');
1237 $this->error($testDetails);
1241 if (!@mysqli_select_db
($conn, $database)) {
1242 $testDetails[2] = ts('Could not select the database.');
1243 $this->error($testDetails);
1247 $result = mysqli_query($conn, "SHOW VARIABLES LIKE 'thread_stack'"); // bytes => kb
1249 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
1250 $this->error($testDetails);
1253 $values = mysqli_fetch_row($result);
1254 if ($values[1] < (1024 * $minValueKB)) {
1255 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
1256 $this->error($testDetails);
1263 * @param string $username
1266 * @param $testDetails
1267 * @param bool $onlyRequire
1269 public function requireDatabaseOrCreatePermissions(
1275 $onlyRequire = FALSE
1277 $this->testing($testDetails);
1278 $conn = $this->connect($server, $username, $password);
1281 if (@mysqli_select_db
($conn, $database)) {
1282 $okay = "Database '$database' exists";
1284 elseif ($onlyRequire) {
1285 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
1286 $this->error($testDetails);
1290 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1291 if (@mysqli_query
($conn, $query)) {
1292 $okay = ts("Able to create a new database.");
1295 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
1296 $this->error($testDetails);
1302 $testDetails[3] = $okay;
1303 $this->testing($testDetails);
1309 * @param $errorMessage
1311 public function requireServerVariables($varNames, $errorMessage) {
1312 //$this->testing($testDetails);
1313 foreach ($varNames as $varName) {
1314 if (!$_SERVER[$varName]) {
1315 $missing[] = '$_SERVER[' . $varName . ']';
1318 if (!isset($missing)) {
1322 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
1323 $this->error($testDetails);
1328 * @param $testDetails
1332 public function isRunningApache($testDetails) {
1333 $this->testing($testDetails);
1334 if (function_exists('apache_get_modules') ||
stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1338 $this->warning($testDetails);
1345 public function getBaseDir() {
1346 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR
;
1350 * @param $testDetails
1352 public function testing($testDetails) {
1353 if (!$testDetails) {
1357 $section = $testDetails[0];
1358 $test = $testDetails[1];
1360 $message = ts("OK");
1361 if (isset($testDetails[3])) {
1362 $message .= " ($testDetails[3])";
1365 $this->tests
[$section][$test] = array("good", $message);
1369 * @param $testDetails
1371 public function error($testDetails) {
1372 $section = $testDetails[0];
1373 $test = $testDetails[1];
1375 $this->tests
[$section][$test] = array("error", $testDetails[2]);
1376 $this->errors
[] = $testDetails;
1380 * @param $testDetails
1382 public function warning($testDetails) {
1383 $section = $testDetails[0];
1384 $test = $testDetails[1];
1386 $this->tests
[$section][$test] = array("warning", $testDetails[2]);
1387 $this->warnings
[] = $testDetails;
1393 public function hasErrors() {
1394 return count($this->errors
);
1400 public function hasWarnings() {
1401 return count($this->warnings
);
1409 class Installer
extends InstallRequirements
{
1416 public function createDatabaseIfNotExists($server, $username, $password, $database) {
1417 $conn = $this->connect($server, $username, $password);
1419 if (@mysqli_select_db
($conn, $database)) {
1420 // skip if database already present
1423 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1424 if (@mysqli_query
($conn, $query)) {
1427 $errorTitle = ts("Oops! Could not create database %1", array(1 => $database));
1428 $errorMsg = ts("We encountered an error when attempting to create the database. Please check your MySQL server permissions and the database name and try again.");
1429 errorDisplayPage($errorTitle, $errorMsg);
1438 public function install($config) {
1439 global $installDirPath;
1441 // create database if does not exists
1442 $this->createDatabaseIfNotExists($config['mysql']['server'],
1443 $config['mysql']['username'],
1444 $config['mysql']['password'],
1445 $config['mysql']['database']
1448 global $installDirPath;
1451 require_once $installDirPath . 'civicrm.php';
1452 civicrm_main($config);
1454 if (!$this->errors
) {
1455 global $installType, $installURLPath;
1457 $registerSiteURL = "https://civicrm.org/register-site";
1458 $commonOutputMessage
1459 = "<li>" . ts("Have you registered this site at CiviCRM.org? If not, please help strengthen the CiviCRM ecosystem by taking a few minutes to <a %1>fill out the site registration form</a>. The information collected will help us prioritize improvements, target our communications and build the community. If you have a technical role for this site, be sure to check Keep in Touch to receive technical updates (a low volume mailing list).", array(1 => "href='$registerSiteURL' target='_blank'")) . "</li>"
1460 . "<li>" . ts("We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.") . "</li>";
1465 $installType == 'drupal' &&
1466 version_compare(VERSION
, '7.0-rc1') >= 0
1472 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1473 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1474 $output .= '<head>';
1475 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1476 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1477 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1478 $output .= '</head>';
1479 $output .= '<body>';
1480 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1483 $drupalURL = civicrm_cms_base();
1484 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1485 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1487 $output .= "<li>" . ts("Drupal user permissions have been automatically set - giving anonymous and authenticated users access to public CiviCRM forms and features. We recommend that you <a %1>review these permissions</a> to ensure that they are appropriate for your requirements (<a %2>learn more...</a>)", array(1 => "target='_blank' href='{$drupalPermissionsURL}'", 2 => "target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'")) . "</li>";
1488 $output .= "<li>" . ts("Use the <a %1>Configuration Checklist</a> to review and configure settings for your new site", array(1 => "target='_blank' href='$drupalURL'")) . "</li>";
1489 $output .= $commonOutputMessage;
1491 // automatically enable CiviCRM module once it is installed successfully.
1492 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1493 global $cmsPath, $crmPath;
1495 // relative / abosolute paths are not working for drupal, hence using chdir()
1498 // Force the re-initialisation of the config singleton on the next call
1499 // since so far, we had used the Config object without loading the DB.
1500 $c = CRM_Core_Config
::singleton(FALSE);
1503 include_once "./includes/bootstrap.inc";
1504 include_once "./includes/unicode.inc";
1506 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1508 // prevent session information from being saved.
1509 drupal_save_session(FALSE);
1511 // Force the current user to anonymous.
1512 $original_user = $GLOBALS['user'];
1513 $GLOBALS['user'] = drupal_anonymous_user();
1515 // explicitly setting error reporting, since we cannot handle drupal related notices
1518 // rebuild modules, so that civicrm is added
1519 system_rebuild_module_data();
1521 // now enable civicrm module.
1522 module_enable(array('civicrm', 'civicrmtheme'));
1524 // SystemInstallEvent will be called from here with the first call of CRM_Core_Config,
1525 // which calls Core_BAO_ConfigSetting::applyLocale(), who will default to calling
1526 // Civi::settings()->get('lcMessages');
1527 // Therefore, we need to pass the seedLanguage before that.
1528 global $civicrm_setting;
1529 $civicrm_setting['domain']['lcMessages'] = $config['seedLanguage'];
1531 // clear block, page, theme, and hook caches
1532 drupal_flush_all_caches();
1534 //add basic drupal permissions
1535 civicrm_install_set_drupal_perms();
1537 // restore the user.
1538 $GLOBALS['user'] = $original_user;
1539 drupal_save_session(TRUE);
1542 $output .= '</div>';
1543 $output .= '</body>';
1544 $output .= '</html>';
1548 $installType == 'backdrop'
1554 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1555 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1556 $output .= '<head>';
1557 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1558 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1559 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1560 $output .= '</head>';
1561 $output .= '<body>';
1562 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1565 $backdropURL = civicrm_cms_base();
1566 $backdropPermissionsURL = "{$backdropURL}index.php?q=admin/config/people/permissions";
1567 $backdropURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1569 $output .= "<li>" . ts("Backdrop user permissions have been automatically set - giving anonymous and authenticated users access to public CiviCRM forms and features. We recommend that you <a %1>review these permissions</a> to ensure that they are appropriate for your requirements (<a %2>learn more...</a>)", array(1 => "target='_blank' href='{$backdropPermissionsURL}'", 2 => "target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'")) . "</li>";
1570 $output .= "<li>" . ts("Use the <a %1>Configuration Checklist</a> to review and configure settings for your new site", array(1 => "target='_blank' href='$backdropURL'")) . "</li>";
1571 $output .= $commonOutputMessage;
1573 // automatically enable CiviCRM module once it is installed successfully.
1574 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1575 global $cmsPath, $crmPath;
1577 // relative / abosolute paths are not working for drupal, hence using chdir()
1580 // Force the re-initialisation of the config singleton on the next call
1581 // since so far, we had used the Config object without loading the DB.
1582 $c = CRM_Core_Config
::singleton(FALSE);
1585 include_once "./core/includes/bootstrap.inc";
1586 include_once "./core/includes/unicode.inc";
1587 include_once "./core/includes/config.inc";
1589 backdrop_bootstrap(BACKDROP_BOOTSTRAP_FULL
);
1591 // prevent session information from being saved.
1592 backdrop_save_session(FALSE);
1594 // Force the current user to anonymous.
1595 $original_user = $GLOBALS['user'];
1596 $GLOBALS['user'] = backdrop_anonymous_user();
1598 // explicitly setting error reporting, since we cannot handle drupal related notices
1601 // rebuild modules, so that civicrm is added
1602 system_rebuild_module_data();
1604 // now enable civicrm module.
1605 module_enable(array('civicrm', 'civicrmtheme'));
1607 // clear block, page, theme, and hook caches
1608 backdrop_flush_all_caches();
1610 //add basic backdrop permissions
1611 civicrm_install_set_backdrop_perms();
1613 // restore the user.
1614 $GLOBALS['user'] = $original_user;
1615 backdrop_save_session(TRUE);
1617 //change the default language to one chosen
1618 if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
1619 civicrm_api3('Setting', 'create', array(
1620 'domain_id' => 'current_domain',
1621 'lcMessages' => $config['seedLanguage'],
1627 $output .= '</div>';
1628 $output .= '</body>';
1629 $output .= '</html>';
1632 elseif ($installType == 'drupal' && version_compare(VERSION
, '6.0') >= 0) {
1636 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1637 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1638 $output .= '<head>';
1639 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1640 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1641 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1642 $output .= '</head>';
1643 $output .= '<body>';
1644 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
1647 $drupalURL = civicrm_cms_base();
1648 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1649 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1651 $output .= "<li>" . ts("Drupal user permissions have been automatically set - giving anonymous and authenticated users access to public CiviCRM forms and features. We recommend that you <a %1>review these permissions</a> to ensure that they are appropriate for your requirements (<a %2>learn more...</a>)", array(1 => "target='_blank' href='{$drupalPermissionsURL}'", 2 => "target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'")) . "</li>";
1652 $output .= "<li>" . ts("Use the <a %1>Configuration Checklist</a> to review and configure settings for your new site", array(1 => "target='_blank' href='$drupalURL'")) . "</li>";
1653 $output .= $commonOutputMessage;
1655 // explicitly setting error reporting, since we cannot handle drupal related notices
1658 // automatically enable CiviCRM module once it is installed successfully.
1659 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1660 global $cmsPath, $crmPath;
1662 // relative / abosolute paths are not working for drupal, hence using chdir()
1665 // Force the re-initialisation of the config singleton on the next call
1666 // since so far, we had used the Config object without loading the DB.
1667 $c = CRM_Core_Config
::singleton(FALSE);
1670 include_once "./includes/bootstrap.inc";
1671 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL
);
1673 // rebuild modules, so that civicrm is added
1674 module_rebuild_cache();
1676 // now enable civicrm module.
1677 module_enable(array('civicrm'));
1679 // clear block, page, theme, and hook caches
1680 drupal_flush_all_caches();
1682 //add basic drupal permissions
1683 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)');
1687 elseif ($installType == 'wordpress') {
1688 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
1689 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
1692 $cmsURL = civicrm_cms_base();
1693 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1694 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1696 $output .= "<li>" . ts("WordPress user permissions have been automatically set - giving Anonymous and Subscribers access to public CiviCRM forms and features. We recommend that you <a %1>review these permissions</a> to ensure that they are appropriate for your requirements (<a %2>learn more...</a>)", array(1 => "target='_blank' href='{$wpPermissionsURL}'", 2 => "target='_blank' href='http://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles'")) . "</li>";
1697 $output .= "<li>" . ts("Use the <a %1>Configuration Checklist</a> to review and configure settings for your new site", array(1 => "target='_blank' href='$cmsURL'")) . "</li>";
1698 $output .= $commonOutputMessage;
1703 $c = CRM_Core_Config
::singleton(FALSE);
1705 $wpInstallRedirect = admin_url("?page=CiviCRM&q=civicrm&reset=1");
1707 window.location = '$wpInstallRedirect';
1712 return $this->errors
;
1717 function civicrm_install_set_drupal_perms() {
1718 if (!function_exists('db_select')) {
1719 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)');
1723 'access all custom data',
1724 'access uploaded files',
1725 'make online contributions',
1729 'register for events',
1731 'view event participants',
1732 'access CiviMail subscribe/unsubscribe pages',
1735 // Adding a permission that has not yet been assigned to a module by
1736 // a hook_permission implementation results in a database error.
1738 $allPerms = array_keys(module_invoke_all('permission'));
1739 foreach (array_diff($perms, $allPerms) as $perm) {
1741 'Cannot grant the %perm permission because it does not yet exist.',
1742 array('%perm' => $perm),
1746 $perms = array_intersect($perms, $allPerms);
1747 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID
, $perms);
1748 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID
, $perms);
1752 function civicrm_install_set_backdrop_perms() {
1754 'access all custom data',
1755 'access uploaded files',
1756 'make online contributions',
1760 'register for events',
1762 'view event participants',
1763 'access CiviMail subscribe/unsubscribe pages',
1766 // Adding a permission that has not yet been assigned to a module by
1767 // a hook_permission implementation results in a database error.
1769 $allPerms = array_keys(module_invoke_all('permission'));
1770 foreach (array_diff($perms, $allPerms) as $perm) {
1772 'Cannot grant the %perm permission because it does not yet exist.',
1773 array('%perm' => $perm),
1777 $perms = array_intersect($perms, $allPerms);
1778 user_role_grant_permissions(BACKDROP_AUTHENTICATED_ROLE
, $perms);
1779 user_role_grant_permissions(BACKDROP_ANONYMOUS_ROLE
, $perms);
1788 function getSiteDir($cmsPath, $str) {
1789 static $siteDir = '';
1795 $sites = CIVICRM_DIRECTORY_SEPARATOR
. 'sites' . CIVICRM_DIRECTORY_SEPARATOR
;
1796 $modules = CIVICRM_DIRECTORY_SEPARATOR
. 'modules' . CIVICRM_DIRECTORY_SEPARATOR
;
1797 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR
) .
1798 "([\-a-zA-Z0-9_.]+)" .
1799 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR
) . "/",
1800 $_SERVER['SCRIPT_FILENAME'], $matches
1802 $siteDir = isset($matches[1]) ?
$matches[1] : 'default';
1804 if (strtolower($siteDir) == 'all') {
1805 // For this case - use drupal's way of finding out multi-site directory
1806 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR
, $_SERVER['SCRIPT_FILENAME']);
1807 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1808 for ($i = count($uri) - 1; $i > 0; $i--) {
1809 for ($j = count($server); $j > 0; $j--) {
1810 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1811 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR
.
1812 'sites' . CIVICRM_DIRECTORY_SEPARATOR
. $dir
1819 $siteDir = 'default';
1826 * @param $errorTitle
1830 function errorDisplayPage($errorTitle, $errorMsg, $showRefer = TRUE) {
1832 $docLink = CRM_Utils_System
::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
1834 if (function_exists('ts')) {
1835 $errorMsg .= '<p>' . ts("<a %1>Refer to the online documentation for more information</a>", array(1 => "href='$docLink'")) . '</p>';
1838 $errorMsg .= '<p>' . sprintf("<a %s>Refer to the online documentation for more information</a>", "href='$docLink'") . '</p>';
1842 include 'error.html';