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