Advertisement
Guest User

Untitled

a guest
Jul 15th, 2014
250
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 52.08 KB | None | 0 0
  1. <?php
  2.  
  3. /************************************************************************************
  4. ************************************************************************************
  5. ** **
  6. ** If you can read this text in your browser then you don't have PHP installed. **
  7. ** Please install PHP 5.3.2 or higher, preferably PHP 5.3.4+. **
  8. ** **
  9. ************************************************************************************
  10. ************************************************************************************/
  11.  
  12. /**
  13. * SilverStripe CMS Installer
  14. * This installer doesn't use any of the fancy SilverStripe stuff in case it's unsupported.
  15. */
  16.  
  17. date_default_timezone_set('America/Los_Angeles');
  18.  
  19. // speed up mysql_connect timeout if the server can't be found
  20. ini_set('mysql.connect_timeout', 5);
  21. // Don't die half was through installation; that does more harm than good
  22. ini_set('max_execution_time', 0);
  23.  
  24. // set display_errors php setting to on to force installer to avoid blank screen of death.
  25. // get the original value so it can be used in PHP requirement checks later in this script.
  26. $originalDisplayErrorsValue = ini_get('display_errors');
  27. ini_set('display_errors', '1');
  28.  
  29. error_reporting(E_ALL | E_STRICT);
  30.  
  31. // Attempt to start a session so that the username and password can be sent back to the user.
  32. if(function_exists('session_start') && !session_id()) {
  33. session_start();
  34. }
  35.  
  36. /**
  37. * Include _ss_environment.php file
  38. */
  39. $usingEnv = false;
  40. $envFileExists = false;
  41. //define the name of the environment file
  42. $envFile = '_ss_environment.php';
  43. //define the dirs to start scanning from (have to add the trailing slash)
  44. // we're going to check the realpath AND the path as the script sees it
  45. $dirsToCheck = array(
  46. realpath('.'),
  47. dirname($_SERVER['SCRIPT_FILENAME'])
  48. );
  49. //if they are the same, remove one of them
  50. if($dirsToCheck[0] == $dirsToCheck[1]) {
  51. unset($dirsToCheck[1]);
  52. }
  53. foreach($dirsToCheck as $dir) {
  54. //check this dir and every parent dir (until we hit the base of the drive)
  55. // or until we hit a dir we can't read
  56. do {
  57. //add the trailing slash we need to concatenate properly
  58. $dir .= DIRECTORY_SEPARATOR;
  59. //if it's readable, go ahead
  60. if(@is_readable($dir)) {
  61. //if the file exists, then we include it, set relevant vars and break out
  62. if(file_exists($dir . $envFile)) {
  63. include_once($dir . $envFile);
  64. $envFileExists = true;
  65. //legacy variable assignment
  66. $usingEnv = true;
  67. //break out of BOTH loops because we found the $envFile
  68. break(2);
  69. }
  70. } else {
  71. //break out of the while loop, we can't read the dir
  72. break;
  73. }
  74. //go up a directory
  75. $dir = dirname($dir);
  76. //here we need to check that the path of the last dir and the next one are
  77. // not the same, if they are, we have hit the root of the drive
  78. } while(dirname($dir) != $dir);
  79. }
  80.  
  81. if($envFileExists) {
  82. if(!empty($_REQUEST['useEnv'])) {
  83. $usingEnv = true;
  84. } else {
  85. $usingEnv = false;
  86. }
  87. }
  88.  
  89. require_once FRAMEWORK_NAME . '/core/Constants.php'; // this also includes TempPath.php
  90. require_once FRAMEWORK_NAME . '/dev/install/DatabaseConfigurationHelper.php';
  91. require_once FRAMEWORK_NAME . '/dev/install/DatabaseAdapterRegistry.php';
  92.  
  93. // Set default locale, but try and sniff from the user agent
  94. $defaultLocale = 'en_US';
  95. $locales = array(
  96. 'af_ZA' => 'Afrikaans (South Africa)',
  97. 'ar_EG' => 'Arabic (Egypt)',
  98. 'hy_AM' => 'Armenian (Armenia)',
  99. 'ast_ES' => 'Asturian (Spain)',
  100. 'az_AZ' => 'Azerbaijani (Azerbaijan)',
  101. 'bs_BA' => 'Bosnian (Bosnia and Herzegovina)',
  102. 'bg_BG' => 'Bulgarian (Bulgaria)',
  103. 'ca_ES' => 'Catalan (Spain)',
  104. 'zh_CN' => 'Chinese (China)',
  105. 'zh_TW' => 'Chinese (Taiwan)',
  106. 'hr_HR' => 'Croatian (Croatia)',
  107. 'cs_CZ' => 'Czech (Czech Republic)',
  108. 'da_DK' => 'Danish (Denmark)',
  109. 'nl_NL' => 'Dutch (Netherlands)',
  110. 'en_GB' => 'English (United Kingdom)',
  111. 'en_US' => 'English (United States)',
  112. 'eo_XX' => 'Esperanto',
  113. 'et_EE' => 'Estonian (Estonia)',
  114. 'fo_FO' => 'Faroese (Faroe Islands)',
  115. 'fi_FI' => 'Finnish (Finland)',
  116. 'fr_FR' => 'French (France)',
  117. 'de_DE' => 'German (Germany)',
  118. 'el_GR' => 'Greek (Greece)',
  119. 'he_IL' => 'Hebrew (Israel)',
  120. 'hu_HU' => 'Hungarian (Hungary)',
  121. 'is_IS' => 'Icelandic (Iceland)',
  122. 'id_ID' => 'Indonesian (Indonesia)',
  123. 'it_IT' => 'Italian (Italy)',
  124. 'ja_JP' => 'Japanese (Japan)',
  125. 'km_KH' => 'Khmer (Cambodia)',
  126. 'lc_XX' => 'LOLCAT',
  127. 'lv_LV' => 'Latvian (Latvia)',
  128. 'lt_LT' => 'Lithuanian (Lithuania)',
  129. 'ms_MY' => 'Malay (Malaysia)',
  130. 'mi_NZ' => 'Maori (New Zealand)',
  131. 'ne_NP' => 'Nepali (Nepal)',
  132. 'nb_NO' => 'Norwegian',
  133. 'fa_IR' => 'Persian (Iran)',
  134. 'pl_PL' => 'Polish (Poland)',
  135. 'pt_BR' => 'Portuguese (Brazil)',
  136. 'pa_IN' => 'Punjabi (India)',
  137. 'ro_RO' => 'Romanian (Romania)',
  138. 'ru_RU' => 'Russian (Russia)',
  139. 'sr_RS' => 'Serbian (Serbia)',
  140. 'si_LK' => 'Sinhalese (Sri Lanka)',
  141. 'sk_SK' => 'Slovak (Slovakia)',
  142. 'sl_SI' => 'Slovenian (Slovenia)',
  143. 'es_AR' => 'Spanish (Argentina)',
  144. 'es_MX' => 'Spanish (Mexico)',
  145. 'es_ES' => 'Spanish (Spain)',
  146. 'sv_SE' => 'Swedish (Sweden)',
  147. 'th_TH' => 'Thai (Thailand)',
  148. 'tr_TR' => 'Turkish (Turkey)',
  149. 'uk_UA' => 'Ukrainian (Ukraine)',
  150. 'uz_UZ' => 'Uzbek (Uzbekistan)',
  151. 'vi_VN' => 'Vietnamese (Vietnam)',
  152. );
  153.  
  154. // Discover which databases are available
  155. DatabaseAdapterRegistry::autodiscover();
  156.  
  157. // Determine which external database modules are USABLE
  158. foreach(DatabaseAdapterRegistry::get_adapters() as $class => $details) {
  159. $databaseClasses[$class] = $details;
  160. if(file_exists($details['helperPath'])) {
  161. $databaseClasses[$class]['hasModule'] = true;
  162. include_once($details['helperPath']);
  163. } else {
  164. $databaseClasses[$class]['hasModule'] = false;
  165. }
  166. }
  167.  
  168. // Load database config
  169. if(isset($_REQUEST['db'])) {
  170. if(isset($_REQUEST['db']['type'])) $type = $_REQUEST['db']['type'];
  171. else $type = $_REQUEST['db']['type'] = defined('SS_DATABASE_CLASS') ? SS_DATABASE_CLASS : 'MySQLDatabase';
  172.  
  173. // Disabled inputs don't submit anything - we need to use the environment (except the database name)
  174. if($usingEnv) {
  175. $_REQUEST['db'][$type] = $databaseConfig = array(
  176. "type" => defined('SS_DATABASE_CLASS') ? SS_DATABASE_CLASS : $type,
  177. "server" => defined('SS_DATABASE_SERVER') ? SS_DATABASE_SERVER : "localhost",
  178. "username" => defined('SS_DATABASE_USERNAME') ? SS_DATABASE_USERNAME : "root",
  179. "password" => defined('SS_DATABASE_PASSWORD') ? SS_DATABASE_PASSWORD : "",
  180. "database" => $_REQUEST['db'][$type]['database'],
  181. );
  182.  
  183. } else {
  184. // Normal behaviour without the environment
  185. $databaseConfig = $_REQUEST['db'][$type];
  186. $databaseConfig['type'] = $type;
  187. }
  188. } else {
  189. $type = $_REQUEST['db']['type'] = defined('SS_DATABASE_CLASS') ? SS_DATABASE_CLASS : 'MySQLDatabase';
  190. $_REQUEST['db'][$type] = $databaseConfig = array(
  191. "type" => $type,
  192. "server" => defined('SS_DATABASE_SERVER') ? SS_DATABASE_SERVER : "localhost",
  193. "username" => defined('SS_DATABASE_USERNAME') ? SS_DATABASE_USERNAME : "root",
  194. "password" => defined('SS_DATABASE_PASSWORD') ? SS_DATABASE_PASSWORD : "",
  195. "database" => isset($_SERVER['argv'][2]) ? $_SERVER['argv'][2] : "SS_mysite",
  196. );
  197. }
  198.  
  199. if(isset($_REQUEST['admin'])) {
  200. // Disabled inputs don't submit anything - we need to use the environment (except the database name)
  201. if($usingEnv) {
  202. $_REQUEST['admin'] = $adminConfig = array(
  203. 'username' => defined('SS_DEFAULT_ADMIN_USERNAME') ? SS_DEFAULT_ADMIN_USERNAME : 'admin',
  204. 'password' => defined('SS_DEFAULT_ADMIN_PASSWORD') ? SS_DEFAULT_ADMIN_PASSWORD : '',
  205. );
  206. } else {
  207. $adminConfig = $_REQUEST['admin'];
  208. }
  209. } else {
  210. $_REQUEST['admin'] = $adminConfig = array(
  211. 'username' => defined('SS_DEFAULT_ADMIN_USERNAME') ? SS_DEFAULT_ADMIN_USERNAME : 'admin',
  212. 'password' => defined('SS_DEFAULT_ADMIN_PASSWORD') ? SS_DEFAULT_ADMIN_PASSWORD : '',
  213. );
  214. }
  215.  
  216. $alreadyInstalled = false;
  217. if(file_exists('mysite/_config.php')) {
  218. // Find the $database variable in the relevant config file without having to execute the config file
  219. if(preg_match("/\\\$database\s*=\s*[^\n\r]+[\n\r]/", file_get_contents("mysite/_config.php"), $parts)) {
  220. eval($parts[0]);
  221. if($database) $alreadyInstalled = true;
  222. // Assume that if $databaseConfig is defined in mysite/_config.php, then a non-environment-based installation has
  223. // already gone ahead
  224. } else if(preg_match("/\\\$databaseConfig\s*=\s*[^\n\r]+[\n\r]/", file_get_contents("mysite/_config.php"), $parts)) {
  225. $alreadyInstalled = true;
  226. }
  227. }
  228.  
  229. if(file_exists(FRAMEWORK_NAME . '/silverstripe_version')) {
  230. $silverstripe_version = file_get_contents(FRAMEWORK_NAME . '/silverstripe_version');
  231. } else {
  232. $silverstripe_version = "unknown";
  233. }
  234.  
  235. // Check requirements
  236. $req = new InstallRequirements();
  237. $req->check();
  238.  
  239. $webserverConfigFile = '';
  240. if($req->isIIS()) {
  241. $webserverConfigFile = 'web.config';
  242. } else {
  243. $webserverConfigFile = '.htaccess';
  244. }
  245.  
  246. if($req->hasErrors()) {
  247. $hasErrorOtherThanDatabase = true;
  248. $phpIniLocation = php_ini_loaded_file();
  249. }
  250.  
  251. if($databaseConfig) {
  252. $dbReq = new InstallRequirements();
  253. $dbReq->checkDatabase($databaseConfig);
  254. }
  255.  
  256. if($adminConfig) {
  257. $adminReq = new InstallRequirements();
  258. $adminReq->checkAdminConfig($adminConfig);
  259. }
  260.  
  261. // Actual processor
  262. $installFromCli = (isset($_SERVER['argv'][1]) && $_SERVER['argv'][1] == 'install');
  263.  
  264. // CLI-install error message. exit(1) will halt any makefile.
  265. if($installFromCli && ($req->hasErrors() || $dbReq->hasErrors())) {
  266. echo "Cannot install due to errors:\n";
  267. $req->listErrors();
  268. $dbReq->listErrors();
  269. exit(1);
  270. }
  271.  
  272. if((isset($_REQUEST['go']) || $installFromCli) && !$req->hasErrors() && !$dbReq->hasErrors() && $adminConfig['username'] && $adminConfig['password']) {
  273. // Confirm before reinstalling
  274. if(!$installFromCli && $alreadyInstalled) {
  275. include(FRAMEWORK_NAME . '/dev/install/config-form.html');
  276.  
  277. } else {
  278. $inst = new Installer();
  279. if($_REQUEST) $inst->install($_REQUEST);
  280. else $inst->install(array(
  281. 'db' => $databaseConfig,
  282. 'admin' => $adminConfig,
  283. ));
  284. }
  285.  
  286. // Show the config form
  287. } else {
  288. include(FRAMEWORK_NAME . '/dev/install/config-form.html');
  289. }
  290.  
  291. /**
  292. * This class checks requirements
  293. * Each of the requireXXX functions takes an argument which gives a user description of the test.
  294. * It's an array of 3 parts:
  295. * $description[0] - The test catetgory
  296. * $description[1] - The test title
  297. * $description[2] - The test error to show, if it goes wrong
  298. */
  299. class InstallRequirements {
  300. var $errors, $warnings, $tests;
  301.  
  302. /**
  303. * Check the database configuration. These are done one after another
  304. * starting with checking the database function exists in PHP, and
  305. * continuing onto more difficult checks like database permissions.
  306. */
  307. function checkDatabase($databaseConfig) {
  308. if($this->requireDatabaseFunctions(
  309. $databaseConfig,
  310. array(
  311. "Database Configuration",
  312. "Database support",
  313. "Database support in PHP",
  314. $this->getDatabaseTypeNice($databaseConfig['type'])
  315. )
  316. )) {
  317. if($this->requireDatabaseServer(
  318. $databaseConfig,
  319. array(
  320. "Database Configuration",
  321. "Database server",
  322. $databaseConfig['type'] == 'SQLiteDatabase' ? "I couldn't write to path '$databaseConfig[path]'" : "I couldn't find a database server on '$databaseConfig[server]'",
  323. $databaseConfig['type'] == 'SQLiteDatabase' ? $databaseConfig['path'] : $databaseConfig['server']
  324. )
  325. )) {
  326. if($this->requireDatabaseConnection(
  327. $databaseConfig,
  328. array(
  329. "Database Configuration",
  330. "Database access credentials",
  331. "That username/password doesn't work"
  332. )
  333. )) {
  334. if($this->requireDatabaseVersion(
  335. $databaseConfig,
  336. array(
  337. "Database Configuration",
  338. "Database server version requirement",
  339. '',
  340. 'Version ' . $this->getDatabaseConfigurationHelper($databaseConfig['type'])->getDatabaseVersion($databaseConfig)
  341. )
  342. )) {
  343. $this->requireDatabaseOrCreatePermissions(
  344. $databaseConfig,
  345. array(
  346. "Database Configuration",
  347. "Can I access/create the database",
  348. "I can't create new databases and the database '$databaseConfig[database]' doesn't exist"
  349. )
  350. );
  351. }
  352. }
  353. }
  354. }
  355. }
  356.  
  357. function checkAdminConfig($adminConfig) {
  358. if(!$adminConfig['username']) {
  359. $this->error(array('', 'Please enter a username!'));
  360. }
  361. if(!$adminConfig['password']) {
  362. $this->error(array('', 'Please enter a password!'));
  363. }
  364. }
  365.  
  366. /**
  367. * Check if the web server is IIS and version greater than the given version.
  368. * @return boolean
  369. */
  370. function isIIS($fromVersion = 7) {
  371. if(strpos($this->findWebserver(), 'IIS/') === false) {
  372. return false;
  373. }
  374. return substr(strstr($this->findWebserver(), '/'), -3, 1) >= $fromVersion;
  375. }
  376.  
  377. function isApache() {
  378. if(strpos($this->findWebserver(), 'Apache') !== false) {
  379. return true;
  380. } else {
  381. return false;
  382. }
  383. }
  384.  
  385. /**
  386. * Find the webserver software running on the PHP host.
  387. * @return string|boolean Server software or boolean FALSE
  388. */
  389. function findWebserver() {
  390. // Try finding from SERVER_SIGNATURE or SERVER_SOFTWARE
  391. if(!empty($_SERVER['SERVER_SIGNATURE'])) {
  392. $webserver = $_SERVER['SERVER_SIGNATURE'];
  393. } elseif(!empty($_SERVER['SERVER_SOFTWARE'])) {
  394. $webserver = $_SERVER['SERVER_SOFTWARE'];
  395. } else {
  396. return false;
  397. }
  398.  
  399. return strip_tags(trim($webserver));
  400. }
  401.  
  402. /**
  403. * Check everything except the database
  404. */
  405. function check() {
  406. $this->errors = null;
  407. $isApache = $this->isApache();
  408. $isIIS = $this->isIIS();
  409. $webserver = $this->findWebserver();
  410.  
  411. $this->requirePHPVersion('5.3.4', '5.3.2', array(
  412. "PHP Configuration",
  413. "PHP5 installed",
  414. null,
  415. "PHP version " . phpversion()
  416. ));
  417.  
  418. // Check that we can identify the root folder successfully
  419. $this->requireFile(FRAMEWORK_NAME . '/dev/install/config-form.html', array("File permissions",
  420. "Does the webserver know where files are stored?",
  421. "The webserver isn't letting me identify where files are stored.",
  422. $this->getBaseDir()
  423. ));
  424.  
  425. $this->requireModule('mysite', array("File permissions", "mysite/ directory exists?"));
  426. $this->requireModule(FRAMEWORK_NAME, array("File permissions", FRAMEWORK_NAME . "/ directory exists?"));
  427.  
  428. if($isApache) {
  429. $this->checkApacheVersion(array(
  430. "Webserver Configuration",
  431. "Webserver is not Apache 1.x", "SilverStripe requires Apache version 2 or greater",
  432. $webserver
  433. ));
  434. $this->requireWriteable('.htaccess', array("File permissions", "Is the .htaccess file writeable?", null));
  435. } elseif($isIIS) {
  436. $this->requireWriteable('web.config', array("File permissions", "Is the web.config file writeable?", null));
  437. }
  438.  
  439. $this->requireWriteable('mysite/_config.php', array(
  440. "File permissions",
  441. "Is the mysite/_config.php file writeable?",
  442. null
  443. ));
  444. if(!$this->checkModuleExists('cms')) {
  445. $this->requireWriteable('mysite/code/RootURLController.php', array(
  446. "File permissions",
  447. "Is the mysite/code/RootURLController.php file writeable?",
  448. null
  449. ));
  450. }
  451. $this->requireWriteable('assets', array("File permissions", "Is the assets/ directory writeable?", null));
  452.  
  453. try {
  454. $tempFolder = getTempFolder();
  455. } catch(Exception $e) {
  456. $tempFolder = false;
  457. }
  458.  
  459. $this->requireTempFolder(array('File permissions', 'Is a temporary directory available?', null, $tempFolder));
  460. if($tempFolder) {
  461. // in addition to the temp folder being available, check it is writable
  462. $this->requireWriteable($tempFolder, array(
  463. "File permissions",
  464. sprintf("Is the temporary directory writeable?", $tempFolder),
  465. null
  466. ), true);
  467. }
  468.  
  469. // Check for web server, unless we're calling the installer from the command-line
  470. $this->isRunningWebServer(array("Webserver Configuration", "Server software", "Unknown", $webserver));
  471.  
  472. if($isApache) {
  473. $this->requireApacheRewriteModule('mod_rewrite', array(
  474. "Webserver Configuration",
  475. "URL rewriting support",
  476. "You need mod_rewrite to use friendly URLs with SilverStripe, but it is not enabled."
  477. ));
  478. } elseif($isIIS) {
  479. $this->requireIISRewriteModule('IIS_UrlRewriteModule', array(
  480. "Webserver Configuration",
  481. "URL rewriting support",
  482. "You need to enable the IIS URL Rewrite Module to use friendly URLs with SilverStripe, "
  483. . "but it is not installed or enabled. Download it for IIS 7 from http://www.iis.net/expand/URLRewrite"
  484. ));
  485. } else {
  486. $this->warning(array(
  487. "Webserver Configuration",
  488. "URL rewriting support",
  489. "I can't tell whether any rewriting module is running. You may need to configure a rewriting rule yourself."));
  490. }
  491.  
  492. $this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
  493. "Webserver Configuration",
  494. "Recognised webserver",
  495. "You seem to be using an unsupported webserver. "
  496. . "The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."
  497. ));
  498.  
  499. $this->requirePostSupport(array(
  500. "Webserver Configuration",
  501. "POST Support",
  502. 'I can\'t find $_POST, make sure POST is enabled.'
  503. ));
  504.  
  505. // Check for GD support
  506. if(!$this->requireFunction("imagecreatetruecolor", array(
  507. "PHP Configuration",
  508. "GD2 support",
  509. "PHP must have GD version 2."
  510. ))) {
  511. $this->requireFunction("imagecreate", array(
  512. "PHP Configuration",
  513. "GD2 support",
  514. "GD support for PHP not included."
  515. ));
  516. }
  517.  
  518. // Check for XML support
  519. $this->requireFunction('xml_set_object', array(
  520. "PHP Configuration",
  521. "XML support",
  522. "XML support not included in PHP."
  523. ));
  524. $this->requireClass('DOMDocument', array(
  525. "PHP Configuration",
  526. "DOM/XML support",
  527. "DOM/XML support not included in PHP."
  528. ));
  529. $this->requireFunction('simplexml_load_file', array(
  530. 'PHP Configuration',
  531. 'SimpleXML support',
  532. 'SimpleXML support not included in PHP.'
  533. ));
  534.  
  535. // Check for token_get_all
  536. $this->requireFunction('token_get_all', array(
  537. "PHP Configuration",
  538. "Tokenizer support",
  539. "Tokenizer support not included in PHP."
  540. ));
  541.  
  542. // Check for CType support
  543. $this->requireFunction('ctype_digit', array(
  544. 'PHP Configuration',
  545. 'CType support',
  546. 'CType support not included in PHP.'
  547. ));
  548.  
  549. // Check for session support
  550. $this->requireFunction('session_start', array(
  551. 'PHP Configuration',
  552. 'Session support',
  553. 'Session support not included in PHP.'
  554. ));
  555.  
  556. // Check for iconv support
  557. $this->requireFunction('iconv', array(
  558. 'PHP Configuration',
  559. 'iconv support',
  560. 'iconv support not included in PHP.'
  561. ));
  562.  
  563. // Check for hash support
  564. $this->requireFunction('hash', array('PHP Configuration', 'hash support', 'hash support not included in PHP.'));
  565.  
  566. // Check for mbstring support
  567. $this->requireFunction('mb_internal_encoding', array(
  568. 'PHP Configuration',
  569. 'mbstring support',
  570. 'mbstring support not included in PHP.'
  571. ));
  572.  
  573. // Check for Reflection support
  574. $this->requireClass('ReflectionClass', array(
  575. 'PHP Configuration',
  576. 'Reflection support',
  577. 'Reflection support not included in PHP.'
  578. ));
  579.  
  580. // Check for Standard PHP Library (SPL) support
  581. $this->requireFunction('spl_classes', array(
  582. 'PHP Configuration',
  583. 'SPL support',
  584. 'Standard PHP Library (SPL) not included in PHP.'
  585. ));
  586.  
  587. $this->requireDateTimezone(array(
  588. 'PHP Configuration',
  589. 'date.timezone setting and validity',
  590. 'date.timezone option in php.ini must be set correctly.',
  591. ini_get('date.timezone')
  592. ));
  593.  
  594. $this->suggestClass('finfo', array(
  595. 'PHP Configuration',
  596. 'fileinfo support',
  597. 'fileinfo should be enabled in PHP. SilverStripe uses it for MIME type detection of files. '
  598. . 'SilverStripe will still operate, but email attachments and sending files to browser '
  599. . '(e.g. export data to CSV) may not work correctly without finfo.'
  600. ));
  601.  
  602. $this->suggestFunction('curl_init', array(
  603. 'PHP Configuration',
  604. 'curl support',
  605. 'curl should be enabled in PHP. SilverStripe uses it for consuming web services'
  606. . ' via the RestfulService class and many modules rely on it.'
  607. ));
  608.  
  609. $this->suggestClass('tidy', array(
  610. 'PHP Configuration',
  611. 'tidy support',
  612. 'Tidy provides a library of code to clean up your html. '
  613. . 'SilverStripe will operate fine without tidy but HTMLCleaner will not be effective.'
  614. ));
  615.  
  616. $this->suggestPHPSetting('asp_tags', array(false), array(
  617. 'PHP Configuration',
  618. 'asp_tags option',
  619. 'This should be turned off as it can cause issues with SilverStripe'
  620. ));
  621. $this->requirePHPSetting('magic_quotes_gpc', array(false), array(
  622. 'PHP Configuration',
  623. 'magic_quotes_gpc option',
  624. 'This should be turned off, as it can cause issues with cookies. '
  625. . 'More specifically, unserializing data stored in cookies.'
  626. ));
  627. $this->suggestPHPSetting('display_errors', array(false), array(
  628. 'PHP Configuration',
  629. 'display_errors option',
  630. 'Unless you\'re in a development environment, this should be turned off, '
  631. . 'as it can expose sensitive data to website users.'
  632. ));
  633. // on some weirdly configured webservers arg_separator.output is set to &amp;
  634. // which will results in links like ?param=value&amp;foo=bar which will not be i
  635. $this->suggestPHPSetting('arg_separator.output', array('&', ''), array(
  636. 'PHP Configuration',
  637. 'arg_separator.output option',
  638. 'This option defines how URL parameters are concatenated. '
  639. . 'If not set to \'&\' this may cause issues with URL GET parameters'
  640. ));
  641.  
  642. // Check memory allocation
  643. $this->requireMemory(32 * 1024 * 1024, 64 * 1024 * 1024, array(
  644. "PHP Configuration",
  645. "Memory allocation (PHP config option 'memory_limit')",
  646. "SilverStripe needs a minimum of 32M allocated to PHP, but recommends 64M.",
  647. ini_get("memory_limit")
  648. ));
  649.  
  650. return $this->errors;
  651. }
  652.  
  653. function suggestPHPSetting($settingName, $settingValues, $testDetails) {
  654. $this->testing($testDetails);
  655.  
  656. // special case for display_errors, check the original value before
  657. // it was changed at the start of this script.
  658. if($settingName == 'display_errors') {
  659. global $originalDisplayErrorsValue;
  660. $val = $originalDisplayErrorsValue;
  661. } else {
  662. $val = ini_get($settingName);
  663. }
  664.  
  665. if(!in_array($val, $settingValues) && $val != $settingValues) {
  666. $testDetails[2] = "$settingName is set to '$val' in php.ini. $testDetails[2]";
  667. $this->warning($testDetails);
  668. }
  669. }
  670.  
  671. function requirePHPSetting($settingName, $settingValues, $testDetails) {
  672. $this->testing($testDetails);
  673.  
  674. $val = ini_get($settingName);
  675. if(!in_array($val, $settingValues) && $val != $settingValues) {
  676. $testDetails[2] = "$settingName is set to '$val' in php.ini. $testDetails[2]";
  677. $this->error($testDetails);
  678. }
  679. }
  680.  
  681. function suggestClass($class, $testDetails) {
  682. $this->testing($testDetails);
  683.  
  684. if(!class_exists($class)) {
  685. $this->warning($testDetails);
  686. }
  687. }
  688.  
  689. function suggestFunction($class, $testDetails) {
  690. $this->testing($testDetails);
  691.  
  692. if(!function_exists($class)) {
  693. $this->warning($testDetails);
  694. }
  695. }
  696.  
  697. function requireDateTimezone($testDetails) {
  698. $this->testing($testDetails);
  699.  
  700. $result = ini_get('date.timezone') && in_array(ini_get('date.timezone'), timezone_identifiers_list());
  701. if(!$result) {
  702. $this->error($testDetails);
  703. }
  704. }
  705.  
  706. function requireMemory($min, $recommended, $testDetails) {
  707. $_SESSION['forcemem'] = false;
  708.  
  709. $mem = $this->getPHPMemory();
  710. if($mem < (64 * 1024 * 1024)) {
  711. ini_set('memory_limit', '64M');
  712. $mem = $this->getPHPMemory();
  713. $testDetails[3] = ini_get("memory_limit");
  714. }
  715.  
  716. $this->testing($testDetails);
  717.  
  718. if($mem < $min && $mem > 0) {
  719. $testDetails[2] .= " You only have " . ini_get("memory_limit") . " allocated";
  720. $this->error($testDetails);
  721. } else if($mem < $recommended && $mem > 0) {
  722. $testDetails[2] .= " You only have " . ini_get("memory_limit") . " allocated";
  723. $this->warning($testDetails);
  724. } elseif($mem == 0) {
  725. $testDetails[2] .= " We can't determine how much memory you have allocated. "
  726. . "Install only if you're sure you've allocated at least 20 MB.";
  727. $this->warning($testDetails);
  728. }
  729. }
  730.  
  731. function getPHPMemory() {
  732. $memString = ini_get("memory_limit");
  733.  
  734. switch(strtolower(substr($memString, -1))) {
  735. case "k":
  736. return round(substr($memString, 0, -1) * 1024);
  737.  
  738. case "m":
  739. return round(substr($memString, 0, -1) * 1024 * 1024);
  740.  
  741. case "g":
  742. return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
  743.  
  744. default:
  745. return round($memString);
  746. }
  747. }
  748.  
  749. function listErrors() {
  750. if($this->errors) {
  751. echo "<p>The following problems are preventing me from installing SilverStripe CMS:</p>\n\n";
  752. foreach($this->errors as $error) {
  753. echo "<li>" . htmlentities(implode(", ", $error), ENT_COMPAT, 'UTF-8') . "</li>\n";
  754. }
  755. }
  756. }
  757.  
  758. function showTable($section = null) {
  759. if($section) {
  760. $tests = $this->tests[$section];
  761. $id = strtolower(str_replace(' ', '_', $section));
  762. echo "<table id=\"{$id}_results\" class=\"testResults\" width=\"100%\">";
  763. foreach($tests as $test => $result) {
  764. echo "<tr class=\"$result[0]\"><td>$test</td><td>"
  765. . nl2br(htmlentities($result[1], ENT_COMPAT, 'UTF-8')) . "</td></tr>";
  766. }
  767. echo "</table>";
  768.  
  769. } else {
  770. foreach($this->tests as $section => $tests) {
  771. $failedRequirements = 0;
  772. $warningRequirements = 0;
  773.  
  774. $output = "";
  775.  
  776. foreach($tests as $test => $result) {
  777. if(isset($result['0'])) {
  778. switch($result['0']) {
  779. case 'error':
  780. $failedRequirements++;
  781. break;
  782. case 'warning':
  783. $warningRequirements++;
  784. break;
  785. }
  786. }
  787. $output .= "<tr class=\"$result[0]\"><td>$test</td><td>"
  788. . nl2br(htmlentities($result[1], ENT_COMPAT, 'UTF-8')) . "</td></tr>";
  789. }
  790. $className = "good";
  791. $text = "All Requirements Pass";
  792. $pluralWarnings = ($warningRequirements == 1) ? 'Warning' : 'Warnings';
  793.  
  794. if($failedRequirements > 0) {
  795. $className = "error";
  796. $pluralWarnings = ($warningRequirements == 1) ? 'Warning' : 'Warnings';
  797.  
  798. $text = $failedRequirements . ' Failed and ' . $warningRequirements . ' ' . $pluralWarnings;
  799. } else if($warningRequirements > 0) {
  800. $className = "warning";
  801. $text = "All Requirements Pass but " . $warningRequirements . ' ' . $pluralWarnings;
  802. }
  803.  
  804. echo "<h5 class='requirement $className'>$section <a href='#'>Show All Requirements</a> <span>$text</span></h5>";
  805. echo "<table class=\"testResults\">";
  806. echo $output;
  807. echo "</table>";
  808. }
  809. }
  810. }
  811.  
  812. function requireFunction($funcName, $testDetails) {
  813. $this->testing($testDetails);
  814.  
  815. if(!function_exists($funcName)) {
  816. $this->error($testDetails);
  817. } else {
  818. return true;
  819. }
  820. }
  821.  
  822. function requireClass($className, $testDetails) {
  823. $this->testing($testDetails);
  824. if(!class_exists($className)) {
  825. $this->error($testDetails);
  826. } else {
  827. return false;
  828. }
  829. }
  830.  
  831. /**
  832. * Require that the given class doesn't exist
  833. */
  834. function requireNoClasses($classNames, $testDetails) {
  835. $this->testing($testDetails);
  836. $badClasses = array();
  837. foreach($classNames as $className) {
  838. if(class_exists($className)) $badClasses[] = $className;
  839. }
  840. if($badClasses) {
  841. $testDetails[2] .= ". The following classes are at fault: " . implode(', ', $badClasses);
  842. $this->error($testDetails);
  843. } else {
  844. return true;
  845. }
  846. }
  847.  
  848. function checkApacheVersion($testDetails) {
  849. $this->testing($testDetails);
  850.  
  851. $is1pointx = preg_match('#Apache[/ ]1\.#', $testDetails[3]);
  852. if($is1pointx) {
  853. $this->error($testDetails);
  854. }
  855.  
  856. return true;
  857. }
  858.  
  859. function requirePHPVersion($recommendedVersion, $requiredVersion, $testDetails) {
  860. $this->testing($testDetails);
  861.  
  862. $installedVersion = phpversion();
  863.  
  864. if(version_compare($installedVersion, $requiredVersion, '<')) {
  865. $testDetails[2] = "SilverStripe requires PHP version $requiredVersion or later.\n
  866. PHP version $installedVersion is currently installed.\n
  867. While SilverStripe requires at least PHP version $requiredVersion, upgrading to $recommendedVersion or later is recommended.\n
  868. If you are installing SilverStripe on a shared web server, please ask your web hosting provider to upgrade PHP for you.";
  869. $this->error($testDetails);
  870. return;
  871. }
  872.  
  873. if(version_compare($installedVersion, $recommendedVersion, '<')) {
  874. $testDetails[2] = "PHP version $installedVersion is currently installed.\n
  875. Upgrading to at least PHP version $recommendedVersion is recommended.\n
  876. SilverStripe should run, but you may run into issues. Future releases may require a later version of PHP.\n";
  877. $this->warning($testDetails);
  878. return;
  879. }
  880.  
  881. return true;
  882. }
  883.  
  884. /**
  885. * Check that a module exists
  886. */
  887. function checkModuleExists($dirname) {
  888. $path = $this->getBaseDir() . $dirname;
  889. return file_exists($path) && ($dirname == 'mysite' || file_exists($path . '/_config.php'));
  890. }
  891.  
  892. /**
  893. * The same as {@link requireFile()} but does additional checks
  894. * to ensure the module directory is intact.
  895. */
  896. function requireModule($dirname, $testDetails) {
  897. $this->testing($testDetails);
  898. $path = $this->getBaseDir() . $dirname;
  899. if(!file_exists($path)) {
  900. $testDetails[2] .= " Directory '$path' not found. Please make sure you have uploaded the SilverStripe files to your webserver correctly.";
  901. $this->error($testDetails);
  902. } elseif(!file_exists($path . '/_config.php') && $dirname != 'mysite') {
  903. $testDetails[2] .= " Directory '$path' exists, but is missing files. Please make sure you have uploaded "
  904. . "the SilverStripe files to your webserver correctly.";
  905. $this->error($testDetails);
  906. }
  907. }
  908.  
  909. function requireFile($filename, $testDetails) {
  910. $this->testing($testDetails);
  911. $filename = $this->getBaseDir() . $filename;
  912. if(!file_exists($filename)) {
  913. $testDetails[2] .= " (file '$filename' not found)";
  914. $this->error($testDetails);
  915. }
  916. }
  917.  
  918. function requireWriteable($filename, $testDetails, $absolute = false) {
  919. $this->testing($testDetails);
  920.  
  921. if($absolute) {
  922. $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
  923. } else {
  924. $filename = $this->getBaseDir() . str_replace('/', DIRECTORY_SEPARATOR, $filename);
  925. }
  926.  
  927. if(file_exists($filename)) $isWriteable = is_writeable($filename);
  928. else $isWriteable = is_writeable(dirname($filename));
  929.  
  930. if(!$isWriteable) {
  931. if(function_exists('posix_getgroups')) {
  932. $userID = posix_geteuid();
  933. $user = posix_getpwuid($userID);
  934.  
  935. $currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename));
  936. $currentOwner = posix_getpwuid($currentOwnerID);
  937.  
  938. $testDetails[2] .= "User '$user[name]' needs to be able to write to this file:\n$filename\n\nThe "
  939. . "file is currently owned by '$currentOwner[name]'. ";
  940.  
  941. if($user['name'] == $currentOwner['name']) {
  942. $testDetails[2] .= "We recommend that you make the file writeable.";
  943. } else {
  944.  
  945. $groups = posix_getgroups();
  946. $groupList = array();
  947. foreach($groups as $group) {
  948. $groupInfo = posix_getgrgid($group);
  949. if(in_array($currentOwner['name'], $groupInfo['members'])) $groupList[] = $groupInfo['name'];
  950. }
  951. if($groupList) {
  952. $testDetails[2] .= " We recommend that you make the file group-writeable "
  953. . "and change the group to one of these groups:\n - " . implode("\n - ", $groupList)
  954. . "\n\nFor example:\nchmod g+w $filename\nchgrp " . $groupList[0] . " $filename";
  955. } else {
  956. $testDetails[2] .= " There is no user-group that contains both the web-server user and the "
  957. . "owner of this file. Change the ownership of the file, create a new group, or "
  958. . "temporarily make the file writeable by everyone during the install process.";
  959. }
  960. }
  961.  
  962. } else {
  963. $testDetails[2] .= "The webserver user needs to be able to write to this file:\n$filename";
  964. }
  965.  
  966. $this->error($testDetails);
  967. }
  968. }
  969.  
  970. function requireTempFolder($testDetails) {
  971. $this->testing($testDetails);
  972.  
  973. try {
  974. $tempFolder = getTempFolder();
  975. } catch(Exception $e) {
  976. $tempFolder = false;
  977. }
  978.  
  979. if(!$tempFolder) {
  980. $testDetails[2] = "Permission problem gaining access to a temp directory. " .
  981. "Please create a folder named silverstripe-cache in the base directory " .
  982. "of the installation and ensure it has the adequate permissions.";
  983. $this->error($testDetails);
  984. }
  985. }
  986.  
  987. function requireApacheModule($moduleName, $testDetails) {
  988. $this->testing($testDetails);
  989. if(!in_array($moduleName, apache_get_modules())) {
  990. $this->error($testDetails);
  991. return false;
  992. } else {
  993. return true;
  994. }
  995. }
  996.  
  997. function testApacheRewriteExists($moduleName = 'mod_rewrite') {
  998. if(function_exists('apache_get_modules') && in_array($moduleName, apache_get_modules())) {
  999. return true;
  1000. } elseif(isset($_SERVER['HTTP_MOD_REWRITE']) && $_SERVER['HTTP_MOD_REWRITE'] == 'On') {
  1001. return true;
  1002. } else {
  1003. return false;
  1004. }
  1005. }
  1006.  
  1007. function testIISRewriteModuleExists($moduleName = 'IIS_UrlRewriteModule') {
  1008. if(isset($_SERVER[$moduleName]) && $_SERVER[$moduleName]) {
  1009. return true;
  1010. } else {
  1011. return false;
  1012. }
  1013. }
  1014.  
  1015. function requireApacheRewriteModule($moduleName, $testDetails) {
  1016. $this->testing($testDetails);
  1017. if($this->testApacheRewriteExists()) {
  1018. return true;
  1019. } else {
  1020. $this->warning($testDetails);
  1021. return false;
  1022. }
  1023. }
  1024.  
  1025. /**
  1026. * Determines if the web server has any rewriting capability.
  1027. * @return boolean
  1028. */
  1029. function hasRewritingCapability() {
  1030. return ($this->testApacheRewriteExists() || $this->testIISRewriteModuleExists());
  1031. }
  1032.  
  1033. function requireIISRewriteModule($moduleName, $testDetails) {
  1034. $this->testing($testDetails);
  1035. if($this->testIISRewriteModuleExists()) {
  1036. return true;
  1037. } else {
  1038. $this->warning($testDetails);
  1039. return false;
  1040. }
  1041. }
  1042.  
  1043. function getDatabaseTypeNice($databaseClass) {
  1044. return substr($databaseClass, 0, -8);
  1045. }
  1046.  
  1047. /**
  1048. * Get an instance of a helper class for the specific database.
  1049. * @param string $databaseClass e.g. MySQLDatabase or MSSQLDatabase
  1050. */
  1051. function getDatabaseConfigurationHelper($databaseClass) {
  1052. $adapters = DatabaseAdapterRegistry::get_adapters();
  1053. if(isset($adapters[$databaseClass])) {
  1054. $helperPath = $adapters[$databaseClass]['helperPath'];
  1055. $class = str_replace('.php', '', basename($helperPath));
  1056. }
  1057. return (class_exists($class)) ? new $class() : false;
  1058. }
  1059.  
  1060. function requireDatabaseFunctions($databaseConfig, $testDetails) {
  1061. $this->testing($testDetails);
  1062. $helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
  1063. if (!$helper) {
  1064. $this->error("Couldn't load database helper code for ". $databaseConfig['type']);
  1065. return false;
  1066. }
  1067. $result = $helper->requireDatabaseFunctions($databaseConfig);
  1068. if($result) {
  1069. return true;
  1070. } else {
  1071. $this->error($testDetails);
  1072. return false;
  1073. }
  1074. }
  1075.  
  1076. function requireDatabaseConnection($databaseConfig, $testDetails) {
  1077. $this->testing($testDetails);
  1078. $helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
  1079. $result = $helper->requireDatabaseConnection($databaseConfig);
  1080. if($result['success']) {
  1081. return true;
  1082. } else {
  1083. $testDetails[2] .= ": " . $result['error'];
  1084. $this->error($testDetails);
  1085. return false;
  1086. }
  1087. }
  1088.  
  1089. function requireDatabaseVersion($databaseConfig, $testDetails) {
  1090. $this->testing($testDetails);
  1091. $helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
  1092. if(method_exists($helper, 'requireDatabaseVersion')) {
  1093. $result = $helper->requireDatabaseVersion($databaseConfig);
  1094. if($result['success']) {
  1095. return true;
  1096. } else {
  1097. $testDetails[2] .= $result['error'];
  1098. $this->warning($testDetails);
  1099. return false;
  1100. }
  1101. }
  1102. // Skipped test because this database has no required version
  1103. return true;
  1104. }
  1105.  
  1106. function requireDatabaseServer($databaseConfig, $testDetails) {
  1107. $this->testing($testDetails);
  1108. $helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
  1109. $result = $helper->requireDatabaseServer($databaseConfig);
  1110. if($result['success']) {
  1111. return true;
  1112. } else {
  1113. $testDetails[2] .= ": " . $result['error'];
  1114. $this->error($testDetails);
  1115. return false;
  1116. }
  1117. }
  1118.  
  1119. function requireDatabaseOrCreatePermissions($databaseConfig, $testDetails) {
  1120. $this->testing($testDetails);
  1121. $helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
  1122. $result = $helper->requireDatabaseOrCreatePermissions($databaseConfig);
  1123. if($result['success']) {
  1124. if($result['alreadyExists']) $testDetails[3] = "Database $databaseConfig[database]";
  1125. else $testDetails[3] = "Able to create a new database";
  1126. $this->testing($testDetails);
  1127. return true;
  1128. } else {
  1129. if(empty($result['cannotCreate'])) {
  1130. $testDetails[2] .= ". Please create the database manually.";
  1131. } else {
  1132. $testDetails[2] .= " (user '$databaseConfig[username]' doesn't have CREATE DATABASE permissions.)";
  1133. }
  1134.  
  1135. $this->error($testDetails);
  1136. return false;
  1137. }
  1138. }
  1139.  
  1140. function requireServerVariables($varNames, $testDetails) {
  1141. $this->testing($testDetails);
  1142. $missing = array();
  1143.  
  1144. foreach($varNames as $varName) {
  1145. if(!isset($_SERVER[$varName]) || !$_SERVER[$varName]) {
  1146. $missing[] = '$_SERVER[' . $varName . ']';
  1147. }
  1148. }
  1149.  
  1150. if(!$missing) {
  1151. return true;
  1152. } else {
  1153. $testDetails[2] .= " (the following PHP variables are missing: " . implode(", ", $missing) . ")";
  1154. $this->error($testDetails);
  1155. }
  1156. }
  1157.  
  1158.  
  1159. function requirePostSupport($testDetails) {
  1160. $this->testing($testDetails);
  1161.  
  1162. if(!isset($_POST)) {
  1163. $this->error($testDetails);
  1164.  
  1165. return false;
  1166. }
  1167.  
  1168. return true;
  1169. }
  1170.  
  1171. function isRunningWebServer($testDetails) {
  1172. $this->testing($testDetails);
  1173. if($testDetails[3]) {
  1174. return true;
  1175. } else {
  1176. $this->warning($testDetails);
  1177. return false;
  1178. }
  1179. }
  1180.  
  1181. // Must be PHP4 compatible
  1182. var $baseDir;
  1183.  
  1184. function getBaseDir() {
  1185. // Cache the value so that when the installer mucks with SCRIPT_FILENAME half way through, this method
  1186. // still returns the correct value.
  1187. if(!$this->baseDir) $this->baseDir = realpath(dirname($_SERVER['SCRIPT_FILENAME'])) . DIRECTORY_SEPARATOR;
  1188. return $this->baseDir;
  1189. }
  1190.  
  1191. function testing($testDetails) {
  1192. if(!$testDetails) return;
  1193.  
  1194. $section = $testDetails[0];
  1195. $test = $testDetails[1];
  1196.  
  1197. $message = "OK";
  1198. if(isset($testDetails[3])) $message .= " ($testDetails[3])";
  1199.  
  1200. $this->tests[$section][$test] = array("good", $message);
  1201. }
  1202.  
  1203. function error($testDetails) {
  1204. $section = $testDetails[0];
  1205. $test = $testDetails[1];
  1206.  
  1207. $this->tests[$section][$test] = array("error", isset($testDetails[2]) ? $testDetails[2] : null);
  1208. $this->errors[] = $testDetails;
  1209. }
  1210.  
  1211. function warning($testDetails) {
  1212. $section = $testDetails[0];
  1213. $test = $testDetails[1];
  1214.  
  1215. $this->tests[$section][$test] = array("warning", isset($testDetails[2]) ? $testDetails[2] : null);
  1216. $this->warnings[] = $testDetails;
  1217. }
  1218.  
  1219. function hasErrors() {
  1220. return sizeof($this->errors);
  1221. }
  1222.  
  1223. function hasWarnings() {
  1224. return sizeof($this->warnings);
  1225. }
  1226.  
  1227. }
  1228.  
  1229. class Installer extends InstallRequirements {
  1230. function __construct() {
  1231. // Cache the baseDir value
  1232. $this->getBaseDir();
  1233. }
  1234.  
  1235. function install($config) {
  1236. ?>
  1237. <html>
  1238. <head>
  1239. <meta charset="utf-8"/>
  1240. <title>Installing SilverStripe...</title>
  1241. <link rel="stylesheet" type="text/css" href="<?php echo FRAMEWORK_NAME; ?>/dev/install/css/install.css"/>
  1242. <script src="<?php echo FRAMEWORK_NAME; ?>/thirdparty/jquery/jquery.js"></script>
  1243. </head>
  1244. <body>
  1245. <div class="install-header">
  1246. <div class="inner">
  1247. <div class="brand">
  1248. <span class="logo"></span>
  1249.  
  1250. <h1>SilverStripe</h1>
  1251. </div>
  1252. </div>
  1253. </div>
  1254.  
  1255. <div id="Navigation">&nbsp;</div>
  1256. <div class="clear"><!-- --></div>
  1257.  
  1258. <div class="main">
  1259. <div class="inner">
  1260. <h2>Installing SilverStripe...</h2>
  1261.  
  1262. <p>I am now running through the installation steps (this should take about 30 seconds)</p>
  1263.  
  1264. <p>If you receive a fatal error, refresh this page to continue the installation</p>
  1265. <ul>
  1266. <?php
  1267.  
  1268. $webserver = $this->findWebserver();
  1269. $isIIS = $this->isIIS();
  1270. $isApache = $this->isApache();
  1271.  
  1272. flush();
  1273.  
  1274. if(isset($config['stats'])) {
  1275. if(file_exists(FRAMEWORK_NAME . '/silverstripe_version')) {
  1276. $silverstripe_version = file_get_contents(FRAMEWORK_NAME . '/silverstripe_version');
  1277. } else {
  1278. $silverstripe_version = "unknown";
  1279. }
  1280.  
  1281. $phpVersion = urlencode(phpversion());
  1282. $encWebserver = urlencode($webserver);
  1283. $dbType = $config['db']['type'];
  1284.  
  1285. // Try to determine the database version from the helper
  1286. $databaseVersion = $config['db']['type'];
  1287. $helper = $this->getDatabaseConfigurationHelper($dbType);
  1288. if($helper && method_exists($helper, 'getDatabaseVersion')) {
  1289. $databaseVersion = urlencode($dbType . ': ' . $helper->getDatabaseVersion($config['db'][$dbType]));
  1290. }
  1291.  
  1292. $url = "http://ss2stat.silverstripe.com/Installation/add?SilverStripe=$silverstripe_version&PHP=$phpVersion&Database=$databaseVersion&WebServer=$encWebserver";
  1293.  
  1294. if(isset($_SESSION['StatsID']) && $_SESSION['StatsID']) {
  1295. $url .= '&ID=' . $_SESSION['StatsID'];
  1296. }
  1297.  
  1298. @$_SESSION['StatsID'] = file_get_contents($url);
  1299. }
  1300.  
  1301. if(file_exists('mysite/_config.php')) {
  1302. // Truncate the contents of _config instead of deleting it - we can't re-create it because Windows handles permissions slightly
  1303. // differently to UNIX based filesystems - it takes the permissions from the parent directory instead of retaining them
  1304. $fh = fopen('mysite/_config.php', 'wb');
  1305. fclose($fh);
  1306. }
  1307.  
  1308. // Escape user input for safe insertion into PHP file
  1309. $theme = isset($_POST['template']) ? addcslashes($_POST['template'], "\'") : 'simple';
  1310. $locale = isset($_POST['locale']) ? addcslashes($_POST['locale'], "\'") : 'en_US';
  1311. $type = addcslashes($config['db']['type'], "\'");
  1312. $dbConfig = $config['db'][$type];
  1313. $dbConfig = array_map(create_function('$v', 'return addcslashes($v, "\\\'");'), $dbConfig);
  1314. if(!isset($dbConfig['path'])) $dbConfig['path'] = '';
  1315. if(!$dbConfig) {
  1316. echo "<p style=\"color: red\">Bad config submitted</p><pre>";
  1317. print_r($config);
  1318. echo "</pre>";
  1319. die();
  1320. }
  1321.  
  1322. // Write the config file
  1323. global $usingEnv;
  1324. if($usingEnv) {
  1325.  
  1326. $this->statusMessage("Setting up 'mysite/_config.php' for use with _ss_environment.php...");
  1327. $this->writeToFile("mysite/_config.php", <<<PHP
  1328. <?php
  1329.  
  1330. global \$project;
  1331. \$project = 'mysite';
  1332.  
  1333. global \$database;
  1334. \$database = '{$dbConfig['database']}';
  1335.  
  1336. require_once('conf/ConfigureFromEnv.php');
  1337.  
  1338. // Set the site locale
  1339. i18n::set_locale('$locale');
  1340. PHP
  1341. );
  1342.  
  1343. } else {
  1344. $this->statusMessage("Setting up 'mysite/_config.php'...");
  1345. $escapedPassword = addslashes($dbConfig['password']);
  1346. $this->writeToFile("mysite/_config.php", <<<PHP
  1347. <?php
  1348.  
  1349. global \$project;
  1350. \$project = 'mysite';
  1351.  
  1352. global \$databaseConfig;
  1353. \$databaseConfig = array(
  1354. "type" => '{$type}',
  1355. "server" => '{$dbConfig['server']}',
  1356. "username" => '{$dbConfig['username']}',
  1357. "password" => '{$escapedPassword}',
  1358. "database" => '{$dbConfig['database']}',
  1359. "path" => '{$dbConfig['path']}',
  1360. );
  1361.  
  1362. // Set the site locale
  1363. i18n::set_locale('$locale');
  1364. PHP
  1365. );
  1366. }
  1367.  
  1368. if(!$this->checkModuleExists('cms')) {
  1369. $this->writeToFile("mysite/code/RootURLController.php", <<<PHP
  1370. <?php
  1371.  
  1372. class RootURLController extends Controller {
  1373.  
  1374. function index() {
  1375. echo "<html>Your site is now set up. Start adding controllers to mysite to get started.</html>";
  1376. }
  1377.  
  1378. }
  1379. PHP
  1380. );
  1381. }
  1382.  
  1383. // Write the appropriate web server configuration file for rewriting support
  1384. if($this->hasRewritingCapability()) {
  1385. if($isApache) {
  1386. $this->statusMessage("Setting up '.htaccess' file...");
  1387. $this->createHtaccess();
  1388. } elseif($isIIS) {
  1389. $this->statusMessage("Setting up 'web.config' file...");
  1390. $this->createWebConfig();
  1391. }
  1392. }
  1393.  
  1394. // Load the SilverStripe runtime
  1395. $_SERVER['SCRIPT_FILENAME'] = dirname(realpath($_SERVER['SCRIPT_FILENAME'])) . '/' . FRAMEWORK_NAME . '/main.php';
  1396. chdir(FRAMEWORK_NAME);
  1397.  
  1398. // Rebuild the manifest
  1399. $_GET['flush'] = true;
  1400. // Show errors as if you're in development mode
  1401. $_SESSION['isDev'] = 1;
  1402.  
  1403. $this->statusMessage("Building database schema...");
  1404.  
  1405. require_once 'core/Core.php';
  1406.  
  1407. // Build database
  1408. $con = new Controller();
  1409. $con->pushCurrent();
  1410.  
  1411. global $databaseConfig;
  1412. DB::connect($databaseConfig);
  1413.  
  1414. $dbAdmin = new DatabaseAdmin();
  1415. $dbAdmin->init();
  1416.  
  1417. $dbAdmin->doBuild(true);
  1418.  
  1419. // Create default administrator user and group in database
  1420. // (not using Security::setDefaultAdmin())
  1421. $adminMember = Security::findAnAdministrator();
  1422. $adminMember->Email = $config['admin']['username'];
  1423. $adminMember->Password = $config['admin']['password'];
  1424. $adminMember->PasswordEncryption = Security::get_password_encryption_algorithm();
  1425.  
  1426. try {
  1427. $this->statusMessage('Creating default CMS admin account...');
  1428. $adminMember->write();
  1429. } catch(Exception $e) {
  1430. $this->statusMessage(
  1431. sprintf('Warning: Default CMS admin account could not be created (error: %s)', $e->getMessage())
  1432. );
  1433. }
  1434.  
  1435. // Syncing filesystem (so /assets/Uploads is available instantly, see ticket #2266)
  1436. // show a warning if there was a problem doing so
  1437. try {
  1438. $this->statusMessage('Creating initial filesystem assets...');
  1439. Filesystem::sync();
  1440. } catch(Exception $e) {
  1441. $this->statusMessage(
  1442. sprintf('Warning: Creating initial filesystem assets failed (error: %s)', $e->getMessage())
  1443. );
  1444. }
  1445.  
  1446. $_SESSION['username'] = $config['admin']['username'];
  1447. $_SESSION['password'] = $config['admin']['password'];
  1448.  
  1449. if(!$this->errors) {
  1450. if(isset($_SERVER['HTTP_HOST']) && $this->hasRewritingCapability()) {
  1451. $this->statusMessage("Checking that friendly URLs work...");
  1452. $this->checkRewrite();
  1453. } else {
  1454. require_once 'core/startup/ParameterConfirmationToken.php';
  1455. $token = new ParameterConfirmationToken('flush');
  1456. $params = http_build_query($token->params());
  1457.  
  1458. $destinationURL = 'index.php/' .
  1459. ($this->checkModuleExists('cms') ? "home/successfullyinstalled?$params" : "?$params");
  1460.  
  1461. echo <<<HTML
  1462. <li>SilverStripe successfully installed; I am now redirecting you to your SilverStripe site...</li>
  1463. <script>
  1464. setTimeout(function() {
  1465. window.location = "$destinationURL";
  1466. }, 2000);
  1467. </script>
  1468. <noscript>
  1469. <li><a href="$destinationURL">Click here to access your site.</a></li>
  1470. </noscript>
  1471. HTML;
  1472. }
  1473. }
  1474.  
  1475. return $this->errors;
  1476. }
  1477.  
  1478. function writeToFile($filename, $content) {
  1479. $base = $this->getBaseDir();
  1480. $this->statusMessage("Setting up $base$filename");
  1481.  
  1482. if((@$fh = fopen($base . $filename, 'wb')) && fwrite($fh, $content) && fclose($fh)) {
  1483. return true;
  1484. } else {
  1485. $this->error("Couldn't write to file $base$filename");
  1486. }
  1487. }
  1488.  
  1489. function createHtaccess() {
  1490. $start = "### SILVERSTRIPE START ###\n";
  1491. $end = "\n### SILVERSTRIPE END ###";
  1492.  
  1493. $base = dirname($_SERVER['SCRIPT_NAME']);
  1494. if(defined('DIRECTORY_SEPARATOR')) $base = str_replace(DIRECTORY_SEPARATOR, '/', $base);
  1495. else $base = str_replace("\\", '/', $base);
  1496.  
  1497. if($base != '.') $baseClause = "RewriteBase '$base'\n";
  1498. else $baseClause = "";
  1499. $modulePath = FRAMEWORK_NAME;
  1500. $rewrite = <<<TEXT
  1501. <Files *.ss>
  1502. Order deny,allow
  1503. Deny from all
  1504. Allow from 127.0.0.1
  1505. </Files>
  1506.  
  1507. <Files web.config>
  1508. Order deny,allow
  1509. Deny from all
  1510. </Files>
  1511.  
  1512. # This denies access to all yml files, since developers might include sensitive
  1513. # information in them. See the docs for work-arounds to serve some yaml files
  1514. <Files *.yml>
  1515. Order allow,deny
  1516. Deny from all
  1517. </Files>
  1518.  
  1519. ErrorDocument 404 /assets/error-404.html
  1520. ErrorDocument 500 /assets/error-500.html
  1521.  
  1522. <IfModule mod_rewrite.c>
  1523. SetEnv HTTP_MOD_REWRITE On
  1524. RewriteEngine On
  1525. $baseClause
  1526.  
  1527. RewriteRule ^vendor(/|$) - [F,L,NC]
  1528. RewriteRule silverstripe-cache(/|$) - [F,L,NC]
  1529. RewriteRule composer\.(json|lock) - [F,L,NC]
  1530.  
  1531. RewriteCond %{REQUEST_URI} ^(.*)$
  1532. RewriteCond %{REQUEST_FILENAME} !-f
  1533. RewriteCond %{REQUEST_URI} !\.php$
  1534. RewriteRule .* $modulePath/main.php?url=%1&%{QUERY_STRING} [L]
  1535. </IfModule>
  1536. TEXT;
  1537.  
  1538. if(file_exists('.htaccess')) {
  1539. $htaccess = file_get_contents('.htaccess');
  1540.  
  1541. if(strpos($htaccess, '### SILVERSTRIPE START ###') === false && strpos($htaccess, '### SILVERSTRIPE END ###') === false) {
  1542. $htaccess .= "\n### SILVERSTRIPE START ###\n### SILVERSTRIPE END ###\n";
  1543. }
  1544.  
  1545. if(strpos($htaccess, '### SILVERSTRIPE START ###') !== false && strpos($htaccess, '### SILVERSTRIPE END ###') !== false) {
  1546. $start = substr($htaccess, 0, strpos($htaccess, '### SILVERSTRIPE START ###')) . "### SILVERSTRIPE START ###\n";
  1547. $end = "\n" . substr($htaccess, strpos($htaccess, '### SILVERSTRIPE END ###'));
  1548. }
  1549. }
  1550.  
  1551. $this->writeToFile('.htaccess', $start . $rewrite . $end);
  1552. }
  1553.  
  1554. /**
  1555. * Writes basic configuration to the web.config for IIS
  1556. * so that rewriting capability can be use.
  1557. */
  1558. function createWebConfig() {
  1559. $modulePath = FRAMEWORK_NAME;
  1560. $content = <<<TEXT
  1561. <?xml version="1.0" encoding="utf-8"?>
  1562. <configuration>
  1563. <system.webServer>
  1564. <security>
  1565. <requestFiltering>
  1566. <hiddenSegments applyToWebDAV="false">
  1567. <add segment="silverstripe-cache" />
  1568. <add segment="vendor" />
  1569. <add segment="composer.json" />
  1570. <add segment="composer.lock" />
  1571. </hiddenSegments>
  1572. <fileExtensions allowUnlisted="true" >
  1573. <add fileExtension=".ss" allowed="false"/>
  1574. <add fileExtension=".yml" allowed="false"/>
  1575. </fileExtensions>
  1576. </requestFiltering>
  1577. </security>
  1578. <rewrite>
  1579. <rules>
  1580. <rule name="SilverStripe Clean URLs" stopProcessing="true">
  1581. <match url="^(.*)$" />
  1582. <conditions>
  1583. <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  1584. </conditions>
  1585. <action type="Rewrite" url="$modulePath/main.php?url={R:1}" appendQueryString="true" />
  1586. </rule>
  1587. </rules>
  1588. </rewrite>
  1589. </system.webServer>
  1590. </configuration>
  1591. TEXT;
  1592.  
  1593. $this->writeToFile('web.config', $content);
  1594. }
  1595.  
  1596. function checkRewrite() {
  1597. require_once 'core/startup/ParameterConfirmationToken.php';
  1598. $token = new ParameterConfirmationToken('flush');
  1599. $params = http_build_query($token->params());
  1600.  
  1601. $destinationURL = str_replace('install.php', '', $_SERVER['SCRIPT_NAME']) .
  1602. ($this->checkModuleExists('cms') ? "home/successfullyinstalled?$params" : "?$params");
  1603.  
  1604. echo <<<HTML
  1605. <li id="ModRewriteResult">Testing...</li>
  1606. <script>
  1607. if(typeof $ == 'undefined') {
  1608. document.getElemenyById('ModeRewriteResult').innerHTML = "I can't run jQuery ajax to set rewriting; I will redirect you to the homepage to see if everything is working.";
  1609. setTimeout(function() {
  1610. window.location = "$destinationURL";
  1611. }, 10000);
  1612. } else {
  1613. $.ajax({
  1614. method: 'get',
  1615. url: 'InstallerTest/testrewrite',
  1616. complete: function(response) {
  1617. var r = response.responseText.replace(/[^A-Z]?/g,"");
  1618. if(r === "OK") {
  1619. $('#ModRewriteResult').html("Friendly URLs set up successfully; I am now redirecting you to your SilverStripe site...")
  1620. setTimeout(function() {
  1621. window.location = "$destinationURL";
  1622. }, 2000);
  1623. } else {
  1624. $('#ModRewriteResult').html("Friendly URLs are not working. This is most likely because a rewrite module isn't configured "
  1625. + "correctly on your site. You may need to get your web host or server administrator to do this for you: "
  1626. + "<ul>"
  1627. + "<li><strong>mod_rewrite</strong> or other rewrite module is enabled on your web server</li>"
  1628. + "<li><strong>AllowOverride All</strong> is set for the directory where SilverStripe is installed</li>"
  1629. + "</ul>");
  1630. }
  1631. }
  1632. });
  1633. }
  1634. </script>
  1635. <noscript>
  1636. <li><a href="$destinationURL">Click here</a> to check friendly URLs are working. If you get a 404 then something is wrong.</li>
  1637. </noscript>
  1638. HTML;
  1639. }
  1640.  
  1641. function var_export_array_nokeys($array) {
  1642. $retval = "array(\n";
  1643. foreach($array as $item) {
  1644. $retval .= "\t'";
  1645. $retval .= trim($item);
  1646. $retval .= "',\n";
  1647. }
  1648. $retval .= ")";
  1649. return $retval;
  1650. }
  1651.  
  1652. /**
  1653. * Show an installation status message.
  1654. * The output differs depending on whether this is CLI or web based
  1655. */
  1656. function statusMessage($msg) {
  1657. echo "<li>$msg</li>\n";
  1658. flush();
  1659. }
  1660. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement