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