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