Merge pull request #10922 from eileenmcnaughton/tpl
[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 707
927a045d
J
708 // Check for XML support
709 $this->requireFunction('simplexml_load_file', array(
710 ts("PHP Configuration"),
8d241549
J
711 ts("SimpleXML support"),
712 ts("SimpleXML support not included in PHP."),
927a045d
J
713 ));
714
6a488035 715 // Check for JSON support
2f8082cd
ML
716 $this->requireFunction('json_encode', array(
717 ts("PHP Configuration"),
718 ts("JSON support"),
719 ts("JSON support not included in PHP."),
720 ));
6a488035
TO
721
722 // Check for xcache_isset and emit warning if exists
723 $this->checkXCache(array(
2f8082cd
ML
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."),
56fdfc52 727 ));
6a488035
TO
728
729 // Check memory allocation
730 $this->requireMemory(32 * 1024 * 1024,
731 64 * 1024 * 1024,
732 array(
2f8082cd
ML
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)),
6a488035
TO
736 ini_get("memory_limit"),
737 )
738 );
739
740 return $this->errors;
741 }
742
627456b5
EM
743 /**
744 * @param $min
745 * @param $recommended
746 * @param $testDetails
747 */
971d41b1 748 public function requireMemory($min, $recommended, $testDetails) {
6a488035
TO
749 $this->testing($testDetails);
750 $mem = $this->getPHPMemory();
751
752 if ($mem < $min && $mem > 0) {
2f8082cd 753 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
6a488035
TO
754 $this->error($testDetails);
755 }
756 elseif ($mem < $recommended && $mem > 0) {
2f8082cd 757 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
6a488035
TO
758 $this->warning($testDetails);
759 }
760 elseif ($mem == 0) {
2f8082cd 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));
6a488035
TO
762 $this->warning($testDetails);
763 }
764 }
765
627456b5
EM
766 /**
767 * @return float
768 */
971d41b1 769 public function getPHPMemory() {
6a488035
TO
770 $memString = ini_get("memory_limit");
771
772 switch (strtolower(substr($memString, -1))) {
773 case "k":
774 return round(substr($memString, 0, -1) * 1024);
775
776 case "m":
777 return round(substr($memString, 0, -1) * 1024 * 1024);
778
779 case "g":
780 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
781
782 default:
783 return round($memString);
784 }
785 }
786
971d41b1 787 public function listErrors() {
6a488035 788 if ($this->errors) {
2f8082cd 789 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
6a488035
TO
790 foreach ($this->errors as $error) {
791 echo "<li>" . htmlentities($error) . "</li>";
792 }
793 }
794 }
795
627456b5
EM
796 /**
797 * @param null $section
798 */
971d41b1 799 public function showTable($section = NULL) {
6a488035
TO
800 if ($section) {
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>";
805 }
806 echo "</table>";
807 }
808 else {
809 foreach ($this->tests as $section => $tests) {
810 echo "<h3>$section</h3>";
811 echo "<table class=\"testResults\" width=\"100%\">";
812
813 foreach ($tests as $test => $result) {
814 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
815 }
816 echo "</table>";
817 }
818 }
819 }
820
627456b5 821 /**
100fef9d 822 * @param string $funcName
627456b5
EM
823 * @param $testDetails
824 *
825 * @return bool
826 */
971d41b1 827 public function requireFunction($funcName, $testDetails) {
6a488035
TO
828 $this->testing($testDetails);
829
830 if (!function_exists($funcName)) {
831 $this->error($testDetails);
832 return FALSE;
833 }
834 else {
835 return TRUE;
836 }
837 }
838
627456b5
EM
839 /**
840 * @param $testDetails
841 */
971d41b1 842 public function checkXCache($testDetails) {
6a488035
TO
843 if (function_exists('xcache_isset') &&
844 ini_get('xcache.size') > 0
845 ) {
846 $this->testing($testDetails);
847 $this->warning($testDetails);
848 }
849 }
850
627456b5
EM
851 /**
852 * @param $minVersion
853 * @param $testDetails
854 * @param null $maxVersion
855 */
971d41b1 856 public function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
6a488035
TO
857
858 $this->testing($testDetails);
859
56fdfc52 860 $phpVersion = phpversion();
6a488035
TO
861 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
862 $belowMaxVersion = $maxVersion ? version_compare($phpVersion, $maxVersion) < 0 : TRUE;
863
ef064e55
CW
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(
867 1 => phpversion(),
868 2 => CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER,
869 ));
870 $this->warning($testDetails);
871 }
6a488035
TO
872 return TRUE;
873 }
874
875 if (!$testDetails[2]) {
876 if (!$aboveMinVersion) {
2f8082cd 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));
6a488035
TO
878 }
879 else {
2f8082cd 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));
6a488035
TO
881 }
882 }
883
884 $this->error($testDetails);
885 }
886
627456b5 887 /**
100fef9d 888 * @param string $filename
627456b5
EM
889 * @param $testDetails
890 * @param bool $absolute
891 */
971d41b1 892 public function requireFile($filename, $testDetails, $absolute = FALSE) {
6a488035
TO
893 $this->testing($testDetails);
894 if (!$absolute) {
895 $filename = $this->getBaseDir() . $filename;
896 }
897 if (!file_exists($filename)) {
2f8082cd 898 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
6a488035
TO
899 $this->error($testDetails);
900 }
901 }
902
627456b5
EM
903 /**
904 * @param $testDetails
905 */
971d41b1 906 public function requireNoPathSeparator($testDetails) {
6a488035
TO
907 $this->testing($testDetails);
908 if (substr_count($this->getBaseDir(), PATH_SEPARATOR)) {
909 $this->error($testDetails);
910 }
911 }
912
627456b5 913 /**
100fef9d 914 * @param string $filename
627456b5
EM
915 * @param $testDetails
916 */
971d41b1 917 public function requireNoFile($filename, $testDetails) {
6a488035
TO
918 $this->testing($testDetails);
919 $filename = $this->getBaseDir() . $filename;
920 if (file_exists($filename)) {
2f8082cd 921 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
6a488035
TO
922 $this->error($testDetails);
923 }
924 }
925
627456b5 926 /**
100fef9d 927 * @param string $filename
627456b5
EM
928 * @param $testDetails
929 */
971d41b1 930 public function moveFileOutOfTheWay($filename, $testDetails) {
6a488035
TO
931 $this->testing($testDetails);
932 $filename = $this->getBaseDir() . $filename;
933 if (file_exists($filename)) {
934 if (file_exists("$filename.bak")) {
935 rm("$filename.bak");
936 }
937 rename($filename, "$filename.bak");
938 }
939 }
940
627456b5 941 /**
100fef9d 942 * @param string $filename
627456b5
EM
943 * @param $testDetails
944 * @param bool $absolute
945 */
971d41b1 946 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
6a488035
TO
947 $this->testing($testDetails);
948 if (!$absolute) {
949 $filename = $this->getBaseDir() . $filename;
950 }
951
22e263ad 952 if (!is_writable($filename)) {
6a488035
TO
953 $name = NULL;
954 if (function_exists('posix_getpwuid')) {
955 $user = posix_getpwuid(posix_geteuid());
956 $name = '- ' . $user['name'] . ' -';
957 }
958
959 if (!isset($testDetails[2])) {
960 $testDetails[2] = NULL;
961 }
2f8082cd 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";
6a488035
TO
963 $this->error($testDetails);
964 }
965 }
966
627456b5 967 /**
100fef9d 968 * @param string $moduleName
627456b5
EM
969 * @param $testDetails
970 */
971d41b1 971 public function requireApacheModule($moduleName, $testDetails) {
6a488035
TO
972 $this->testing($testDetails);
973 if (!in_array($moduleName, apache_get_modules())) {
974 $this->error($testDetails);
975 }
976 }
977
627456b5
EM
978 /**
979 * @param $server
100fef9d 980 * @param string $username
627456b5
EM
981 * @param $password
982 * @param $testDetails
983 */
971d41b1 984 public function requireMysqlConnection($server, $username, $password, $testDetails) {
6a488035 985 $this->testing($testDetails);
6a511829 986 $this->conn = $this->connect($server, $username, $password);
6a488035 987
fcf908c6 988 if ($this->conn) {
6a488035
TO
989 return TRUE;
990 }
991 else {
fcf908c6 992 $testDetails[2] .= ": " . mysqli_connect_error();
6a488035
TO
993 $this->error($testDetails);
994 }
995 }
996
627456b5
EM
997 /**
998 * @param $server
999 * @param $testDetails
1000 */
971d41b1 1001 public function requireMySQLServer($server, $testDetails) {
6a488035 1002 $this->testing($testDetails);
6a511829 1003 $conn = $this->connect($server, NULL, NULL);
6a488035 1004
fcf908c6 1005 if ($conn || mysqli_connect_errno() < 2000) {
6a488035
TO
1006 return TRUE;
1007 }
1008 else {
fcf908c6 1009 $testDetails[2] .= ": " . mysqli_connect_error();
6a488035
TO
1010 $this->error($testDetails);
1011 }
1012 }
1013
627456b5
EM
1014 /**
1015 * @param $version
1016 * @param $testDetails
1017 */
971d41b1 1018 public function requireMySQLVersion($version, $testDetails) {
6a488035
TO
1019 $this->testing($testDetails);
1020
fcf908c6 1021 if (!mysqli_get_server_info($this->conn)) {
2f8082cd 1022 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
6a488035
TO
1023 $this->warning($testDetails);
1024 }
1025 else {
1026 list($majorRequested, $minorRequested) = explode('.', $version);
fcf908c6 1027 list($majorHas, $minorHas) = explode('.', mysqli_get_server_info($this->conn));
6a488035
TO
1028
1029 if (($majorHas > $majorRequested) || ($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
1030 return TRUE;
1031 }
1032 else {
1033 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
1034 $this->error($testDetails);
1035 }
1036 }
1037 }
1038
627456b5
EM
1039 /**
1040 * @param $server
100fef9d 1041 * @param string $username
627456b5
EM
1042 * @param $password
1043 * @param $database
1044 * @param $testDetails
1045 */
971d41b1 1046 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
6a488035 1047 $this->testing($testDetails);
6a511829 1048 $conn = $this->connect($server, $username, $password);
6a488035 1049 if (!$conn) {
2f8082cd 1050 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
6a488035
TO
1051 $this->error($testDetails);
1052 return;
1053 }
1054
1055 $innodb_support = FALSE;
fcf908c6 1056 $result = mysqli_query($conn, "SHOW ENGINES");
1057 while ($values = mysqli_fetch_array($result)) {
6a488035
TO
1058 if ($values['Engine'] == 'InnoDB') {
1059 if (strtolower($values['Support']) == 'yes' ||
1060 strtolower($values['Support']) == 'default'
1061 ) {
1062 $innodb_support = TRUE;
1063 }
1064 }
1065 }
1066 if ($innodb_support) {
2f8082cd 1067 $testDetails[3] = ts('MySQL server does have InnoDB support');
6a488035
TO
1068 }
1069 else {
2f8082cd 1070 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
6a488035
TO
1071 }
1072 }
1073
627456b5
EM
1074 /**
1075 * @param $server
100fef9d 1076 * @param string $username
627456b5
EM
1077 * @param $password
1078 * @param $database
1079 * @param $testDetails
1080 */
971d41b1 1081 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
6a488035 1082 $this->testing($testDetails);
6a511829 1083 $conn = $this->connect($server, $username, $password);
6a488035 1084 if (!$conn) {
2f8082cd 1085 $testDetails[2] = ts('Could not login to the database.');
6a488035
TO
1086 $this->error($testDetails);
1087 return;
1088 }
1089
fcf908c6 1090 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1091 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1092 $this->error($testDetails);
1093 return;
1094 }
1095
fcf908c6 1096 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
6a488035 1097 if (!$result) {
2f8082cd 1098 $testDetails[2] = ts('Could not create a temp table.');
6a488035
TO
1099 $this->error($testDetails);
1100 }
fcf908c6 1101 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1102 }
1103
627456b5
EM
1104 /**
1105 * @param $server
100fef9d 1106 * @param string $username
627456b5
EM
1107 * @param $password
1108 * @param $database
1109 * @param $testDetails
1110 */
971d41b1 1111 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
6a488035 1112 $this->testing($testDetails);
6a511829 1113 $conn = $this->connect($server, $username, $password);
6a488035 1114 if (!$conn) {
2f8082cd 1115 $testDetails[2] = ts('Could not login to the database.');
6a488035
TO
1116 $this->error($testDetails);
1117 return;
1118 }
1119
fcf908c6 1120 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1121 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1122 $this->error($testDetails);
1123 return;
1124 }
1125
fcf908c6 1126 $result = mysqli_query($conn, 'CREATE TABLE civicrm_install_temp_table_test (test text)');
6a488035 1127 if (!$result) {
2f8082cd 1128 $testDetails[2] = ts('Could not create a table in the database.');
6a488035
TO
1129 $this->error($testDetails);
1130 }
1131
fcf908c6 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');
6a488035 1133 if (!$result) {
fcf908c6 1134 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
2f8082cd 1135 $testDetails[2] = ts('Could not create a database trigger.');
6a488035
TO
1136 $this->error($testDetails);
1137 }
1138
fcf908c6 1139 mysqli_query($conn, 'DROP TRIGGER civicrm_install_temp_table_test_trigger');
1140 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
6a488035
TO
1141 }
1142
1143
627456b5
EM
1144 /**
1145 * @param $server
100fef9d 1146 * @param string $username
627456b5
EM
1147 * @param $password
1148 * @param $database
1149 * @param $testDetails
1150 */
971d41b1 1151 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
6a488035 1152 $this->testing($testDetails);
6a511829 1153 $conn = $this->connect($server, $username, $password);
6a488035 1154 if (!$conn) {
2f8082cd 1155 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1156 $this->error($testDetails);
1157 return;
1158 }
1159
fcf908c6 1160 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1161 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1162 $this->error($testDetails);
1163 return;
1164 }
1165
fcf908c6 1166 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
6a488035 1167 if (!$result) {
2f8082cd 1168 $testDetails[2] = ts('Could not create a table in the database.');
6a488035
TO
1169 $this->error($testDetails);
1170 return;
1171 }
1172
fcf908c6 1173 $result = mysqli_query($conn, 'LOCK TABLES civicrm_install_temp_table_test WRITE');
6a488035 1174 if (!$result) {
2f8082cd 1175 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
6a488035 1176 $this->error($testDetails);
fcf908c6 1177 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1178 return;
1179 }
1180
fcf908c6 1181 $result = mysqli_query($conn, 'UNLOCK TABLES');
6a488035 1182 if (!$result) {
2f8082cd 1183 $testDetails[2] = ts('Could not release the lock for the database table.');
6a488035 1184 $this->error($testDetails);
fcf908c6 1185 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1186 return;
1187 }
1188
fcf908c6 1189 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1190 }
1191
627456b5
EM
1192 /**
1193 * @param $server
100fef9d 1194 * @param string $username
627456b5
EM
1195 * @param $password
1196 * @param $testDetails
1197 */
971d41b1 1198 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
6a488035 1199 $this->testing($testDetails);
6a511829 1200 $conn = $this->connect($server, $username, $password);
6a488035 1201 if (!$conn) {
2f8082cd 1202 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1203 $this->error($testDetails);
1204 return;
1205 }
1206
fcf908c6 1207 $result = mysqli_query($conn, "SHOW variables like 'auto_increment_increment'");
6a488035 1208 if (!$result) {
2f8082cd 1209 $testDetails[2] = ts('Could not query database server variables.');
6a488035
TO
1210 $this->error($testDetails);
1211 return;
1212 }
1213 else {
fcf908c6 1214 $values = mysqli_fetch_row($result);
6a488035 1215 if ($values[1] == 1) {
2f8082cd 1216 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
6a488035
TO
1217 }
1218 else {
1219 $this->error($testDetails);
1220 }
1221 }
1222 }
1223
627456b5
EM
1224 /**
1225 * @param $server
100fef9d 1226 * @param string $username
627456b5
EM
1227 * @param $password
1228 * @param $database
1229 * @param $minValueKB
1230 * @param $testDetails
1231 */
971d41b1 1232 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
6a488035 1233 $this->testing($testDetails);
6a511829 1234 $conn = $this->connect($server, $username, $password);
6a488035 1235 if (!$conn) {
2f8082cd 1236 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1237 $this->error($testDetails);
1238 return;
1239 }
1240
fcf908c6 1241 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1242 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1243 $this->error($testDetails);
1244 return;
1245 }
1246
fcf908c6 1247 $result = mysqli_query($conn, "SHOW VARIABLES LIKE 'thread_stack'"); // bytes => kb
6a488035 1248 if (!$result) {
2f8082cd 1249 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
6a488035 1250 $this->error($testDetails);
0db6c3e1
TO
1251 }
1252 else {
fcf908c6 1253 $values = mysqli_fetch_row($result);
1f5f3294 1254 if ($values[1] < (1024 * $minValueKB)) {
2f8082cd 1255 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
6a488035
TO
1256 $this->error($testDetails);
1257 }
1258 }
1259 }
1260
627456b5
EM
1261 /**
1262 * @param $server
100fef9d 1263 * @param string $username
627456b5
EM
1264 * @param $password
1265 * @param $database
1266 * @param $testDetails
1267 * @param bool $onlyRequire
1268 */
971d41b1 1269 public function requireDatabaseOrCreatePermissions(
56fdfc52 1270 $server,
6a488035
TO
1271 $username,
1272 $password,
1273 $database,
1274 $testDetails,
1275 $onlyRequire = FALSE
1276 ) {
1277 $this->testing($testDetails);
6a511829 1278 $conn = $this->connect($server, $username, $password);
6a488035
TO
1279
1280 $okay = NULL;
fcf908c6 1281 if (@mysqli_select_db($conn, $database)) {
6a488035
TO
1282 $okay = "Database '$database' exists";
1283 }
1284 elseif ($onlyRequire) {
2f8082cd 1285 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
6a488035
TO
1286 $this->error($testDetails);
1287 return;
1288 }
1289 else {
fcf908c6 1290 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1291 if (@mysqli_query($conn, $query)) {
2f8082cd 1292 $okay = ts("Able to create a new database.");
6a488035
TO
1293 }
1294 else {
2f8082cd 1295 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
6a488035
TO
1296 $this->error($testDetails);
1297 return;
1298 }
1299 }
1300
1301 if ($okay) {
1302 $testDetails[3] = $okay;
1303 $this->testing($testDetails);
1304 }
1305 }
1306
627456b5
EM
1307 /**
1308 * @param $varNames
1309 * @param $errorMessage
1310 */
971d41b1 1311 public function requireServerVariables($varNames, $errorMessage) {
6a488035
TO
1312 //$this->testing($testDetails);
1313 foreach ($varNames as $varName) {
1314 if (!$_SERVER[$varName]) {
1315 $missing[] = '$_SERVER[' . $varName . ']';
1316 }
1317 }
1318 if (!isset($missing)) {
1319 return TRUE;
1320 }
1321 else {
2f8082cd 1322 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
6a488035
TO
1323 $this->error($testDetails);
1324 }
1325 }
1326
627456b5
EM
1327 /**
1328 * @param $testDetails
1329 *
1330 * @return bool
1331 */
971d41b1 1332 public function isRunningApache($testDetails) {
6a488035
TO
1333 $this->testing($testDetails);
1334 if (function_exists('apache_get_modules') || stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1335 return TRUE;
1336 }
1337
1338 $this->warning($testDetails);
1339 return FALSE;
1340 }
1341
627456b5
EM
1342 /**
1343 * @return string
1344 */
971d41b1 1345 public function getBaseDir() {
6a488035
TO
1346 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR;
1347 }
1348
627456b5
EM
1349 /**
1350 * @param $testDetails
1351 */
971d41b1 1352 public function testing($testDetails) {
6a488035
TO
1353 if (!$testDetails) {
1354 return;
1355 }
1356
1357 $section = $testDetails[0];
1358 $test = $testDetails[1];
1359
2f8082cd 1360 $message = ts("OK");
6a488035
TO
1361 if (isset($testDetails[3])) {
1362 $message .= " ($testDetails[3])";
1363 }
1364
1365 $this->tests[$section][$test] = array("good", $message);
1366 }
1367
627456b5
EM
1368 /**
1369 * @param $testDetails
1370 */
971d41b1 1371 public function error($testDetails) {
6a488035
TO
1372 $section = $testDetails[0];
1373 $test = $testDetails[1];
1374
1375 $this->tests[$section][$test] = array("error", $testDetails[2]);
1376 $this->errors[] = $testDetails;
1377 }
1378
627456b5
EM
1379 /**
1380 * @param $testDetails
1381 */
971d41b1 1382 public function warning($testDetails) {
6a488035
TO
1383 $section = $testDetails[0];
1384 $test = $testDetails[1];
1385
6a488035
TO
1386 $this->tests[$section][$test] = array("warning", $testDetails[2]);
1387 $this->warnings[] = $testDetails;
1388 }
1389
627456b5
EM
1390 /**
1391 * @return int
1392 */
971d41b1
CW
1393 public function hasErrors() {
1394 return count($this->errors);
6a488035
TO
1395 }
1396
627456b5
EM
1397 /**
1398 * @return int
1399 */
971d41b1
CW
1400 public function hasWarnings() {
1401 return count($this->warnings);
6a488035 1402 }
96025800 1403
6a488035
TO
1404}
1405
627456b5
EM
1406/**
1407 * Class Installer
1408 */
6a488035 1409class Installer extends InstallRequirements {
627456b5
EM
1410 /**
1411 * @param $server
1412 * @param $username
1413 * @param $password
1414 * @param $database
1415 */
971d41b1 1416 public function createDatabaseIfNotExists($server, $username, $password, $database) {
6a511829 1417 $conn = $this->connect($server, $username, $password);
6a488035 1418
fcf908c6 1419 if (@mysqli_select_db($conn, $database)) {
6a488035
TO
1420 // skip if database already present
1421 return;
1422 }
fcf908c6 1423 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1424 if (@mysqli_query($conn, $query)) {
56fdfc52 1425 }
6a488035 1426 else {
6a9514e1
ML
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.");
6a488035
TO
1429 errorDisplayPage($errorTitle, $errorMsg);
1430 }
1431 }
1432
627456b5
EM
1433 /**
1434 * @param $config
1435 *
1436 * @return mixed
1437 */
971d41b1 1438 public function install($config) {
6a488035
TO
1439 global $installDirPath;
1440
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']
1446 );
1447
1448 global $installDirPath;
1449
1450 // Build database
1451 require_once $installDirPath . 'civicrm.php';
1452 civicrm_main($config);
1453
1454 if (!$this->errors) {
1455 global $installType, $installURLPath;
1456
bb216f68 1457 $registerSiteURL = "https://civicrm.org/register-site";
56de7273
ML
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>";
41547a19 1461
6a488035 1462 $output = NULL;
97b8e6b2 1463
6a488035
TO
1464 if (
1465 $installType == 'drupal' &&
1466 version_compare(VERSION, '7.0-rc1') >= 0
1467 ) {
1468
1469 // clean output
1470 @ob_clean();
1471
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>';
2f8082cd 1475 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
6a9514e1 1476 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6a488035
TO
1477 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1478 $output .= '</head>';
1479 $output .= '<body>';
2f8082cd 1480 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
6a488035 1481 $output .= '<ul>';
6a9514e1 1482
6a488035
TO
1483 $drupalURL = civicrm_cms_base();
1484 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1485 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
6a488035 1486
6a9514e1
ML
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;
6a488035
TO
1490
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;
1494
1495 // relative / abosolute paths are not working for drupal, hence using chdir()
1496 chdir($cmsPath);
1497
97b8e6b2 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);
1501 $c->free();
1502
6a488035
TO
1503 include_once "./includes/bootstrap.inc";
1504 include_once "./includes/unicode.inc";
1505
1506 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1507
1508 // prevent session information from being saved.
1509 drupal_save_session(FALSE);
1510
1511 // Force the current user to anonymous.
1512 $original_user = $GLOBALS['user'];
1513 $GLOBALS['user'] = drupal_anonymous_user();
1514
1515 // explicitly setting error reporting, since we cannot handle drupal related notices
1516 error_reporting(1);
1517
1518 // rebuild modules, so that civicrm is added
1519 system_rebuild_module_data();
1520
1521 // now enable civicrm module.
1522 module_enable(array('civicrm', 'civicrmtheme'));
1523
ece6501c
ML
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'];
1530
d8a4acc0
C
1531 // clear block, page, theme, and hook caches
1532 drupal_flush_all_caches();
6a488035
TO
1533
1534 //add basic drupal permissions
1535 civicrm_install_set_drupal_perms();
1536
1537 // restore the user.
1538 $GLOBALS['user'] = $original_user;
1539 drupal_save_session(TRUE);
1540
1541 $output .= '</ul>';
1542 $output .= '</div>';
1543 $output .= '</body>';
1544 $output .= '</html>';
1545 echo $output;
1546 }
5757adf3
HD
1547 elseif (
1548 $installType == 'backdrop'
1549 ) {
1550
1551 // clean output
1552 @ob_clean();
1553
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>';
1563 $output .= '<ul>';
1564
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";
1568
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;
1572
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;
1576
1577 // relative / abosolute paths are not working for drupal, hence using chdir()
1578 chdir($cmsPath);
1579
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);
1583 $c->free();
1584
1585 include_once "./core/includes/bootstrap.inc";
1586 include_once "./core/includes/unicode.inc";
228391b3 1587 include_once "./core/includes/config.inc";
5757adf3
HD
1588
1589 backdrop_bootstrap(BACKDROP_BOOTSTRAP_FULL);
1590
1591 // prevent session information from being saved.
1592 backdrop_save_session(FALSE);
1593
1594 // Force the current user to anonymous.
1595 $original_user = $GLOBALS['user'];
1596 $GLOBALS['user'] = backdrop_anonymous_user();
1597
1598 // explicitly setting error reporting, since we cannot handle drupal related notices
1599 error_reporting(1);
1600
1601 // rebuild modules, so that civicrm is added
1602 system_rebuild_module_data();
1603
1604 // now enable civicrm module.
1605 module_enable(array('civicrm', 'civicrmtheme'));
1606
1607 // clear block, page, theme, and hook caches
1608 backdrop_flush_all_caches();
1609
1610 //add basic backdrop permissions
1611 civicrm_install_set_backdrop_perms();
1612
1613 // restore the user.
1614 $GLOBALS['user'] = $original_user;
1615 backdrop_save_session(TRUE);
1616
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'],
1622 )
1623 );
1624 }
1625
1626 $output .= '</ul>';
1627 $output .= '</div>';
1628 $output .= '</body>';
1629 $output .= '</html>';
1630 echo $output;
1631 }
6a488035
TO
1632 elseif ($installType == 'drupal' && version_compare(VERSION, '6.0') >= 0) {
1633 // clean output
1634 @ob_clean();
1635
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>';
6a9514e1
ML
1639 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1640 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6a488035
TO
1641 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1642 $output .= '</head>';
1643 $output .= '<body>';
97b8e6b2 1644 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
6a488035 1645 $output .= '<ul>';
6a9514e1 1646
6a488035
TO
1647 $drupalURL = civicrm_cms_base();
1648 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1649 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
6a488035 1650
6a9514e1
ML
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;
6a488035
TO
1654
1655 // explicitly setting error reporting, since we cannot handle drupal related notices
1656 error_reporting(1);
1657
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;
1661
1662 // relative / abosolute paths are not working for drupal, hence using chdir()
1663 chdir($cmsPath);
1664
2f8082cd
ML
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);
1668 $c->free();
1669
6a488035
TO
1670 include_once "./includes/bootstrap.inc";
1671 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1672
1673 // rebuild modules, so that civicrm is added
1674 module_rebuild_cache();
1675
1676 // now enable civicrm module.
1677 module_enable(array('civicrm'));
1678
d8a4acc0
C
1679 // clear block, page, theme, and hook caches
1680 drupal_flush_all_caches();
6a488035
TO
1681
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)');
1684
1685 echo $output;
1686 }
1687 elseif ($installType == 'wordpress') {
6a9514e1 1688 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
97b8e6b2 1689 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
6a488035 1690 echo '<ul>';
6a488035
TO
1691
1692 $cmsURL = civicrm_cms_base();
1693 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
41547a19
DL
1694 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1695
6a9514e1
ML
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;
41547a19 1699
1f5f3294
TO
1700 echo '</ul>';
1701 echo '</div>';
b232c132 1702
1703 $c = CRM_Core_Config::singleton(FALSE);
1704 $c->free();
7ba2c8ad
KC
1705 $wpInstallRedirect = admin_url("?page=CiviCRM&q=civicrm&reset=1");
1706 echo "<script>
1707 window.location = '$wpInstallRedirect';
1708 </script>";
1f5f3294
TO
1709 }
1710 }
6a488035
TO
1711
1712 return $this->errors;
1713 }
96025800 1714
6a488035
TO
1715}
1716
1717function 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)');
1720 }
1721 else {
1722 $perms = array(
1723 'access all custom data',
1724 'access uploaded files',
1725 'make online contributions',
1726 'profile create',
1727 'profile edit',
1728 'profile view',
1729 'register for events',
1730 'view event info',
1731 'view event participants',
1732 'access CiviMail subscribe/unsubscribe pages',
1733 );
1734
1735 // Adding a permission that has not yet been assigned to a module by
1736 // a hook_permission implementation results in a database error.
1737 // CRM-9042
1738 $allPerms = array_keys(module_invoke_all('permission'));
1739 foreach (array_diff($perms, $allPerms) as $perm) {
1740 watchdog('civicrm',
1741 'Cannot grant the %perm permission because it does not yet exist.',
971d41b1
CW
1742 array('%perm' => $perm),
1743 WATCHDOG_ERROR
6a488035
TO
1744 );
1745 }
1746 $perms = array_intersect($perms, $allPerms);
1747 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, $perms);
1748 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, $perms);
1749 }
1750}
1751
5757adf3
HD
1752function civicrm_install_set_backdrop_perms() {
1753 $perms = array(
1754 'access all custom data',
1755 'access uploaded files',
1756 'make online contributions',
1757 'profile create',
1758 'profile edit',
1759 'profile view',
1760 'register for events',
1761 'view event info',
1762 'view event participants',
1763 'access CiviMail subscribe/unsubscribe pages',
1764 );
1765
1766 // Adding a permission that has not yet been assigned to a module by
1767 // a hook_permission implementation results in a database error.
1768 // CRM-9042
1769 $allPerms = array_keys(module_invoke_all('permission'));
1770 foreach (array_diff($perms, $allPerms) as $perm) {
1771 watchdog('civicrm',
1772 'Cannot grant the %perm permission because it does not yet exist.',
1773 array('%perm' => $perm),
1774 WATCHDOG_ERROR
1775 );
1776 }
1777 $perms = array_intersect($perms, $allPerms);
1778 user_role_grant_permissions(BACKDROP_AUTHENTICATED_ROLE, $perms);
1779 user_role_grant_permissions(BACKDROP_ANONYMOUS_ROLE, $perms);
1780}
1781
627456b5
EM
1782/**
1783 * @param $cmsPath
1784 * @param $str
1785 *
1786 * @return string
1787 */
6a488035
TO
1788function getSiteDir($cmsPath, $str) {
1789 static $siteDir = '';
1790
1791 if ($siteDir) {
1792 return $siteDir;
1793 }
1794
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
1801 );
1802 $siteDir = isset($matches[1]) ? $matches[1] : 'default';
1803
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 .
56fdfc52
TO
1812 'sites' . CIVICRM_DIRECTORY_SEPARATOR . $dir
1813 )) {
6a488035
TO
1814 $siteDir = $dir;
1815 return $siteDir;
1816 }
1817 }
1818 }
1819 $siteDir = 'default';
1820 }
1821
1822 return $siteDir;
1823}
1824
627456b5
EM
1825/**
1826 * @param $errorTitle
1827 * @param $errorMsg
6a9514e1 1828 * @param $showRefer
627456b5 1829 */
6a9514e1
ML
1830function errorDisplayPage($errorTitle, $errorMsg, $showRefer = TRUE) {
1831 if ($showRefer) {
1832 $docLink = CRM_Utils_System::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
1833
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>';
1836 }
1837 else {
1838 $errorMsg .= '<p>' . sprintf("<a %s>Refer to the online documentation for more information</a>", "href='$docLink'") . '</p>';
1839 }
1840 }
1841
1f5f3294 1842 include 'error.html';
6a488035
TO
1843 exit();
1844}