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