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