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