Update 5.13.3.md
[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']);
683bf891 166 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR . 'civicrm.settings.php');
5757adf3 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 {
683bf891
SL
427 public $errors;
428 public $warnings;
429 public $tests;
430 public $conn;
6a488035
TO
431
432 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
433 const MINIMUM_THREAD_STACK = 192;
434
435 /**
fe482240 436 * Just check that the database configuration is okay.
d7c8cf03
EM
437 * @param $databaseConfig
438 * @param $dbName
6a488035 439 */
971d41b1 440 public function checkdatabase($databaseConfig, $dbName) {
fcf908c6 441 if ($this->requireFunction('mysqli_connect',
56fdfc52 442 array(
97b8e6b2 443 ts("PHP Configuration"),
444 ts("MySQL support"),
445 ts("MySQL support not included in PHP."),
56fdfc52
TO
446 )
447 )
448 ) {
6a488035
TO
449 $this->requireMySQLServer($databaseConfig['server'],
450 array(
2f8082cd
ML
451 ts("MySQL %1 Configuration", array(1 => $dbName)),
452 ts("Does the server exist?"),
453 ts("Can't find the a MySQL server on '%1'.", array(1 => $databaseConfig['server'])),
6a488035
TO
454 $databaseConfig['server'],
455 )
456 );
457 if ($this->requireMysqlConnection($databaseConfig['server'],
56fdfc52
TO
458 $databaseConfig['username'],
459 $databaseConfig['password'],
460 array(
2f8082cd
ML
461 ts("MySQL %1 Configuration", array(1 => $dbName)),
462 ts("Are the access credentials correct?"),
463 ts("That username/password doesn't work"),
56fdfc52
TO
464 )
465 )
466 ) {
6a488035
TO
467 @$this->requireMySQLVersion("5.1",
468 array(
2f8082cd
ML
469 ts("MySQL %1 Configuration", array(1 => $dbName)),
470 ts("MySQL version at least %1", array(1 => '5.1')),
fcf908c6 471 ts("MySQL version %1 or higher is required, you are running MySQL %2.", array(1 => '5.1', 2 => mysqli_get_server_info($this->conn))),
472 ts("MySQL %1", array(1 => mysqli_get_server_info($this->conn))),
6a488035
TO
473 )
474 );
475 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
476 $databaseConfig['username'],
477 $databaseConfig['password'],
478 array(
2f8082cd
ML
479 ts("MySQL %1 Configuration", array(1 => $dbName)),
480 ts("Is auto_increment_increment set to 1"),
481 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
482 )
483 );
e5d3a11d
PN
484 $testDetails = array(
485 ts("MySQL %1 Configuration", array(1 => $dbName)),
486 ts("Is the provided database name valid?"),
ee17d64d 487 ts("The database name provided is not valid. Please use only 0-9, a-z, A-Z, _ and - as characters in the name."),
e5d3a11d 488 );
ee17d64d 489 if (!CRM_Core_DAO::requireSafeDBName($databaseConfig['database'])) {
e5d3a11d 490 $this->error($testDetails);
ff3f52f7
PN
491 return FALSE;
492 }
e5d3a11d
PN
493 else {
494 $this->testing($testDetails);
495 }
6a488035
TO
496 $this->requireMySQLThreadStack($databaseConfig['server'],
497 $databaseConfig['username'],
498 $databaseConfig['password'],
499 $databaseConfig['database'],
500 self::MINIMUM_THREAD_STACK,
501 array(
2f8082cd
ML
502 ts("MySQL %1 Configuration", array(1 => $dbName)),
503 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self::MINIMUM_THREAD_STACK)),
56fdfc52
TO
504 "",
505 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
6a488035
TO
506 )
507 );
508 }
5757adf3 509 $onlyRequire = ($dbName == 'Drupal' || $dbName == 'Backdrop') ? TRUE : FALSE;
6a488035
TO
510 $this->requireDatabaseOrCreatePermissions(
511 $databaseConfig['server'],
512 $databaseConfig['username'],
513 $databaseConfig['password'],
514 $databaseConfig['database'],
515 array(
2f8082cd
ML
516 ts("MySQL %1 Configuration", array(1 => $dbName)),
517 ts("Can I access/create the database?"),
5f40a878 518 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
6a488035
TO
519 ),
520 $onlyRequire
521 );
5757adf3 522 if ($dbName != 'Drupal' && $dbName != 'Backdrop') {
1b4a049e
AP
523 $this->requireNoExistingData(
524 $databaseConfig['server'],
525 $databaseConfig['username'],
526 $databaseConfig['password'],
527 $databaseConfig['database'],
528 array(
529 ts("MySQL %1 Configuration", array(1 => $dbName)),
c66b58c9 530 ts("Does the database have data from a previous installation?"),
1b4a049e
AP
531 ts("CiviCRM data from previous installation exists in '%1'.", array(1 => $databaseConfig['database'])),
532 )
533 );
6a488035
TO
534 $this->requireMySQLInnoDB($databaseConfig['server'],
535 $databaseConfig['username'],
536 $databaseConfig['password'],
537 $databaseConfig['database'],
538 array(
2f8082cd
ML
539 ts("MySQL %1 Configuration", array(1 => $dbName)),
540 ts("Can I access/create InnoDB tables in the database?"),
541 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
542 )
543 );
544 $this->requireMySQLTempTables($databaseConfig['server'],
545 $databaseConfig['username'],
546 $databaseConfig['password'],
547 $databaseConfig['database'],
548 array(
2f8082cd
ML
549 ts("MySQL %1 Configuration", array(1 => $dbName)),
550 ts('Can I create temporary tables in the database?'),
551 ts('Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.'),
6a488035
TO
552 )
553 );
554 $this->requireMySQLLockTables($databaseConfig['server'],
555 $databaseConfig['username'],
556 $databaseConfig['password'],
557 $databaseConfig['database'],
558 array(
2f8082cd
ML
559 ts("MySQL %1 Configuration", array(1 => $dbName)),
560 ts('Can I create lock tables in the database?'),
561 ts('Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.'),
6a488035
TO
562 )
563 );
564 $this->requireMySQLTrigger($databaseConfig['server'],
565 $databaseConfig['username'],
566 $databaseConfig['password'],
567 $databaseConfig['database'],
568 array(
2f8082cd
ML
569 ts("MySQL %1 Configuration", array(1 => $dbName)),
570 ts('Can I create triggers in the database?'),
571 ts('Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.'),
6a488035
TO
572 )
573 );
75615982 574 $this->requireMySQLUtf8mb4($databaseConfig['server'],
575 $databaseConfig['username'],
576 $databaseConfig['password'],
577 $databaseConfig['database'],
578 array(
579 ts("MySQL %1 Configuration", array(1 => $dbName)),
580 ts('Is the <code>utf8mb4</code> character set supported?'),
581 ts('This MySQL server does not support the <code>utf8mb4</code> character set.'),
582 )
583 );
6a488035
TO
584 }
585 }
586 }
587
6a511829
TO
588 /**
589 * Connect via mysqli.
590 *
591 * This is exactly the same as mysqli_connect(), except that it accepts
592 * the port as part of the `$host`.
593 *
28d4c718
TO
594 * @param string $host
595 * Ex: 'localhost', 'localhost:3307', '127.0.0.1:3307', '[::1]', '[::1]:3307'.
596 * @param string $username
597 * @param string $password
6a511829
TO
598 * @param string $database
599 * @return \mysqli
600 */
601 protected function connect($host, $username, $password, $database = '') {
602 $hostParts = explode(':', $host);
8e1997f9
TO
603 if (count($hostParts) > 1 && strrpos($host, ']') !== strlen($host) - 1) {
604 $port = array_pop($hostParts);
605 $host = implode(':', $hostParts);
6a511829
TO
606 }
607 else {
5df2c60d 608 $port = NULL;
6a511829
TO
609 }
610 $conn = @mysqli_connect($host, $username, $password, $database, $port);
611 return $conn;
612 }
613
6a488035 614 /**
fe482240 615 * Check everything except the database.
6a488035 616 */
971d41b1 617 public function check() {
6a488035
TO
618 global $crmPath, $installType;
619
620 $this->errors = NULL;
621
cc1f4988 622 $this->requirePHPVersion(array(
2f8082cd
ML
623 ts("PHP Configuration"),
624 ts("PHP5 installed"),
56fdfc52 625 ));
6a488035
TO
626
627 // Check that we can identify the root folder successfully
d34d7fa8 628 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'README.md',
6a488035 629 array(
2f8082cd
ML
630 ts("File permissions"),
631 ts("Does the webserver know where files are stored?"),
632 ts("The webserver isn't letting me identify where files are stored."),
6a488035
TO
633 $this->getBaseDir(),
634 ),
635 TRUE
636 );
637
638 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
639 $this->requireNoPathSeparator(
640 array(
2f8082cd
ML
641 ts("File permissions"),
642 ts('Does the CiviCRM path contain PATH_SEPARATOR?'),
643 ts('The path %1 contains PATH_SEPARATOR (the %2 character).', array(1 => $this->getBaseDir(), 2 => PATH_SEPARATOR)),
6a488035
TO
644 $this->getBaseDir(),
645 )
646 );
647
648 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
649 foreach ($requiredDirectories as $dir) {
650 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . $dir,
651 array(
2f8082cd
ML
652 ts("File permissions"),
653 ts("Folder '%1' exists?", array(1 => $dir)),
654 ts("There is no '%1' folder.", array(1 => $dir)),
56fdfc52 655 ), TRUE
6a488035
TO
656 );
657 }
658
659 $configIDSiniDir = NULL;
660 global $cmsPath;
3fdcdfbb 661 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
6a488035 662 if ($installType == 'drupal') {
6a488035
TO
663
664 // make sure that we can write to sites/default and files/
665 $writableDirectories = array(
666 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
667 'sites' . CIVICRM_DIRECTORY_SEPARATOR .
668 $siteDir . CIVICRM_DIRECTORY_SEPARATOR .
669 'files',
670 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
671 'sites' . CIVICRM_DIRECTORY_SEPARATOR .
672 $siteDir,
673 );
674 }
5757adf3
HD
675 elseif ($installType == 'backdrop') {
676
677 // make sure that we can write to sites/default and files/
678 $writableDirectories = array(
679 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
680 'files',
681 $cmsPath,
682 );
683 }
6a488035 684 elseif ($installType == 'wordpress') {
7ba2c8ad
KC
685 // make sure that we can write to uploads/civicrm/
686 $upload_dir = wp_upload_dir();
687 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm';
688 if (!file_exists($files_dirname)) {
689 wp_mkdir_p($files_dirname);
690 }
691 $writableDirectories = array($files_dirname);
6a488035
TO
692 }
693
694 foreach ($writableDirectories as $dir) {
695 $dirName = CIVICRM_WINDOWS ? $dir : CIVICRM_DIRECTORY_SEPARATOR . $dir;
2f8082cd
ML
696 $testDetails = array(
697 ts("File permissions"),
698 ts("Is the %1 folder writeable?", array(1 => $dir)),
699 NULL,
6a488035 700 );
2f8082cd 701 $this->requireWriteable($dirName, $testDetails, TRUE);
6a488035
TO
702 }
703
704 //check for Config.IDS.ini, file may exist in re-install
705 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
706
707 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
708 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR, $configIDSiniDir);
709 if (file_exists($configIDSiniFile)) {
710 unlink($configIDSiniFile);
711 }
712 }
713
714 // Check for rewriting
715 if (isset($_SERVER['SERVER_SOFTWARE'])) {
716 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
717 }
718 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
719 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
720 }
721
722 if ($webserver == '') {
2f8082cd 723 $webserver = ts("I can't tell what webserver you are running");
6a488035
TO
724 }
725
726 // Check for $_SERVER configuration
56fdfc52 727 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
2f8082cd
ML
728 ts("Webserver config"),
729 ts("Recognised webserver"),
730 ts("You seem to be using an unsupported webserver. The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."),
56fdfc52 731 ));
6a488035
TO
732
733 // Check for MySQL support
fcf908c6 734 $this->requireFunction('mysqli_connect', array(
2f8082cd
ML
735 ts("PHP Configuration"),
736 ts("MySQL support"),
737 ts("MySQL support not included in PHP."),
738 ));
6a488035 739
927a045d
J
740 // Check for XML support
741 $this->requireFunction('simplexml_load_file', array(
742 ts("PHP Configuration"),
8d241549
J
743 ts("SimpleXML support"),
744 ts("SimpleXML support not included in PHP."),
927a045d
J
745 ));
746
6a488035 747 // Check for JSON support
2f8082cd
ML
748 $this->requireFunction('json_encode', array(
749 ts("PHP Configuration"),
750 ts("JSON support"),
751 ts("JSON support not included in PHP."),
752 ));
6a488035 753
cbd60be4
SL
754 // check for Multibyte support such as mb_substr. Required for proper handling of Multilingual setups.
755 $this->requireFunction('mb_substr', array(
756 ts("PHP Configuration"),
757 ts("Multibyte support"),
758 ts("Multibyte support not enabled in PHP."),
759 ));
760
6a488035
TO
761 // Check for xcache_isset and emit warning if exists
762 $this->checkXCache(array(
2f8082cd
ML
763 ts("PHP Configuration"),
764 ts("XCache compatibility"),
765 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 766 ));
6a488035
TO
767
768 // Check memory allocation
769 $this->requireMemory(32 * 1024 * 1024,
770 64 * 1024 * 1024,
771 array(
2f8082cd
ML
772 ts("PHP Configuration"),
773 ts("Memory allocated (PHP config option 'memory_limit')"),
774 ts("CiviCRM needs a minimum of %1 MB allocated to PHP, but recommends %2 MB.", array(1 => 32, 2 => 64)),
6a488035
TO
775 ini_get("memory_limit"),
776 )
777 );
778
779 return $this->errors;
780 }
781
627456b5
EM
782 /**
783 * @param $min
784 * @param $recommended
785 * @param $testDetails
786 */
971d41b1 787 public function requireMemory($min, $recommended, $testDetails) {
6a488035
TO
788 $this->testing($testDetails);
789 $mem = $this->getPHPMemory();
790
791 if ($mem < $min && $mem > 0) {
2f8082cd 792 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
6a488035
TO
793 $this->error($testDetails);
794 }
795 elseif ($mem < $recommended && $mem > 0) {
2f8082cd 796 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
6a488035
TO
797 $this->warning($testDetails);
798 }
799 elseif ($mem == 0) {
2f8082cd 800 $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
801 $this->warning($testDetails);
802 }
803 }
804
627456b5
EM
805 /**
806 * @return float
807 */
971d41b1 808 public function getPHPMemory() {
6a488035
TO
809 $memString = ini_get("memory_limit");
810
811 switch (strtolower(substr($memString, -1))) {
812 case "k":
813 return round(substr($memString, 0, -1) * 1024);
814
815 case "m":
816 return round(substr($memString, 0, -1) * 1024 * 1024);
817
818 case "g":
819 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
820
821 default:
822 return round($memString);
823 }
824 }
825
971d41b1 826 public function listErrors() {
6a488035 827 if ($this->errors) {
2f8082cd 828 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
6a488035
TO
829 foreach ($this->errors as $error) {
830 echo "<li>" . htmlentities($error) . "</li>";
831 }
832 }
833 }
834
627456b5
EM
835 /**
836 * @param null $section
837 */
971d41b1 838 public function showTable($section = NULL) {
6a488035
TO
839 if ($section) {
840 $tests = $this->tests[$section];
841 echo "<table class=\"testResults\" width=\"100%\">";
842 foreach ($tests as $test => $result) {
843 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
844 }
845 echo "</table>";
846 }
847 else {
848 foreach ($this->tests as $section => $tests) {
849 echo "<h3>$section</h3>";
850 echo "<table class=\"testResults\" width=\"100%\">";
851
852 foreach ($tests as $test => $result) {
853 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
854 }
855 echo "</table>";
856 }
857 }
858 }
859
627456b5 860 /**
100fef9d 861 * @param string $funcName
627456b5
EM
862 * @param $testDetails
863 *
864 * @return bool
865 */
971d41b1 866 public function requireFunction($funcName, $testDetails) {
6a488035
TO
867 $this->testing($testDetails);
868
869 if (!function_exists($funcName)) {
870 $this->error($testDetails);
871 return FALSE;
872 }
873 else {
874 return TRUE;
875 }
876 }
877
627456b5
EM
878 /**
879 * @param $testDetails
880 */
971d41b1 881 public function checkXCache($testDetails) {
6a488035
TO
882 if (function_exists('xcache_isset') &&
883 ini_get('xcache.size') > 0
884 ) {
885 $this->testing($testDetails);
886 $this->warning($testDetails);
887 }
888 }
889
627456b5 890 /**
cc1f4988
CW
891 * @param array $testDetails
892 * @return bool
627456b5 893 */
cc1f4988 894 public function requirePHPVersion($testDetails) {
6a488035
TO
895
896 $this->testing($testDetails);
897
56fdfc52 898 $phpVersion = phpversion();
cc1f4988 899 $aboveMinVersion = version_compare($phpVersion, CRM_Upgrade_Incremental_General::MIN_INSTALL_PHP_VER) >= 0;
6a488035 900
cc1f4988 901 if ($aboveMinVersion) {
f0c475b0 902 if (version_compare($phpVersion, CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER) < 0) {
cc1f4988 903 $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 904 1 => $phpVersion,
ef064e55 905 2 => CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER,
cc1f4988 906 3 => CRM_Upgrade_Incremental_General::RECOMMENDED_PHP_VER,
ef064e55
CW
907 ));
908 $this->warning($testDetails);
909 }
6a488035
TO
910 return TRUE;
911 }
912
cc1f4988
CW
913 if (empty($testDetails[2])) {
914 $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
915 }
916
917 $this->error($testDetails);
918 }
919
627456b5 920 /**
100fef9d 921 * @param string $filename
627456b5
EM
922 * @param $testDetails
923 * @param bool $absolute
924 */
971d41b1 925 public function requireFile($filename, $testDetails, $absolute = FALSE) {
6a488035
TO
926 $this->testing($testDetails);
927 if (!$absolute) {
928 $filename = $this->getBaseDir() . $filename;
929 }
930 if (!file_exists($filename)) {
2f8082cd 931 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
6a488035
TO
932 $this->error($testDetails);
933 }
934 }
935
627456b5
EM
936 /**
937 * @param $testDetails
938 */
971d41b1 939 public function requireNoPathSeparator($testDetails) {
6a488035
TO
940 $this->testing($testDetails);
941 if (substr_count($this->getBaseDir(), PATH_SEPARATOR)) {
942 $this->error($testDetails);
943 }
944 }
945
627456b5 946 /**
100fef9d 947 * @param string $filename
627456b5
EM
948 * @param $testDetails
949 */
971d41b1 950 public function requireNoFile($filename, $testDetails) {
6a488035
TO
951 $this->testing($testDetails);
952 $filename = $this->getBaseDir() . $filename;
953 if (file_exists($filename)) {
2f8082cd 954 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
6a488035
TO
955 $this->error($testDetails);
956 }
957 }
958
627456b5 959 /**
100fef9d 960 * @param string $filename
627456b5
EM
961 * @param $testDetails
962 */
971d41b1 963 public function moveFileOutOfTheWay($filename, $testDetails) {
6a488035
TO
964 $this->testing($testDetails);
965 $filename = $this->getBaseDir() . $filename;
966 if (file_exists($filename)) {
967 if (file_exists("$filename.bak")) {
968 rm("$filename.bak");
969 }
970 rename($filename, "$filename.bak");
971 }
972 }
973
627456b5 974 /**
100fef9d 975 * @param string $filename
627456b5
EM
976 * @param $testDetails
977 * @param bool $absolute
978 */
971d41b1 979 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
6a488035
TO
980 $this->testing($testDetails);
981 if (!$absolute) {
982 $filename = $this->getBaseDir() . $filename;
983 }
984
22e263ad 985 if (!is_writable($filename)) {
6a488035
TO
986 $name = NULL;
987 if (function_exists('posix_getpwuid')) {
988 $user = posix_getpwuid(posix_geteuid());
989 $name = '- ' . $user['name'] . ' -';
990 }
991
992 if (!isset($testDetails[2])) {
993 $testDetails[2] = NULL;
994 }
2f8082cd 995 $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
996 $this->error($testDetails);
997 }
998 }
999
627456b5 1000 /**
100fef9d 1001 * @param string $moduleName
627456b5
EM
1002 * @param $testDetails
1003 */
971d41b1 1004 public function requireApacheModule($moduleName, $testDetails) {
6a488035
TO
1005 $this->testing($testDetails);
1006 if (!in_array($moduleName, apache_get_modules())) {
1007 $this->error($testDetails);
1008 }
1009 }
1010
627456b5
EM
1011 /**
1012 * @param $server
100fef9d 1013 * @param string $username
627456b5
EM
1014 * @param $password
1015 * @param $testDetails
1016 */
971d41b1 1017 public function requireMysqlConnection($server, $username, $password, $testDetails) {
6a488035 1018 $this->testing($testDetails);
6a511829 1019 $this->conn = $this->connect($server, $username, $password);
6a488035 1020
fcf908c6 1021 if ($this->conn) {
6a488035
TO
1022 return TRUE;
1023 }
1024 else {
fcf908c6 1025 $testDetails[2] .= ": " . mysqli_connect_error();
6a488035
TO
1026 $this->error($testDetails);
1027 }
1028 }
1029
627456b5
EM
1030 /**
1031 * @param $server
1032 * @param $testDetails
1033 */
971d41b1 1034 public function requireMySQLServer($server, $testDetails) {
6a488035 1035 $this->testing($testDetails);
6a511829 1036 $conn = $this->connect($server, NULL, NULL);
6a488035 1037
fcf908c6 1038 if ($conn || mysqli_connect_errno() < 2000) {
6a488035
TO
1039 return TRUE;
1040 }
1041 else {
fcf908c6 1042 $testDetails[2] .= ": " . mysqli_connect_error();
6a488035
TO
1043 $this->error($testDetails);
1044 }
1045 }
1046
627456b5
EM
1047 /**
1048 * @param $version
1049 * @param $testDetails
1050 */
971d41b1 1051 public function requireMySQLVersion($version, $testDetails) {
6a488035
TO
1052 $this->testing($testDetails);
1053
fcf908c6 1054 if (!mysqli_get_server_info($this->conn)) {
2f8082cd 1055 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
6a488035
TO
1056 $this->warning($testDetails);
1057 }
1058 else {
1059 list($majorRequested, $minorRequested) = explode('.', $version);
fcf908c6 1060 list($majorHas, $minorHas) = explode('.', mysqli_get_server_info($this->conn));
6a488035
TO
1061
1062 if (($majorHas > $majorRequested) || ($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
1063 return TRUE;
1064 }
1065 else {
1066 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
1067 $this->error($testDetails);
1068 }
1069 }
1070 }
1071
627456b5
EM
1072 /**
1073 * @param $server
100fef9d 1074 * @param string $username
627456b5
EM
1075 * @param $password
1076 * @param $database
1077 * @param $testDetails
1078 */
971d41b1 1079 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
6a488035 1080 $this->testing($testDetails);
6a511829 1081 $conn = $this->connect($server, $username, $password);
6a488035 1082 if (!$conn) {
2f8082cd 1083 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
6a488035
TO
1084 $this->error($testDetails);
1085 return;
1086 }
1087
1088 $innodb_support = FALSE;
fcf908c6 1089 $result = mysqli_query($conn, "SHOW ENGINES");
1090 while ($values = mysqli_fetch_array($result)) {
6a488035
TO
1091 if ($values['Engine'] == 'InnoDB') {
1092 if (strtolower($values['Support']) == 'yes' ||
1093 strtolower($values['Support']) == 'default'
1094 ) {
1095 $innodb_support = TRUE;
1096 }
1097 }
1098 }
1099 if ($innodb_support) {
2f8082cd 1100 $testDetails[3] = ts('MySQL server does have InnoDB support');
6a488035
TO
1101 }
1102 else {
2f8082cd 1103 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
6a488035
TO
1104 }
1105 }
1106
627456b5
EM
1107 /**
1108 * @param $server
100fef9d 1109 * @param string $username
627456b5
EM
1110 * @param $password
1111 * @param $database
1112 * @param $testDetails
1113 */
971d41b1 1114 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
6a488035 1115 $this->testing($testDetails);
6a511829 1116 $conn = $this->connect($server, $username, $password);
6a488035 1117 if (!$conn) {
2f8082cd 1118 $testDetails[2] = ts('Could not login to the database.');
6a488035
TO
1119 $this->error($testDetails);
1120 return;
1121 }
1122
fcf908c6 1123 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1124 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1125 $this->error($testDetails);
1126 return;
1127 }
1128
fcf908c6 1129 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
6a488035 1130 if (!$result) {
2f8082cd 1131 $testDetails[2] = ts('Could not create a temp table.');
6a488035
TO
1132 $this->error($testDetails);
1133 }
fcf908c6 1134 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1135 }
1136
627456b5
EM
1137 /**
1138 * @param $server
100fef9d 1139 * @param string $username
627456b5
EM
1140 * @param $password
1141 * @param $database
1142 * @param $testDetails
1143 */
971d41b1 1144 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
6a488035 1145 $this->testing($testDetails);
6a511829 1146 $conn = $this->connect($server, $username, $password);
6a488035 1147 if (!$conn) {
2f8082cd 1148 $testDetails[2] = ts('Could not login to the database.');
6a488035
TO
1149 $this->error($testDetails);
1150 return;
1151 }
1152
fcf908c6 1153 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1154 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1155 $this->error($testDetails);
1156 return;
1157 }
1158
fcf908c6 1159 $result = mysqli_query($conn, 'CREATE TABLE civicrm_install_temp_table_test (test text)');
6a488035 1160 if (!$result) {
2f8082cd 1161 $testDetails[2] = ts('Could not create a table in the database.');
6a488035
TO
1162 $this->error($testDetails);
1163 }
1164
fcf908c6 1165 $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 1166 if (!$result) {
fcf908c6 1167 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
2f8082cd 1168 $testDetails[2] = ts('Could not create a database trigger.');
6a488035
TO
1169 $this->error($testDetails);
1170 }
1171
fcf908c6 1172 mysqli_query($conn, 'DROP TRIGGER civicrm_install_temp_table_test_trigger');
1173 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
6a488035
TO
1174 }
1175
627456b5
EM
1176 /**
1177 * @param $server
100fef9d 1178 * @param string $username
627456b5
EM
1179 * @param $password
1180 * @param $database
1181 * @param $testDetails
1182 */
971d41b1 1183 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
6a488035 1184 $this->testing($testDetails);
6a511829 1185 $conn = $this->connect($server, $username, $password);
6a488035 1186 if (!$conn) {
2f8082cd 1187 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1188 $this->error($testDetails);
1189 return;
1190 }
1191
fcf908c6 1192 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1193 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1194 $this->error($testDetails);
1195 return;
1196 }
1197
fcf908c6 1198 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
6a488035 1199 if (!$result) {
2f8082cd 1200 $testDetails[2] = ts('Could not create a table in the database.');
6a488035
TO
1201 $this->error($testDetails);
1202 return;
1203 }
1204
fcf908c6 1205 $result = mysqli_query($conn, 'LOCK TABLES civicrm_install_temp_table_test WRITE');
6a488035 1206 if (!$result) {
2f8082cd 1207 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
6a488035 1208 $this->error($testDetails);
fcf908c6 1209 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1210 return;
1211 }
1212
fcf908c6 1213 $result = mysqli_query($conn, 'UNLOCK TABLES');
6a488035 1214 if (!$result) {
2f8082cd 1215 $testDetails[2] = ts('Could not release the lock for the database table.');
6a488035 1216 $this->error($testDetails);
fcf908c6 1217 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1218 return;
1219 }
1220
fcf908c6 1221 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
6a488035
TO
1222 }
1223
627456b5
EM
1224 /**
1225 * @param $server
100fef9d 1226 * @param string $username
627456b5
EM
1227 * @param $password
1228 * @param $testDetails
1229 */
971d41b1 1230 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
6a488035 1231 $this->testing($testDetails);
6a511829 1232 $conn = $this->connect($server, $username, $password);
6a488035 1233 if (!$conn) {
2f8082cd 1234 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1235 $this->error($testDetails);
1236 return;
1237 }
1238
fcf908c6 1239 $result = mysqli_query($conn, "SHOW variables like 'auto_increment_increment'");
6a488035 1240 if (!$result) {
2f8082cd 1241 $testDetails[2] = ts('Could not query database server variables.');
6a488035
TO
1242 $this->error($testDetails);
1243 return;
1244 }
1245 else {
fcf908c6 1246 $values = mysqli_fetch_row($result);
6a488035 1247 if ($values[1] == 1) {
2f8082cd 1248 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
6a488035
TO
1249 }
1250 else {
1251 $this->error($testDetails);
1252 }
1253 }
1254 }
1255
627456b5
EM
1256 /**
1257 * @param $server
100fef9d 1258 * @param string $username
627456b5
EM
1259 * @param $password
1260 * @param $database
1261 * @param $minValueKB
1262 * @param $testDetails
1263 */
971d41b1 1264 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
6a488035 1265 $this->testing($testDetails);
6a511829 1266 $conn = $this->connect($server, $username, $password);
6a488035 1267 if (!$conn) {
2f8082cd 1268 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1269 $this->error($testDetails);
1270 return;
1271 }
1272
fcf908c6 1273 if (!@mysqli_select_db($conn, $database)) {
2f8082cd 1274 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1275 $this->error($testDetails);
1276 return;
1277 }
1278
683bf891
SL
1279 // bytes => kb
1280 $result = mysqli_query($conn, "SHOW VARIABLES LIKE 'thread_stack'");
6a488035 1281 if (!$result) {
2f8082cd 1282 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
6a488035 1283 $this->error($testDetails);
0db6c3e1
TO
1284 }
1285 else {
fcf908c6 1286 $values = mysqli_fetch_row($result);
1f5f3294 1287 if ($values[1] < (1024 * $minValueKB)) {
2f8082cd 1288 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
6a488035
TO
1289 $this->error($testDetails);
1290 }
1291 }
1292 }
1293
1b4a049e
AP
1294 /**
1295 * @param $server
1296 * @param $username
1297 * @param $password
1298 * @param $database
1299 * @param $testDetails
1300 */
1301 public function requireNoExistingData(
1302 $server,
1303 $username,
1304 $password,
1305 $database,
1306 $testDetails
1307 ) {
1308 $this->testing($testDetails);
1309 $conn = $this->connect($server, $username, $password);
1310
1311 @mysqli_select_db($conn, $database);
1312 $contactRecords = mysqli_query($conn, "SELECT count(*) as contactscount FROM civicrm_contact");
1313 if ($contactRecords) {
1314 $contactRecords = mysqli_fetch_object($contactRecords);
1315 if ($contactRecords->contactscount > 0) {
1316 $this->error($testDetails);
1317 return;
1318 }
1319 }
1320
c66b58c9 1321 $testDetails[3] = ts('CiviCRM data from previous installation does not exist in %1.', array(1 => $database));
1b4a049e
AP
1322 $this->testing($testDetails);
1323 }
1324
627456b5
EM
1325 /**
1326 * @param $server
100fef9d 1327 * @param string $username
627456b5
EM
1328 * @param $password
1329 * @param $database
1330 * @param $testDetails
1331 * @param bool $onlyRequire
1332 */
971d41b1 1333 public function requireDatabaseOrCreatePermissions(
56fdfc52 1334 $server,
6a488035
TO
1335 $username,
1336 $password,
1337 $database,
1338 $testDetails,
1339 $onlyRequire = FALSE
1340 ) {
1341 $this->testing($testDetails);
6a511829 1342 $conn = $this->connect($server, $username, $password);
6a488035
TO
1343
1344 $okay = NULL;
fcf908c6 1345 if (@mysqli_select_db($conn, $database)) {
6a488035
TO
1346 $okay = "Database '$database' exists";
1347 }
1348 elseif ($onlyRequire) {
2f8082cd 1349 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
6a488035
TO
1350 $this->error($testDetails);
1351 return;
1352 }
1353 else {
fcf908c6 1354 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1355 if (@mysqli_query($conn, $query)) {
2f8082cd 1356 $okay = ts("Able to create a new database.");
6a488035
TO
1357 }
1358 else {
2f8082cd 1359 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
6a488035
TO
1360 $this->error($testDetails);
1361 return;
1362 }
1363 }
1364
1365 if ($okay) {
1366 $testDetails[3] = $okay;
1367 $this->testing($testDetails);
1368 }
1369 }
1370
627456b5
EM
1371 /**
1372 * @param $varNames
1373 * @param $errorMessage
1374 */
971d41b1 1375 public function requireServerVariables($varNames, $errorMessage) {
6a488035
TO
1376 //$this->testing($testDetails);
1377 foreach ($varNames as $varName) {
1378 if (!$_SERVER[$varName]) {
1379 $missing[] = '$_SERVER[' . $varName . ']';
1380 }
1381 }
1382 if (!isset($missing)) {
1383 return TRUE;
1384 }
1385 else {
2f8082cd 1386 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
6a488035
TO
1387 $this->error($testDetails);
1388 }
1389 }
1390
75615982 1391 /**
1392 * @param $server
1393 * @param string $username
1394 * @param $password
1395 * @param $database
1396 * @param $testDetails
1397 */
1398 public function requireMysqlUtf8mb4($server, $username, $password, $database, $testDetails) {
1399 $this->testing($testDetails);
1400 $conn = $this->connect($server, $username, $password);
1401 if (!$conn) {
1402 $testDetails[2] = ts('Could not connect to the database server.');
1403 $this->error($testDetails);
1404 return;
1405 }
1406
1407 if (!@mysqli_select_db($conn, $database)) {
1408 $testDetails[2] = ts('Could not select the database.');
1409 $this->error($testDetails);
1410 return;
1411 }
1412
1413 $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');
1414 if (!$result) {
1415 $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');
1416 $this->warning($testDetails);
1417 return;
1418 }
1419 $result = mysqli_query($conn, 'DROP TABLE civicrm_utf8mb4_test');
1420
1421 // Ensure that the MySQL driver supports utf8mb4 encoding.
1422 $version = mysqli_get_client_info($conn);
1423 if (strpos($version, 'mysqlnd') !== FALSE) {
1424 // The mysqlnd driver supports utf8mb4 starting at version 5.0.9.
1425 $version = preg_replace('/^\D+([\d.]+).*/', '$1', $version);
1426 if (version_compare($version, '5.0.9', '<')) {
1427 $testDetails[2] = 'It is recommended, though not yet required, to upgrade your PHP MySQL driver (mysqlnd) to >= 5.0.9 for utf8mb4 support.';
1428 $this->warning($testDetails);
1429 return;
1430 }
1431 }
1432 else {
1433 // The libmysqlclient driver supports utf8mb4 starting at version 5.5.3.
1434 if (version_compare($version, '5.5.3', '<')) {
1435 $testDetails[2] = 'It is recommended, though not yet required, to upgrade your PHP MySQL driver (libmysqlclient) to >= 5.5.3 for utf8mb4 support.';
1436 $this->warning($testDetails);
1437 return;
1438 }
1439 }
1440 }
1441
627456b5
EM
1442 /**
1443 * @param $testDetails
1444 *
1445 * @return bool
1446 */
971d41b1 1447 public function isRunningApache($testDetails) {
6a488035
TO
1448 $this->testing($testDetails);
1449 if (function_exists('apache_get_modules') || stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1450 return TRUE;
1451 }
1452
1453 $this->warning($testDetails);
1454 return FALSE;
1455 }
1456
627456b5
EM
1457 /**
1458 * @return string
1459 */
971d41b1 1460 public function getBaseDir() {
6a488035
TO
1461 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR;
1462 }
1463
627456b5
EM
1464 /**
1465 * @param $testDetails
1466 */
971d41b1 1467 public function testing($testDetails) {
6a488035
TO
1468 if (!$testDetails) {
1469 return;
1470 }
1471
1472 $section = $testDetails[0];
1473 $test = $testDetails[1];
1474
2f8082cd 1475 $message = ts("OK");
6a488035
TO
1476 if (isset($testDetails[3])) {
1477 $message .= " ($testDetails[3])";
1478 }
1479
1480 $this->tests[$section][$test] = array("good", $message);
1481 }
1482
627456b5
EM
1483 /**
1484 * @param $testDetails
1485 */
971d41b1 1486 public function error($testDetails) {
6a488035
TO
1487 $section = $testDetails[0];
1488 $test = $testDetails[1];
1489
1490 $this->tests[$section][$test] = array("error", $testDetails[2]);
1491 $this->errors[] = $testDetails;
1492 }
1493
627456b5
EM
1494 /**
1495 * @param $testDetails
1496 */
971d41b1 1497 public function warning($testDetails) {
6a488035
TO
1498 $section = $testDetails[0];
1499 $test = $testDetails[1];
1500
6a488035
TO
1501 $this->tests[$section][$test] = array("warning", $testDetails[2]);
1502 $this->warnings[] = $testDetails;
1503 }
1504
627456b5
EM
1505 /**
1506 * @return int
1507 */
971d41b1 1508 public function hasErrors() {
f0879544 1509 return !empty($this->errors);
6a488035
TO
1510 }
1511
627456b5
EM
1512 /**
1513 * @return int
1514 */
971d41b1 1515 public function hasWarnings() {
f0879544 1516 return !empty($this->warnings);
6a488035 1517 }
96025800 1518
6a488035
TO
1519}
1520
627456b5
EM
1521/**
1522 * Class Installer
1523 */
6a488035 1524class Installer extends InstallRequirements {
683bf891 1525
627456b5
EM
1526 /**
1527 * @param $server
1528 * @param $username
1529 * @param $password
1530 * @param $database
1531 */
971d41b1 1532 public function createDatabaseIfNotExists($server, $username, $password, $database) {
6a511829 1533 $conn = $this->connect($server, $username, $password);
6a488035 1534
fcf908c6 1535 if (@mysqli_select_db($conn, $database)) {
6a488035
TO
1536 // skip if database already present
1537 return;
1538 }
fcf908c6 1539 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1540 if (@mysqli_query($conn, $query)) {
56fdfc52 1541 }
6a488035 1542 else {
6a9514e1
ML
1543 $errorTitle = ts("Oops! Could not create database %1", array(1 => $database));
1544 $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
1545 errorDisplayPage($errorTitle, $errorMsg);
1546 }
1547 }
1548
627456b5
EM
1549 /**
1550 * @param $config
1551 *
1552 * @return mixed
1553 */
971d41b1 1554 public function install($config) {
6a488035
TO
1555 global $installDirPath;
1556
1557 // create database if does not exists
1558 $this->createDatabaseIfNotExists($config['mysql']['server'],
1559 $config['mysql']['username'],
1560 $config['mysql']['password'],
1561 $config['mysql']['database']
1562 );
1563
1564 global $installDirPath;
1565
1566 // Build database
1567 require_once $installDirPath . 'civicrm.php';
1568 civicrm_main($config);
1569
1570 if (!$this->errors) {
1571 global $installType, $installURLPath;
1572
bb216f68 1573 $registerSiteURL = "https://civicrm.org/register-site";
56de7273
ML
1574 $commonOutputMessage
1575 = "<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>"
1576 . "<li>" . ts("We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.") . "</li>";
41547a19 1577
6a488035 1578 $output = NULL;
97b8e6b2 1579
6a488035
TO
1580 if (
1581 $installType == 'drupal' &&
1582 version_compare(VERSION, '7.0-rc1') >= 0
1583 ) {
1584
1585 // clean output
1586 @ob_clean();
1587
1588 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1589 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1590 $output .= '<head>';
2f8082cd 1591 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
6a9514e1 1592 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6a488035
TO
1593 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1594 $output .= '</head>';
1595 $output .= '<body>';
2f8082cd 1596 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
6a488035 1597 $output .= '<ul>';
6a9514e1 1598
6a488035
TO
1599 $drupalURL = civicrm_cms_base();
1600 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1601 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
6a488035 1602
6a9514e1
ML
1603 $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>";
1604 $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>";
1605 $output .= $commonOutputMessage;
6a488035
TO
1606
1607 // automatically enable CiviCRM module once it is installed successfully.
1608 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1609 global $cmsPath, $crmPath;
1610
1611 // relative / abosolute paths are not working for drupal, hence using chdir()
1612 chdir($cmsPath);
1613
97b8e6b2 1614 // Force the re-initialisation of the config singleton on the next call
1615 // since so far, we had used the Config object without loading the DB.
1616 $c = CRM_Core_Config::singleton(FALSE);
1617 $c->free();
1618
6a488035
TO
1619 include_once "./includes/bootstrap.inc";
1620 include_once "./includes/unicode.inc";
1621
1622 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1623
1624 // prevent session information from being saved.
1625 drupal_save_session(FALSE);
1626
1627 // Force the current user to anonymous.
1628 $original_user = $GLOBALS['user'];
1629 $GLOBALS['user'] = drupal_anonymous_user();
1630
1631 // explicitly setting error reporting, since we cannot handle drupal related notices
1632 error_reporting(1);
1633
1634 // rebuild modules, so that civicrm is added
1635 system_rebuild_module_data();
1636
1637 // now enable civicrm module.
1638 module_enable(array('civicrm', 'civicrmtheme'));
1639
ece6501c
ML
1640 // SystemInstallEvent will be called from here with the first call of CRM_Core_Config,
1641 // which calls Core_BAO_ConfigSetting::applyLocale(), who will default to calling
1642 // Civi::settings()->get('lcMessages');
1643 // Therefore, we need to pass the seedLanguage before that.
1644 global $civicrm_setting;
1645 $civicrm_setting['domain']['lcMessages'] = $config['seedLanguage'];
1646
d8a4acc0
C
1647 // clear block, page, theme, and hook caches
1648 drupal_flush_all_caches();
6a488035
TO
1649
1650 //add basic drupal permissions
1651 civicrm_install_set_drupal_perms();
1652
1653 // restore the user.
1654 $GLOBALS['user'] = $original_user;
1655 drupal_save_session(TRUE);
1656
1657 $output .= '</ul>';
1658 $output .= '</div>';
1659 $output .= '</body>';
1660 $output .= '</html>';
1661 echo $output;
1662 }
5757adf3
HD
1663 elseif (
1664 $installType == 'backdrop'
1665 ) {
1666
1667 // clean output
1668 @ob_clean();
1669
1670 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1671 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1672 $output .= '<head>';
1673 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1674 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1675 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1676 $output .= '</head>';
1677 $output .= '<body>';
1678 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1679 $output .= '<ul>';
1680
1681 $backdropURL = civicrm_cms_base();
1682 $backdropPermissionsURL = "{$backdropURL}index.php?q=admin/config/people/permissions";
1683 $backdropURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1684
1685 $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>";
1686 $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>";
1687 $output .= $commonOutputMessage;
1688
1689 // automatically enable CiviCRM module once it is installed successfully.
1690 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1691 global $cmsPath, $crmPath;
1692
1693 // relative / abosolute paths are not working for drupal, hence using chdir()
1694 chdir($cmsPath);
1695
1696 // Force the re-initialisation of the config singleton on the next call
1697 // since so far, we had used the Config object without loading the DB.
1698 $c = CRM_Core_Config::singleton(FALSE);
1699 $c->free();
1700
1701 include_once "./core/includes/bootstrap.inc";
1702 include_once "./core/includes/unicode.inc";
228391b3 1703 include_once "./core/includes/config.inc";
5757adf3
HD
1704
1705 backdrop_bootstrap(BACKDROP_BOOTSTRAP_FULL);
1706
1707 // prevent session information from being saved.
1708 backdrop_save_session(FALSE);
1709
1710 // Force the current user to anonymous.
1711 $original_user = $GLOBALS['user'];
1712 $GLOBALS['user'] = backdrop_anonymous_user();
1713
1714 // explicitly setting error reporting, since we cannot handle drupal related notices
1715 error_reporting(1);
1716
1717 // rebuild modules, so that civicrm is added
1718 system_rebuild_module_data();
1719
1720 // now enable civicrm module.
1721 module_enable(array('civicrm', 'civicrmtheme'));
1722
1723 // clear block, page, theme, and hook caches
1724 backdrop_flush_all_caches();
1725
1726 //add basic backdrop permissions
1727 civicrm_install_set_backdrop_perms();
1728
1729 // restore the user.
1730 $GLOBALS['user'] = $original_user;
1731 backdrop_save_session(TRUE);
1732
1733 //change the default language to one chosen
1734 if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
1735 civicrm_api3('Setting', 'create', array(
683bf891
SL
1736 'domain_id' => 'current_domain',
1737 'lcMessages' => $config['seedLanguage'],
1738 ));
5757adf3
HD
1739 }
1740
1741 $output .= '</ul>';
1742 $output .= '</div>';
1743 $output .= '</body>';
1744 $output .= '</html>';
1745 echo $output;
1746 }
6a488035
TO
1747 elseif ($installType == 'drupal' && version_compare(VERSION, '6.0') >= 0) {
1748 // clean output
1749 @ob_clean();
1750
1751 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1752 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1753 $output .= '<head>';
6a9514e1
ML
1754 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1755 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6a488035
TO
1756 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1757 $output .= '</head>';
1758 $output .= '<body>';
97b8e6b2 1759 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
6a488035 1760 $output .= '<ul>';
6a9514e1 1761
6a488035
TO
1762 $drupalURL = civicrm_cms_base();
1763 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1764 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
6a488035 1765
6a9514e1
ML
1766 $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>";
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='$drupalURL'")) . "</li>";
1768 $output .= $commonOutputMessage;
6a488035
TO
1769
1770 // explicitly setting error reporting, since we cannot handle drupal related notices
1771 error_reporting(1);
1772
1773 // automatically enable CiviCRM module once it is installed successfully.
1774 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1775 global $cmsPath, $crmPath;
1776
1777 // relative / abosolute paths are not working for drupal, hence using chdir()
1778 chdir($cmsPath);
1779
2f8082cd
ML
1780 // Force the re-initialisation of the config singleton on the next call
1781 // since so far, we had used the Config object without loading the DB.
1782 $c = CRM_Core_Config::singleton(FALSE);
1783 $c->free();
1784
6a488035
TO
1785 include_once "./includes/bootstrap.inc";
1786 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1787
1788 // rebuild modules, so that civicrm is added
1789 module_rebuild_cache();
1790
1791 // now enable civicrm module.
1792 module_enable(array('civicrm'));
1793
d8a4acc0
C
1794 // clear block, page, theme, and hook caches
1795 drupal_flush_all_caches();
6a488035
TO
1796
1797 //add basic drupal permissions
1798 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)');
1799
1800 echo $output;
1801 }
1802 elseif ($installType == 'wordpress') {
6a9514e1 1803 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
97b8e6b2 1804 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
6a488035 1805 echo '<ul>';
6a488035
TO
1806
1807 $cmsURL = civicrm_cms_base();
1808 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
41547a19
DL
1809 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1810
6a9514e1
ML
1811 $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>";
1812 $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>";
1813 $output .= $commonOutputMessage;
41547a19 1814
138a7961
KC
1815 $output .= '</ul>';
1816 $output .= '</div>';
1817 echo $output;
b232c132 1818
1819 $c = CRM_Core_Config::singleton(FALSE);
1820 $c->free();
138a7961 1821 $wpInstallRedirect = admin_url('admin.php?page=CiviCRM&q=civicrm&reset=1');
7ba2c8ad
KC
1822 echo "<script>
1823 window.location = '$wpInstallRedirect';
1824 </script>";
1f5f3294
TO
1825 }
1826 }
6a488035
TO
1827
1828 return $this->errors;
1829 }
96025800 1830
6a488035
TO
1831}
1832
1833function civicrm_install_set_drupal_perms() {
1834 if (!function_exists('db_select')) {
1835 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)');
1836 }
1837 else {
1838 $perms = array(
1839 'access all custom data',
1840 'access uploaded files',
1841 'make online contributions',
1842 'profile create',
1843 'profile edit',
1844 'profile view',
1845 'register for events',
1846 'view event info',
1847 'view event participants',
1848 'access CiviMail subscribe/unsubscribe pages',
1849 );
1850
1851 // Adding a permission that has not yet been assigned to a module by
1852 // a hook_permission implementation results in a database error.
1853 // CRM-9042
1854 $allPerms = array_keys(module_invoke_all('permission'));
1855 foreach (array_diff($perms, $allPerms) as $perm) {
1856 watchdog('civicrm',
1857 'Cannot grant the %perm permission because it does not yet exist.',
971d41b1
CW
1858 array('%perm' => $perm),
1859 WATCHDOG_ERROR
6a488035
TO
1860 );
1861 }
1862 $perms = array_intersect($perms, $allPerms);
1863 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, $perms);
1864 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, $perms);
1865 }
1866}
1867
5757adf3
HD
1868function civicrm_install_set_backdrop_perms() {
1869 $perms = array(
1870 'access all custom data',
1871 'access uploaded files',
1872 'make online contributions',
1873 'profile create',
1874 'profile edit',
1875 'profile view',
1876 'register for events',
1877 'view event info',
1878 'view event participants',
1879 'access CiviMail subscribe/unsubscribe pages',
1880 );
1881
1882 // Adding a permission that has not yet been assigned to a module by
1883 // a hook_permission implementation results in a database error.
1884 // CRM-9042
1885 $allPerms = array_keys(module_invoke_all('permission'));
1886 foreach (array_diff($perms, $allPerms) as $perm) {
1887 watchdog('civicrm',
1888 'Cannot grant the %perm permission because it does not yet exist.',
1889 array('%perm' => $perm),
1890 WATCHDOG_ERROR
1891 );
1892 }
1893 $perms = array_intersect($perms, $allPerms);
1894 user_role_grant_permissions(BACKDROP_AUTHENTICATED_ROLE, $perms);
1895 user_role_grant_permissions(BACKDROP_ANONYMOUS_ROLE, $perms);
1896}
1897
627456b5
EM
1898/**
1899 * @param $cmsPath
1900 * @param $str
1901 *
1902 * @return string
1903 */
6a488035
TO
1904function getSiteDir($cmsPath, $str) {
1905 static $siteDir = '';
1906
1907 if ($siteDir) {
1908 return $siteDir;
1909 }
1910
1911 $sites = CIVICRM_DIRECTORY_SEPARATOR . 'sites' . CIVICRM_DIRECTORY_SEPARATOR;
1912 $modules = CIVICRM_DIRECTORY_SEPARATOR . 'modules' . CIVICRM_DIRECTORY_SEPARATOR;
1913 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR) .
1914 "([\-a-zA-Z0-9_.]+)" .
1915 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR) . "/",
1916 $_SERVER['SCRIPT_FILENAME'], $matches
1917 );
1918 $siteDir = isset($matches[1]) ? $matches[1] : 'default';
1919
1920 if (strtolower($siteDir) == 'all') {
1921 // For this case - use drupal's way of finding out multi-site directory
1922 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR, $_SERVER['SCRIPT_FILENAME']);
1923 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1924 for ($i = count($uri) - 1; $i > 0; $i--) {
1925 for ($j = count($server); $j > 0; $j--) {
1926 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1927 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
56fdfc52
TO
1928 'sites' . CIVICRM_DIRECTORY_SEPARATOR . $dir
1929 )) {
6a488035
TO
1930 $siteDir = $dir;
1931 return $siteDir;
1932 }
1933 }
1934 }
1935 $siteDir = 'default';
1936 }
1937
1938 return $siteDir;
1939}
1940
627456b5
EM
1941/**
1942 * @param $errorTitle
1943 * @param $errorMsg
6a9514e1 1944 * @param $showRefer
627456b5 1945 */
6a9514e1 1946function errorDisplayPage($errorTitle, $errorMsg, $showRefer = TRUE) {
e0b29e26
WM
1947
1948 // Add a link to the documentation
6a9514e1 1949 if ($showRefer) {
e0b29e26
WM
1950 if (is_callable(array('CRM_Utils_System', 'docURL2'))) {
1951 $docLink = CRM_Utils_System::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
1952 }
2c99dd75
WM
1953 else {
1954 $docLink = '';
1955 }
e0b29e26
WM
1956
1957 if (function_exists('ts')) {
1958 $errorMsg .= '<p>' . ts("Refer to the online documentation for more information: ") . $docLink . '</p>';
1959 }
1960 else {
1961 $errorMsg .= '<p>' . 'Refer to the online documentation for more information: ' . $docLink . '</p>';
1962 }
6a9514e1
ML
1963 }
1964
1f5f3294 1965 include 'error.html';
6a488035
TO
1966 exit();
1967}