Merge pull request #10924 from MegaphoneJon/CRM-21129
[civicrm-core.git] / install / index.php
CommitLineData
6a488035
TO
1<?php
2
3/**
4 * Note that this installer has been based of the SilverStripe installer.
5 * You can get more information from the SilverStripe Website at
47465875 6 * http://www.silverstripe.com/.
6a488035
TO
7 *
8 * Copyright (c) 2006-7, SilverStripe Limited - www.silverstripe.com
9 * All rights reserved.
10 *
47465875
DS
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
14 * met:
15 *
16 * Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 *
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.
22 *
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.
26 *
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.
38 *
626f739f 39 * Changes and modifications (c) 2007-2017 by CiviCRM LLC
6a488035
TO
40 *
41 */
42
43/**
44 * CiviCRM Installer
45 */
6a488035
TO
46ini_set('max_execution_time', 3000);
47
48if (stristr(PHP_OS, 'WIN')) {
49 define('CIVICRM_DIRECTORY_SEPARATOR', '/');
481a74f4 50 define('CIVICRM_WINDOWS', 1);
6a488035
TO
51}
52else {
53 define('CIVICRM_DIRECTORY_SEPARATOR', DIRECTORY_SEPARATOR);
481a74f4 54 define('CIVICRM_WINDOWS', 0);
6a488035
TO
55}
56
57// set installation type - drupal
58if (!session_id()) {
064bf239
CB
59 if (defined('PANTHEON_ENVIRONMENT')) {
60 ini_set('session.save_handler', 'files');
61 }
6a488035
TO
62 session_start();
63}
64
65// unset civicrm session if any
66if (array_key_exists('CiviCRM', $_SESSION)) {
67 unset($_SESSION['CiviCRM']);
68}
69
70if (isset($_GET['civicrm_install_type'])) {
71 $_SESSION['civicrm_install_type'] = $_GET['civicrm_install_type'];
72}
73else {
74 if (!isset($_SESSION['civicrm_install_type'])) {
75 $_SESSION['civicrm_install_type'] = "drupal";
76 }
77}
78
79global $installType;
6a488035 80global $crmPath;
97b8e6b2 81global $pkgPath;
6a488035
TO
82global $installDirPath;
83global $installURLPath;
97b8e6b2 84
6a9514e1
ML
85$installType = strtolower($_SESSION['civicrm_install_type']);
86
5757adf3 87if ($installType == 'drupal' || $installType == 'backdrop') {
6a488035
TO
88 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
89 $installDirPath = $installURLPath = '';
90}
91elseif ($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;
6a488035
TO
94 $installURLPath = WP_PLUGIN_URL . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR;
95}
6a9514e1
ML
96else {
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);
100}
6a488035 101
97b8e6b2 102$pkgPath = $crmPath . DIRECTORY_SEPARATOR . 'packages';
103
6a488035
TO
104require_once $crmPath . '/CRM/Core/ClassLoader.php';
105CRM_Core_ClassLoader::singleton()->register();
106
6a488035 107// Load civicrm database config
aca6ce6e
PN
108if (isset($_POST['mysql'])) {
109 $databaseConfig = $_POST['mysql'];
6a488035
TO
110}
111else {
7267b6be
KC
112 $databaseConfig = array(
113 "server" => "localhost",
114 "username" => "civicrm",
115 "password" => "",
116 "database" => "civicrm",
117 );
118}
119
120if ($installType == 'wordpress') {
f27341c6
KC
121 // Load WP database config
122 if (isset($_POST['mysql'])) {
123 $databaseConfig = $_POST['mysql'];
124 }
125 else {
e849a50e
KC
126 $databaseConfig = array(
127 "server" => DB_HOST,
128 "username" => DB_USER,
129 "password" => DB_PASSWORD,
130 "database" => DB_NAME,
131 );
f27341c6 132 }
6a488035
TO
133}
134
135if ($installType == 'drupal') {
136 // Load drupal database config
aca6ce6e
PN
137 if (isset($_POST['drupal'])) {
138 $drupalConfig = $_POST['drupal'];
6a488035
TO
139 }
140 else {
141 $drupalConfig = array(
142 "server" => "localhost",
143 "username" => "drupal",
144 "password" => "",
145 "database" => "drupal",
146 );
147 }
148}
149
5757adf3
HD
150if ($installType == 'backdrop') {
151 // Load backdrop database config
152 if (isset($_POST['backdrop'])) {
153 $backdropConfig = $_POST['backdrop'];
154 }
155 else {
156 $backdropConfig = array(
157 "server" => "localhost",
158 "username" => "backdrop",
159 "password" => "",
160 "database" => "backdrop",
161 );
162 }
163}
164
6a488035 165$loadGenerated = 0;
aca6ce6e 166if (isset($_POST['loadGenerated'])) {
6a488035
TO
167 $loadGenerated = 1;
168}
169
170require_once dirname(__FILE__) . CIVICRM_DIRECTORY_SEPARATOR . 'langs.php';
171foreach ($langs as $locale => $_) {
172 if ($locale == 'en_US') {
173 continue;
174 }
4f99ca55
TO
175 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
176 unset($langs[$locale]);
1f5f3294 177 }
6a488035
TO
178}
179
ece6501c 180// Set the CMS
97b8e6b2 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',
5757adf3 186 'backdrop' => 'Backdrop',
97b8e6b2 187);
188
c8ab0a65 189$uf = (isset($installTypeToUF[$installType]) ? $installTypeToUF[$installType] : 'Drupal');
97b8e6b2 190define('CIVICRM_UF', $uf);
191
ece6501c 192// Set the Locale (required by CRM_Core_Config)
97b8e6b2 193global $tsLocale;
194
195$tsLocale = 'en_US';
6a488035 196$seedLanguage = 'en_US';
97b8e6b2 197
5f6b3b5d
ML
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.
201if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
202 $seedLanguage = $_REQUEST['seedLanguage'];
203 $tsLocale = $_REQUEST['seedLanguage'];
6a488035
TO
204}
205
97b8e6b2 206$config = CRM_Core_Config::singleton(FALSE);
0ad1e2de
ML
207$GLOBALS['civicrm_default_error_scope'] = NULL;
208
97b8e6b2 209// The translation files are in the parent directory (l10n)
97b8e6b2 210$i18n = CRM_Core_I18n::singleton();
211
3a55aa6b
ML
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');
216
6a488035
TO
217global $cmsPath;
218if ($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();
222
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'
228 );
229}
5757adf3
HD
230elseif ($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');
235}
6a488035
TO
236elseif ($installType == 'wordpress') {
237 $cmsPath = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'civicrm';
7ba2c8ad
KC
238 $upload_dir = wp_upload_dir();
239 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm';
895a7985 240 $wp_civi_settings = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm.settings.php';
e7bf24e8
KC
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;
244 }
245 elseif (file_exists($wp_civi_settings)) {
246 $alreadyInstalled = $wp_civi_settings;
247 }
6a488035
TO
248}
249
6a9514e1
ML
250if ($installType == 'drupal') {
251 // Lets check only /modules/.
252 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR . 'modules', CIVICRM_DIRECTORY_SEPARATOR) . '/';
253
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);
259 }
260}
261
5757adf3
HD
262if ($installType == 'backdrop') {
263 // Lets check only /modules/.
264 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR . 'modules', CIVICRM_DIRECTORY_SEPARATOR) . '/';
265
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);
271 }
272}
273
6a488035
TO
274// Exit with error if CiviCRM has already been installed.
275if ($alreadyInstalled) {
6a9514e1
ML
276 $errorTitle = ts("Oops! CiviCRM is already installed");
277 $settings_directory = $cmsPath;
6a488035 278
6a9514e1
ML
279 if ($installType == 'drupal') {
280 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR, array(
281 ts('[your Drupal root directory]'),
282 'sites',
283 $siteDir,
284 ));
6a488035 285 }
5757adf3
HD
286 if ($installType == 'backdrop') {
287 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR, array(
288 ts('[your Backdrop root directory]'),
289 $siteDir,
290 ));
291 }
6a9514e1
ML
292
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);
6a488035
TO
296}
297
298$versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'civicrm-version.php';
299if (file_exists($versionFile)) {
1f5f3294 300 require_once $versionFile;
6a488035
TO
301 $civicrm_version = civicrmVersion();
302}
303else {
304 $civicrm_version = 'unknown';
305}
306
307if ($installType == 'drupal') {
308 // Ensure that they have downloaded the correct version of CiviCRM
6a9514e1
ML
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.");
6a488035
TO
312 errorDisplayPage($errorTitle, $errorMsg);
313 }
314
315 define('DRUPAL_ROOT', $cmsPath);
316 $drupalVersionFiles = array(
317 // D6
318 implode(CIVICRM_DIRECTORY_SEPARATOR, array($cmsPath, 'modules', 'system', 'system.module')),
319 // D7
320 implode(CIVICRM_DIRECTORY_SEPARATOR, array($cmsPath, 'includes', 'bootstrap.inc')),
321 );
322 foreach ($drupalVersionFiles as $drupalVersionFile) {
323 if (file_exists($drupalVersionFile)) {
324 require_once $drupalVersionFile;
325 }
326 }
327
328 if (!defined('VERSION') or version_compare(VERSION, '6.0') < 0) {
6a9514e1
ML
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)));
6a488035
TO
331 errorDisplayPage($errorTitle, $errorMsg);
332 }
333}
5757adf3
HD
334elseif ($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);
340 }
341
342 define('BACKDROP_ROOT', $cmsPath);
343
344 $backdropVersionFiles = array(
345 // Backdrop
346 implode(CIVICRM_DIRECTORY_SEPARATOR, array($cmsPath, 'core', 'includes', 'bootstrap.inc')),
347 );
348 foreach ($backdropVersionFiles as $backdropVersionFile) {
349 if (file_exists($backdropVersionFile)) {
350 require_once $backdropVersionFile;
351 }
352 }
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);
357 }
358}
6a488035
TO
359elseif ($installType == 'wordpress') {
360 //HACK for now
361 $civicrm_version['cms'] = 'WordPress';
362
363 // Ensure that they have downloaded the correct version of CiviCRM
364 if ($civicrm_version['cms'] != 'WordPress') {
6a9514e1
ML
365 $errorTitle = ts("Oops! Incorrect CiviCRM version");
366 $errorMsg = ts("This installer can only be used for the WordPress version of CiviCRM.");
6a488035
TO
367 errorDisplayPage($errorTitle, $errorMsg);
368 }
369}
370
371// Check requirements
372$req = new InstallRequirements();
373$req->check();
374
375if ($req->hasErrors()) {
376 $hasErrorOtherThanDatabase = TRUE;
377}
378
379if ($databaseConfig) {
380 $dbReq = new InstallRequirements();
381 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
382 if ($installType == 'drupal') {
383 $dbReq->checkdatabase($drupalConfig, 'Drupal');
384 }
5757adf3
HD
385 if ($installType == 'backdrop') {
386 $dbReq->checkdatabase($backdropConfig, 'Backdrop');
387 }
6a488035
TO
388}
389
390// Actual processor
aca6ce6e 391if (isset($_POST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
6a488035 392 // Confirm before reinstalling
aca6ce6e 393 if (!isset($_POST['force_reinstall']) && $alreadyInstalled) {
1f5f3294 394 include $installDirPath . 'template.html';
6a488035
TO
395 }
396 else {
397 $inst = new Installer();
aca6ce6e 398 $inst->install($_POST);
6a488035
TO
399 }
400
401 // Show the config form
402}
403else {
1f5f3294 404 include $installDirPath . 'template.html';
6a488035
TO
405}
406
407/**
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
410 * of 3 parts:
6a9514e1 411 * $description[0] - The test category
6a488035
TO
412 * $description[1] - The test title
413 * $description[2] - The test error to show, if it goes wrong
414 */
415class InstallRequirements {
fcf908c6 416 var $errors, $warnings, $tests, $conn;
6a488035
TO
417
418 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
419 const MINIMUM_THREAD_STACK = 192;
420
421 /**
fe482240 422 * Just check that the database configuration is okay.
d7c8cf03
EM
423 * @param $databaseConfig
424 * @param $dbName
6a488035 425 */
971d41b1 426 public function checkdatabase($databaseConfig, $dbName) {
fcf908c6 427 if ($this->requireFunction('mysqli_connect',
56fdfc52 428 array(
97b8e6b2 429 ts("PHP Configuration"),
430 ts("MySQL support"),
431 ts("MySQL support not included in PHP."),
56fdfc52
TO
432 )
433 )
434 ) {
6a488035
TO
435 $this->requireMySQLServer($databaseConfig['server'],
436 array(
2f8082cd
ML
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'])),
6a488035
TO
440 $databaseConfig['server'],
441 )
442 );
443 if ($this->requireMysqlConnection($databaseConfig['server'],
56fdfc52
TO
444 $databaseConfig['username'],
445 $databaseConfig['password'],
446 array(
2f8082cd
ML
447 ts("MySQL %1 Configuration", array(1 => $dbName)),
448 ts("Are the access credentials correct?"),
449 ts("That username/password doesn't work"),
56fdfc52
TO
450 )
451 )
452 ) {
6a488035
TO
453 @$this->requireMySQLVersion("5.1",
454 array(
2f8082cd
ML
455 ts("MySQL %1 Configuration", array(1 => $dbName)),
456 ts("MySQL version at least %1", array(1 => '5.1')),
fcf908c6 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))),
6a488035
TO
459 )
460 );
461 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
462 $databaseConfig['username'],
463 $databaseConfig['password'],
464 array(
2f8082cd
ML
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."),
6a488035
TO
468 )
469 );
e5d3a11d
PN
470 $testDetails = array(
471 ts("MySQL %1 Configuration", array(1 => $dbName)),
472 ts("Is the provided database name valid?"),
ee17d64d 473 ts("The database name provided is not valid. Please use only 0-9, a-z, A-Z, _ and - as characters in the name."),
e5d3a11d 474 );
ee17d64d 475 if (!CRM_Core_DAO::requireSafeDBName($databaseConfig['database'])) {
e5d3a11d 476 $this->error($testDetails);
ff3f52f7
PN
477 return FALSE;
478 }
e5d3a11d
PN
479 else {
480 $this->testing($testDetails);
481 }
6a488035
TO
482 $this->requireMySQLThreadStack($databaseConfig['server'],
483 $databaseConfig['username'],
484 $databaseConfig['password'],
485 $databaseConfig['database'],
486 self::MINIMUM_THREAD_STACK,
487 array(
2f8082cd
ML
488 ts("MySQL %1 Configuration", array(1 => $dbName)),
489 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self::MINIMUM_THREAD_STACK)),
56fdfc52
TO
490 "",
491 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
6a488035
TO
492 )
493 );
494 }
5757adf3 495 $onlyRequire = ($dbName == 'Drupal' || $dbName == 'Backdrop') ? TRUE : FALSE;
6a488035
TO
496 $this->requireDatabaseOrCreatePermissions(
497 $databaseConfig['server'],
498 $databaseConfig['username'],
499 $databaseConfig['password'],
500 $databaseConfig['database'],
501 array(
2f8082cd
ML
502 ts("MySQL %1 Configuration", array(1 => $dbName)),
503 ts("Can I access/create the database?"),
5f40a878 504 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
6a488035
TO
505 ),
506 $onlyRequire
507 );
5757adf3 508 if ($dbName != 'Drupal' && $dbName != 'Backdrop') {
6a488035
TO
509 $this->requireMySQLInnoDB($databaseConfig['server'],
510 $databaseConfig['username'],
511 $databaseConfig['password'],
512 $databaseConfig['database'],
513 array(
2f8082cd
ML
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."),
6a488035
TO
517 )
518 );
519 $this->requireMySQLTempTables($databaseConfig['server'],
520 $databaseConfig['username'],
521 $databaseConfig['password'],
522 $databaseConfig['database'],
523 array(
2f8082cd
ML
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.'),
6a488035
TO
527 )
528 );
529 $this->requireMySQLLockTables($databaseConfig['server'],
530 $databaseConfig['username'],
531 $databaseConfig['password'],
532 $databaseConfig['database'],
533 array(
2f8082cd
ML
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.'),
6a488035
TO
537 )
538 );
539 $this->requireMySQLTrigger($databaseConfig['server'],
540 $databaseConfig['username'],
541 $databaseConfig['password'],
542 $databaseConfig['database'],
543 array(
2f8082cd
ML
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.'),
6a488035
TO
547 )
548 );
549 }
550 }
551 }
552
6a511829
TO
553 /**
554 * Connect via mysqli.
555 *
556 * This is exactly the same as mysqli_connect(), except that it accepts
557 * the port as part of the `$host`.
558 *
28d4c718
TO
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
6a511829
TO
563 * @param string $database
564 * @return \mysqli
565 */
566 protected function connect($host, $username, $password, $database = '') {
567 $hostParts = explode(':', $host);
8e1997f9
TO
568 if (count($hostParts) > 1 && strrpos($host, ']') !== strlen($host) - 1) {
569 $port = array_pop($hostParts);
570 $host = implode(':', $hostParts);
6a511829
TO
571 }
572 else {
5df2c60d 573 $port = NULL;
6a511829
TO
574 }
575 $conn = @mysqli_connect($host, $username, $password, $database, $port);
576 return $conn;
577 }
578
6a488035 579 /**
fe482240 580 * Check everything except the database.
6a488035 581 */
971d41b1 582 public function check() {
6a488035
TO
583 global $crmPath, $installType;
584
585 $this->errors = NULL;
586
d0c1e96f
TO
587 // See also: CRM_Upgrade_Incremental_General::MIN_INSTALL_PHP_VER
588 $this->requirePHPVersion('5.3.4', array(
2f8082cd
ML
589 ts("PHP Configuration"),
590 ts("PHP5 installed"),
56fdfc52 591 NULL,
2f8082cd 592 ts("PHP version %1", array(1 => phpversion())),
56fdfc52 593 ));
6a488035
TO
594
595 // Check that we can identify the root folder successfully
d34d7fa8 596 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'README.md',
6a488035 597 array(
2f8082cd
ML
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."),
6a488035
TO
601 $this->getBaseDir(),
602 ),
603 TRUE
604 );
605
606 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
607 $this->requireNoPathSeparator(
608 array(
2f8082cd
ML
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)),
6a488035
TO
612 $this->getBaseDir(),
613 )
614 );
615
616 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
617 foreach ($requiredDirectories as $dir) {
618 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . $dir,
619 array(
2f8082cd
ML
620 ts("File permissions"),
621 ts("Folder '%1' exists?", array(1 => $dir)),
622 ts("There is no '%1' folder.", array(1 => $dir)),
56fdfc52 623 ), TRUE
6a488035
TO
624 );
625 }
626
627 $configIDSiniDir = NULL;
628 global $cmsPath;
3fdcdfbb 629 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
6a488035 630 if ($installType == 'drupal') {
6a488035
TO
631
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 .
637 'files',
638 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
639 'sites' . CIVICRM_DIRECTORY_SEPARATOR .
640 $siteDir,
641 );
642 }
5757adf3
HD
643 elseif ($installType == 'backdrop') {
644
645 // make sure that we can write to sites/default and files/
646 $writableDirectories = array(
647 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
648 'files',
649 $cmsPath,
650 );
651 }
6a488035 652 elseif ($installType == 'wordpress') {
7ba2c8ad
KC
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);
658 }
659 $writableDirectories = array($files_dirname);
6a488035
TO
660 }
661
662 foreach ($writableDirectories as $dir) {
663 $dirName = CIVICRM_WINDOWS ? $dir : CIVICRM_DIRECTORY_SEPARATOR . $dir;
2f8082cd
ML
664 $testDetails = array(
665 ts("File permissions"),
666 ts("Is the %1 folder writeable?", array(1 => $dir)),
667 NULL,
6a488035 668 );
2f8082cd 669 $this->requireWriteable($dirName, $testDetails, TRUE);
6a488035
TO
670 }
671
672 //check for Config.IDS.ini, file may exist in re-install
673 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
674
675 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
676 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR, $configIDSiniDir);
677 if (file_exists($configIDSiniFile)) {
678 unlink($configIDSiniFile);
679 }
680 }
681
682 // Check for rewriting
683 if (isset($_SERVER['SERVER_SOFTWARE'])) {
684 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
685 }
686 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
687 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
688 }
689
690 if ($webserver == '') {
2f8082cd 691 $webserver = ts("I can't tell what webserver you are running");
6a488035
TO
692 }
693
694 // Check for $_SERVER configuration
56fdfc52 695 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
2f8082cd
ML
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."),
56fdfc52 699 ));
6a488035
TO
700
701 // Check for MySQL support
fcf908c6 702 $this->requireFunction('mysqli_connect', array(
2f8082cd
ML
703 ts("PHP Configuration"),
704 ts("MySQL support"),
705 ts("MySQL support not included in PHP."),
706 ));
6a488035
TO
707
708 // Check for JSON support
2f8082cd
ML
709 $this->requireFunction('json_encode', array(
710 ts("PHP Configuration"),
711 ts("JSON support"),
712 ts("JSON support not included in PHP."),
713 ));
6a488035
TO
714
715 // Check for xcache_isset and emit warning if exists
716 $this->checkXCache(array(
2f8082cd
ML
717 ts("PHP Configuration"),
718 ts("XCache compatibility"),
719 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."),
56fdfc52 720 ));
6a488035
TO
721
722 // Check memory allocation
723 $this->requireMemory(32 * 1024 * 1024,
724 64 * 1024 * 1024,
725 array(
2f8082cd
ML
726 ts("PHP Configuration"),
727 ts("Memory allocated (PHP config option 'memory_limit')"),
728 ts("CiviCRM needs a minimum of %1 MB allocated to PHP, but recommends %2 MB.", array(1 => 32, 2 => 64)),
6a488035
TO
729 ini_get("memory_limit"),
730 )
731 );
732
733 return $this->errors;
734 }
735
627456b5
EM
736 /**
737 * @param $min
738 * @param $recommended
739 * @param $testDetails
740 */
971d41b1 741 public function requireMemory($min, $recommended, $testDetails) {
6a488035
TO
742 $this->testing($testDetails);
743 $mem = $this->getPHPMemory();
744
745 if ($mem < $min && $mem > 0) {
2f8082cd 746 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
6a488035
TO
747 $this->error($testDetails);
748 }
749 elseif ($mem < $recommended && $mem > 0) {
2f8082cd 750 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
6a488035
TO
751 $this->warning($testDetails);
752 }
753 elseif ($mem == 0) {
2f8082cd 754 $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));
6a488035
TO
755 $this->warning($testDetails);
756 }
757 }
758
627456b5
EM
759 /**
760 * @return float
761 */
971d41b1 762 public function getPHPMemory() {
6a488035
TO
763 $memString = ini_get("memory_limit");
764
765 switch (strtolower(substr($memString, -1))) {
766 case "k":
767 return round(substr($memString, 0, -1) * 1024);
768
769 case "m":
770 return round(substr($memString, 0, -1) * 1024 * 1024);
771
772 case "g":
773 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
774
775 default:
776 return round($memString);
777 }
778 }
779
971d41b1 780 public function listErrors() {
6a488035 781 if ($this->errors) {
2f8082cd 782 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
6a488035
TO
783 foreach ($this->errors as $error) {
784 echo "<li>" . htmlentities($error) . "</li>";
785 }
786 }
787 }
788
627456b5
EM
789 /**
790 * @param null $section
791 */
971d41b1 792 public function showTable($section = NULL) {
6a488035
TO
793 if ($section) {
794 $tests = $this->tests[$section];
795 echo "<table class=\"testResults\" width=\"100%\">";
796 foreach ($tests as $test => $result) {
797 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
798 }
799 echo "</table>";
800 }
801 else {
802 foreach ($this->tests as $section => $tests) {
803 echo "<h3>$section</h3>";
804 echo "<table class=\"testResults\" width=\"100%\">";
805
806 foreach ($tests as $test => $result) {
807 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
808 }
809 echo "</table>";
810 }
811 }
812 }
813
627456b5 814 /**
100fef9d 815 * @param string $funcName
627456b5
EM
816 * @param $testDetails
817 *
818 * @return bool
819 */
971d41b1 820 public function requireFunction($funcName, $testDetails) {
6a488035
TO
821 $this->testing($testDetails);
822
823 if (!function_exists($funcName)) {
824 $this->error($testDetails);
825 return FALSE;
826 }
827 else {
828 return TRUE;
829 }
830 }
831
627456b5
EM
832 /**
833 * @param $testDetails
834 */
971d41b1 835 public function checkXCache($testDetails) {
6a488035
TO
836 if (function_exists('xcache_isset') &&
837 ini_get('xcache.size') > 0
838 ) {
839 $this->testing($testDetails);
840 $this->warning($testDetails);
841 }
842 }
843
627456b5
EM
844 /**
845 * @param $minVersion
846 * @param $testDetails
847 * @param null $maxVersion
848 */
971d41b1 849 public function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
6a488035
TO
850
851 $this->testing($testDetails);
852
56fdfc52 853 $phpVersion = phpversion();
6a488035
TO
854 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
855 $belowMaxVersion = $maxVersion ? version_compare($phpVersion, $maxVersion) < 0 : TRUE;
856
ef064e55
CW
857 if ($aboveMinVersion && $belowMaxVersion) {
858 if (version_compare(phpversion(), CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER) < 0) {
859 $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(
860 1 => phpversion(),
861 2 => CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER,
862 ));
863 $this->warning($testDetails);
864 }
6a488035
TO
865 return TRUE;
866 }
867
868 if (!$testDetails[2]) {
869 if (!$aboveMinVersion) {
2f8082cd 870 $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));
6a488035
TO
871 }
872 else {
2f8082cd 873 $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));
6a488035
TO
874 }
875 }
876
877 $this->error($testDetails);
878 }
879
627456b5 880 /**
100fef9d 881 * @param string $filename
627456b5
EM
882 * @param $testDetails
883 * @param bool $absolute
884 */
971d41b1 885 public function requireFile($filename, $testDetails, $absolute = FALSE) {
6a488035
TO
886 $this->testing($testDetails);
887 if (!$absolute) {
888 $filename = $this->getBaseDir() . $filename;
889 }
890 if (!file_exists($filename)) {
2f8082cd 891 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
6a488035
TO
892 $this->error($testDetails);
893 }
894 }
895
627456b5
EM
896 /**
897 * @param $testDetails
898 */
971d41b1 899 public function requireNoPathSeparator($testDetails) {
6a488035
TO
900 $this->testing($testDetails);
901 if (substr_count($this->getBaseDir(), PATH_SEPARATOR)) {
902 $this->error($testDetails);
903 }
904 }
905
627456b5 906 /**
100fef9d 907 * @param string $filename
627456b5
EM
908 * @param $testDetails
909 */
971d41b1 910 public function requireNoFile($filename, $testDetails) {
6a488035
TO
911 $this->testing($testDetails);
912 $filename = $this->getBaseDir() . $filename;
913 if (file_exists($filename)) {
2f8082cd 914 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
6a488035
TO
915 $this->error($testDetails);
916 }
917 }
918
627456b5 919 /**
100fef9d 920 * @param string $filename
627456b5
EM
921 * @param $testDetails
922 */
971d41b1 923 public function moveFileOutOfTheWay($filename, $testDetails) {
6a488035
TO
924 $this->testing($testDetails);
925 $filename = $this->getBaseDir() . $filename;
926 if (file_exists($filename)) {
927 if (file_exists("$filename.bak")) {
928 rm("$filename.bak");
929 }
930 rename($filename, "$filename.bak");
931 }
932 }
933
627456b5 934 /**
100fef9d 935 * @param string $filename
627456b5
EM
936 * @param $testDetails
937 * @param bool $absolute
938 */
971d41b1 939 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
6a488035
TO
940 $this->testing($testDetails);
941 if (!$absolute) {
942 $filename = $this->getBaseDir() . $filename;
943 }
944
22e263ad 945 if (!is_writable($filename)) {
6a488035
TO
946 $name = NULL;
947 if (function_exists('posix_getpwuid')) {
948 $user = posix_getpwuid(posix_geteuid());
949 $name = '- ' . $user['name'] . ' -';
950 }
951
952 if (!isset($testDetails[2])) {
953 $testDetails[2] = NULL;
954 }
2f8082cd 955 $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";
6a488035
TO
956 $this->error($testDetails);
957 }
958 }
959
627456b5 960 /**
100fef9d 961 * @param string $moduleName
627456b5
EM
962 * @param $testDetails
963 */
971d41b1 964 public function requireApacheModule($moduleName, $testDetails) {
6a488035
TO
965 $this->testing($testDetails);
966 if (!in_array($moduleName, apache_get_modules())) {
967 $this->error($testDetails);
968 }
969 }
970
627456b5
EM
971 /**
972 * @param $server
100fef9d 973 * @param string $username
627456b5
EM
974 * @param $password
975 * @param $testDetails
976 */
971d41b1 977 public function requireMysqlConnection($server, $username, $password, $testDetails) {
6a488035 978 $this->testing($testDetails);
6a511829 979 $this->conn = $this->connect($server, $username, $password);
6a488035 980
fcf908c6 981 if ($this->conn) {
6a488035
TO
982 return TRUE;
983 }
984 else {
fcf908c6 985 $testDetails[2] .= ": " . mysqli_connect_error();
6a488035
TO
986 $this->error($testDetails);
987 }
988 }
989
627456b5
EM
990 /**
991 * @param $server
992 * @param $testDetails
993 */
971d41b1 994 public function requireMySQLServer($server, $testDetails) {
6a488035 995 $this->testing($testDetails);
6a511829 996 $conn = $this->connect($server, NULL, NULL);
6a488035 997
fcf908c6 998 if ($conn || mysqli_connect_errno() < 2000) {
6a488035
TO
999 return TRUE;
1000 }
1001 else {
fcf908c6 1002 $testDetails[2] .= ": " . mysqli_connect_error();
6a488035
TO
1003 $this->error($testDetails);
1004 }
1005 }
1006
627456b5
EM
1007 /**
1008 * @param $version
1009 * @param $testDetails
1010 */
971d41b1 1011 public function requireMySQLVersion($version, $testDetails) {
6a488035
TO
1012 $this->testing($testDetails);
1013
fcf908c6 1014 if (!mysqli_get_server_info($this->conn)) {
2f8082cd 1015 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
6a488035
TO
1016 $this->warning($testDetails);
1017 }
1018 else {
1019 list($majorRequested, $minorRequested) = explode('.', $version);
fcf908c6 1020 list($majorHas, $minorHas) = explode('.', mysqli_get_server_info($this->conn));
6a488035
TO
1021
1022 if (($majorHas > $majorRequested) || ($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
1023 return TRUE;
1024 }
1025 else {
1026 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
1027 $this->error($testDetails);
1028 }
1029 }
1030 }
1031
627456b5
EM
1032 /**
1033 * @param $server
100fef9d 1034 * @param string $username
627456b5
EM
1035 * @param $password
1036 * @param $database
1037 * @param $testDetails
1038 */
971d41b1 1039 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
6a488035 1040 $this->testing($testDetails);
6a511829 1041 $conn = $this->connect($server, $username, $password);
6a488035 1042 if (!$conn) {
2f8082cd 1043 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
6a488035
TO
1044 $this->error($testDetails);
1045 return;
1046 }
1047
1048 $innodb_support = FALSE;
fcf908c6 1049 $result = mysqli_query($conn, "SHOW ENGINES");
1050 while ($values = mysqli_fetch_array($result)) {
6a488035
TO
1051 if ($values['Engine'] == 'InnoDB') {
1052 if (strtolower($values['Support']) == 'yes' ||
1053 strtolower($values['Support']) == 'default'
1054 ) {
1055 $innodb_support = TRUE;
1056 }
1057 }
1058 }
1059 if ($innodb_support) {
2f8082cd 1060 $testDetails[3] = ts('MySQL server does have InnoDB support');
6a488035
TO
1061 }
1062 else {
2f8082cd 1063 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
6a488035
TO
1064 }
1065 }
1066
627456b5
EM
1067 /**
1068 * @param $server
100fef9d 1069 * @param string $username
627456b5
EM
1070 * @param $password
1071 * @param $database
1072 * @param $testDetails
1073 */
971d41b1 1074 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
6a488035 1075 $this->testing($testDetails);
6a511829 1076 $conn = $this->connect($server, $username, $password);
6a488035 1077 if (!$conn) {
2f8082cd 1078 $testDetails[2] = ts('Could not login to the database.');
6a488035
TO
1079 $this->error($testDetails);
1080 return;
1081 }
1082
fcf908c6 1083 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1084 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1085 $this->error($testDetails);
1086 return;
1087 }
1088
fcf908c6 1089 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
6a488035 1090 if (!$result) {
2f8082cd 1091 $testDetails[2] = ts('Could not create a temp table.');
6a488035
TO
1092 $this->error($testDetails);
1093 }
fcf908c6 1094 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1095 }
1096
627456b5
EM
1097 /**
1098 * @param $server
100fef9d 1099 * @param string $username
627456b5
EM
1100 * @param $password
1101 * @param $database
1102 * @param $testDetails
1103 */
971d41b1 1104 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
6a488035 1105 $this->testing($testDetails);
6a511829 1106 $conn = $this->connect($server, $username, $password);
6a488035 1107 if (!$conn) {
2f8082cd 1108 $testDetails[2] = ts('Could not login to the database.');
6a488035
TO
1109 $this->error($testDetails);
1110 return;
1111 }
1112
fcf908c6 1113 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1114 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1115 $this->error($testDetails);
1116 return;
1117 }
1118
fcf908c6 1119 $result = mysqli_query($conn, 'CREATE TABLE civicrm_install_temp_table_test (test text)');
6a488035 1120 if (!$result) {
2f8082cd 1121 $testDetails[2] = ts('Could not create a table in the database.');
6a488035
TO
1122 $this->error($testDetails);
1123 }
1124
fcf908c6 1125 $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');
6a488035 1126 if (!$result) {
fcf908c6 1127 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
2f8082cd 1128 $testDetails[2] = ts('Could not create a database trigger.');
6a488035
TO
1129 $this->error($testDetails);
1130 }
1131
fcf908c6 1132 mysqli_query($conn, 'DROP TRIGGER civicrm_install_temp_table_test_trigger');
1133 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
6a488035
TO
1134 }
1135
1136
627456b5
EM
1137 /**
1138 * @param $server
100fef9d 1139 * @param string $username
627456b5
EM
1140 * @param $password
1141 * @param $database
1142 * @param $testDetails
1143 */
971d41b1 1144 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
6a488035 1145 $this->testing($testDetails);
6a511829 1146 $conn = $this->connect($server, $username, $password);
6a488035 1147 if (!$conn) {
2f8082cd 1148 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1149 $this->error($testDetails);
1150 return;
1151 }
1152
fcf908c6 1153 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1154 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1155 $this->error($testDetails);
1156 return;
1157 }
1158
fcf908c6 1159 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
6a488035 1160 if (!$result) {
2f8082cd 1161 $testDetails[2] = ts('Could not create a table in the database.');
6a488035
TO
1162 $this->error($testDetails);
1163 return;
1164 }
1165
fcf908c6 1166 $result = mysqli_query($conn, 'LOCK TABLES civicrm_install_temp_table_test WRITE');
6a488035 1167 if (!$result) {
2f8082cd 1168 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
6a488035 1169 $this->error($testDetails);
fcf908c6 1170 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1171 return;
1172 }
1173
fcf908c6 1174 $result = mysqli_query($conn, 'UNLOCK TABLES');
6a488035 1175 if (!$result) {
2f8082cd 1176 $testDetails[2] = ts('Could not release the lock for the database table.');
6a488035 1177 $this->error($testDetails);
fcf908c6 1178 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1179 return;
1180 }
1181
fcf908c6 1182 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1183 }
1184
627456b5
EM
1185 /**
1186 * @param $server
100fef9d 1187 * @param string $username
627456b5
EM
1188 * @param $password
1189 * @param $testDetails
1190 */
971d41b1 1191 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
6a488035 1192 $this->testing($testDetails);
6a511829 1193 $conn = $this->connect($server, $username, $password);
6a488035 1194 if (!$conn) {
2f8082cd 1195 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1196 $this->error($testDetails);
1197 return;
1198 }
1199
fcf908c6 1200 $result = mysqli_query($conn, "SHOW variables like 'auto_increment_increment'");
6a488035 1201 if (!$result) {
2f8082cd 1202 $testDetails[2] = ts('Could not query database server variables.');
6a488035
TO
1203 $this->error($testDetails);
1204 return;
1205 }
1206 else {
fcf908c6 1207 $values = mysqli_fetch_row($result);
6a488035 1208 if ($values[1] == 1) {
2f8082cd 1209 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
6a488035
TO
1210 }
1211 else {
1212 $this->error($testDetails);
1213 }
1214 }
1215 }
1216
627456b5
EM
1217 /**
1218 * @param $server
100fef9d 1219 * @param string $username
627456b5
EM
1220 * @param $password
1221 * @param $database
1222 * @param $minValueKB
1223 * @param $testDetails
1224 */
971d41b1 1225 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
6a488035 1226 $this->testing($testDetails);
6a511829 1227 $conn = $this->connect($server, $username, $password);
6a488035 1228 if (!$conn) {
2f8082cd 1229 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1230 $this->error($testDetails);
1231 return;
1232 }
1233
fcf908c6 1234 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1235 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1236 $this->error($testDetails);
1237 return;
1238 }
1239
fcf908c6 1240 $result = mysqli_query($conn, "SHOW VARIABLES LIKE 'thread_stack'"); // bytes => kb
6a488035 1241 if (!$result) {
2f8082cd 1242 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
6a488035 1243 $this->error($testDetails);
0db6c3e1
TO
1244 }
1245 else {
fcf908c6 1246 $values = mysqli_fetch_row($result);
1f5f3294 1247 if ($values[1] < (1024 * $minValueKB)) {
2f8082cd 1248 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
6a488035
TO
1249 $this->error($testDetails);
1250 }
1251 }
1252 }
1253
627456b5
EM
1254 /**
1255 * @param $server
100fef9d 1256 * @param string $username
627456b5
EM
1257 * @param $password
1258 * @param $database
1259 * @param $testDetails
1260 * @param bool $onlyRequire
1261 */
971d41b1 1262 public function requireDatabaseOrCreatePermissions(
56fdfc52 1263 $server,
6a488035
TO
1264 $username,
1265 $password,
1266 $database,
1267 $testDetails,
1268 $onlyRequire = FALSE
1269 ) {
1270 $this->testing($testDetails);
6a511829 1271 $conn = $this->connect($server, $username, $password);
6a488035
TO
1272
1273 $okay = NULL;
fcf908c6 1274 if (@mysqli_select_db($conn, $database)) {
6a488035
TO
1275 $okay = "Database '$database' exists";
1276 }
1277 elseif ($onlyRequire) {
2f8082cd 1278 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
6a488035
TO
1279 $this->error($testDetails);
1280 return;
1281 }
1282 else {
fcf908c6 1283 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1284 if (@mysqli_query($conn, $query)) {
2f8082cd 1285 $okay = ts("Able to create a new database.");
6a488035
TO
1286 }
1287 else {
2f8082cd 1288 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
6a488035
TO
1289 $this->error($testDetails);
1290 return;
1291 }
1292 }
1293
1294 if ($okay) {
1295 $testDetails[3] = $okay;
1296 $this->testing($testDetails);
1297 }
1298 }
1299
627456b5
EM
1300 /**
1301 * @param $varNames
1302 * @param $errorMessage
1303 */
971d41b1 1304 public function requireServerVariables($varNames, $errorMessage) {
6a488035
TO
1305 //$this->testing($testDetails);
1306 foreach ($varNames as $varName) {
1307 if (!$_SERVER[$varName]) {
1308 $missing[] = '$_SERVER[' . $varName . ']';
1309 }
1310 }
1311 if (!isset($missing)) {
1312 return TRUE;
1313 }
1314 else {
2f8082cd 1315 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
6a488035
TO
1316 $this->error($testDetails);
1317 }
1318 }
1319
627456b5
EM
1320 /**
1321 * @param $testDetails
1322 *
1323 * @return bool
1324 */
971d41b1 1325 public function isRunningApache($testDetails) {
6a488035
TO
1326 $this->testing($testDetails);
1327 if (function_exists('apache_get_modules') || stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1328 return TRUE;
1329 }
1330
1331 $this->warning($testDetails);
1332 return FALSE;
1333 }
1334
627456b5
EM
1335 /**
1336 * @return string
1337 */
971d41b1 1338 public function getBaseDir() {
6a488035
TO
1339 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR;
1340 }
1341
627456b5
EM
1342 /**
1343 * @param $testDetails
1344 */
971d41b1 1345 public function testing($testDetails) {
6a488035
TO
1346 if (!$testDetails) {
1347 return;
1348 }
1349
1350 $section = $testDetails[0];
1351 $test = $testDetails[1];
1352
2f8082cd 1353 $message = ts("OK");
6a488035
TO
1354 if (isset($testDetails[3])) {
1355 $message .= " ($testDetails[3])";
1356 }
1357
1358 $this->tests[$section][$test] = array("good", $message);
1359 }
1360
627456b5
EM
1361 /**
1362 * @param $testDetails
1363 */
971d41b1 1364 public function error($testDetails) {
6a488035
TO
1365 $section = $testDetails[0];
1366 $test = $testDetails[1];
1367
1368 $this->tests[$section][$test] = array("error", $testDetails[2]);
1369 $this->errors[] = $testDetails;
1370 }
1371
627456b5
EM
1372 /**
1373 * @param $testDetails
1374 */
971d41b1 1375 public function warning($testDetails) {
6a488035
TO
1376 $section = $testDetails[0];
1377 $test = $testDetails[1];
1378
6a488035
TO
1379 $this->tests[$section][$test] = array("warning", $testDetails[2]);
1380 $this->warnings[] = $testDetails;
1381 }
1382
627456b5
EM
1383 /**
1384 * @return int
1385 */
971d41b1
CW
1386 public function hasErrors() {
1387 return count($this->errors);
6a488035
TO
1388 }
1389
627456b5
EM
1390 /**
1391 * @return int
1392 */
971d41b1
CW
1393 public function hasWarnings() {
1394 return count($this->warnings);
6a488035 1395 }
96025800 1396
6a488035
TO
1397}
1398
627456b5
EM
1399/**
1400 * Class Installer
1401 */
6a488035 1402class Installer extends InstallRequirements {
627456b5
EM
1403 /**
1404 * @param $server
1405 * @param $username
1406 * @param $password
1407 * @param $database
1408 */
971d41b1 1409 public function createDatabaseIfNotExists($server, $username, $password, $database) {
6a511829 1410 $conn = $this->connect($server, $username, $password);
6a488035 1411
fcf908c6 1412 if (@mysqli_select_db($conn, $database)) {
6a488035
TO
1413 // skip if database already present
1414 return;
1415 }
fcf908c6 1416 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1417 if (@mysqli_query($conn, $query)) {
56fdfc52 1418 }
6a488035 1419 else {
6a9514e1
ML
1420 $errorTitle = ts("Oops! Could not create database %1", array(1 => $database));
1421 $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.");
6a488035
TO
1422 errorDisplayPage($errorTitle, $errorMsg);
1423 }
1424 }
1425
627456b5
EM
1426 /**
1427 * @param $config
1428 *
1429 * @return mixed
1430 */
971d41b1 1431 public function install($config) {
6a488035
TO
1432 global $installDirPath;
1433
1434 // create database if does not exists
1435 $this->createDatabaseIfNotExists($config['mysql']['server'],
1436 $config['mysql']['username'],
1437 $config['mysql']['password'],
1438 $config['mysql']['database']
1439 );
1440
1441 global $installDirPath;
1442
1443 // Build database
1444 require_once $installDirPath . 'civicrm.php';
1445 civicrm_main($config);
1446
1447 if (!$this->errors) {
1448 global $installType, $installURLPath;
1449
bb216f68 1450 $registerSiteURL = "https://civicrm.org/register-site";
56de7273
ML
1451 $commonOutputMessage
1452 = "<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>"
1453 . "<li>" . ts("We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.") . "</li>";
41547a19 1454
6a488035 1455 $output = NULL;
97b8e6b2 1456
6a488035
TO
1457 if (
1458 $installType == 'drupal' &&
1459 version_compare(VERSION, '7.0-rc1') >= 0
1460 ) {
1461
1462 // clean output
1463 @ob_clean();
1464
1465 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1466 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1467 $output .= '<head>';
2f8082cd 1468 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
6a9514e1 1469 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6a488035
TO
1470 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1471 $output .= '</head>';
1472 $output .= '<body>';
2f8082cd 1473 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
6a488035 1474 $output .= '<ul>';
6a9514e1 1475
6a488035
TO
1476 $drupalURL = civicrm_cms_base();
1477 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1478 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
6a488035 1479
6a9514e1
ML
1480 $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>";
1481 $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>";
1482 $output .= $commonOutputMessage;
6a488035
TO
1483
1484 // automatically enable CiviCRM module once it is installed successfully.
1485 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1486 global $cmsPath, $crmPath;
1487
1488 // relative / abosolute paths are not working for drupal, hence using chdir()
1489 chdir($cmsPath);
1490
97b8e6b2 1491 // Force the re-initialisation of the config singleton on the next call
1492 // since so far, we had used the Config object without loading the DB.
1493 $c = CRM_Core_Config::singleton(FALSE);
1494 $c->free();
1495
6a488035
TO
1496 include_once "./includes/bootstrap.inc";
1497 include_once "./includes/unicode.inc";
1498
1499 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1500
1501 // prevent session information from being saved.
1502 drupal_save_session(FALSE);
1503
1504 // Force the current user to anonymous.
1505 $original_user = $GLOBALS['user'];
1506 $GLOBALS['user'] = drupal_anonymous_user();
1507
1508 // explicitly setting error reporting, since we cannot handle drupal related notices
1509 error_reporting(1);
1510
1511 // rebuild modules, so that civicrm is added
1512 system_rebuild_module_data();
1513
1514 // now enable civicrm module.
1515 module_enable(array('civicrm', 'civicrmtheme'));
1516
ece6501c
ML
1517 // SystemInstallEvent will be called from here with the first call of CRM_Core_Config,
1518 // which calls Core_BAO_ConfigSetting::applyLocale(), who will default to calling
1519 // Civi::settings()->get('lcMessages');
1520 // Therefore, we need to pass the seedLanguage before that.
1521 global $civicrm_setting;
1522 $civicrm_setting['domain']['lcMessages'] = $config['seedLanguage'];
1523
d8a4acc0
C
1524 // clear block, page, theme, and hook caches
1525 drupal_flush_all_caches();
6a488035
TO
1526
1527 //add basic drupal permissions
1528 civicrm_install_set_drupal_perms();
1529
1530 // restore the user.
1531 $GLOBALS['user'] = $original_user;
1532 drupal_save_session(TRUE);
1533
1534 $output .= '</ul>';
1535 $output .= '</div>';
1536 $output .= '</body>';
1537 $output .= '</html>';
1538 echo $output;
1539 }
5757adf3
HD
1540 elseif (
1541 $installType == 'backdrop'
1542 ) {
1543
1544 // clean output
1545 @ob_clean();
1546
1547 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1548 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1549 $output .= '<head>';
1550 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1551 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1552 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1553 $output .= '</head>';
1554 $output .= '<body>';
1555 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1556 $output .= '<ul>';
1557
1558 $backdropURL = civicrm_cms_base();
1559 $backdropPermissionsURL = "{$backdropURL}index.php?q=admin/config/people/permissions";
1560 $backdropURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1561
1562 $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>";
1563 $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>";
1564 $output .= $commonOutputMessage;
1565
1566 // automatically enable CiviCRM module once it is installed successfully.
1567 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1568 global $cmsPath, $crmPath;
1569
1570 // relative / abosolute paths are not working for drupal, hence using chdir()
1571 chdir($cmsPath);
1572
1573 // Force the re-initialisation of the config singleton on the next call
1574 // since so far, we had used the Config object without loading the DB.
1575 $c = CRM_Core_Config::singleton(FALSE);
1576 $c->free();
1577
1578 include_once "./core/includes/bootstrap.inc";
1579 include_once "./core/includes/unicode.inc";
228391b3 1580 include_once "./core/includes/config.inc";
5757adf3
HD
1581
1582 backdrop_bootstrap(BACKDROP_BOOTSTRAP_FULL);
1583
1584 // prevent session information from being saved.
1585 backdrop_save_session(FALSE);
1586
1587 // Force the current user to anonymous.
1588 $original_user = $GLOBALS['user'];
1589 $GLOBALS['user'] = backdrop_anonymous_user();
1590
1591 // explicitly setting error reporting, since we cannot handle drupal related notices
1592 error_reporting(1);
1593
1594 // rebuild modules, so that civicrm is added
1595 system_rebuild_module_data();
1596
1597 // now enable civicrm module.
1598 module_enable(array('civicrm', 'civicrmtheme'));
1599
1600 // clear block, page, theme, and hook caches
1601 backdrop_flush_all_caches();
1602
1603 //add basic backdrop permissions
1604 civicrm_install_set_backdrop_perms();
1605
1606 // restore the user.
1607 $GLOBALS['user'] = $original_user;
1608 backdrop_save_session(TRUE);
1609
1610 //change the default language to one chosen
1611 if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
1612 civicrm_api3('Setting', 'create', array(
1613 'domain_id' => 'current_domain',
1614 'lcMessages' => $config['seedLanguage'],
1615 )
1616 );
1617 }
1618
1619 $output .= '</ul>';
1620 $output .= '</div>';
1621 $output .= '</body>';
1622 $output .= '</html>';
1623 echo $output;
1624 }
6a488035
TO
1625 elseif ($installType == 'drupal' && version_compare(VERSION, '6.0') >= 0) {
1626 // clean output
1627 @ob_clean();
1628
1629 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1630 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1631 $output .= '<head>';
6a9514e1
ML
1632 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1633 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6a488035
TO
1634 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1635 $output .= '</head>';
1636 $output .= '<body>';
97b8e6b2 1637 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
6a488035 1638 $output .= '<ul>';
6a9514e1 1639
6a488035
TO
1640 $drupalURL = civicrm_cms_base();
1641 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1642 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
6a488035 1643
6a9514e1
ML
1644 $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>";
1645 $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>";
1646 $output .= $commonOutputMessage;
6a488035
TO
1647
1648 // explicitly setting error reporting, since we cannot handle drupal related notices
1649 error_reporting(1);
1650
1651 // automatically enable CiviCRM module once it is installed successfully.
1652 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1653 global $cmsPath, $crmPath;
1654
1655 // relative / abosolute paths are not working for drupal, hence using chdir()
1656 chdir($cmsPath);
1657
2f8082cd
ML
1658 // Force the re-initialisation of the config singleton on the next call
1659 // since so far, we had used the Config object without loading the DB.
1660 $c = CRM_Core_Config::singleton(FALSE);
1661 $c->free();
1662
6a488035
TO
1663 include_once "./includes/bootstrap.inc";
1664 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1665
1666 // rebuild modules, so that civicrm is added
1667 module_rebuild_cache();
1668
1669 // now enable civicrm module.
1670 module_enable(array('civicrm'));
1671
d8a4acc0
C
1672 // clear block, page, theme, and hook caches
1673 drupal_flush_all_caches();
6a488035
TO
1674
1675 //add basic drupal permissions
1676 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)');
1677
1678 echo $output;
1679 }
1680 elseif ($installType == 'wordpress') {
6a9514e1 1681 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
97b8e6b2 1682 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
6a488035 1683 echo '<ul>';
6a488035
TO
1684
1685 $cmsURL = civicrm_cms_base();
1686 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
41547a19
DL
1687 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1688
6a9514e1
ML
1689 $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>";
1690 $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>";
1691 $output .= $commonOutputMessage;
41547a19 1692
1f5f3294
TO
1693 echo '</ul>';
1694 echo '</div>';
b232c132 1695
1696 $c = CRM_Core_Config::singleton(FALSE);
1697 $c->free();
7ba2c8ad
KC
1698 $wpInstallRedirect = admin_url("?page=CiviCRM&q=civicrm&reset=1");
1699 echo "<script>
1700 window.location = '$wpInstallRedirect';
1701 </script>";
1f5f3294
TO
1702 }
1703 }
6a488035
TO
1704
1705 return $this->errors;
1706 }
96025800 1707
6a488035
TO
1708}
1709
1710function civicrm_install_set_drupal_perms() {
1711 if (!function_exists('db_select')) {
1712 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)');
1713 }
1714 else {
1715 $perms = array(
1716 'access all custom data',
1717 'access uploaded files',
1718 'make online contributions',
1719 'profile create',
1720 'profile edit',
1721 'profile view',
1722 'register for events',
1723 'view event info',
1724 'view event participants',
1725 'access CiviMail subscribe/unsubscribe pages',
1726 );
1727
1728 // Adding a permission that has not yet been assigned to a module by
1729 // a hook_permission implementation results in a database error.
1730 // CRM-9042
1731 $allPerms = array_keys(module_invoke_all('permission'));
1732 foreach (array_diff($perms, $allPerms) as $perm) {
1733 watchdog('civicrm',
1734 'Cannot grant the %perm permission because it does not yet exist.',
971d41b1
CW
1735 array('%perm' => $perm),
1736 WATCHDOG_ERROR
6a488035
TO
1737 );
1738 }
1739 $perms = array_intersect($perms, $allPerms);
1740 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, $perms);
1741 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, $perms);
1742 }
1743}
1744
5757adf3
HD
1745function civicrm_install_set_backdrop_perms() {
1746 $perms = array(
1747 'access all custom data',
1748 'access uploaded files',
1749 'make online contributions',
1750 'profile create',
1751 'profile edit',
1752 'profile view',
1753 'register for events',
1754 'view event info',
1755 'view event participants',
1756 'access CiviMail subscribe/unsubscribe pages',
1757 );
1758
1759 // Adding a permission that has not yet been assigned to a module by
1760 // a hook_permission implementation results in a database error.
1761 // CRM-9042
1762 $allPerms = array_keys(module_invoke_all('permission'));
1763 foreach (array_diff($perms, $allPerms) as $perm) {
1764 watchdog('civicrm',
1765 'Cannot grant the %perm permission because it does not yet exist.',
1766 array('%perm' => $perm),
1767 WATCHDOG_ERROR
1768 );
1769 }
1770 $perms = array_intersect($perms, $allPerms);
1771 user_role_grant_permissions(BACKDROP_AUTHENTICATED_ROLE, $perms);
1772 user_role_grant_permissions(BACKDROP_ANONYMOUS_ROLE, $perms);
1773}
1774
627456b5
EM
1775/**
1776 * @param $cmsPath
1777 * @param $str
1778 *
1779 * @return string
1780 */
6a488035
TO
1781function getSiteDir($cmsPath, $str) {
1782 static $siteDir = '';
1783
1784 if ($siteDir) {
1785 return $siteDir;
1786 }
1787
1788 $sites = CIVICRM_DIRECTORY_SEPARATOR . 'sites' . CIVICRM_DIRECTORY_SEPARATOR;
1789 $modules = CIVICRM_DIRECTORY_SEPARATOR . 'modules' . CIVICRM_DIRECTORY_SEPARATOR;
1790 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR) .
1791 "([\-a-zA-Z0-9_.]+)" .
1792 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR) . "/",
1793 $_SERVER['SCRIPT_FILENAME'], $matches
1794 );
1795 $siteDir = isset($matches[1]) ? $matches[1] : 'default';
1796
1797 if (strtolower($siteDir) == 'all') {
1798 // For this case - use drupal's way of finding out multi-site directory
1799 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR, $_SERVER['SCRIPT_FILENAME']);
1800 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1801 for ($i = count($uri) - 1; $i > 0; $i--) {
1802 for ($j = count($server); $j > 0; $j--) {
1803 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1804 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
56fdfc52
TO
1805 'sites' . CIVICRM_DIRECTORY_SEPARATOR . $dir
1806 )) {
6a488035
TO
1807 $siteDir = $dir;
1808 return $siteDir;
1809 }
1810 }
1811 }
1812 $siteDir = 'default';
1813 }
1814
1815 return $siteDir;
1816}
1817
627456b5
EM
1818/**
1819 * @param $errorTitle
1820 * @param $errorMsg
6a9514e1 1821 * @param $showRefer
627456b5 1822 */
6a9514e1
ML
1823function errorDisplayPage($errorTitle, $errorMsg, $showRefer = TRUE) {
1824 if ($showRefer) {
1825 $docLink = CRM_Utils_System::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
1826
1827 if (function_exists('ts')) {
1828 $errorMsg .= '<p>' . ts("<a %1>Refer to the online documentation for more information</a>", array(1 => "href='$docLink'")) . '</p>';
1829 }
1830 else {
1831 $errorMsg .= '<p>' . sprintf("<a %s>Refer to the online documentation for more information</a>", "href='$docLink'") . '</p>';
1832 }
1833 }
1834
1f5f3294 1835 include 'error.html';
6a488035
TO
1836 exit();
1837}