Merge pull request #14358 from samuelsov/billingblockts
[civicrm-core.git] / install / index.php
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
6 * http://www.silverstripe.com/.
7 *
8 * Copyright (c) 2006-7, SilverStripe Limited - www.silverstripe.com
9 * All rights reserved.
10 *
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 *
39 * Changes and modifications (c) 2007-2017 by CiviCRM LLC
40 *
41 */
42
43 /**
44 * CiviCRM Installer
45 */
46 ini_set('max_execution_time', 3000);
47
48 if (stristr(PHP_OS, 'WIN')) {
49 define('CIVICRM_DIRECTORY_SEPARATOR', '/');
50 define('CIVICRM_WINDOWS', 1);
51 }
52 else {
53 define('CIVICRM_DIRECTORY_SEPARATOR', DIRECTORY_SEPARATOR);
54 define('CIVICRM_WINDOWS', 0);
55 }
56
57 global $installType;
58 global $crmPath;
59 global $pkgPath;
60 global $installDirPath;
61 global $installURLPath;
62
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
66 // only permit acceptable installation types to prevent issues;
67 $acceptableInstallTypes = ['drupal', 'wordpress', 'backdrop'];
68 if (isset($_POST['civicrm_install_type']) && in_array($_POST['civicrm_install_type'], $acceptableInstallTypes)) {
69 $installType = $_POST['civicrm_install_type'];
70 }
71 elseif (isset($_GET['civicrm_install_type']) && in_array(strtolower($_GET['civicrm_install_type']), $acceptableInstallTypes)) {
72 $installType = strtolower($_GET['civicrm_install_type']);
73 }
74 else {
75 // default value if not set and not an acceptable install type.
76 $installType = "drupal";
77 }
78
79 if ($installType == 'drupal' || $installType == 'backdrop') {
80 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
81 $installDirPath = $installURLPath = '';
82 }
83 elseif ($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;
86 $installURLPath = WP_PLUGIN_URL . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR;
87 }
88 else {
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 }
93
94 $pkgPath = $crmPath . DIRECTORY_SEPARATOR . 'packages';
95
96 require_once $crmPath . '/CRM/Core/ClassLoader.php';
97 CRM_Core_ClassLoader::singleton()->register();
98
99 $loadGenerated = 0;
100 if (isset($_POST['loadGenerated'])) {
101 $loadGenerated = 1;
102 }
103
104 require_once dirname(__FILE__) . CIVICRM_DIRECTORY_SEPARATOR . 'langs.php';
105 foreach ($langs as $locale => $_) {
106 if ($locale == 'en_US') {
107 continue;
108 }
109 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
110 unset($langs[$locale]);
111 }
112 }
113
114 // Set the CMS
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',
120 'backdrop' => 'Backdrop',
121 );
122
123 $uf = (isset($installTypeToUF[$installType]) ? $installTypeToUF[$installType] : 'Drupal');
124 define('CIVICRM_UF', $uf);
125
126 // Set the Locale (required by CRM_Core_Config)
127 global $tsLocale;
128
129 $tsLocale = 'en_US';
130 $seedLanguage = 'en_US';
131
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.
135 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
136 $seedLanguage = $_REQUEST['seedLanguage'];
137 $tsLocale = $_REQUEST['seedLanguage'];
138 }
139
140 $config = CRM_Core_Config::singleton(FALSE);
141 $GLOBALS['civicrm_default_error_scope'] = NULL;
142
143 // The translation files are in the parent directory (l10n)
144 $i18n = CRM_Core_I18n::singleton();
145
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
151 global $cmsPath;
152 if ($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 }
164 elseif ($installType == 'backdrop') {
165 $object = new CRM_Utils_System_Backdrop();
166 $cmsPath = $object->cmsRootPath();
167 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
168 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR . 'civicrm.settings.php');
169 }
170 elseif ($installType == 'wordpress') {
171 $cmsPath = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'civicrm';
172 $upload_dir = wp_upload_dir();
173 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm';
174 $wp_civi_settings = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm.settings.php';
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 }
182 }
183
184 if ($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
196 if ($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
208 // Exit with error if CiviCRM has already been installed.
209 if ($alreadyInstalled) {
210 $errorTitle = ts("Oops! CiviCRM is already installed");
211 $settings_directory = $cmsPath;
212
213 if ($installType == 'drupal') {
214 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR, array(
215 ts('[your Drupal root directory]'),
216 'sites',
217 $siteDir,
218 ));
219 }
220 if ($installType == 'backdrop') {
221 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR, array(
222 ts('[your Backdrop root directory]'),
223 $siteDir,
224 ));
225 }
226
227 $docLink = CRM_Utils_System::docURL2('Installation and Upgrades', FALSE, ts('Installation Guide'), NULL, NULL, "wiki");
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));
229 errorDisplayPage($errorTitle, $errorMsg, FALSE);
230 }
231
232 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'civicrm-version.php';
233 if (file_exists($versionFile)) {
234 require_once $versionFile;
235 $civicrm_version = civicrmVersion();
236 }
237 else {
238 $civicrm_version = 'unknown';
239 }
240
241 if ($installType == 'drupal') {
242 // Ensure that they have downloaded the correct version of CiviCRM
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.");
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
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 }
276
277 if (!defined('VERSION') or version_compare(VERSION, '6.0') < 0) {
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)));
280 errorDisplayPage($errorTitle, $errorMsg);
281 }
282 }
283 elseif ($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 }
308 elseif ($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') {
314 $errorTitle = ts("Oops! Incorrect CiviCRM version");
315 $errorMsg = ts("This installer can only be used for the WordPress version of CiviCRM.");
316 errorDisplayPage($errorTitle, $errorMsg);
317 }
318 }
319
320 // Load CiviCRM database config
321 if (isset($_POST['mysql'])) {
322 $databaseConfig = $_POST['mysql'];
323 }
324
325 if ($installType == 'wordpress') {
326 // Load WP database config
327 if (isset($_POST['mysql'])) {
328 $databaseConfig = $_POST['mysql'];
329 }
330 else {
331 $databaseConfig = array(
332 "server" => DB_HOST,
333 "username" => DB_USER,
334 "password" => DB_PASSWORD,
335 "database" => DB_NAME,
336 );
337 }
338 }
339
340 if ($installType == 'drupal') {
341 // Load drupal database config
342 if (isset($_POST['drupal'])) {
343 $drupalConfig = $_POST['drupal'];
344 }
345 else {
346 $dbServer = $databases['default']['default']['host'];
347 if (!empty($databases['default']['default']['port'])) {
348 $dbServer .= ':' . $databases['default']['default']['port'];
349 }
350 $drupalConfig = array(
351 "server" => $dbServer,
352 "username" => $databases['default']['default']['username'],
353 "password" => $databases['default']['default']['password'],
354 "database" => $databases['default']['default']['database'],
355 );
356 }
357 }
358
359 if ($installType == 'backdrop') {
360 // Load backdrop database config
361 if (isset($_POST['backdrop'])) {
362 $backdropConfig = $_POST['backdrop'];
363 }
364 else {
365 $backdropConfig = array(
366 "server" => "localhost",
367 "username" => "backdrop",
368 "password" => "",
369 "database" => "backdrop",
370 );
371 }
372 }
373
374 // By default set CiviCRM database to be same as CMS database
375 if (!isset($databaseConfig)) {
376 if (($installType == 'drupal') && (isset($drupalConfig))) {
377 $databaseConfig = $drupalConfig;
378 }
379 if (($installType == 'backdrop') && (isset($backdropConfig))) {
380 $databaseConfig = $backdropConfig;
381 }
382 }
383
384 // Check requirements
385 $req = new InstallRequirements();
386 $req->check();
387
388 if ($req->hasErrors()) {
389 $hasErrorOtherThanDatabase = TRUE;
390 }
391
392 if ($databaseConfig) {
393 $dbReq = new InstallRequirements();
394 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
395 if ($installType == 'drupal') {
396 $dbReq->checkdatabase($drupalConfig, 'Drupal');
397 }
398 if ($installType == 'backdrop') {
399 $dbReq->checkdatabase($backdropConfig, 'Backdrop');
400 }
401 }
402
403 // Actual processor
404 if (isset($_POST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
405 // Confirm before reinstalling
406 if (!isset($_POST['force_reinstall']) && $alreadyInstalled) {
407 include $installDirPath . 'template.html';
408 }
409 else {
410 $inst = new Installer();
411 $inst->install($_POST);
412 }
413
414 // Show the config form
415 }
416 else {
417 include $installDirPath . 'template.html';
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:
424 * $description[0] - The test category
425 * $description[1] - The test title
426 * $description[2] - The test error to show, if it goes wrong
427 */
428 class InstallRequirements {
429 public $errors;
430 public $warnings;
431 public $tests;
432 public $conn;
433
434 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
435 const MINIMUM_THREAD_STACK = 192;
436
437 /**
438 * Just check that the database configuration is okay.
439 * @param $databaseConfig
440 * @param $dbName
441 */
442 public function checkdatabase($databaseConfig, $dbName) {
443 if ($this->requireFunction('mysqli_connect',
444 array(
445 ts("PHP Configuration"),
446 ts("MySQL support"),
447 ts("MySQL support not included in PHP."),
448 )
449 )
450 ) {
451 $this->requireMySQLServer($databaseConfig['server'],
452 array(
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'])),
456 $databaseConfig['server'],
457 )
458 );
459 if ($this->requireMysqlConnection($databaseConfig['server'],
460 $databaseConfig['username'],
461 $databaseConfig['password'],
462 array(
463 ts("MySQL %1 Configuration", array(1 => $dbName)),
464 ts("Are the access credentials correct?"),
465 ts("That username/password doesn't work"),
466 )
467 )
468 ) {
469 @$this->requireMySQLVersion("5.1",
470 array(
471 ts("MySQL %1 Configuration", array(1 => $dbName)),
472 ts("MySQL version at least %1", array(1 => '5.1')),
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))),
475 )
476 );
477 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
478 $databaseConfig['username'],
479 $databaseConfig['password'],
480 array(
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."),
484 )
485 );
486 $testDetails = array(
487 ts("MySQL %1 Configuration", array(1 => $dbName)),
488 ts("Is the provided database name valid?"),
489 ts("The database name provided is not valid. Please use only 0-9, a-z, A-Z, _ and - as characters in the name."),
490 );
491 if (!CRM_Core_DAO::requireSafeDBName($databaseConfig['database'])) {
492 $this->error($testDetails);
493 return FALSE;
494 }
495 else {
496 $this->testing($testDetails);
497 }
498 $this->requireMySQLThreadStack($databaseConfig['server'],
499 $databaseConfig['username'],
500 $databaseConfig['password'],
501 $databaseConfig['database'],
502 self::MINIMUM_THREAD_STACK,
503 array(
504 ts("MySQL %1 Configuration", array(1 => $dbName)),
505 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self::MINIMUM_THREAD_STACK)),
506 "",
507 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
508 )
509 );
510 }
511 $onlyRequire = ($dbName == 'Drupal' || $dbName == 'Backdrop') ? TRUE : FALSE;
512 $this->requireDatabaseOrCreatePermissions(
513 $databaseConfig['server'],
514 $databaseConfig['username'],
515 $databaseConfig['password'],
516 $databaseConfig['database'],
517 array(
518 ts("MySQL %1 Configuration", array(1 => $dbName)),
519 ts("Can I access/create the database?"),
520 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
521 ),
522 $onlyRequire
523 );
524 if ($dbName != 'Drupal' && $dbName != 'Backdrop') {
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)),
532 ts("Does the database have data from a previous installation?"),
533 ts("CiviCRM data from previous installation exists in '%1'.", array(1 => $databaseConfig['database'])),
534 )
535 );
536 $this->requireMySQLInnoDB($databaseConfig['server'],
537 $databaseConfig['username'],
538 $databaseConfig['password'],
539 $databaseConfig['database'],
540 array(
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."),
544 )
545 );
546 $this->requireMySQLTempTables($databaseConfig['server'],
547 $databaseConfig['username'],
548 $databaseConfig['password'],
549 $databaseConfig['database'],
550 array(
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.'),
554 )
555 );
556 $this->requireMySQLLockTables($databaseConfig['server'],
557 $databaseConfig['username'],
558 $databaseConfig['password'],
559 $databaseConfig['database'],
560 array(
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.'),
564 )
565 );
566 $this->requireMySQLTrigger($databaseConfig['server'],
567 $databaseConfig['username'],
568 $databaseConfig['password'],
569 $databaseConfig['database'],
570 array(
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.'),
574 )
575 );
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 );
586 }
587 }
588 }
589
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 *
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
600 * @param string $database
601 * @return \mysqli
602 */
603 protected function connect($host, $username, $password, $database = '') {
604 $hostParts = explode(':', $host);
605 if (count($hostParts) > 1 && strrpos($host, ']') !== strlen($host) - 1) {
606 $port = array_pop($hostParts);
607 $host = implode(':', $hostParts);
608 }
609 else {
610 $port = NULL;
611 }
612 $conn = @mysqli_connect($host, $username, $password, $database, $port);
613 return $conn;
614 }
615
616 /**
617 * Check everything except the database.
618 */
619 public function check() {
620 global $crmPath, $installType;
621
622 $this->errors = NULL;
623
624 $this->requirePHPVersion(array(
625 ts("PHP Configuration"),
626 ts("PHP5 installed"),
627 ));
628
629 // Check that we can identify the root folder successfully
630 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'README.md',
631 array(
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."),
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(
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)),
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(
654 ts("File permissions"),
655 ts("Folder '%1' exists?", array(1 => $dir)),
656 ts("There is no '%1' folder.", array(1 => $dir)),
657 ), TRUE
658 );
659 }
660
661 $configIDSiniDir = NULL;
662 global $cmsPath;
663 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
664 if ($installType == 'drupal') {
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 }
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 }
686 elseif ($installType == 'wordpress') {
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);
694 }
695
696 foreach ($writableDirectories as $dir) {
697 $dirName = CIVICRM_WINDOWS ? $dir : CIVICRM_DIRECTORY_SEPARATOR . $dir;
698 $testDetails = array(
699 ts("File permissions"),
700 ts("Is the %1 folder writeable?", array(1 => $dir)),
701 NULL,
702 );
703 $this->requireWriteable($dirName, $testDetails, TRUE);
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 == '') {
725 $webserver = ts("I can't tell what webserver you are running");
726 }
727
728 // Check for $_SERVER configuration
729 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
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."),
733 ));
734
735 // Check for MySQL support
736 $this->requireFunction('mysqli_connect', array(
737 ts("PHP Configuration"),
738 ts("MySQL support"),
739 ts("MySQL support not included in PHP."),
740 ));
741
742 // Check for XML support
743 $this->requireFunction('simplexml_load_file', array(
744 ts("PHP Configuration"),
745 ts("SimpleXML support"),
746 ts("SimpleXML support not included in PHP."),
747 ));
748
749 // Check for JSON support
750 $this->requireFunction('json_encode', array(
751 ts("PHP Configuration"),
752 ts("JSON support"),
753 ts("JSON support not included in PHP."),
754 ));
755
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
763 // Check for xcache_isset and emit warning if exists
764 $this->checkXCache(array(
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."),
768 ));
769
770 // Check memory allocation
771 $this->requireMemory(32 * 1024 * 1024,
772 64 * 1024 * 1024,
773 array(
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)),
777 ini_get("memory_limit"),
778 )
779 );
780
781 return $this->errors;
782 }
783
784 /**
785 * @param $min
786 * @param $recommended
787 * @param $testDetails
788 */
789 public function requireMemory($min, $recommended, $testDetails) {
790 $this->testing($testDetails);
791 $mem = $this->getPHPMemory();
792
793 if ($mem < $min && $mem > 0) {
794 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
795 $this->error($testDetails);
796 }
797 elseif ($mem < $recommended && $mem > 0) {
798 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
799 $this->warning($testDetails);
800 }
801 elseif ($mem == 0) {
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));
803 $this->warning($testDetails);
804 }
805 }
806
807 /**
808 * @return float
809 */
810 public function getPHPMemory() {
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
828 public function listErrors() {
829 if ($this->errors) {
830 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
831 foreach ($this->errors as $error) {
832 echo "<li>" . htmlentities($error) . "</li>";
833 }
834 }
835 }
836
837 /**
838 * @param null $section
839 */
840 public function showTable($section = NULL) {
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
862 /**
863 * @param string $funcName
864 * @param $testDetails
865 *
866 * @return bool
867 */
868 public function requireFunction($funcName, $testDetails) {
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
880 /**
881 * @param $testDetails
882 */
883 public function checkXCache($testDetails) {
884 if (function_exists('xcache_isset') &&
885 ini_get('xcache.size') > 0
886 ) {
887 $this->testing($testDetails);
888 $this->warning($testDetails);
889 }
890 }
891
892 /**
893 * @param array $testDetails
894 * @return bool
895 */
896 public function requirePHPVersion($testDetails) {
897
898 $this->testing($testDetails);
899
900 $phpVersion = phpversion();
901 $aboveMinVersion = version_compare($phpVersion, CRM_Upgrade_Incremental_General::MIN_INSTALL_PHP_VER) >= 0;
902
903 if ($aboveMinVersion) {
904 if (version_compare($phpVersion, CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER) < 0) {
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(
906 1 => $phpVersion,
907 2 => CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER,
908 3 => CRM_Upgrade_Incremental_General::RECOMMENDED_PHP_VER,
909 ));
910 $this->warning($testDetails);
911 }
912 return TRUE;
913 }
914
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));
917 }
918
919 $this->error($testDetails);
920 }
921
922 /**
923 * @param string $filename
924 * @param $testDetails
925 * @param bool $absolute
926 */
927 public function requireFile($filename, $testDetails, $absolute = FALSE) {
928 $this->testing($testDetails);
929 if (!$absolute) {
930 $filename = $this->getBaseDir() . $filename;
931 }
932 if (!file_exists($filename)) {
933 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
934 $this->error($testDetails);
935 }
936 }
937
938 /**
939 * @param $testDetails
940 */
941 public function requireNoPathSeparator($testDetails) {
942 $this->testing($testDetails);
943 if (substr_count($this->getBaseDir(), PATH_SEPARATOR)) {
944 $this->error($testDetails);
945 }
946 }
947
948 /**
949 * @param string $filename
950 * @param $testDetails
951 */
952 public function requireNoFile($filename, $testDetails) {
953 $this->testing($testDetails);
954 $filename = $this->getBaseDir() . $filename;
955 if (file_exists($filename)) {
956 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
957 $this->error($testDetails);
958 }
959 }
960
961 /**
962 * @param string $filename
963 * @param $testDetails
964 */
965 public function moveFileOutOfTheWay($filename, $testDetails) {
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
976 /**
977 * @param string $filename
978 * @param $testDetails
979 * @param bool $absolute
980 */
981 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
982 $this->testing($testDetails);
983 if (!$absolute) {
984 $filename = $this->getBaseDir() . $filename;
985 }
986
987 if (!is_writable($filename)) {
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 }
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";
998 $this->error($testDetails);
999 }
1000 }
1001
1002 /**
1003 * @param string $moduleName
1004 * @param $testDetails
1005 */
1006 public function requireApacheModule($moduleName, $testDetails) {
1007 $this->testing($testDetails);
1008 if (!in_array($moduleName, apache_get_modules())) {
1009 $this->error($testDetails);
1010 }
1011 }
1012
1013 /**
1014 * @param $server
1015 * @param string $username
1016 * @param $password
1017 * @param $testDetails
1018 */
1019 public function requireMysqlConnection($server, $username, $password, $testDetails) {
1020 $this->testing($testDetails);
1021 $this->conn = $this->connect($server, $username, $password);
1022
1023 if ($this->conn) {
1024 return TRUE;
1025 }
1026 else {
1027 $testDetails[2] .= ": " . mysqli_connect_error();
1028 $this->error($testDetails);
1029 }
1030 }
1031
1032 /**
1033 * @param $server
1034 * @param $testDetails
1035 */
1036 public function requireMySQLServer($server, $testDetails) {
1037 $this->testing($testDetails);
1038 $conn = $this->connect($server, NULL, NULL);
1039
1040 if ($conn || mysqli_connect_errno() < 2000) {
1041 return TRUE;
1042 }
1043 else {
1044 $testDetails[2] .= ": " . mysqli_connect_error();
1045 $this->error($testDetails);
1046 }
1047 }
1048
1049 /**
1050 * @param $version
1051 * @param $testDetails
1052 */
1053 public function requireMySQLVersion($version, $testDetails) {
1054 $this->testing($testDetails);
1055
1056 if (!mysqli_get_server_info($this->conn)) {
1057 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
1058 $this->warning($testDetails);
1059 }
1060 else {
1061 list($majorRequested, $minorRequested) = explode('.', $version);
1062 list($majorHas, $minorHas) = explode('.', mysqli_get_server_info($this->conn));
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
1074 /**
1075 * @param $server
1076 * @param string $username
1077 * @param $password
1078 * @param $database
1079 * @param $testDetails
1080 */
1081 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
1082 $this->testing($testDetails);
1083 $conn = $this->connect($server, $username, $password);
1084 if (!$conn) {
1085 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
1086 $this->error($testDetails);
1087 return;
1088 }
1089
1090 $innodb_support = FALSE;
1091 $result = mysqli_query($conn, "SHOW ENGINES");
1092 while ($values = mysqli_fetch_array($result)) {
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) {
1102 $testDetails[3] = ts('MySQL server does have InnoDB support');
1103 }
1104 else {
1105 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
1106 }
1107 }
1108
1109 /**
1110 * @param $server
1111 * @param string $username
1112 * @param $password
1113 * @param $database
1114 * @param $testDetails
1115 */
1116 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
1117 $this->testing($testDetails);
1118 $conn = $this->connect($server, $username, $password);
1119 if (!$conn) {
1120 $testDetails[2] = ts('Could not login to the database.');
1121 $this->error($testDetails);
1122 return;
1123 }
1124
1125 if (!@mysqli_select_db($conn, $database)) {
1126 $testDetails[2] = ts('Could not select the database.');
1127 $this->error($testDetails);
1128 return;
1129 }
1130
1131 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
1132 if (!$result) {
1133 $testDetails[2] = ts('Could not create a temp table.');
1134 $this->error($testDetails);
1135 }
1136 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1137 }
1138
1139 /**
1140 * @param $server
1141 * @param string $username
1142 * @param $password
1143 * @param $database
1144 * @param $testDetails
1145 */
1146 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
1147 $this->testing($testDetails);
1148 $conn = $this->connect($server, $username, $password);
1149 if (!$conn) {
1150 $testDetails[2] = ts('Could not login to the database.');
1151 $this->error($testDetails);
1152 return;
1153 }
1154
1155 if (!@mysqli_select_db($conn, $database)) {
1156 $testDetails[2] = ts('Could not select the database.');
1157 $this->error($testDetails);
1158 return;
1159 }
1160
1161 $result = mysqli_query($conn, 'CREATE TABLE civicrm_install_temp_table_test (test text)');
1162 if (!$result) {
1163 $testDetails[2] = ts('Could not create a table in the database.');
1164 $this->error($testDetails);
1165 }
1166
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');
1168 if (!$result) {
1169 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
1170 $testDetails[2] = ts('Could not create a database trigger.');
1171 $this->error($testDetails);
1172 }
1173
1174 mysqli_query($conn, 'DROP TRIGGER civicrm_install_temp_table_test_trigger');
1175 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
1176 }
1177
1178 /**
1179 * @param $server
1180 * @param string $username
1181 * @param $password
1182 * @param $database
1183 * @param $testDetails
1184 */
1185 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
1186 $this->testing($testDetails);
1187 $conn = $this->connect($server, $username, $password);
1188 if (!$conn) {
1189 $testDetails[2] = ts('Could not connect to the database server.');
1190 $this->error($testDetails);
1191 return;
1192 }
1193
1194 if (!@mysqli_select_db($conn, $database)) {
1195 $testDetails[2] = ts('Could not select the database.');
1196 $this->error($testDetails);
1197 return;
1198 }
1199
1200 $result = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
1201 if (!$result) {
1202 $testDetails[2] = ts('Could not create a table in the database.');
1203 $this->error($testDetails);
1204 return;
1205 }
1206
1207 $result = mysqli_query($conn, 'LOCK TABLES civicrm_install_temp_table_test WRITE');
1208 if (!$result) {
1209 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
1210 $this->error($testDetails);
1211 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1212 return;
1213 }
1214
1215 $result = mysqli_query($conn, 'UNLOCK TABLES');
1216 if (!$result) {
1217 $testDetails[2] = ts('Could not release the lock for the database table.');
1218 $this->error($testDetails);
1219 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1220 return;
1221 }
1222
1223 $result = mysqli_query($conn, 'DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1224 }
1225
1226 /**
1227 * @param $server
1228 * @param string $username
1229 * @param $password
1230 * @param $testDetails
1231 */
1232 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
1233 $this->testing($testDetails);
1234 $conn = $this->connect($server, $username, $password);
1235 if (!$conn) {
1236 $testDetails[2] = ts('Could not connect to the database server.');
1237 $this->error($testDetails);
1238 return;
1239 }
1240
1241 $result = mysqli_query($conn, "SHOW variables like 'auto_increment_increment'");
1242 if (!$result) {
1243 $testDetails[2] = ts('Could not query database server variables.');
1244 $this->error($testDetails);
1245 return;
1246 }
1247 else {
1248 $values = mysqli_fetch_row($result);
1249 if ($values[1] == 1) {
1250 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
1251 }
1252 else {
1253 $this->error($testDetails);
1254 }
1255 }
1256 }
1257
1258 /**
1259 * @param $server
1260 * @param string $username
1261 * @param $password
1262 * @param $database
1263 * @param $minValueKB
1264 * @param $testDetails
1265 */
1266 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
1267 $this->testing($testDetails);
1268 $conn = $this->connect($server, $username, $password);
1269 if (!$conn) {
1270 $testDetails[2] = ts('Could not connect to the database server.');
1271 $this->error($testDetails);
1272 return;
1273 }
1274
1275 if (!@mysqli_select_db($conn, $database)) {
1276 $testDetails[2] = ts('Could not select the database.');
1277 $this->error($testDetails);
1278 return;
1279 }
1280
1281 // bytes => kb
1282 $result = mysqli_query($conn, "SHOW VARIABLES LIKE 'thread_stack'");
1283 if (!$result) {
1284 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
1285 $this->error($testDetails);
1286 }
1287 else {
1288 $values = mysqli_fetch_row($result);
1289 if ($values[1] < (1024 * $minValueKB)) {
1290 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
1291 $this->error($testDetails);
1292 }
1293 }
1294 }
1295
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
1323 $testDetails[3] = ts('CiviCRM data from previous installation does not exist in %1.', array(1 => $database));
1324 $this->testing($testDetails);
1325 }
1326
1327 /**
1328 * @param $server
1329 * @param string $username
1330 * @param $password
1331 * @param $database
1332 * @param $testDetails
1333 * @param bool $onlyRequire
1334 */
1335 public function requireDatabaseOrCreatePermissions(
1336 $server,
1337 $username,
1338 $password,
1339 $database,
1340 $testDetails,
1341 $onlyRequire = FALSE
1342 ) {
1343 $this->testing($testDetails);
1344 $conn = $this->connect($server, $username, $password);
1345
1346 $okay = NULL;
1347 if (@mysqli_select_db($conn, $database)) {
1348 $okay = "Database '$database' exists";
1349 }
1350 elseif ($onlyRequire) {
1351 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
1352 $this->error($testDetails);
1353 return;
1354 }
1355 else {
1356 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1357 if (@mysqli_query($conn, $query)) {
1358 $okay = ts("Able to create a new database.");
1359 }
1360 else {
1361 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
1362 $this->error($testDetails);
1363 return;
1364 }
1365 }
1366
1367 if ($okay) {
1368 $testDetails[3] = $okay;
1369 $this->testing($testDetails);
1370 }
1371 }
1372
1373 /**
1374 * @param $varNames
1375 * @param $errorMessage
1376 */
1377 public function requireServerVariables($varNames, $errorMessage) {
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 {
1388 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
1389 $this->error($testDetails);
1390 }
1391 }
1392
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
1444 /**
1445 * @param $testDetails
1446 *
1447 * @return bool
1448 */
1449 public function isRunningApache($testDetails) {
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
1459 /**
1460 * @return string
1461 */
1462 public function getBaseDir() {
1463 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR;
1464 }
1465
1466 /**
1467 * @param $testDetails
1468 */
1469 public function testing($testDetails) {
1470 if (!$testDetails) {
1471 return;
1472 }
1473
1474 $section = $testDetails[0];
1475 $test = $testDetails[1];
1476
1477 $message = ts("OK");
1478 if (isset($testDetails[3])) {
1479 $message .= " ($testDetails[3])";
1480 }
1481
1482 $this->tests[$section][$test] = array("good", $message);
1483 }
1484
1485 /**
1486 * @param $testDetails
1487 */
1488 public function error($testDetails) {
1489 $section = $testDetails[0];
1490 $test = $testDetails[1];
1491
1492 $this->tests[$section][$test] = array("error", $testDetails[2]);
1493 $this->errors[] = $testDetails;
1494 }
1495
1496 /**
1497 * @param $testDetails
1498 */
1499 public function warning($testDetails) {
1500 $section = $testDetails[0];
1501 $test = $testDetails[1];
1502
1503 $this->tests[$section][$test] = array("warning", $testDetails[2]);
1504 $this->warnings[] = $testDetails;
1505 }
1506
1507 /**
1508 * @return int
1509 */
1510 public function hasErrors() {
1511 return !empty($this->errors);
1512 }
1513
1514 /**
1515 * @return int
1516 */
1517 public function hasWarnings() {
1518 return !empty($this->warnings);
1519 }
1520
1521 }
1522
1523 /**
1524 * Class Installer
1525 */
1526 class Installer extends InstallRequirements {
1527
1528 /**
1529 * @param $server
1530 * @param $username
1531 * @param $password
1532 * @param $database
1533 */
1534 public function createDatabaseIfNotExists($server, $username, $password, $database) {
1535 $conn = $this->connect($server, $username, $password);
1536
1537 if (@mysqli_select_db($conn, $database)) {
1538 // skip if database already present
1539 return;
1540 }
1541 $query = sprintf("CREATE DATABASE %s", mysqli_real_escape_string($conn, $database));
1542 if (@mysqli_query($conn, $query)) {
1543 }
1544 else {
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.");
1547 errorDisplayPage($errorTitle, $errorMsg);
1548 }
1549 }
1550
1551 /**
1552 * @param $config
1553 *
1554 * @return mixed
1555 */
1556 public function install($config) {
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
1575 $registerSiteURL = "https://civicrm.org/register-site";
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>";
1579
1580 $output = NULL;
1581
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>';
1593 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1594 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1595 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1596 $output .= '</head>';
1597 $output .= '<body>';
1598 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1599 $output .= '<ul>';
1600
1601 $drupalURL = civicrm_cms_base();
1602 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1603 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1604
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;
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
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
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
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
1649 // clear block, page, theme, and hook caches
1650 drupal_flush_all_caches();
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 }
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";
1705 include_once "./core/includes/config.inc";
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(
1738 'domain_id' => 'current_domain',
1739 'lcMessages' => $config['seedLanguage'],
1740 ));
1741 }
1742
1743 $output .= '</ul>';
1744 $output .= '</div>';
1745 $output .= '</body>';
1746 $output .= '</html>';
1747 echo $output;
1748 }
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>';
1756 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1757 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1758 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1759 $output .= '</head>';
1760 $output .= '<body>';
1761 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
1762 $output .= '<ul>';
1763
1764 $drupalURL = civicrm_cms_base();
1765 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1766 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1767
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;
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
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
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
1796 // clear block, page, theme, and hook caches
1797 drupal_flush_all_caches();
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') {
1805 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
1806 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
1807 echo '<ul>';
1808
1809 $cmsURL = civicrm_cms_base();
1810 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1811 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1812
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;
1816
1817 $output .= '</ul>';
1818 $output .= '</div>';
1819 echo $output;
1820
1821 $c = CRM_Core_Config::singleton(FALSE);
1822 $c->free();
1823 $wpInstallRedirect = admin_url('admin.php?page=CiviCRM&q=civicrm&reset=1');
1824 echo "<script>
1825 window.location = '$wpInstallRedirect';
1826 </script>";
1827 }
1828 }
1829
1830 return $this->errors;
1831 }
1832
1833 }
1834
1835 function 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.',
1860 array('%perm' => $perm),
1861 WATCHDOG_ERROR
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
1870 function 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
1900 /**
1901 * @param $cmsPath
1902 * @param $str
1903 *
1904 * @return string
1905 */
1906 function 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 .
1930 'sites' . CIVICRM_DIRECTORY_SEPARATOR . $dir
1931 )) {
1932 $siteDir = $dir;
1933 return $siteDir;
1934 }
1935 }
1936 }
1937 $siteDir = 'default';
1938 }
1939
1940 return $siteDir;
1941 }
1942
1943 /**
1944 * @param $errorTitle
1945 * @param $errorMsg
1946 * @param $showRefer
1947 */
1948 function errorDisplayPage($errorTitle, $errorMsg, $showRefer = TRUE) {
1949
1950 // Add a link to the documentation
1951 if ($showRefer) {
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 }
1955 else {
1956 $docLink = '';
1957 }
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 }
1965 }
1966
1967 include 'error.html';
1968 exit();
1969 }