Merge pull request #7603 from jitendrapurohit/CRM-17810
[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()) {
064bf239
CB
60 if (defined('PANTHEON_ENVIRONMENT')) {
61 ini_set('session.save_handler', 'files');
62 }
6a488035
TO
63 session_start();
64}
65
66// unset civicrm session if any
67if (array_key_exists('CiviCRM', $_SESSION)) {
68 unset($_SESSION['CiviCRM']);
69}
70
71if (isset($_GET['civicrm_install_type'])) {
72 $_SESSION['civicrm_install_type'] = $_GET['civicrm_install_type'];
73}
74else {
75 if (!isset($_SESSION['civicrm_install_type'])) {
76 $_SESSION['civicrm_install_type'] = "drupal";
77 }
78}
79
80global $installType;
6a488035 81global $crmPath;
97b8e6b2 82global $pkgPath;
6a488035
TO
83global $installDirPath;
84global $installURLPath;
97b8e6b2 85
6a9514e1
ML
86$installType = strtolower($_SESSION['civicrm_install_type']);
87
6a488035
TO
88if ($installType == 'drupal') {
89 $crmPath = dirname(dirname($_SERVER['SCRIPT_FILENAME']));
90 $installDirPath = $installURLPath = '';
91}
92elseif ($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;
6a488035
TO
95 $installURLPath = WP_PLUGIN_URL . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR;
96}
6a9514e1
ML
97else {
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}
6a488035 102
97b8e6b2 103$pkgPath = $crmPath . DIRECTORY_SEPARATOR . 'packages';
104
6a488035
TO
105require_once $crmPath . '/CRM/Core/ClassLoader.php';
106CRM_Core_ClassLoader::singleton()->register();
107
6a488035 108// Load civicrm database config
aca6ce6e
PN
109if (isset($_POST['mysql'])) {
110 $databaseConfig = $_POST['mysql'];
6a488035
TO
111}
112else {
7267b6be
KC
113 $databaseConfig = array(
114 "server" => "localhost",
115 "username" => "civicrm",
116 "password" => "",
117 "database" => "civicrm",
118 );
119}
120
121if ($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 );
6a488035
TO
129}
130
131if ($installType == 'drupal') {
132 // Load drupal database config
aca6ce6e
PN
133 if (isset($_POST['drupal'])) {
134 $drupalConfig = $_POST['drupal'];
6a488035
TO
135 }
136 else {
137 $drupalConfig = array(
138 "server" => "localhost",
139 "username" => "drupal",
140 "password" => "",
141 "database" => "drupal",
142 );
143 }
144}
145
146$loadGenerated = 0;
aca6ce6e 147if (isset($_POST['loadGenerated'])) {
6a488035
TO
148 $loadGenerated = 1;
149}
150
151require_once dirname(__FILE__) . CIVICRM_DIRECTORY_SEPARATOR . 'langs.php';
152foreach ($langs as $locale => $_) {
153 if ($locale == 'en_US') {
154 continue;
155 }
4f99ca55
TO
156 if (!file_exists(implode(CIVICRM_DIRECTORY_SEPARATOR, array($crmPath, 'sql', "civicrm_data.$locale.mysql")))) {
157 unset($langs[$locale]);
1f5f3294 158 }
6a488035
TO
159}
160
97b8e6b2 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
c8ab0a65 169$uf = (isset($installTypeToUF[$installType]) ? $installTypeToUF[$installType] : 'Drupal');
97b8e6b2 170define('CIVICRM_UF', $uf);
171
172global $tsLocale;
173
174$tsLocale = 'en_US';
6a488035 175$seedLanguage = 'en_US';
97b8e6b2 176
aca6ce6e
PN
177if (isset($_POST['seedLanguage']) and isset($langs[$_POST['seedLanguage']])) {
178 $seedLanguage = $_POST['seedLanguage'];
179 $tsLocale = $_POST['seedLanguage'];
6a488035
TO
180}
181
97b8e6b2 182$config = CRM_Core_Config::singleton(FALSE);
0ad1e2de
ML
183$GLOBALS['civicrm_default_error_scope'] = NULL;
184
97b8e6b2 185// The translation files are in the parent directory (l10n)
97b8e6b2 186$i18n = CRM_Core_I18n::singleton();
187
6a488035
TO
188global $cmsPath;
189if ($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}
201elseif ($installType == 'wordpress') {
202 $cmsPath = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'civicrm';
7ba2c8ad
KC
203 $upload_dir = wp_upload_dir();
204 $files_dirname = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm';
e7bf24e8
KC
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 }
6a488035
TO
213}
214
6a9514e1
ML
215if ($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
6a488035
TO
227// Exit with error if CiviCRM has already been installed.
228if ($alreadyInstalled) {
6a9514e1
ML
229 $errorTitle = ts("Oops! CiviCRM is already installed");
230 $settings_directory = $cmsPath;
6a488035 231
6a9514e1
ML
232 if ($installType == 'drupal') {
233 $settings_directory = implode(CIVICRM_DIRECTORY_SEPARATOR, array(
234 ts('[your Drupal root directory]'),
235 'sites',
236 $siteDir,
237 ));
6a488035 238 }
6a9514e1
ML
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);
6a488035
TO
243}
244
245$versionFile = $crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'civicrm-version.php';
246if (file_exists($versionFile)) {
1f5f3294 247 require_once $versionFile;
6a488035
TO
248 $civicrm_version = civicrmVersion();
249}
250else {
251 $civicrm_version = 'unknown';
252}
253
254if ($installType == 'drupal') {
255 // Ensure that they have downloaded the correct version of CiviCRM
6a9514e1
ML
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.");
6a488035
TO
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) {
6a9514e1
ML
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)));
6a488035
TO
278 errorDisplayPage($errorTitle, $errorMsg);
279 }
280}
281elseif ($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') {
6a9514e1
ML
287 $errorTitle = ts("Oops! Incorrect CiviCRM version");
288 $errorMsg = ts("This installer can only be used for the WordPress version of CiviCRM.");
6a488035
TO
289 errorDisplayPage($errorTitle, $errorMsg);
290 }
291}
292
293// Check requirements
294$req = new InstallRequirements();
295$req->check();
296
297if ($req->hasErrors()) {
298 $hasErrorOtherThanDatabase = TRUE;
299}
300
301if ($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
aca6ce6e 310if (isset($_POST['go']) && !$req->hasErrors() && !$dbReq->hasErrors()) {
6a488035 311 // Confirm before reinstalling
aca6ce6e 312 if (!isset($_POST['force_reinstall']) && $alreadyInstalled) {
1f5f3294 313 include $installDirPath . 'template.html';
6a488035
TO
314 }
315 else {
316 $inst = new Installer();
aca6ce6e 317 $inst->install($_POST);
6a488035
TO
318 }
319
320 // Show the config form
321}
322else {
1f5f3294 323 include $installDirPath . 'template.html';
6a488035
TO
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:
6a9514e1 330 * $description[0] - The test category
6a488035
TO
331 * $description[1] - The test title
332 * $description[2] - The test error to show, if it goes wrong
333 */
334class InstallRequirements {
335 var $errors, $warnings, $tests;
336
337 // @see CRM_Upgrade_Form::MINIMUM_THREAD_STACK
338 const MINIMUM_THREAD_STACK = 192;
339
340 /**
fe482240 341 * Just check that the database configuration is okay.
d7c8cf03
EM
342 * @param $databaseConfig
343 * @param $dbName
6a488035 344 */
971d41b1 345 public function checkdatabase($databaseConfig, $dbName) {
6a488035 346 if ($this->requireFunction('mysql_connect',
56fdfc52 347 array(
97b8e6b2 348 ts("PHP Configuration"),
349 ts("MySQL support"),
350 ts("MySQL support not included in PHP."),
56fdfc52
TO
351 )
352 )
353 ) {
6a488035
TO
354 $this->requireMySQLServer($databaseConfig['server'],
355 array(
2f8082cd
ML
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'])),
6a488035
TO
359 $databaseConfig['server'],
360 )
361 );
362 if ($this->requireMysqlConnection($databaseConfig['server'],
56fdfc52
TO
363 $databaseConfig['username'],
364 $databaseConfig['password'],
365 array(
2f8082cd
ML
366 ts("MySQL %1 Configuration", array(1 => $dbName)),
367 ts("Are the access credentials correct?"),
368 ts("That username/password doesn't work"),
56fdfc52
TO
369 )
370 )
371 ) {
6a488035
TO
372 @$this->requireMySQLVersion("5.1",
373 array(
2f8082cd
ML
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())),
6a488035
TO
378 )
379 );
380 $this->requireMySQLAutoIncrementIncrementOne($databaseConfig['server'],
381 $databaseConfig['username'],
382 $databaseConfig['password'],
383 array(
2f8082cd
ML
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."),
6a488035
TO
387 )
388 );
389 $this->requireMySQLThreadStack($databaseConfig['server'],
390 $databaseConfig['username'],
391 $databaseConfig['password'],
392 $databaseConfig['database'],
393 self::MINIMUM_THREAD_STACK,
394 array(
2f8082cd
ML
395 ts("MySQL %1 Configuration", array(1 => $dbName)),
396 ts("Does MySQL thread_stack meet minimum (%1k)", array(1 => self::MINIMUM_THREAD_STACK)),
56fdfc52
TO
397 "",
398 // "The MySQL thread_stack does not meet minimum " . CRM_Upgrade_Form::MINIMUM_THREAD_STACK . "k. Please update thread_stack in my.cnf.",
6a488035
TO
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(
2f8082cd
ML
409 ts("MySQL %1 Configuration", array(1 => $dbName)),
410 ts("Can I access/create the database?"),
5f40a878 411 ts("I can't create new databases and the database '%1' doesn't exist.", array(1 => $databaseConfig['database'])),
6a488035
TO
412 ),
413 $onlyRequire
414 );
415 if ($dbName != 'Drupal') {
416 $this->requireMySQLInnoDB($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 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."),
6a488035
TO
424 )
425 );
426 $this->requireMySQLTempTables($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 temporary tables in the database?'),
433 ts('Unable to create temporary tables. This MySQL user is missing the CREATE TEMPORARY TABLES privilege.'),
6a488035
TO
434 )
435 );
436 $this->requireMySQLLockTables($databaseConfig['server'],
437 $databaseConfig['username'],
438 $databaseConfig['password'],
439 $databaseConfig['database'],
440 array(
2f8082cd
ML
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.'),
6a488035
TO
444 )
445 );
446 $this->requireMySQLTrigger($databaseConfig['server'],
447 $databaseConfig['username'],
448 $databaseConfig['password'],
449 $databaseConfig['database'],
450 array(
2f8082cd
ML
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.'),
6a488035
TO
454 )
455 );
456 }
457 }
458 }
459
460 /**
fe482240 461 * Check everything except the database.
6a488035 462 */
971d41b1 463 public function check() {
6a488035
TO
464 global $crmPath, $installType;
465
466 $this->errors = NULL;
467
678d6d82 468 $this->requirePHPVersion('5.3.4', array(
2f8082cd
ML
469 ts("PHP Configuration"),
470 ts("PHP5 installed"),
56fdfc52 471 NULL,
2f8082cd 472 ts("PHP version %1", array(1 => phpversion())),
56fdfc52 473 ));
6a488035
TO
474
475 // Check that we can identify the root folder successfully
476 $this->requireFile($crmPath . CIVICRM_DIRECTORY_SEPARATOR . 'README.txt',
477 array(
2f8082cd
ML
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."),
6a488035
TO
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(
2f8082cd
ML
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)),
6a488035
TO
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(
2f8082cd
ML
500 ts("File permissions"),
501 ts("Folder '%1' exists?", array(1 => $dir)),
502 ts("There is no '%1' folder.", array(1 => $dir)),
56fdfc52 503 ), TRUE
6a488035
TO
504 );
505 }
506
507 $configIDSiniDir = NULL;
508 global $cmsPath;
3fdcdfbb 509 $siteDir = getSiteDir($cmsPath, $_SERVER['SCRIPT_FILENAME']);
6a488035 510 if ($installType == 'drupal') {
6a488035
TO
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') {
7ba2c8ad
KC
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);
6a488035
TO
531 }
532
533 foreach ($writableDirectories as $dir) {
534 $dirName = CIVICRM_WINDOWS ? $dir : CIVICRM_DIRECTORY_SEPARATOR . $dir;
2f8082cd
ML
535 $testDetails = array(
536 ts("File permissions"),
537 ts("Is the %1 folder writeable?", array(1 => $dir)),
538 NULL,
6a488035 539 );
2f8082cd 540 $this->requireWriteable($dirName, $testDetails, TRUE);
6a488035
TO
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 == '') {
2f8082cd 562 $webserver = ts("I can't tell what webserver you are running");
6a488035
TO
563 }
564
565 // Check for $_SERVER configuration
56fdfc52 566 $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
2f8082cd
ML
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."),
56fdfc52 570 ));
6a488035
TO
571
572 // Check for MySQL support
2f8082cd
ML
573 $this->requireFunction('mysql_connect', array(
574 ts("PHP Configuration"),
575 ts("MySQL support"),
576 ts("MySQL support not included in PHP."),
577 ));
6a488035
TO
578
579 // Check for JSON support
2f8082cd
ML
580 $this->requireFunction('json_encode', array(
581 ts("PHP Configuration"),
582 ts("JSON support"),
583 ts("JSON support not included in PHP."),
584 ));
6a488035
TO
585
586 // Check for xcache_isset and emit warning if exists
587 $this->checkXCache(array(
2f8082cd
ML
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."),
56fdfc52 591 ));
6a488035
TO
592
593 // Check memory allocation
594 $this->requireMemory(32 * 1024 * 1024,
595 64 * 1024 * 1024,
596 array(
2f8082cd
ML
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)),
6a488035
TO
600 ini_get("memory_limit"),
601 )
602 );
603
604 return $this->errors;
605 }
606
627456b5
EM
607 /**
608 * @param $min
609 * @param $recommended
610 * @param $testDetails
611 */
971d41b1 612 public function requireMemory($min, $recommended, $testDetails) {
6a488035
TO
613 $this->testing($testDetails);
614 $mem = $this->getPHPMemory();
615
616 if ($mem < $min && $mem > 0) {
2f8082cd 617 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
6a488035
TO
618 $this->error($testDetails);
619 }
620 elseif ($mem < $recommended && $mem > 0) {
2f8082cd 621 $testDetails[2] .= " " . ts("You only have %1 allocated", array(1 => ini_get("memory_limit")));
6a488035
TO
622 $this->warning($testDetails);
623 }
624 elseif ($mem == 0) {
2f8082cd 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));
6a488035
TO
626 $this->warning($testDetails);
627 }
628 }
629
627456b5
EM
630 /**
631 * @return float
632 */
971d41b1 633 public function getPHPMemory() {
6a488035
TO
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
971d41b1 651 public function listErrors() {
6a488035 652 if ($this->errors) {
2f8082cd 653 echo "<p>" . ts("The following problems are preventing me from installing CiviCRM:") . "</p>";
6a488035
TO
654 foreach ($this->errors as $error) {
655 echo "<li>" . htmlentities($error) . "</li>";
656 }
657 }
658 }
659
627456b5
EM
660 /**
661 * @param null $section
662 */
971d41b1 663 public function showTable($section = NULL) {
6a488035
TO
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
627456b5 685 /**
100fef9d 686 * @param string $funcName
627456b5
EM
687 * @param $testDetails
688 *
689 * @return bool
690 */
971d41b1 691 public function requireFunction($funcName, $testDetails) {
6a488035
TO
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
627456b5
EM
703 /**
704 * @param $testDetails
705 */
971d41b1 706 public function checkXCache($testDetails) {
6a488035
TO
707 if (function_exists('xcache_isset') &&
708 ini_get('xcache.size') > 0
709 ) {
710 $this->testing($testDetails);
711 $this->warning($testDetails);
712 }
713 }
714
627456b5
EM
715 /**
716 * @param $minVersion
717 * @param $testDetails
718 * @param null $maxVersion
719 */
971d41b1 720 public function requirePHPVersion($minVersion, $testDetails, $maxVersion = NULL) {
6a488035
TO
721
722 $this->testing($testDetails);
723
56fdfc52 724 $phpVersion = phpversion();
6a488035
TO
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) {
2f8082cd 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));
6a488035
TO
738 }
739 else {
2f8082cd 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));
6a488035
TO
741 }
742 }
743
744 $this->error($testDetails);
745 }
746
627456b5 747 /**
100fef9d 748 * @param string $filename
627456b5
EM
749 * @param $testDetails
750 * @param bool $absolute
751 */
971d41b1 752 public function requireFile($filename, $testDetails, $absolute = FALSE) {
6a488035
TO
753 $this->testing($testDetails);
754 if (!$absolute) {
755 $filename = $this->getBaseDir() . $filename;
756 }
757 if (!file_exists($filename)) {
2f8082cd 758 $testDetails[2] .= " (" . ts("file '%1' not found", array(1 => $filename)) . ')';
6a488035
TO
759 $this->error($testDetails);
760 }
761 }
762
627456b5
EM
763 /**
764 * @param $testDetails
765 */
971d41b1 766 public function requireNoPathSeparator($testDetails) {
6a488035
TO
767 $this->testing($testDetails);
768 if (substr_count($this->getBaseDir(), PATH_SEPARATOR)) {
769 $this->error($testDetails);
770 }
771 }
772
627456b5 773 /**
100fef9d 774 * @param string $filename
627456b5
EM
775 * @param $testDetails
776 */
971d41b1 777 public function requireNoFile($filename, $testDetails) {
6a488035
TO
778 $this->testing($testDetails);
779 $filename = $this->getBaseDir() . $filename;
780 if (file_exists($filename)) {
2f8082cd 781 $testDetails[2] .= " (" . ts("file '%1' found", array(1 => $filename)) . ")";
6a488035
TO
782 $this->error($testDetails);
783 }
784 }
785
627456b5 786 /**
100fef9d 787 * @param string $filename
627456b5
EM
788 * @param $testDetails
789 */
971d41b1 790 public function moveFileOutOfTheWay($filename, $testDetails) {
6a488035
TO
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
627456b5 801 /**
100fef9d 802 * @param string $filename
627456b5
EM
803 * @param $testDetails
804 * @param bool $absolute
805 */
971d41b1 806 public function requireWriteable($filename, $testDetails, $absolute = FALSE) {
6a488035
TO
807 $this->testing($testDetails);
808 if (!$absolute) {
809 $filename = $this->getBaseDir() . $filename;
810 }
811
22e263ad 812 if (!is_writable($filename)) {
6a488035
TO
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 }
2f8082cd 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";
6a488035
TO
823 $this->error($testDetails);
824 }
825 }
826
627456b5 827 /**
100fef9d 828 * @param string $moduleName
627456b5
EM
829 * @param $testDetails
830 */
971d41b1 831 public function requireApacheModule($moduleName, $testDetails) {
6a488035
TO
832 $this->testing($testDetails);
833 if (!in_array($moduleName, apache_get_modules())) {
834 $this->error($testDetails);
835 }
836 }
837
627456b5
EM
838 /**
839 * @param $server
100fef9d 840 * @param string $username
627456b5
EM
841 * @param $password
842 * @param $testDetails
843 */
971d41b1 844 public function requireMysqlConnection($server, $username, $password, $testDetails) {
6a488035
TO
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
627456b5
EM
857 /**
858 * @param $server
859 * @param $testDetails
860 */
971d41b1 861 public function requireMySQLServer($server, $testDetails) {
6a488035
TO
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
627456b5
EM
874 /**
875 * @param $version
876 * @param $testDetails
877 */
971d41b1 878 public function requireMySQLVersion($version, $testDetails) {
6a488035
TO
879 $this->testing($testDetails);
880
881 if (!mysql_get_server_info()) {
2f8082cd 882 $testDetails[2] = ts('Cannot determine the version of MySQL installed. Please ensure at least version %1 is installed.', array(1 => $version));
6a488035
TO
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
627456b5
EM
899 /**
900 * @param $server
100fef9d 901 * @param string $username
627456b5
EM
902 * @param $password
903 * @param $database
904 * @param $testDetails
905 */
971d41b1 906 public function requireMySQLInnoDB($server, $username, $password, $database, $testDetails) {
6a488035
TO
907 $this->testing($testDetails);
908 $conn = @mysql_connect($server, $username, $password);
909 if (!$conn) {
2f8082cd 910 $testDetails[2] .= ' ' . ts("Could not determine if MySQL has InnoDB support. Assuming no.");
6a488035
TO
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) {
2f8082cd 927 $testDetails[3] = ts('MySQL server does have InnoDB support');
6a488035
TO
928 }
929 else {
2f8082cd 930 $testDetails[2] .= ' ' . ts('Could not determine if MySQL has InnoDB support. Assuming no');
6a488035
TO
931 }
932 }
933
627456b5
EM
934 /**
935 * @param $server
100fef9d 936 * @param string $username
627456b5
EM
937 * @param $password
938 * @param $database
939 * @param $testDetails
940 */
971d41b1 941 public function requireMySQLTempTables($server, $username, $password, $database, $testDetails) {
6a488035
TO
942 $this->testing($testDetails);
943 $conn = @mysql_connect($server, $username, $password);
944 if (!$conn) {
2f8082cd 945 $testDetails[2] = ts('Could not login to the database.');
6a488035
TO
946 $this->error($testDetails);
947 return;
948 }
949
950 if (!@mysql_select_db($database, $conn)) {
2f8082cd 951 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
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) {
2f8082cd 958 $testDetails[2] = ts('Could not create a temp table.');
6a488035
TO
959 $this->error($testDetails);
960 }
961 $result = mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
962 }
963
627456b5
EM
964 /**
965 * @param $server
100fef9d 966 * @param string $username
627456b5
EM
967 * @param $password
968 * @param $database
969 * @param $testDetails
970 */
971d41b1 971 public function requireMySQLTrigger($server, $username, $password, $database, $testDetails) {
6a488035
TO
972 $this->testing($testDetails);
973 $conn = @mysql_connect($server, $username, $password);
974 if (!$conn) {
2f8082cd 975 $testDetails[2] = ts('Could not login to the database.');
6a488035
TO
976 $this->error($testDetails);
977 return;
978 }
979
980 if (!@mysql_select_db($database, $conn)) {
2f8082cd 981 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
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) {
2f8082cd 988 $testDetails[2] = ts('Could not create a table in the database.');
6a488035
TO
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');
2f8082cd 995 $testDetails[2] = ts('Could not create a database trigger.');
6a488035
TO
996 $this->error($testDetails);
997 }
998
6a488035
TO
999 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
1000 mysql_query('DROP TABLE civicrm_install_temp_table_test');
1001 }
1002
1003
627456b5
EM
1004 /**
1005 * @param $server
100fef9d 1006 * @param string $username
627456b5
EM
1007 * @param $password
1008 * @param $database
1009 * @param $testDetails
1010 */
971d41b1 1011 public function requireMySQLLockTables($server, $username, $password, $database, $testDetails) {
6a488035
TO
1012 $this->testing($testDetails);
1013 $conn = @mysql_connect($server, $username, $password);
1014 if (!$conn) {
2f8082cd 1015 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1016 $this->error($testDetails);
1017 return;
1018 }
1019
1020 if (!@mysql_select_db($database, $conn)) {
2f8082cd 1021 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
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) {
2f8082cd 1028 $testDetails[2] = ts('Could not create a table in the database.');
6a488035
TO
1029 $this->error($testDetails);
1030 return;
1031 }
1032
1033 $result = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
1034 if (!$result) {
2f8082cd 1035 $testDetails[2] = ts('Could not obtain a write lock for the database table.');
6a488035
TO
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) {
2f8082cd 1043 $testDetails[2] = ts('Could not release the lock for the database table.');
6a488035
TO
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');
6a488035
TO
1050 }
1051
627456b5
EM
1052 /**
1053 * @param $server
100fef9d 1054 * @param string $username
627456b5
EM
1055 * @param $password
1056 * @param $testDetails
1057 */
971d41b1 1058 public function requireMySQLAutoIncrementIncrementOne($server, $username, $password, $testDetails) {
6a488035
TO
1059 $this->testing($testDetails);
1060 $conn = @mysql_connect($server, $username, $password);
1061 if (!$conn) {
2f8082cd 1062 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1063 $this->error($testDetails);
1064 return;
1065 }
1066
1067 $result = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
1068 if (!$result) {
2f8082cd 1069 $testDetails[2] = ts('Could not query database server variables.');
6a488035
TO
1070 $this->error($testDetails);
1071 return;
1072 }
1073 else {
1074 $values = mysql_fetch_row($result);
1075 if ($values[1] == 1) {
2f8082cd 1076 $testDetails[3] = ts('MySQL server auto_increment_increment is 1');
6a488035
TO
1077 }
1078 else {
1079 $this->error($testDetails);
1080 }
1081 }
1082 }
1083
627456b5
EM
1084 /**
1085 * @param $server
100fef9d 1086 * @param string $username
627456b5
EM
1087 * @param $password
1088 * @param $database
1089 * @param $minValueKB
1090 * @param $testDetails
1091 */
971d41b1 1092 public function requireMySQLThreadStack($server, $username, $password, $database, $minValueKB, $testDetails) {
6a488035
TO
1093 $this->testing($testDetails);
1094 $conn = @mysql_connect($server, $username, $password);
1095 if (!$conn) {
2f8082cd 1096 $testDetails[2] = ts('Could not connect to the database server.');
6a488035
TO
1097 $this->error($testDetails);
1098 return;
1099 }
1100
1101 if (!@mysql_select_db($database, $conn)) {
2f8082cd 1102 $testDetails[2] = ts('Could not select the database.');
6a488035
TO
1103 $this->error($testDetails);
1104 return;
1105 }
1106
032c9d10 1107 $result = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
6a488035 1108 if (!$result) {
2f8082cd 1109 $testDetails[2] = ts('Could not get information about the thread_stack of the database.');
6a488035 1110 $this->error($testDetails);
0db6c3e1
TO
1111 }
1112 else {
6a488035 1113 $values = mysql_fetch_row($result);
1f5f3294 1114 if ($values[1] < (1024 * $minValueKB)) {
2f8082cd 1115 $testDetails[2] = ts('MySQL "thread_stack" is %1 kb', array(1 => ($values[1] / 1024)));
6a488035
TO
1116 $this->error($testDetails);
1117 }
1118 }
1119 }
1120
627456b5
EM
1121 /**
1122 * @param $server
100fef9d 1123 * @param string $username
627456b5
EM
1124 * @param $password
1125 * @param $database
1126 * @param $testDetails
1127 * @param bool $onlyRequire
1128 */
971d41b1 1129 public function requireDatabaseOrCreatePermissions(
56fdfc52 1130 $server,
6a488035
TO
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) {
2f8082cd 1145 $testDetails[2] = ts("The database: '%1' does not exist.", array(1 => $database));
6a488035
TO
1146 $this->error($testDetails);
1147 return;
1148 }
1149 else {
1150 if (@mysql_query("CREATE DATABASE $database")) {
2f8082cd 1151 $okay = ts("Able to create a new database.");
6a488035
TO
1152 }
1153 else {
2f8082cd 1154 $testDetails[2] .= " (" . ts("user '%1' doesn't have CREATE DATABASE permissions.", array(1 => $username)) . ")";
6a488035
TO
1155 $this->error($testDetails);
1156 return;
1157 }
1158 }
1159
1160 if ($okay) {
1161 $testDetails[3] = $okay;
1162 $this->testing($testDetails);
1163 }
1164 }
1165
627456b5
EM
1166 /**
1167 * @param $varNames
1168 * @param $errorMessage
1169 */
971d41b1 1170 public function requireServerVariables($varNames, $errorMessage) {
6a488035
TO
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 {
2f8082cd 1181 $testDetails[2] = " (" . ts('the following PHP variables are missing: %1', array(1 => implode(", ", $missing))) . ")";
6a488035
TO
1182 $this->error($testDetails);
1183 }
1184 }
1185
627456b5
EM
1186 /**
1187 * @param $testDetails
1188 *
1189 * @return bool
1190 */
971d41b1 1191 public function isRunningApache($testDetails) {
6a488035
TO
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
627456b5
EM
1201 /**
1202 * @return string
1203 */
971d41b1 1204 public function getBaseDir() {
6a488035
TO
1205 return dirname($_SERVER['SCRIPT_FILENAME']) . CIVICRM_DIRECTORY_SEPARATOR;
1206 }
1207
627456b5
EM
1208 /**
1209 * @param $testDetails
1210 */
971d41b1 1211 public function testing($testDetails) {
6a488035
TO
1212 if (!$testDetails) {
1213 return;
1214 }
1215
1216 $section = $testDetails[0];
1217 $test = $testDetails[1];
1218
2f8082cd 1219 $message = ts("OK");
6a488035
TO
1220 if (isset($testDetails[3])) {
1221 $message .= " ($testDetails[3])";
1222 }
1223
1224 $this->tests[$section][$test] = array("good", $message);
1225 }
1226
627456b5
EM
1227 /**
1228 * @param $testDetails
1229 */
971d41b1 1230 public function error($testDetails) {
6a488035
TO
1231 $section = $testDetails[0];
1232 $test = $testDetails[1];
1233
1234 $this->tests[$section][$test] = array("error", $testDetails[2]);
1235 $this->errors[] = $testDetails;
1236 }
1237
627456b5
EM
1238 /**
1239 * @param $testDetails
1240 */
971d41b1 1241 public function warning($testDetails) {
6a488035
TO
1242 $section = $testDetails[0];
1243 $test = $testDetails[1];
1244
6a488035
TO
1245 $this->tests[$section][$test] = array("warning", $testDetails[2]);
1246 $this->warnings[] = $testDetails;
1247 }
1248
627456b5
EM
1249 /**
1250 * @return int
1251 */
971d41b1
CW
1252 public function hasErrors() {
1253 return count($this->errors);
6a488035
TO
1254 }
1255
627456b5
EM
1256 /**
1257 * @return int
1258 */
971d41b1
CW
1259 public function hasWarnings() {
1260 return count($this->warnings);
6a488035 1261 }
96025800 1262
6a488035
TO
1263}
1264
627456b5
EM
1265/**
1266 * Class Installer
1267 */
6a488035 1268class Installer extends InstallRequirements {
627456b5
EM
1269 /**
1270 * @param $server
1271 * @param $username
1272 * @param $password
1273 * @param $database
1274 */
971d41b1 1275 public function createDatabaseIfNotExists($server, $username, $password, $database) {
6a488035
TO
1276 $conn = @mysql_connect($server, $username, $password);
1277
1278 if (@mysql_select_db($database)) {
1279 // skip if database already present
1280 return;
1281 }
1282
56fdfc52
TO
1283 if (@mysql_query("CREATE DATABASE $database")) {
1284 }
6a488035 1285 else {
6a9514e1
ML
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.");
6a488035
TO
1288 errorDisplayPage($errorTitle, $errorMsg);
1289 }
1290 }
1291
627456b5
EM
1292 /**
1293 * @param $config
1294 *
1295 * @return mixed
1296 */
971d41b1 1297 public function install($config) {
6a488035
TO
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
bb216f68 1316 $registerSiteURL = "https://civicrm.org/register-site";
56de7273
ML
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>";
41547a19 1320
6a488035 1321 $output = NULL;
97b8e6b2 1322
6a488035
TO
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>';
2f8082cd 1334 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
6a9514e1 1335 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6a488035
TO
1336 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1337 $output .= '</head>';
1338 $output .= '<body>';
2f8082cd 1339 $output .= '<div style="padding: 1em;"><p class="good">' . ts('CiviCRM has been successfully installed') . '</p>';
6a488035 1340 $output .= '<ul>';
6a9514e1 1341
6a488035
TO
1342 $drupalURL = civicrm_cms_base();
1343 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/people/permissions";
1344 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
6a488035 1345
6a9514e1
ML
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;
6a488035
TO
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
97b8e6b2 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
6a488035
TO
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
d8a4acc0
C
1383 // clear block, page, theme, and hook caches
1384 drupal_flush_all_caches();
6a488035
TO
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
e181e386 1393 //change the default language to one chosen
1394 if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
d2860c54
ML
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
e181e386 1399 civicrm_api3('Setting', 'create', array(
1400 'domain_id' => 'current_domain',
1401 'lcMessages' => $config['seedLanguage'],
1402 )
1403 );
1404 }
1405
6a488035
TO
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>';
6a9514e1
ML
1419 $output .= '<title>' . ts('CiviCRM Installed') . '</title>';
1420 $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6a488035
TO
1421 $output .= '<link rel="stylesheet" type="text/css" href="template.css" />';
1422 $output .= '</head>';
1423 $output .= '<body>';
97b8e6b2 1424 $output .= '<div style="padding: 1em;"><p class="good">' . ts("CiviCRM has been successfully installed") . '</p>';
6a488035 1425 $output .= '<ul>';
6a9514e1 1426
6a488035
TO
1427 $drupalURL = civicrm_cms_base();
1428 $drupalPermissionsURL = "{$drupalURL}index.php?q=admin/user/permissions";
1429 $drupalURL .= "index.php?q=civicrm/admin/configtask&reset=1";
6a488035 1430
6a9514e1
ML
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;
6a488035
TO
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
2f8082cd
ML
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
6a488035
TO
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
d8a4acc0
C
1459 // clear block, page, theme, and hook caches
1460 drupal_flush_all_caches();
6a488035
TO
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') {
6a9514e1 1468 echo '<h1>' . ts('CiviCRM Installed') . '</h1>';
97b8e6b2 1469 echo '<div style="padding: 1em;"><p style="background-color: #0C0; border: 1px #070 solid; color: white;">' . ts("CiviCRM has been successfully installed") . '</p>';
6a488035 1470 echo '<ul>';
6a488035
TO
1471
1472 $cmsURL = civicrm_cms_base();
1473 $cmsURL .= "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/configtask&reset=1";
41547a19
DL
1474 $wpPermissionsURL = "wp-admin/admin.php?page=CiviCRM&q=civicrm/admin/access/wp-permissions&reset=1";
1475
6a9514e1
ML
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;
41547a19 1479
1f5f3294
TO
1480 echo '</ul>';
1481 echo '</div>';
b232c132 1482
1483 $c = CRM_Core_Config::singleton(FALSE);
1484 $c->free();
7ba2c8ad
KC
1485 $wpInstallRedirect = admin_url("?page=CiviCRM&q=civicrm&reset=1");
1486 echo "<script>
1487 window.location = '$wpInstallRedirect';
1488 </script>";
1f5f3294
TO
1489 }
1490 }
6a488035
TO
1491
1492 return $this->errors;
1493 }
96025800 1494
6a488035
TO
1495}
1496
1497function 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.',
971d41b1
CW
1522 array('%perm' => $perm),
1523 WATCHDOG_ERROR
6a488035
TO
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
627456b5
EM
1532/**
1533 * @param $cmsPath
1534 * @param $str
1535 *
1536 * @return string
1537 */
6a488035
TO
1538function 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 .
56fdfc52
TO
1562 'sites' . CIVICRM_DIRECTORY_SEPARATOR . $dir
1563 )) {
6a488035
TO
1564 $siteDir = $dir;
1565 return $siteDir;
1566 }
1567 }
1568 }
1569 $siteDir = 'default';
1570 }
1571
1572 return $siteDir;
1573}
1574
627456b5
EM
1575/**
1576 * @param $errorTitle
1577 * @param $errorMsg
6a9514e1 1578 * @param $showRefer
627456b5 1579 */
6a9514e1
ML
1580function 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
1f5f3294 1592 include 'error.html';
6a488035
TO
1593 exit();
1594}