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