Merge pull request #8068 from colemanw/CRM-17832
[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-2015 by CiviCRM LLC
40 *
41 */
42
43 /**
44 * CiviCRM Installer
45 */
46
47 ini_set('max_execution_time', 3000);
48
49 if (stristr(PHP_OS, 'WIN')) {
50 define('CIVICRM_DIRECTORY_SEPARATOR', '/');
51 define('CIVICRM_WINDOWS', 1);
52 }
53 else {
54 define('CIVICRM_DIRECTORY_SEPARATOR', DIRECTORY_SEPARATOR);
55 define('CIVICRM_WINDOWS', 0);
56 }
57
58 // set installation type - drupal
59 if (!session_id()) {
60 if (defined('PANTHEON_ENVIRONMENT')) {
61 ini_set('session.save_handler', 'files');
62 }
63 session_start();
64 }
65
66 // unset civicrm session if any
67 if (array_key_exists('CiviCRM', $_SESSION)) {
68 unset($_SESSION['CiviCRM']);
69 }
70
71 if (isset($_GET['civicrm_install_type'])) {
72 $_SESSION['civicrm_install_type'] = $_GET['civicrm_install_type'];
73 }
74 else {
75 if (!isset($_SESSION['civicrm_install_type'])) {
76 $_SESSION['civicrm_install_type'] = "drupal";
77 }
78 }
79
80 global $installType;
81 global $crmPath;
82 global $pkgPath;
83 global $installDirPath;
84 global $installURLPath;
85
86 $installType = strtolower($_SESSION['civicrm_install_type']);
87
88 if ($installType == 'drupal') {
89 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
90 $installDirPath = $installURLPath = '';
91 }
92 elseif ($installType == 'wordpress') {
93 $crmPath = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR;
94 $installDirPath = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR;
95 $installURLPath = WP_PLUGIN_URL . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR;
96 }
97 else {
98 $errorTitle = "Oops! Unsupported installation mode";
99 $errorMsg = sprintf('%s: unknown installation mode. Please refer to the online documentation for more information.', $installType);
100 errorDisplayPage($errorTitle, $errorMsg, FALSE);
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 // Load civicrm database config
109 if (isset($_POST['mysql'])) {
110 $databaseConfig = $_POST['mysql'];
111 }
112 else {
113 $databaseConfig = array(
114 "server" => "localhost",
115 "username" => "civicrm",
116 "password" => "",
117 "database" => "civicrm",
118 );
119 }
120
121 if ($installType == 'wordpress') {
122 //WP Database Data
123 $databaseConfig = array(
124 "server" => DB_HOST,
125 "username" => DB_USER,
126 "password" => DB_PASSWORD,
127 "database" => DB_NAME,
128 );
129 }
130
131 if ($installType == 'drupal') {
132 // Load drupal database config
133 if (isset($_POST['drupal'])) {
134 $drupalConfig = $_POST['drupal'];
135 }
136 else {
137 $drupalConfig = array(
138 "server" => "localhost",
139 "username" => "drupal",
140 "password" => "",
141 "database" => "drupal",
142 );
143 }
144 }
145
146 $loadGenerated = 0;
147 if (isset($_POST['loadGenerated'])) {
148 $loadGenerated = 1;
149 }
150
151 require_once dirname(__FILE__) . CIVICRM_DIRECTORY_SEPARATOR . 'langs.php';
152 foreach ($langs as $locale => $_) {
153 if ($locale == 'en_US') {
154 continue;
155 }
156 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
157 unset($langs[$locale]);
158 }
159 }
160
161 // Set the locale (required by CRM_Core_Config)
162 // This is mostly sympbolic, since nothing we do during the install
163 // really requires CIVICRM_UF to be defined.
164 $installTypeToUF = array(
165 'wordpress' => 'WordPress',
166 'drupal' => 'Drupal',
167 );
168
169 $uf = (isset($installTypeToUF[$installType]) ? $installTypeToUF[$installType] : 'Drupal');
170 define('CIVICRM_UF', $uf);
171
172 global $tsLocale;
173
174 $tsLocale = 'en_US';
175 $seedLanguage = 'en_US';
176
177 // CRM-16801 This validates that seedLanguage is valid by looking in $langs.
178 // NB: the variable is initial a $_REQUEST for the initial page reload,
179 // then becomes a $_POST when the installation form is submitted.
180 if (isset($_REQUEST['seedLanguage']) and isset($langs[$_REQUEST['seedLanguage']])) {
181 $seedLanguage = $_REQUEST['seedLanguage'];
182 $tsLocale = $_REQUEST['seedLanguage'];
183 }
184
185 $config = CRM_Core_Config::singleton(FALSE);
186 $GLOBALS['civicrm_default_error_scope'] = NULL;
187
188 // The translation files are in the parent directory (l10n)
189 $i18n = CRM_Core_I18n::singleton();
190
191 // Support for Arabic, Hebrew, Farsi, etc.
192 // Used in the template.html
193 $short_lang_code = CRM_Core_I18n_PseudoConstant::shortForLong($tsLocale);
194 $text_direction = (CRM_Core_I18n::isLanguageRTL($tsLocale) ? 'rtl' : 'ltr');
195
196 global $cmsPath;
197 if ($installType == 'drupal') {
198 //CRM-6840 -don't force to install in sites/all/modules/
199 $object = new CRM_Utils_System_Drupal();
200 $cmsPath = $object->cmsRootPath();
201
202 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
203 $alreadyInstalled = file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
204 'sites' . CIVICRM_DIRECTORY_SEPARATOR .
205 $siteDir . CIVICRM_DIRECTORY_SEPARATOR .
206 'civicrm.settings.php'
207 );
208 }
209 elseif ($installType == 'wordpress') {
210 $cmsPath = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'civicrm';
211 $upload_dir = wp_upload_dir();
212 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm';
213 $wp_civi_settings = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm.settings.php';
214 $wp_civi_settings_deprectated = CIVICRM_PLUGIN_DIR . 'civicrm.settings.php';
215 if (file_exists($wp_civi_settings_deprectated)) {
216 $alreadyInstalled = $wp_civi_settings_deprectated;
217 }
218 elseif (file_exists($wp_civi_settings)) {
219 $alreadyInstalled = $wp_civi_settings;
220 }
221 }
222
223 if ($installType == 'drupal') {
224 // Lets check only /modules/.
225 $pattern = '/' . preg_quote(CIVICRM_DIRECTORY_SEPARATOR . 'modules', CIVICRM_DIRECTORY_SEPARATOR) . '/';
226
227 if (!preg_match($pattern, str_replace("\\", "/", $_SERVER['SCRIPT_FILENAME']))) {
228 $directory = implode(CIVICRM_DIRECTORY_SEPARATOR, array('sites', 'all', 'modules'));
229 $errorTitle = ts("Oops! Please correct your install location");
230 $errorMsg = ts("Please untar (uncompress) your downloaded copy of CiviCRM in the <strong>%1</strong> directory below your Drupal root directory.", array(1 => $directory));
231 errorDisplayPage($errorTitle, $errorMsg);
232 }
233 }
234
235 // Exit with error if CiviCRM has already been installed.
236 if ($alreadyInstalled) {
237 $errorTitle = ts("Oops! CiviCRM is already installed");
238 $settings_directory = $cmsPath;
239
240 if ($installType == 'drupal') {
241 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR, array(
242 ts('[your Drupal root directory]'),
243 'sites',
244 $siteDir,
245 ));
246 }
247
248 $docLink = CRM_Utils_System::docURL2('Installation and Upgrades', FALSE, ts('Installation Guide'), NULL, NULL, "wiki");
249 $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>, <a href='%2'>refer to the online documentation</a>.</li></ul>", array(1 => $settings_directory, 2 => $docLink));
250 errorDisplayPage($errorTitle, $errorMsg, FALSE);
251 }
252
253 $versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'civicrm-version.php';
254 if (file_exists($versionFile)) {
255 require_once $versionFile;
256 $civicrm_version = civicrmVersion();
257 }
258 else {
259 $civicrm_version = 'unknown';
260 }
261
262 if ($installType == 'drupal') {
263 // Ensure that they have downloaded the correct version of CiviCRM
264 if ($civicrm_version['cms'] != 'Drupal' && $civicrm_version['cms'] != 'Drupal6') {
265 $errorTitle = ts("Oops! Incorrect CiviCRM version");
266 $errorMsg = ts("This installer can only be used for the Drupal version of CiviCRM.");
267 errorDisplayPage($errorTitle, $errorMsg);
268 }
269
270 define('DRUPAL_ROOT', $cmsPath);
271 $drupalVersionFiles = array(
272 // D6
273 implode(CIVICRM_DIRECTORY_SEPARATOR, array($cmsPath, 'modules', 'system', 'system.module')),
274 // D7
275 implode(CIVICRM_DIRECTORY_SEPARATOR, array($cmsPath, 'includes', 'bootstrap.inc')),
276 );
277 foreach ($drupalVersionFiles as $drupalVersionFile) {
278 if (file_exists($drupalVersionFile)) {
279 require_once $drupalVersionFile;
280 }
281 }
282
283 if (!defined('VERSION') or version_compare(VERSION, '6.0') < 0) {
284 $errorTitle = ts("Oops! Incorrect Drupal version");
285 $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)));
286 errorDisplayPage($errorTitle, $errorMsg);
287 }
288 }
289 elseif ($installType == 'wordpress') {
290 //HACK for now
291 $civicrm_version['cms'] = 'WordPress';
292
293 // Ensure that they have downloaded the correct version of CiviCRM
294 if ($civicrm_version['cms'] != 'WordPress') {
295 $errorTitle = ts("Oops! Incorrect CiviCRM version");
296 $errorMsg = ts("This installer can only be used for the WordPress version of CiviCRM.");
297 errorDisplayPage($errorTitle, $errorMsg);
298 }
299 }
300
301 // Check requirements
302 $req = new InstallRequirements();
303 $req->check();
304
305 if ($req->hasErrors()) {
306 $hasErrorOtherThanDatabase = TRUE;
307 }
308
309 if ($databaseConfig) {
310 $dbReq = new InstallRequirements();
311 $dbReq->checkdatabase($databaseConfig, 'CiviCRM');
312 if ($installType == 'drupal') {
313 $dbReq->checkdatabase($drupalConfig, 'Drupal');
314 }
315 }
316
317 // Actual processor
318 if (isset($_POST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
319 // Confirm before reinstalling
320 if (!isset($_POST['force_reinstall']) && $alreadyInstalled) {
321 include $installDirPath . 'template.html';
322 }
323 else {
324 $inst = new Installer();
325 $inst->install($_POST);
326 }
327
328 // Show the config form
329 }
330 else {
331 include $installDirPath . 'template.html';
332 }
333
334 /**
335 * This class checks requirements
336 * Each of the requireXXX functions takes an argument which gives a user description of the test. It's an array
337 * of 3 parts:
338 * $description[0] - The test category
339 * $description[1] - The test title
340 * $description[2] - The test error to show, if it goes wrong
341 */
342 class InstallRequirements {
343 var $errors, $warnings, $tests;
344
345 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
346 const MINIMUM_THREAD_STACK = 192;
347
348 /**
349 * Just check that the database configuration is okay.
350 * @param $databaseConfig
351 * @param $dbName
352 */
353 public function checkdatabase($databaseConfig, $dbName) {
354 if ($this->requireFunction('mysql_connect',
355 array(
356 ts("PHP Configuration"),
357 ts("MySQL support"),
358 ts("MySQL support not included in PHP."),
359 )
360 )
361 ) {
362 $this->requireMySQLServer($databaseConfig['server'],
363 array(
364 ts("MySQL %1 Configuration", array(1 => $dbName)),
365 ts("Does the server exist?"),
366 ts("Can't find the a MySQL server on '%1'.", array(1 => $databaseConfig['server'])),
367 $databaseConfig['server'],
368 )
369 );
370 if ($this->requireMysqlConnection($databaseConfig['server'],
371 $databaseConfig['username'],
372 $databaseConfig['password'],
373 array(
374 ts("MySQL %1 Configuration", array(1 => $dbName)),
375 ts("Are the access credentials correct?"),
376 ts("That username/password doesn't work"),
377 )
378 )
379 ) {
380 @$this->requireMySQLVersion("5.1",
381 array(
382 ts("MySQL %1 Configuration", array(1 => $dbName)),
383 ts("MySQL version at least %1", array(1 => '5.1')),
384 ts("MySQL version %1 or higher is required, you are running MySQL %2.", array(1 => '5.1', 2 => mysql_get_server_info())),
385 ts("MySQL %1", array(1 => mysql_get_server_info())),
386 )
387 );
388 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
389 $databaseConfig['username'],
390 $databaseConfig['password'],
391 array(
392 ts("MySQL %1 Configuration", array(1 => $dbName)),
393 ts("Is auto_increment_increment set to 1"),
394 ts("An auto_increment_increment value greater than 1 is not currently supported. Please see issue CRM-7923 for further details and potential workaround."),
395 )
396 );
397 $testDetails = array(
398 ts("MySQL %1 Configuration", array(1 => $dbName)),
399 ts("Is the provided database name valid?"),
400 ts("The database name provided is not valid. Please use only 0-9, a-z, A-Z and _ as characters in the name."),
401 );
402 if (!CRM_Core_DAO::requireValidDBName($databaseConfig['database'])) {
403 $this->error($testDetails);
404 return FALSE;
405 }
406 else {
407 $this->testing($testDetails);
408 }
409 $this->requireMySQLThreadStack($databaseConfig['server'],
410 $databaseConfig['username'],
411 $databaseConfig['password'],
412 $databaseConfig['database'],
413 self::MINIMUM_THREAD_STACK,
414 array(
415 ts("MySQL %1 Configuration", array(1 => $dbName)),
416 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self::MINIMUM_THREAD_STACK)),
417 "",
418 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
419 )
420 );
421 }
422 $onlyRequire = ($dbName == 'Drupal') ? TRUE : FALSE;
423 $this->requireDatabaseOrCreatePermissions(
424 $databaseConfig['server'],
425 $databaseConfig['username'],
426 $databaseConfig['password'],
427 $databaseConfig['database'],
428 array(
429 ts("MySQL %1 Configuration", array(1 => $dbName)),
430 ts("Can I access/create the database?"),
431 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
432 ),
433 $onlyRequire
434 );
435 if ($dbName != 'Drupal') {
436 $this->requireMySQLInnoDB($databaseConfig['server'],
437 $databaseConfig['username'],
438 $databaseConfig['password'],
439 $databaseConfig['database'],
440 array(
441 ts("MySQL %1 Configuration", array(1 => $dbName)),
442 ts("Can I access/create InnoDB tables in the database?"),
443 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."),
444 )
445 );
446 $this->requireMySQLTempTables($databaseConfig['server'],
447 $databaseConfig['username'],
448 $databaseConfig['password'],
449 $databaseConfig['database'],
450 array(
451 ts("MySQL %1 Configuration", array(1 => $dbName)),
452 ts('Can I create temporary tables in the database?'),
453 ts('Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.'),
454 )
455 );
456 $this->requireMySQLLockTables($databaseConfig['server'],
457 $databaseConfig['username'],
458 $databaseConfig['password'],
459 $databaseConfig['database'],
460 array(
461 ts("MySQL %1 Configuration", array(1 => $dbName)),
462 ts('Can I create lock tables in the database?'),
463 ts('Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.'),
464 )
465 );
466 $this->requireMySQLTrigger($databaseConfig['server'],
467 $databaseConfig['username'],
468 $databaseConfig['password'],
469 $databaseConfig['database'],
470 array(
471 ts("MySQL %1 Configuration", array(1 => $dbName)),
472 ts('Can I create triggers in the database?'),
473 ts('Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.'),
474 )
475 );
476 }
477 }
478 }
479
480 /**
481 * Check everything except the database.
482 */
483 public function check() {
484 global $crmPath, $installType;
485
486 $this->errors = NULL;
487
488 $this->requirePHPVersion('5.3.4', array(
489 ts("PHP Configuration"),
490 ts("PHP5 installed"),
491 NULL,
492 ts("PHP version %1", array(1 => phpversion())),
493 ));
494
495 // Check that we can identify the root folder successfully
496 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'README.txt',
497 array(
498 ts("File permissions"),
499 ts("Does the webserver know where files are stored?"),
500 ts("The webserver isn't letting me identify where files are stored."),
501 $this->getBaseDir(),
502 ),
503 TRUE
504 );
505
506 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
507 $this->requireNoPathSeparator(
508 array(
509 ts("File permissions"),
510 ts('Does the CiviCRM path contain PATH_SEPARATOR?'),
511 ts('The path %1 contains PATH_SEPARATOR (the %2 character).', array(1 => $this->getBaseDir(), 2 => PATH_SEPARATOR)),
512 $this->getBaseDir(),
513 )
514 );
515
516 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
517 foreach ($requiredDirectories as $dir) {
518 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . $dir,
519 array(
520 ts("File permissions"),
521 ts("Folder '%1' exists?", array(1 => $dir)),
522 ts("There is no '%1' folder.", array(1 => $dir)),
523 ), TRUE
524 );
525 }
526
527 $configIDSiniDir = NULL;
528 global $cmsPath;
529 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
530 if ($installType == 'drupal') {
531
532 // make sure that we can write to sites/default and files/
533 $writableDirectories = array(
534 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
535 'sites' . CIVICRM_DIRECTORY_SEPARATOR .
536 $siteDir . CIVICRM_DIRECTORY_SEPARATOR .
537 'files',
538 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
539 'sites' . CIVICRM_DIRECTORY_SEPARATOR .
540 $siteDir,
541 );
542 }
543 elseif ($installType == 'wordpress') {
544 // make sure that we can write to uploads/civicrm/
545 $upload_dir = wp_upload_dir();
546 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm';
547 if (!file_exists($files_dirname)) {
548 wp_mkdir_p($files_dirname);
549 }
550 $writableDirectories = array($files_dirname);
551 }
552
553 foreach ($writableDirectories as $dir) {
554 $dirName = CIVICRM_WINDOWS ? $dir : CIVICRM_DIRECTORY_SEPARATOR . $dir;
555 $testDetails = array(
556 ts("File permissions"),
557 ts("Is the %1 folder writeable?", array(1 => $dir)),
558 NULL,
559 );
560 $this->requireWriteable($dirName, $testDetails, TRUE);
561 }
562
563 //check for Config.IDS.ini, file may exist in re-install
564 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
565
566 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
567 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR, $configIDSiniDir);
568 if (file_exists($configIDSiniFile)) {
569 unlink($configIDSiniFile);
570 }
571 }
572
573 // Check for rewriting
574 if (isset($_SERVER['SERVER_SOFTWARE'])) {
575 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
576 }
577 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
578 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
579 }
580
581 if ($webserver == '') {
582 $webserver = ts("I can't tell what webserver you are running");
583 }
584
585 // Check for $_SERVER configuration
586 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
587 ts("Webserver config"),
588 ts("Recognised webserver"),
589 ts("You seem to be using an unsupported webserver. The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."),
590 ));
591
592 // Check for MySQL support
593 $this->requireFunction('mysql_connect', array(
594 ts("PHP Configuration"),
595 ts("MySQL support"),
596 ts("MySQL support not included in PHP."),
597 ));
598
599 // Check for JSON support
600 $this->requireFunction('json_encode', array(
601 ts("PHP Configuration"),
602 ts("JSON support"),
603 ts("JSON support not included in PHP."),
604 ));
605
606 // Check for xcache_isset and emit warning if exists
607 $this->checkXCache(array(
608 ts("PHP Configuration"),
609 ts("XCache compatibility"),
610 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."),
611 ));
612
613 // Check memory allocation
614 $this->requireMemory(32 * 1024 * 1024,
615 64 * 1024 * 1024,
616 array(
617 ts("PHP Configuration"),
618 ts("Memory allocated (PHP config option 'memory_limit')"),
619 ts("CiviCRM needs a minimum of %1 MB allocated to PHP, but recommends %2 MB.", array(1 => 32, 2 => 64)),
620 ini_get("memory_limit"),
621 )
622 );
623
624 return $this->errors;
625 }
626
627 /**
628 * @param $min
629 * @param $recommended
630 * @param $testDetails
631 */
632 public function requireMemory($min, $recommended, $testDetails) {
633 $this->testing($testDetails);
634 $mem = $this->getPHPMemory();
635
636 if ($mem < $min && $mem > 0) {
637 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
638 $this->error($testDetails);
639 }
640 elseif ($mem < $recommended && $mem > 0) {
641 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
642 $this->warning($testDetails);
643 }
644 elseif ($mem == 0) {
645 $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));
646 $this->warning($testDetails);
647 }
648 }
649
650 /**
651 * @return float
652 */
653 public function getPHPMemory() {
654 $memString = ini_get("memory_limit");
655
656 switch (strtolower(substr($memString, -1))) {
657 case "k":
658 return round(substr($memString, 0, -1) * 1024);
659
660 case "m":
661 return round(substr($memString, 0, -1) * 1024 * 1024);
662
663 case "g":
664 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
665
666 default:
667 return round($memString);
668 }
669 }
670
671 public function listErrors() {
672 if ($this->errors) {
673 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
674 foreach ($this->errors as $error) {
675 echo "<li>" . htmlentities($error) . "</li>";
676 }
677 }
678 }
679
680 /**
681 * @param null $section
682 */
683 public function showTable($section = NULL) {
684 if ($section) {
685 $tests = $this->tests[$section];
686 echo "<table class=\"testResults\" width=\"100%\">";
687 foreach ($tests as $test => $result) {
688 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
689 }
690 echo "</table>";
691 }
692 else {
693 foreach ($this->tests as $section => $tests) {
694 echo "<h3>$section</h3>";
695 echo "<table class=\"testResults\" width=\"100%\">";
696
697 foreach ($tests as $test => $result) {
698 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
699 }
700 echo "</table>";
701 }
702 }
703 }
704
705 /**
706 * @param string $funcName
707 * @param $testDetails
708 *
709 * @return bool
710 */
711 public function requireFunction($funcName, $testDetails) {
712 $this->testing($testDetails);
713
714 if (!function_exists($funcName)) {
715 $this->error($testDetails);
716 return FALSE;
717 }
718 else {
719 return TRUE;
720 }
721 }
722
723 /**
724 * @param $testDetails
725 */
726 public function checkXCache($testDetails) {
727 if (function_exists('xcache_isset') &&
728 ini_get('xcache.size') > 0
729 ) {
730 $this->testing($testDetails);
731 $this->warning($testDetails);
732 }
733 }
734
735 /**
736 * @param $minVersion
737 * @param $testDetails
738 * @param null $maxVersion
739 */
740 public function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
741
742 $this->testing($testDetails);
743
744 $phpVersion = phpversion();
745 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
746 $belowMaxVersion = $maxVersion ? version_compare($phpVersion, $maxVersion) < 0 : TRUE;
747
748 if ($aboveMinVersion && $belowMaxVersion) {
749 if (version_compare(phpversion(), CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER) < 0) {
750 $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.', array(
751 1 => phpversion(),
752 2 => CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER,
753 ));
754 $this->warning($testDetails);
755 }
756 return TRUE;
757 }
758
759 if (!$testDetails[2]) {
760 if (!$aboveMinVersion) {
761 $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 => $minVersion, 2 => $phpVersion));
762 }
763 else {
764 $testDetails[2] = ts("PHP version %1 is not supported. PHP version earlier than %2 is required. You might want to downgrade your server, or ask your web-host to do so.", array(1 => $maxVersion, 2 => $phpVersion));
765 }
766 }
767
768 $this->error($testDetails);
769 }
770
771 /**
772 * @param string $filename
773 * @param $testDetails
774 * @param bool $absolute
775 */
776 public function requireFile($filename, $testDetails, $absolute = FALSE) {
777 $this->testing($testDetails);
778 if (!$absolute) {
779 $filename = $this->getBaseDir() . $filename;
780 }
781 if (!file_exists($filename)) {
782 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
783 $this->error($testDetails);
784 }
785 }
786
787 /**
788 * @param $testDetails
789 */
790 public function requireNoPathSeparator($testDetails) {
791 $this->testing($testDetails);
792 if (substr_count($this->getBaseDir(), PATH_SEPARATOR)) {
793 $this->error($testDetails);
794 }
795 }
796
797 /**
798 * @param string $filename
799 * @param $testDetails
800 */
801 public function requireNoFile($filename, $testDetails) {
802 $this->testing($testDetails);
803 $filename = $this->getBaseDir() . $filename;
804 if (file_exists($filename)) {
805 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
806 $this->error($testDetails);
807 }
808 }
809
810 /**
811 * @param string $filename
812 * @param $testDetails
813 */
814 public function moveFileOutOfTheWay($filename, $testDetails) {
815 $this->testing($testDetails);
816 $filename = $this->getBaseDir() . $filename;
817 if (file_exists($filename)) {
818 if (file_exists("$filename.bak")) {
819 rm("$filename.bak");
820 }
821 rename($filename, "$filename.bak");
822 }
823 }
824
825 /**
826 * @param string $filename
827 * @param $testDetails
828 * @param bool $absolute
829 */
830 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
831 $this->testing($testDetails);
832 if (!$absolute) {
833 $filename = $this->getBaseDir() . $filename;
834 }
835
836 if (!is_writable($filename)) {
837 $name = NULL;
838 if (function_exists('posix_getpwuid')) {
839 $user = posix_getpwuid(posix_geteuid());
840 $name = '- ' . $user['name'] . ' -';
841 }
842
843 if (!isset($testDetails[2])) {
844 $testDetails[2] = NULL;
845 }
846 $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";
847 $this->error($testDetails);
848 }
849 }
850
851 /**
852 * @param string $moduleName
853 * @param $testDetails
854 */
855 public function requireApacheModule($moduleName, $testDetails) {
856 $this->testing($testDetails);
857 if (!in_array($moduleName, apache_get_modules())) {
858 $this->error($testDetails);
859 }
860 }
861
862 /**
863 * @param $server
864 * @param string $username
865 * @param $password
866 * @param $testDetails
867 */
868 public function requireMysqlConnection($server, $username, $password, $testDetails) {
869 $this->testing($testDetails);
870 $conn = @mysql_connect($server, $username, $password);
871
872 if ($conn) {
873 return TRUE;
874 }
875 else {
876 $testDetails[2] .= ": " . mysql_error();
877 $this->error($testDetails);
878 }
879 }
880
881 /**
882 * @param $server
883 * @param $testDetails
884 */
885 public function requireMySQLServer($server, $testDetails) {
886 $this->testing($testDetails);
887 $conn = @mysql_connect($server, NULL, NULL);
888
889 if ($conn || mysql_errno() < 2000) {
890 return TRUE;
891 }
892 else {
893 $testDetails[2] .= ": " . mysql_error();
894 $this->error($testDetails);
895 }
896 }
897
898 /**
899 * @param $version
900 * @param $testDetails
901 */
902 public function requireMySQLVersion($version, $testDetails) {
903 $this->testing($testDetails);
904
905 if (!mysql_get_server_info()) {
906 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
907 $this->warning($testDetails);
908 }
909 else {
910 list($majorRequested, $minorRequested) = explode('.', $version);
911 list($majorHas, $minorHas) = explode('.', mysql_get_server_info());
912
913 if (($majorHas > $majorRequested) || ($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
914 return TRUE;
915 }
916 else {
917 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
918 $this->error($testDetails);
919 }
920 }
921 }
922
923 /**
924 * @param $server
925 * @param string $username
926 * @param $password
927 * @param $database
928 * @param $testDetails
929 */
930 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
931 $this->testing($testDetails);
932 $conn = @mysql_connect($server, $username, $password);
933 if (!$conn) {
934 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
935 $this->error($testDetails);
936 return;
937 }
938
939 $innodb_support = FALSE;
940 $result = mysql_query("SHOW ENGINES", $conn);
941 while ($values = mysql_fetch_array($result)) {
942 if ($values['Engine'] == 'InnoDB') {
943 if (strtolower($values['Support']) == 'yes' ||
944 strtolower($values['Support']) == 'default'
945 ) {
946 $innodb_support = TRUE;
947 }
948 }
949 }
950 if ($innodb_support) {
951 $testDetails[3] = ts('MySQL server does have InnoDB support');
952 }
953 else {
954 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
955 }
956 }
957
958 /**
959 * @param $server
960 * @param string $username
961 * @param $password
962 * @param $database
963 * @param $testDetails
964 */
965 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
966 $this->testing($testDetails);
967 $conn = @mysql_connect($server, $username, $password);
968 if (!$conn) {
969 $testDetails[2] = ts('Could not login to the database.');
970 $this->error($testDetails);
971 return;
972 }
973
974 if (!@mysql_select_db($database, $conn)) {
975 $testDetails[2] = ts('Could not select the database.');
976 $this->error($testDetails);
977 return;
978 }
979
980 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
981 if (!$result) {
982 $testDetails[2] = ts('Could not create a temp table.');
983 $this->error($testDetails);
984 }
985 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
986 }
987
988 /**
989 * @param $server
990 * @param string $username
991 * @param $password
992 * @param $database
993 * @param $testDetails
994 */
995 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
996 $this->testing($testDetails);
997 $conn = @mysql_connect($server, $username, $password);
998 if (!$conn) {
999 $testDetails[2] = ts('Could not login to the database.');
1000 $this->error($testDetails);
1001 return;
1002 }
1003
1004 if (!@mysql_select_db($database, $conn)) {
1005 $testDetails[2] = ts('Could not select the database.');
1006 $this->error($testDetails);
1007 return;
1008 }
1009
1010 $result = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
1011 if (!$result) {
1012 $testDetails[2] = ts('Could not create a table in the database.');
1013 $this->error($testDetails);
1014 }
1015
1016 $result = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
1017 if (!$result) {
1018 mysql_query('DROP TABLE civicrm_install_temp_table_test');
1019 $testDetails[2] = ts('Could not create a database trigger.');
1020 $this->error($testDetails);
1021 }
1022
1023 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
1024 mysql_query('DROP TABLE civicrm_install_temp_table_test');
1025 }
1026
1027
1028 /**
1029 * @param $server
1030 * @param string $username
1031 * @param $password
1032 * @param $database
1033 * @param $testDetails
1034 */
1035 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
1036 $this->testing($testDetails);
1037 $conn = @mysql_connect($server, $username, $password);
1038 if (!$conn) {
1039 $testDetails[2] = ts('Could not connect to the database server.');
1040 $this->error($testDetails);
1041 return;
1042 }
1043
1044 if (!@mysql_select_db($database, $conn)) {
1045 $testDetails[2] = ts('Could not select the database.');
1046 $this->error($testDetails);
1047 return;
1048 }
1049
1050 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
1051 if (!$result) {
1052 $testDetails[2] = ts('Could not create a table in the database.');
1053 $this->error($testDetails);
1054 return;
1055 }
1056
1057 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
1058 if (!$result) {
1059 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
1060 $this->error($testDetails);
1061 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1062 return;
1063 }
1064
1065 $result = mysql_query('UNLOCK TABLES', $conn);
1066 if (!$result) {
1067 $testDetails[2] = ts('Could not release the lock for the database table.');
1068 $this->error($testDetails);
1069 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1070 return;
1071 }
1072
1073 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1074 }
1075
1076 /**
1077 * @param $server
1078 * @param string $username
1079 * @param $password
1080 * @param $testDetails
1081 */
1082 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
1083 $this->testing($testDetails);
1084 $conn = @mysql_connect($server, $username, $password);
1085 if (!$conn) {
1086 $testDetails[2] = ts('Could not connect to the database server.');
1087 $this->error($testDetails);
1088 return;
1089 }
1090
1091 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
1092 if (!$result) {
1093 $testDetails[2] = ts('Could not query database server variables.');
1094 $this->error($testDetails);
1095 return;
1096 }
1097 else {
1098 $values = mysql_fetch_row($result);
1099 if ($values[1] == 1) {
1100 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
1101 }
1102 else {
1103 $this->error($testDetails);
1104 }
1105 }
1106 }
1107
1108 /**
1109 * @param $server
1110 * @param string $username
1111 * @param $password
1112 * @param $database
1113 * @param $minValueKB
1114 * @param $testDetails
1115 */
1116 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
1117 $this->testing($testDetails);
1118 $conn = @mysql_connect($server, $username, $password);
1119 if (!$conn) {
1120 $testDetails[2] = ts('Could not connect to the database server.');
1121 $this->error($testDetails);
1122 return;
1123 }
1124
1125 if (!@mysql_select_db($database, $conn)) {
1126 $testDetails[2] = ts('Could not select the database.');
1127 $this->error($testDetails);
1128 return;
1129 }
1130
1131 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
1132 if (!$result) {
1133 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
1134 $this->error($testDetails);
1135 }
1136 else {
1137 $values = mysql_fetch_row($result);
1138 if ($values[1] < (1024 * $minValueKB)) {
1139 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
1140 $this->error($testDetails);
1141 }
1142 }
1143 }
1144
1145 /**
1146 * @param $server
1147 * @param string $username
1148 * @param $password
1149 * @param $database
1150 * @param $testDetails
1151 * @param bool $onlyRequire
1152 */
1153 public function requireDatabaseOrCreatePermissions(
1154 $server,
1155 $username,
1156 $password,
1157 $database,
1158 $testDetails,
1159 $onlyRequire = FALSE
1160 ) {
1161 $this->testing($testDetails);
1162 $conn = @mysql_connect($server, $username, $password);
1163
1164 $okay = NULL;
1165 if (@mysql_select_db($database)) {
1166 $okay = "Database '$database' exists";
1167 }
1168 elseif ($onlyRequire) {
1169 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
1170 $this->error($testDetails);
1171 return;
1172 }
1173 else {
1174 $query = sprintf("CREATE DATABASE %s", mysql_real_escape_string($database));
1175 if (@mysql_query($query)) {
1176 $okay = ts("Able to create a new database.");
1177 }
1178 else {
1179 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
1180 $this->error($testDetails);
1181 return;
1182 }
1183 }
1184
1185 if ($okay) {
1186 $testDetails[3] = $okay;
1187 $this->testing($testDetails);
1188 }
1189 }
1190
1191 /**
1192 * @param $varNames
1193 * @param $errorMessage
1194 */
1195 public function requireServerVariables($varNames, $errorMessage) {
1196 //$this->testing($testDetails);
1197 foreach ($varNames as $varName) {
1198 if (!$_SERVER[$varName]) {
1199 $missing[] = '$_SERVER[' . $varName . ']';
1200 }
1201 }
1202 if (!isset($missing)) {
1203 return TRUE;
1204 }
1205 else {
1206 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
1207 $this->error($testDetails);
1208 }
1209 }
1210
1211 /**
1212 * @param $testDetails
1213 *
1214 * @return bool
1215 */
1216 public function isRunningApache($testDetails) {
1217 $this->testing($testDetails);
1218 if (function_exists('apache_get_modules') || stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1219 return TRUE;
1220 }
1221
1222 $this->warning($testDetails);
1223 return FALSE;
1224 }
1225
1226 /**
1227 * @return string
1228 */
1229 public function getBaseDir() {
1230 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR;
1231 }
1232
1233 /**
1234 * @param $testDetails
1235 */
1236 public function testing($testDetails) {
1237 if (!$testDetails) {
1238 return;
1239 }
1240
1241 $section = $testDetails[0];
1242 $test = $testDetails[1];
1243
1244 $message = ts("OK");
1245 if (isset($testDetails[3])) {
1246 $message .= " ($testDetails[3])";
1247 }
1248
1249 $this->tests[$section][$test] = array("good", $message);
1250 }
1251
1252 /**
1253 * @param $testDetails
1254 */
1255 public function error($testDetails) {
1256 $section = $testDetails[0];
1257 $test = $testDetails[1];
1258
1259 $this->tests[$section][$test] = array("error", $testDetails[2]);
1260 $this->errors[] = $testDetails;
1261 }
1262
1263 /**
1264 * @param $testDetails
1265 */
1266 public function warning($testDetails) {
1267 $section = $testDetails[0];
1268 $test = $testDetails[1];
1269
1270 $this->tests[$section][$test] = array("warning", $testDetails[2]);
1271 $this->warnings[] = $testDetails;
1272 }
1273
1274 /**
1275 * @return int
1276 */
1277 public function hasErrors() {
1278 return count($this->errors);
1279 }
1280
1281 /**
1282 * @return int
1283 */
1284 public function hasWarnings() {
1285 return count($this->warnings);
1286 }
1287
1288 }
1289
1290 /**
1291 * Class Installer
1292 */
1293 class Installer extends InstallRequirements {
1294 /**
1295 * @param $server
1296 * @param $username
1297 * @param $password
1298 * @param $database
1299 */
1300 public function createDatabaseIfNotExists($server, $username, $password, $database) {
1301 $conn = @mysql_connect($server, $username, $password);
1302
1303 if (@mysql_select_db($database)) {
1304 // skip if database already present
1305 return;
1306 }
1307 $query = sprintf("CREATE DATABASE %s", mysql_real_escape_string($database));
1308 if (@mysql_query($query)) {
1309 }
1310 else {
1311 $errorTitle = ts("Oops! Could not create database %1", array(1 => $database));
1312 $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.");
1313 errorDisplayPage($errorTitle, $errorMsg);
1314 }
1315 }
1316
1317 /**
1318 * @param $config
1319 *
1320 * @return mixed
1321 */
1322 public function install($config) {
1323 global $installDirPath;
1324
1325 // create database if does not exists
1326 $this->createDatabaseIfNotExists($config['mysql']['server'],
1327 $config['mysql']['username'],
1328 $config['mysql']['password'],
1329 $config['mysql']['database']
1330 );
1331
1332 global $installDirPath;
1333
1334 // Build database
1335 require_once $installDirPath . 'civicrm.php';
1336 civicrm_main($config);
1337
1338 if (!$this->errors) {
1339 global $installType, $installURLPath;
1340
1341 $registerSiteURL = "https://civicrm.org/register-site";
1342 $commonOutputMessage
1343 = "<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>"
1344 . "<li>" . ts("We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.") . "</li>";
1345
1346 $output = NULL;
1347
1348 if (
1349 $installType == 'drupal' &&
1350 version_compare(VERSION, '7.0-rc1') >= 0
1351 ) {
1352
1353 // clean output
1354 @ob_clean();
1355
1356 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1357 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1358 $output .= '<head>';
1359 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1360 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1361 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1362 $output .= '</head>';
1363 $output .= '<body>';
1364 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1365 $output .= '<ul>';
1366
1367 $drupalURL = civicrm_cms_base();
1368 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1369 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1370
1371 $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>";
1372 $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>";
1373 $output .= $commonOutputMessage;
1374
1375 // automatically enable CiviCRM module once it is installed successfully.
1376 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1377 global $cmsPath, $crmPath;
1378
1379 // relative / abosolute paths are not working for drupal, hence using chdir()
1380 chdir($cmsPath);
1381
1382 // Force the re-initialisation of the config singleton on the next call
1383 // since so far, we had used the Config object without loading the DB.
1384 $c = CRM_Core_Config::singleton(FALSE);
1385 $c->free();
1386
1387 include_once "./includes/bootstrap.inc";
1388 include_once "./includes/unicode.inc";
1389
1390 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1391
1392 // prevent session information from being saved.
1393 drupal_save_session(FALSE);
1394
1395 // Force the current user to anonymous.
1396 $original_user = $GLOBALS['user'];
1397 $GLOBALS['user'] = drupal_anonymous_user();
1398
1399 // explicitly setting error reporting, since we cannot handle drupal related notices
1400 error_reporting(1);
1401
1402 // rebuild modules, so that civicrm is added
1403 system_rebuild_module_data();
1404
1405 // now enable civicrm module.
1406 module_enable(array('civicrm', 'civicrmtheme'));
1407
1408 // clear block, page, theme, and hook caches
1409 drupal_flush_all_caches();
1410
1411 //add basic drupal permissions
1412 civicrm_install_set_drupal_perms();
1413
1414 // restore the user.
1415 $GLOBALS['user'] = $original_user;
1416 drupal_save_session(TRUE);
1417
1418 //change the default language to one chosen
1419 if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
1420 civicrm_api3('Setting', 'create', array(
1421 'domain_id' => 'current_domain',
1422 'lcMessages' => $config['seedLanguage'],
1423 )
1424 );
1425 }
1426
1427 $output .= '</ul>';
1428 $output .= '</div>';
1429 $output .= '</body>';
1430 $output .= '</html>';
1431 echo $output;
1432 }
1433 elseif ($installType == 'drupal' && version_compare(VERSION, '6.0') >= 0) {
1434 // clean output
1435 @ob_clean();
1436
1437 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1438 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1439 $output .= '<head>';
1440 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1441 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1442 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1443 $output .= '</head>';
1444 $output .= '<body>';
1445 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
1446 $output .= '<ul>';
1447
1448 $drupalURL = civicrm_cms_base();
1449 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1450 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1451
1452 $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>";
1453 $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>";
1454 $output .= $commonOutputMessage;
1455
1456 // explicitly setting error reporting, since we cannot handle drupal related notices
1457 error_reporting(1);
1458
1459 // automatically enable CiviCRM module once it is installed successfully.
1460 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1461 global $cmsPath, $crmPath;
1462
1463 // relative / abosolute paths are not working for drupal, hence using chdir()
1464 chdir($cmsPath);
1465
1466 // Force the re-initialisation of the config singleton on the next call
1467 // since so far, we had used the Config object without loading the DB.
1468 $c = CRM_Core_Config::singleton(FALSE);
1469 $c->free();
1470
1471 include_once "./includes/bootstrap.inc";
1472 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1473
1474 // rebuild modules, so that civicrm is added
1475 module_rebuild_cache();
1476
1477 // now enable civicrm module.
1478 module_enable(array('civicrm'));
1479
1480 // clear block, page, theme, and hook caches
1481 drupal_flush_all_caches();
1482
1483 //add basic drupal permissions
1484 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)');
1485
1486 echo $output;
1487 }
1488 elseif ($installType == 'wordpress') {
1489 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
1490 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
1491 echo '<ul>';
1492
1493 $cmsURL = civicrm_cms_base();
1494 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1495 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1496
1497 $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>";
1498 $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>";
1499 $output .= $commonOutputMessage;
1500
1501 echo '</ul>';
1502 echo '</div>';
1503
1504 $c = CRM_Core_Config::singleton(FALSE);
1505 $c->free();
1506 $wpInstallRedirect = admin_url("?page=CiviCRM&q=civicrm&reset=1");
1507 echo "<script>
1508 window.location = '$wpInstallRedirect';
1509 </script>";
1510 }
1511 }
1512
1513 return $this->errors;
1514 }
1515
1516 }
1517
1518 function civicrm_install_set_drupal_perms() {
1519 if (!function_exists('db_select')) {
1520 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)');
1521 }
1522 else {
1523 $perms = array(
1524 'access all custom data',
1525 'access uploaded files',
1526 'make online contributions',
1527 'profile create',
1528 'profile edit',
1529 'profile view',
1530 'register for events',
1531 'view event info',
1532 'view event participants',
1533 'access CiviMail subscribe/unsubscribe pages',
1534 );
1535
1536 // Adding a permission that has not yet been assigned to a module by
1537 // a hook_permission implementation results in a database error.
1538 // CRM-9042
1539 $allPerms = array_keys(module_invoke_all('permission'));
1540 foreach (array_diff($perms, $allPerms) as $perm) {
1541 watchdog('civicrm',
1542 'Cannot grant the %perm permission because it does not yet exist.',
1543 array('%perm' => $perm),
1544 WATCHDOG_ERROR
1545 );
1546 }
1547 $perms = array_intersect($perms, $allPerms);
1548 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, $perms);
1549 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, $perms);
1550 }
1551 }
1552
1553 /**
1554 * @param $cmsPath
1555 * @param $str
1556 *
1557 * @return string
1558 */
1559 function getSiteDir($cmsPath, $str) {
1560 static $siteDir = '';
1561
1562 if ($siteDir) {
1563 return $siteDir;
1564 }
1565
1566 $sites = CIVICRM_DIRECTORY_SEPARATOR . 'sites' . CIVICRM_DIRECTORY_SEPARATOR;
1567 $modules = CIVICRM_DIRECTORY_SEPARATOR . 'modules' . CIVICRM_DIRECTORY_SEPARATOR;
1568 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR) .
1569 "([\-a-zA-Z0-9_.]+)" .
1570 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR) . "/",
1571 $_SERVER['SCRIPT_FILENAME'], $matches
1572 );
1573 $siteDir = isset($matches[1]) ? $matches[1] : 'default';
1574
1575 if (strtolower($siteDir) == 'all') {
1576 // For this case - use drupal's way of finding out multi-site directory
1577 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR, $_SERVER['SCRIPT_FILENAME']);
1578 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1579 for ($i = count($uri) - 1; $i > 0; $i--) {
1580 for ($j = count($server); $j > 0; $j--) {
1581 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1582 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
1583 'sites' . CIVICRM_DIRECTORY_SEPARATOR . $dir
1584 )) {
1585 $siteDir = $dir;
1586 return $siteDir;
1587 }
1588 }
1589 }
1590 $siteDir = 'default';
1591 }
1592
1593 return $siteDir;
1594 }
1595
1596 /**
1597 * @param $errorTitle
1598 * @param $errorMsg
1599 * @param $showRefer
1600 */
1601 function errorDisplayPage($errorTitle, $errorMsg, $showRefer = TRUE) {
1602 if ($showRefer) {
1603 $docLink = CRM_Utils_System::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
1604
1605 if (function_exists('ts')) {
1606 $errorMsg .= '<p>' . ts("<a %1>Refer to the online documentation for more information</a>", array(1 => "href='$docLink'")) . '</p>';
1607 }
1608 else {
1609 $errorMsg .= '<p>' . sprintf("<a %s>Refer to the online documentation for more information</a>", "href='$docLink'") . '</p>';
1610 }
1611 }
1612
1613 include 'error.html';
1614 exit();
1615 }