d0f7f0bada79cb08e275c22fdcf42b56affb7edf
[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 $this->requireMySQLThreadStack($databaseConfig['server'],
398 $databaseConfig['username'],
399 $databaseConfig['password'],
400 $databaseConfig['database'],
401 self::MINIMUM_THREAD_STACK,
402 array(
403 ts("MySQL %1 Configuration", array(1 => $dbName)),
404 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self::MINIMUM_THREAD_STACK)),
405 "",
406 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
407 )
408 );
409 }
410 $onlyRequire = ($dbName == 'Drupal') ? TRUE : FALSE;
411 $this->requireDatabaseOrCreatePermissions(
412 $databaseConfig['server'],
413 $databaseConfig['username'],
414 $databaseConfig['password'],
415 $databaseConfig['database'],
416 array(
417 ts("MySQL %1 Configuration", array(1 => $dbName)),
418 ts("Can I access/create the database?"),
419 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
420 ),
421 $onlyRequire
422 );
423 if ($dbName != 'Drupal') {
424 $this->requireMySQLInnoDB($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 InnoDB tables in the database?"),
431 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."),
432 )
433 );
434 $this->requireMySQLTempTables($databaseConfig['server'],
435 $databaseConfig['username'],
436 $databaseConfig['password'],
437 $databaseConfig['database'],
438 array(
439 ts("MySQL %1 Configuration", array(1 => $dbName)),
440 ts('Can I create temporary tables in the database?'),
441 ts('Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.'),
442 )
443 );
444 $this->requireMySQLLockTables($databaseConfig['server'],
445 $databaseConfig['username'],
446 $databaseConfig['password'],
447 $databaseConfig['database'],
448 array(
449 ts("MySQL %1 Configuration", array(1 => $dbName)),
450 ts('Can I create lock tables in the database?'),
451 ts('Unable to lock tables. This MySQL user is missing the LOCK TABLES privilege.'),
452 )
453 );
454 $this->requireMySQLTrigger($databaseConfig['server'],
455 $databaseConfig['username'],
456 $databaseConfig['password'],
457 $databaseConfig['database'],
458 array(
459 ts("MySQL %1 Configuration", array(1 => $dbName)),
460 ts('Can I create triggers in the database?'),
461 ts('Unable to create triggers. This MySQL user is missing the CREATE TRIGGERS privilege.'),
462 )
463 );
464 }
465 }
466 }
467
468 /**
469 * Check everything except the database.
470 */
471 public function check() {
472 global $crmPath, $installType;
473
474 $this->errors = NULL;
475
476 $this->requirePHPVersion('5.3.4', array(
477 ts("PHP Configuration"),
478 ts("PHP5 installed"),
479 NULL,
480 ts("PHP version %1", array(1 => phpversion())),
481 ));
482
483 // Check that we can identify the root folder successfully
484 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'README.txt',
485 array(
486 ts("File permissions"),
487 ts("Does the webserver know where files are stored?"),
488 ts("The webserver isn't letting me identify where files are stored."),
489 $this->getBaseDir(),
490 ),
491 TRUE
492 );
493
494 // CRM-6485: make sure the path does not contain PATH_SEPARATOR, as we don’t know how to escape it
495 $this->requireNoPathSeparator(
496 array(
497 ts("File permissions"),
498 ts('Does the CiviCRM path contain PATH_SEPARATOR?'),
499 ts('The path %1 contains PATH_SEPARATOR (the %2 character).', array(1 => $this->getBaseDir(), 2 => PATH_SEPARATOR)),
500 $this->getBaseDir(),
501 )
502 );
503
504 $requiredDirectories = array('CRM', 'packages', 'templates', 'js', 'api', 'i', 'sql');
505 foreach ($requiredDirectories as $dir) {
506 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . $dir,
507 array(
508 ts("File permissions"),
509 ts("Folder '%1' exists?", array(1 => $dir)),
510 ts("There is no '%1' folder.", array(1 => $dir)),
511 ), TRUE
512 );
513 }
514
515 $configIDSiniDir = NULL;
516 global $cmsPath;
517 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
518 if ($installType == 'drupal') {
519
520 // make sure that we can write to sites/default and files/
521 $writableDirectories = array(
522 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
523 'sites' . CIVICRM_DIRECTORY_SEPARATOR .
524 $siteDir . CIVICRM_DIRECTORY_SEPARATOR .
525 'files',
526 $cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
527 'sites' . CIVICRM_DIRECTORY_SEPARATOR .
528 $siteDir,
529 );
530 }
531 elseif ($installType == 'wordpress') {
532 // make sure that we can write to uploads/civicrm/
533 $upload_dir = wp_upload_dir();
534 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm';
535 if (!file_exists($files_dirname)) {
536 wp_mkdir_p($files_dirname);
537 }
538 $writableDirectories = array($files_dirname);
539 }
540
541 foreach ($writableDirectories as $dir) {
542 $dirName = CIVICRM_WINDOWS ? $dir : CIVICRM_DIRECTORY_SEPARATOR . $dir;
543 $testDetails = array(
544 ts("File permissions"),
545 ts("Is the %1 folder writeable?", array(1 => $dir)),
546 NULL,
547 );
548 $this->requireWriteable($dirName, $testDetails, TRUE);
549 }
550
551 //check for Config.IDS.ini, file may exist in re-install
552 $configIDSiniDir = array($cmsPath, 'sites', $siteDir, 'files', 'civicrm', 'upload', 'Config.IDS.ini');
553
554 if (is_array($configIDSiniDir) && !empty($configIDSiniDir)) {
555 $configIDSiniFile = implode(CIVICRM_DIRECTORY_SEPARATOR, $configIDSiniDir);
556 if (file_exists($configIDSiniFile)) {
557 unlink($configIDSiniFile);
558 }
559 }
560
561 // Check for rewriting
562 if (isset($_SERVER['SERVER_SOFTWARE'])) {
563 $webserver = strip_tags(trim($_SERVER['SERVER_SOFTWARE']));
564 }
565 elseif (isset($_SERVER['SERVER_SIGNATURE'])) {
566 $webserver = strip_tags(trim($_SERVER['SERVER_SIGNATURE']));
567 }
568
569 if ($webserver == '') {
570 $webserver = ts("I can't tell what webserver you are running");
571 }
572
573 // Check for $_SERVER configuration
574 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
575 ts("Webserver config"),
576 ts("Recognised webserver"),
577 ts("You seem to be using an unsupported webserver. The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."),
578 ));
579
580 // Check for MySQL support
581 $this->requireFunction('mysql_connect', array(
582 ts("PHP Configuration"),
583 ts("MySQL support"),
584 ts("MySQL support not included in PHP."),
585 ));
586
587 // Check for JSON support
588 $this->requireFunction('json_encode', array(
589 ts("PHP Configuration"),
590 ts("JSON support"),
591 ts("JSON support not included in PHP."),
592 ));
593
594 // Check for xcache_isset and emit warning if exists
595 $this->checkXCache(array(
596 ts("PHP Configuration"),
597 ts("XCache compatibility"),
598 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."),
599 ));
600
601 // Check memory allocation
602 $this->requireMemory(32 * 1024 * 1024,
603 64 * 1024 * 1024,
604 array(
605 ts("PHP Configuration"),
606 ts("Memory allocated (PHP config option 'memory_limit')"),
607 ts("CiviCRM needs a minimum of %1 MB allocated to PHP, but recommends %2 MB.", array(1 => 32, 2 => 64)),
608 ini_get("memory_limit"),
609 )
610 );
611
612 return $this->errors;
613 }
614
615 /**
616 * @param $min
617 * @param $recommended
618 * @param $testDetails
619 */
620 public function requireMemory($min, $recommended, $testDetails) {
621 $this->testing($testDetails);
622 $mem = $this->getPHPMemory();
623
624 if ($mem < $min && $mem > 0) {
625 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
626 $this->error($testDetails);
627 }
628 elseif ($mem < $recommended && $mem > 0) {
629 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
630 $this->warning($testDetails);
631 }
632 elseif ($mem == 0) {
633 $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));
634 $this->warning($testDetails);
635 }
636 }
637
638 /**
639 * @return float
640 */
641 public function getPHPMemory() {
642 $memString = ini_get("memory_limit");
643
644 switch (strtolower(substr($memString, -1))) {
645 case "k":
646 return round(substr($memString, 0, -1) * 1024);
647
648 case "m":
649 return round(substr($memString, 0, -1) * 1024 * 1024);
650
651 case "g":
652 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
653
654 default:
655 return round($memString);
656 }
657 }
658
659 public function listErrors() {
660 if ($this->errors) {
661 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
662 foreach ($this->errors as $error) {
663 echo "<li>" . htmlentities($error) . "</li>";
664 }
665 }
666 }
667
668 /**
669 * @param null $section
670 */
671 public function showTable($section = NULL) {
672 if ($section) {
673 $tests = $this->tests[$section];
674 echo "<table class=\"testResults\" width=\"100%\">";
675 foreach ($tests as $test => $result) {
676 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
677 }
678 echo "</table>";
679 }
680 else {
681 foreach ($this->tests as $section => $tests) {
682 echo "<h3>$section</h3>";
683 echo "<table class=\"testResults\" width=\"100%\">";
684
685 foreach ($tests as $test => $result) {
686 echo "<tr class=\"$result[0]\"><td>$test</td><td>" . nl2br(htmlentities($result[1])) . "</td></tr>";
687 }
688 echo "</table>";
689 }
690 }
691 }
692
693 /**
694 * @param string $funcName
695 * @param $testDetails
696 *
697 * @return bool
698 */
699 public function requireFunction($funcName, $testDetails) {
700 $this->testing($testDetails);
701
702 if (!function_exists($funcName)) {
703 $this->error($testDetails);
704 return FALSE;
705 }
706 else {
707 return TRUE;
708 }
709 }
710
711 /**
712 * @param $testDetails
713 */
714 public function checkXCache($testDetails) {
715 if (function_exists('xcache_isset') &&
716 ini_get('xcache.size') > 0
717 ) {
718 $this->testing($testDetails);
719 $this->warning($testDetails);
720 }
721 }
722
723 /**
724 * @param $minVersion
725 * @param $testDetails
726 * @param null $maxVersion
727 */
728 public function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
729
730 $this->testing($testDetails);
731
732 $phpVersion = phpversion();
733 $aboveMinVersion = version_compare($phpVersion, $minVersion) >= 0;
734 $belowMaxVersion = $maxVersion ? version_compare($phpVersion, $maxVersion) < 0 : TRUE;
735
736 if ($maxVersion && $aboveMinVersion && $belowMaxVersion) {
737 return TRUE;
738 }
739 elseif (!$maxVersion && $aboveMinVersion) {
740 return TRUE;
741 }
742
743 if (!$testDetails[2]) {
744 if (!$aboveMinVersion) {
745 $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));
746 }
747 else {
748 $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));
749 }
750 }
751
752 $this->error($testDetails);
753 }
754
755 /**
756 * @param string $filename
757 * @param $testDetails
758 * @param bool $absolute
759 */
760 public function requireFile($filename, $testDetails, $absolute = FALSE) {
761 $this->testing($testDetails);
762 if (!$absolute) {
763 $filename = $this->getBaseDir() . $filename;
764 }
765 if (!file_exists($filename)) {
766 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
767 $this->error($testDetails);
768 }
769 }
770
771 /**
772 * @param $testDetails
773 */
774 public function requireNoPathSeparator($testDetails) {
775 $this->testing($testDetails);
776 if (substr_count($this->getBaseDir(), PATH_SEPARATOR)) {
777 $this->error($testDetails);
778 }
779 }
780
781 /**
782 * @param string $filename
783 * @param $testDetails
784 */
785 public function requireNoFile($filename, $testDetails) {
786 $this->testing($testDetails);
787 $filename = $this->getBaseDir() . $filename;
788 if (file_exists($filename)) {
789 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
790 $this->error($testDetails);
791 }
792 }
793
794 /**
795 * @param string $filename
796 * @param $testDetails
797 */
798 public function moveFileOutOfTheWay($filename, $testDetails) {
799 $this->testing($testDetails);
800 $filename = $this->getBaseDir() . $filename;
801 if (file_exists($filename)) {
802 if (file_exists("$filename.bak")) {
803 rm("$filename.bak");
804 }
805 rename($filename, "$filename.bak");
806 }
807 }
808
809 /**
810 * @param string $filename
811 * @param $testDetails
812 * @param bool $absolute
813 */
814 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
815 $this->testing($testDetails);
816 if (!$absolute) {
817 $filename = $this->getBaseDir() . $filename;
818 }
819
820 if (!is_writable($filename)) {
821 $name = NULL;
822 if (function_exists('posix_getpwuid')) {
823 $user = posix_getpwuid(posix_geteuid());
824 $name = '- ' . $user['name'] . ' -';
825 }
826
827 if (!isset($testDetails[2])) {
828 $testDetails[2] = NULL;
829 }
830 $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";
831 $this->error($testDetails);
832 }
833 }
834
835 /**
836 * @param string $moduleName
837 * @param $testDetails
838 */
839 public function requireApacheModule($moduleName, $testDetails) {
840 $this->testing($testDetails);
841 if (!in_array($moduleName, apache_get_modules())) {
842 $this->error($testDetails);
843 }
844 }
845
846 /**
847 * @param $server
848 * @param string $username
849 * @param $password
850 * @param $testDetails
851 */
852 public function requireMysqlConnection($server, $username, $password, $testDetails) {
853 $this->testing($testDetails);
854 $conn = @mysql_connect($server, $username, $password);
855
856 if ($conn) {
857 return TRUE;
858 }
859 else {
860 $testDetails[2] .= ": " . mysql_error();
861 $this->error($testDetails);
862 }
863 }
864
865 /**
866 * @param $server
867 * @param $testDetails
868 */
869 public function requireMySQLServer($server, $testDetails) {
870 $this->testing($testDetails);
871 $conn = @mysql_connect($server, NULL, NULL);
872
873 if ($conn || mysql_errno() < 2000) {
874 return TRUE;
875 }
876 else {
877 $testDetails[2] .= ": " . mysql_error();
878 $this->error($testDetails);
879 }
880 }
881
882 /**
883 * @param $version
884 * @param $testDetails
885 */
886 public function requireMySQLVersion($version, $testDetails) {
887 $this->testing($testDetails);
888
889 if (!mysql_get_server_info()) {
890 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
891 $this->warning($testDetails);
892 }
893 else {
894 list($majorRequested, $minorRequested) = explode('.', $version);
895 list($majorHas, $minorHas) = explode('.', mysql_get_server_info());
896
897 if (($majorHas > $majorRequested) || ($majorHas == $majorRequested && $minorHas >= $minorRequested)) {
898 return TRUE;
899 }
900 else {
901 $testDetails[2] .= "{$majorHas}.{$minorHas}.";
902 $this->error($testDetails);
903 }
904 }
905 }
906
907 /**
908 * @param $server
909 * @param string $username
910 * @param $password
911 * @param $database
912 * @param $testDetails
913 */
914 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
915 $this->testing($testDetails);
916 $conn = @mysql_connect($server, $username, $password);
917 if (!$conn) {
918 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
919 $this->error($testDetails);
920 return;
921 }
922
923 $innodb_support = FALSE;
924 $result = mysql_query("SHOW ENGINES", $conn);
925 while ($values = mysql_fetch_array($result)) {
926 if ($values['Engine'] == 'InnoDB') {
927 if (strtolower($values['Support']) == 'yes' ||
928 strtolower($values['Support']) == 'default'
929 ) {
930 $innodb_support = TRUE;
931 }
932 }
933 }
934 if ($innodb_support) {
935 $testDetails[3] = ts('MySQL server does have InnoDB support');
936 }
937 else {
938 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
939 }
940 }
941
942 /**
943 * @param $server
944 * @param string $username
945 * @param $password
946 * @param $database
947 * @param $testDetails
948 */
949 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
950 $this->testing($testDetails);
951 $conn = @mysql_connect($server, $username, $password);
952 if (!$conn) {
953 $testDetails[2] = ts('Could not login to the database.');
954 $this->error($testDetails);
955 return;
956 }
957
958 if (!@mysql_select_db($database, $conn)) {
959 $testDetails[2] = ts('Could not select the database.');
960 $this->error($testDetails);
961 return;
962 }
963
964 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
965 if (!$result) {
966 $testDetails[2] = ts('Could not create a temp table.');
967 $this->error($testDetails);
968 }
969 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
970 }
971
972 /**
973 * @param $server
974 * @param string $username
975 * @param $password
976 * @param $database
977 * @param $testDetails
978 */
979 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
980 $this->testing($testDetails);
981 $conn = @mysql_connect($server, $username, $password);
982 if (!$conn) {
983 $testDetails[2] = ts('Could not login to the database.');
984 $this->error($testDetails);
985 return;
986 }
987
988 if (!@mysql_select_db($database, $conn)) {
989 $testDetails[2] = ts('Could not select the database.');
990 $this->error($testDetails);
991 return;
992 }
993
994 $result = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
995 if (!$result) {
996 $testDetails[2] = ts('Could not create a table in the database.');
997 $this->error($testDetails);
998 }
999
1000 $result = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
1001 if (!$result) {
1002 mysql_query('DROP TABLE civicrm_install_temp_table_test');
1003 $testDetails[2] = ts('Could not create a database trigger.');
1004 $this->error($testDetails);
1005 }
1006
1007 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
1008 mysql_query('DROP TABLE civicrm_install_temp_table_test');
1009 }
1010
1011
1012 /**
1013 * @param $server
1014 * @param string $username
1015 * @param $password
1016 * @param $database
1017 * @param $testDetails
1018 */
1019 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
1020 $this->testing($testDetails);
1021 $conn = @mysql_connect($server, $username, $password);
1022 if (!$conn) {
1023 $testDetails[2] = ts('Could not connect to the database server.');
1024 $this->error($testDetails);
1025 return;
1026 }
1027
1028 if (!@mysql_select_db($database, $conn)) {
1029 $testDetails[2] = ts('Could not select the database.');
1030 $this->error($testDetails);
1031 return;
1032 }
1033
1034 $result = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
1035 if (!$result) {
1036 $testDetails[2] = ts('Could not create a table in the database.');
1037 $this->error($testDetails);
1038 return;
1039 }
1040
1041 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
1042 if (!$result) {
1043 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
1044 $this->error($testDetails);
1045 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1046 return;
1047 }
1048
1049 $result = mysql_query('UNLOCK TABLES', $conn);
1050 if (!$result) {
1051 $testDetails[2] = ts('Could not release the lock for the database table.');
1052 $this->error($testDetails);
1053 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1054 return;
1055 }
1056
1057 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
1058 }
1059
1060 /**
1061 * @param $server
1062 * @param string $username
1063 * @param $password
1064 * @param $testDetails
1065 */
1066 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
1067 $this->testing($testDetails);
1068 $conn = @mysql_connect($server, $username, $password);
1069 if (!$conn) {
1070 $testDetails[2] = ts('Could not connect to the database server.');
1071 $this->error($testDetails);
1072 return;
1073 }
1074
1075 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
1076 if (!$result) {
1077 $testDetails[2] = ts('Could not query database server variables.');
1078 $this->error($testDetails);
1079 return;
1080 }
1081 else {
1082 $values = mysql_fetch_row($result);
1083 if ($values[1] == 1) {
1084 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
1085 }
1086 else {
1087 $this->error($testDetails);
1088 }
1089 }
1090 }
1091
1092 /**
1093 * @param $server
1094 * @param string $username
1095 * @param $password
1096 * @param $database
1097 * @param $minValueKB
1098 * @param $testDetails
1099 */
1100 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
1101 $this->testing($testDetails);
1102 $conn = @mysql_connect($server, $username, $password);
1103 if (!$conn) {
1104 $testDetails[2] = ts('Could not connect to the database server.');
1105 $this->error($testDetails);
1106 return;
1107 }
1108
1109 if (!@mysql_select_db($database, $conn)) {
1110 $testDetails[2] = ts('Could not select the database.');
1111 $this->error($testDetails);
1112 return;
1113 }
1114
1115 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
1116 if (!$result) {
1117 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
1118 $this->error($testDetails);
1119 }
1120 else {
1121 $values = mysql_fetch_row($result);
1122 if ($values[1] < (1024 * $minValueKB)) {
1123 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
1124 $this->error($testDetails);
1125 }
1126 }
1127 }
1128
1129 /**
1130 * @param $server
1131 * @param string $username
1132 * @param $password
1133 * @param $database
1134 * @param $testDetails
1135 * @param bool $onlyRequire
1136 */
1137 public function requireDatabaseOrCreatePermissions(
1138 $server,
1139 $username,
1140 $password,
1141 $database,
1142 $testDetails,
1143 $onlyRequire = FALSE
1144 ) {
1145 $this->testing($testDetails);
1146 $conn = @mysql_connect($server, $username, $password);
1147
1148 $okay = NULL;
1149 if (@mysql_select_db($database)) {
1150 $okay = "Database '$database' exists";
1151 }
1152 elseif ($onlyRequire) {
1153 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
1154 $this->error($testDetails);
1155 return;
1156 }
1157 else {
1158 if (@mysql_query("CREATE DATABASE $database")) {
1159 $okay = ts("Able to create a new database.");
1160 }
1161 else {
1162 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
1163 $this->error($testDetails);
1164 return;
1165 }
1166 }
1167
1168 if ($okay) {
1169 $testDetails[3] = $okay;
1170 $this->testing($testDetails);
1171 }
1172 }
1173
1174 /**
1175 * @param $varNames
1176 * @param $errorMessage
1177 */
1178 public function requireServerVariables($varNames, $errorMessage) {
1179 //$this->testing($testDetails);
1180 foreach ($varNames as $varName) {
1181 if (!$_SERVER[$varName]) {
1182 $missing[] = '$_SERVER[' . $varName . ']';
1183 }
1184 }
1185 if (!isset($missing)) {
1186 return TRUE;
1187 }
1188 else {
1189 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
1190 $this->error($testDetails);
1191 }
1192 }
1193
1194 /**
1195 * @param $testDetails
1196 *
1197 * @return bool
1198 */
1199 public function isRunningApache($testDetails) {
1200 $this->testing($testDetails);
1201 if (function_exists('apache_get_modules') || stristr($_SERVER['SERVER_SIGNATURE'], 'Apache')) {
1202 return TRUE;
1203 }
1204
1205 $this->warning($testDetails);
1206 return FALSE;
1207 }
1208
1209 /**
1210 * @return string
1211 */
1212 public function getBaseDir() {
1213 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR;
1214 }
1215
1216 /**
1217 * @param $testDetails
1218 */
1219 public function testing($testDetails) {
1220 if (!$testDetails) {
1221 return;
1222 }
1223
1224 $section = $testDetails[0];
1225 $test = $testDetails[1];
1226
1227 $message = ts("OK");
1228 if (isset($testDetails[3])) {
1229 $message .= " ($testDetails[3])";
1230 }
1231
1232 $this->tests[$section][$test] = array("good", $message);
1233 }
1234
1235 /**
1236 * @param $testDetails
1237 */
1238 public function error($testDetails) {
1239 $section = $testDetails[0];
1240 $test = $testDetails[1];
1241
1242 $this->tests[$section][$test] = array("error", $testDetails[2]);
1243 $this->errors[] = $testDetails;
1244 }
1245
1246 /**
1247 * @param $testDetails
1248 */
1249 public function warning($testDetails) {
1250 $section = $testDetails[0];
1251 $test = $testDetails[1];
1252
1253 $this->tests[$section][$test] = array("warning", $testDetails[2]);
1254 $this->warnings[] = $testDetails;
1255 }
1256
1257 /**
1258 * @return int
1259 */
1260 public function hasErrors() {
1261 return count($this->errors);
1262 }
1263
1264 /**
1265 * @return int
1266 */
1267 public function hasWarnings() {
1268 return count($this->warnings);
1269 }
1270
1271 }
1272
1273 /**
1274 * Class Installer
1275 */
1276 class Installer extends InstallRequirements {
1277 /**
1278 * @param $server
1279 * @param $username
1280 * @param $password
1281 * @param $database
1282 */
1283 public function createDatabaseIfNotExists($server, $username, $password, $database) {
1284 $conn = @mysql_connect($server, $username, $password);
1285
1286 if (@mysql_select_db($database)) {
1287 // skip if database already present
1288 return;
1289 }
1290
1291 if (@mysql_query("CREATE DATABASE $database")) {
1292 }
1293 else {
1294 $errorTitle = ts("Oops! Could not create database %1", array(1 => $database));
1295 $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.");
1296 errorDisplayPage($errorTitle, $errorMsg);
1297 }
1298 }
1299
1300 /**
1301 * @param $config
1302 *
1303 * @return mixed
1304 */
1305 public function install($config) {
1306 global $installDirPath;
1307
1308 // create database if does not exists
1309 $this->createDatabaseIfNotExists($config['mysql']['server'],
1310 $config['mysql']['username'],
1311 $config['mysql']['password'],
1312 $config['mysql']['database']
1313 );
1314
1315 global $installDirPath;
1316
1317 // Build database
1318 require_once $installDirPath . 'civicrm.php';
1319 civicrm_main($config);
1320
1321 if (!$this->errors) {
1322 global $installType, $installURLPath;
1323
1324 $registerSiteURL = "https://civicrm.org/register-site";
1325 $commonOutputMessage
1326 = "<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>"
1327 . "<li>" . ts("We have integrated KCFinder with CKEditor and TinyMCE. This allows a user to upload images. All uploaded images are public.") . "</li>";
1328
1329 $output = NULL;
1330
1331 if (
1332 $installType == 'drupal' &&
1333 version_compare(VERSION, '7.0-rc1') >= 0
1334 ) {
1335
1336 // clean output
1337 @ob_clean();
1338
1339 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1340 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1341 $output .= '<head>';
1342 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1343 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1344 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1345 $output .= '</head>';
1346 $output .= '<body>';
1347 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
1348 $output .= '<ul>';
1349
1350 $drupalURL = civicrm_cms_base();
1351 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1352 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1353
1354 $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>";
1355 $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>";
1356 $output .= $commonOutputMessage;
1357
1358 // automatically enable CiviCRM module once it is installed successfully.
1359 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1360 global $cmsPath, $crmPath;
1361
1362 // relative / abosolute paths are not working for drupal, hence using chdir()
1363 chdir($cmsPath);
1364
1365 // Force the re-initialisation of the config singleton on the next call
1366 // since so far, we had used the Config object without loading the DB.
1367 $c = CRM_Core_Config::singleton(FALSE);
1368 $c->free();
1369
1370 include_once "./includes/bootstrap.inc";
1371 include_once "./includes/unicode.inc";
1372
1373 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1374
1375 // prevent session information from being saved.
1376 drupal_save_session(FALSE);
1377
1378 // Force the current user to anonymous.
1379 $original_user = $GLOBALS['user'];
1380 $GLOBALS['user'] = drupal_anonymous_user();
1381
1382 // explicitly setting error reporting, since we cannot handle drupal related notices
1383 error_reporting(1);
1384
1385 // rebuild modules, so that civicrm is added
1386 system_rebuild_module_data();
1387
1388 // now enable civicrm module.
1389 module_enable(array('civicrm', 'civicrmtheme'));
1390
1391 // clear block, page, theme, and hook caches
1392 drupal_flush_all_caches();
1393
1394 //add basic drupal permissions
1395 civicrm_install_set_drupal_perms();
1396
1397 // restore the user.
1398 $GLOBALS['user'] = $original_user;
1399 drupal_save_session(TRUE);
1400
1401 //change the default language to one chosen
1402 if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
1403 civicrm_api3('Setting', 'create', array(
1404 'domain_id' => 'current_domain',
1405 'lcMessages' => $config['seedLanguage'],
1406 )
1407 );
1408 }
1409
1410 $output .= '</ul>';
1411 $output .= '</div>';
1412 $output .= '</body>';
1413 $output .= '</html>';
1414 echo $output;
1415 }
1416 elseif ($installType == 'drupal' && version_compare(VERSION, '6.0') >= 0) {
1417 // clean output
1418 @ob_clean();
1419
1420 $output .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
1421 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1422 $output .= '<head>';
1423 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1424 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
1425 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1426 $output .= '</head>';
1427 $output .= '<body>';
1428 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
1429 $output .= '<ul>';
1430
1431 $drupalURL = civicrm_cms_base();
1432 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1433 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
1434
1435 $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>";
1436 $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>";
1437 $output .= $commonOutputMessage;
1438
1439 // explicitly setting error reporting, since we cannot handle drupal related notices
1440 error_reporting(1);
1441
1442 // automatically enable CiviCRM module once it is installed successfully.
1443 // so we need to Bootstrap Drupal, so that we can call drupal hooks.
1444 global $cmsPath, $crmPath;
1445
1446 // relative / abosolute paths are not working for drupal, hence using chdir()
1447 chdir($cmsPath);
1448
1449 // Force the re-initialisation of the config singleton on the next call
1450 // since so far, we had used the Config object without loading the DB.
1451 $c = CRM_Core_Config::singleton(FALSE);
1452 $c->free();
1453
1454 include_once "./includes/bootstrap.inc";
1455 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1456
1457 // rebuild modules, so that civicrm is added
1458 module_rebuild_cache();
1459
1460 // now enable civicrm module.
1461 module_enable(array('civicrm'));
1462
1463 // clear block, page, theme, and hook caches
1464 drupal_flush_all_caches();
1465
1466 //add basic drupal permissions
1467 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)');
1468
1469 echo $output;
1470 }
1471 elseif ($installType == 'wordpress') {
1472 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
1473 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
1474 echo '<ul>';
1475
1476 $cmsURL = civicrm_cms_base();
1477 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
1478 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1479
1480 $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>";
1481 $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>";
1482 $output .= $commonOutputMessage;
1483
1484 echo '</ul>';
1485 echo '</div>';
1486
1487 $c = CRM_Core_Config::singleton(FALSE);
1488 $c->free();
1489 $wpInstallRedirect = admin_url("?page=CiviCRM&q=civicrm&reset=1");
1490 echo "<script>
1491 window.location = '$wpInstallRedirect';
1492 </script>";
1493 }
1494 }
1495
1496 return $this->errors;
1497 }
1498
1499 }
1500
1501 function civicrm_install_set_drupal_perms() {
1502 if (!function_exists('db_select')) {
1503 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)');
1504 }
1505 else {
1506 $perms = array(
1507 'access all custom data',
1508 'access uploaded files',
1509 'make online contributions',
1510 'profile create',
1511 'profile edit',
1512 'profile view',
1513 'register for events',
1514 'view event info',
1515 'view event participants',
1516 'access CiviMail subscribe/unsubscribe pages',
1517 );
1518
1519 // Adding a permission that has not yet been assigned to a module by
1520 // a hook_permission implementation results in a database error.
1521 // CRM-9042
1522 $allPerms = array_keys(module_invoke_all('permission'));
1523 foreach (array_diff($perms, $allPerms) as $perm) {
1524 watchdog('civicrm',
1525 'Cannot grant the %perm permission because it does not yet exist.',
1526 array('%perm' => $perm),
1527 WATCHDOG_ERROR
1528 );
1529 }
1530 $perms = array_intersect($perms, $allPerms);
1531 user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, $perms);
1532 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, $perms);
1533 }
1534 }
1535
1536 /**
1537 * @param $cmsPath
1538 * @param $str
1539 *
1540 * @return string
1541 */
1542 function getSiteDir($cmsPath, $str) {
1543 static $siteDir = '';
1544
1545 if ($siteDir) {
1546 return $siteDir;
1547 }
1548
1549 $sites = CIVICRM_DIRECTORY_SEPARATOR . 'sites' . CIVICRM_DIRECTORY_SEPARATOR;
1550 $modules = CIVICRM_DIRECTORY_SEPARATOR . 'modules' . CIVICRM_DIRECTORY_SEPARATOR;
1551 preg_match("/" . preg_quote($sites, CIVICRM_DIRECTORY_SEPARATOR) .
1552 "([\-a-zA-Z0-9_.]+)" .
1553 preg_quote($modules, CIVICRM_DIRECTORY_SEPARATOR) . "/",
1554 $_SERVER['SCRIPT_FILENAME'], $matches
1555 );
1556 $siteDir = isset($matches[1]) ? $matches[1] : 'default';
1557
1558 if (strtolower($siteDir) == 'all') {
1559 // For this case - use drupal's way of finding out multi-site directory
1560 $uri = explode(CIVICRM_DIRECTORY_SEPARATOR, $_SERVER['SCRIPT_FILENAME']);
1561 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
1562 for ($i = count($uri) - 1; $i > 0; $i--) {
1563 for ($j = count($server); $j > 0; $j--) {
1564 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
1565 if (file_exists($cmsPath . CIVICRM_DIRECTORY_SEPARATOR .
1566 'sites' . CIVICRM_DIRECTORY_SEPARATOR . $dir
1567 )) {
1568 $siteDir = $dir;
1569 return $siteDir;
1570 }
1571 }
1572 }
1573 $siteDir = 'default';
1574 }
1575
1576 return $siteDir;
1577 }
1578
1579 /**
1580 * @param $errorTitle
1581 * @param $errorMsg
1582 * @param $showRefer
1583 */
1584 function errorDisplayPage($errorTitle, $errorMsg, $showRefer = TRUE) {
1585 if ($showRefer) {
1586 $docLink = CRM_Utils_System::docURL2('Installation and Upgrades', FALSE, 'Installation Guide', NULL, NULL, "wiki");
1587
1588 if (function_exists('ts')) {
1589 $errorMsg .= '<p>' . ts("<a %1>Refer to the online documentation for more information</a>", array(1 => "href='$docLink'")) . '</p>';
1590 }
1591 else {
1592 $errorMsg .= '<p>' . sprintf("<a %s>Refer to the online documentation for more information</a>", "href='$docLink'") . '</p>';
1593 }
1594 }
1595
1596 include 'error.html';
1597 exit();
1598 }