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