2017-06-22 12:50:45 +02:00
< ? php
namespace SilverStripe\Dev\Install ;
use Exception ;
2017-06-30 04:50:58 +02:00
use SilverStripe\Control\Cookie ;
2017-07-06 03:29:27 +02:00
use SilverStripe\Control\HTTPApplication ;
2017-06-22 12:50:45 +02:00
use SilverStripe\Control\HTTPRequest ;
2017-06-30 04:50:58 +02:00
use SilverStripe\Control\HTTPRequestBuilder ;
2017-06-22 12:50:45 +02:00
use SilverStripe\Core\CoreKernel ;
2017-10-25 03:06:57 +02:00
use SilverStripe\Core\EnvironmentLoader ;
2017-06-22 12:50:45 +02:00
use SilverStripe\Core\Kernel ;
use SilverStripe\Core\Startup\ParameterConfirmationToken ;
use SilverStripe\ORM\DatabaseAdmin ;
use SilverStripe\Security\DefaultAdminService ;
use SilverStripe\Security\Security ;
/**
* This installer doesn 't use any of the fancy SilverStripe stuff in case it' s unsupported .
*/
class Installer extends InstallRequirements
{
2017-11-27 06:15:53 +01:00
/**
* value = '' attribute placeholder for password fields
*/
const PASSWORD_PLACEHOLDER = '********' ;
2017-06-22 12:50:45 +02:00
protected function installHeader ()
{
?>
< html >
< head >
< meta charset = " utf-8 " />
< title > Installing SilverStripe ...</ title >
< link rel = " stylesheet " type = " text/css "
2017-10-02 15:53:35 +02:00
href = " resources/silverstripe/framework/src/Dev/Install/client/styles/install.css " />
2017-06-22 12:50:45 +02:00
< script src = " //code.jquery.com/jquery-1.7.2.min.js " ></ script >
</ head >
< body >
< div class = " install-header " >
< div class = " inner " >
< div class = " brand " >
< span class = " logo " ></ span >
< h1 > SilverStripe </ h1 >
</ div >
</ div >
</ div >
< div id = " Navigation " >& nbsp ; </ div >
< div class = " clear " ><!-- --></ div >
< div class = " main " >
< div class = " inner " >
< h2 > Installing SilverStripe ...</ h2 >
< p > I am now running through the installation steps ( this should take about 30 seconds ) </ p >
< p > If you receive a fatal error , refresh this page to continue the installation </ p >
< ul >
< ? php
}
public function install ( $config )
{
// Render header
$this -> installHeader ();
$isIIS = $this -> isIIS ();
$isApache = $this -> isApache ();
flush ();
2017-08-31 08:17:58 +02:00
// Send install stats
if ( ! empty ( $config [ 'stats' ])) {
$this -> sendInstallStats ( $config );
2017-06-22 12:50:45 +02:00
}
2017-08-31 08:17:58 +02:00
// Cleanup _config.php
2017-06-22 12:50:45 +02:00
if ( file_exists ( 'mysite/_config.php' )) {
// Truncate the contents of _config instead of deleting it - we can't re-create it because Windows handles permissions slightly
// differently to UNIX based filesystems - it takes the permissions from the parent directory instead of retaining them
$fh = fopen ( 'mysite/_config.php' , 'wb' );
fclose ( $fh );
}
2017-08-31 08:17:58 +02:00
// Write all files
2017-10-10 04:23:00 +02:00
$this -> writeIndexPHP ();
2017-08-31 08:17:58 +02:00
$this -> writeConfigPHP ( $config );
$this -> writeConfigYaml ( $config );
$this -> writeConfigEnv ( $config );
2017-06-22 12:50:45 +02:00
2017-08-31 08:17:58 +02:00
// Write other stuff
2017-06-22 12:50:45 +02:00
if ( ! $this -> checkModuleExists ( 'cms' )) {
$this -> writeToFile ( " mysite/code/RootURLController.php " , <<< PHP
< ? php
use SilverStripe\\Control\\Controller ;
class RootURLController extends Controller {
public function index () {
echo " <html>Your site is now set up. Start adding controllers to mysite to get started.</html> " ;
}
}
PHP
);
}
// Write the appropriate web server configuration file for rewriting support
if ( $this -> hasRewritingCapability ()) {
if ( $isApache ) {
$this -> createHtaccess ();
} elseif ( $isIIS ) {
$this -> createWebConfig ();
}
}
2017-06-30 04:50:58 +02:00
// Build request
$request = HTTPRequestBuilder :: createFromEnvironment ();
2017-06-22 12:50:45 +02:00
// Install kernel (fix to dev)
$kernel = new CoreKernel ( BASE_PATH );
$kernel -> setEnvironment ( Kernel :: DEV );
$app = new HTTPApplication ( $kernel );
// Build db within HTTPApplication
$app -> execute ( $request , function ( HTTPRequest $request ) use ( $config ) {
2017-06-30 04:50:58 +02:00
// Suppress cookie errors on install
Cookie :: config () -> set ( 'report_errors' , false );
2017-06-22 12:50:45 +02:00
// Start session and execute
2017-06-28 07:59:16 +02:00
$request -> getSession () -> init ( $request );
2017-06-22 12:50:45 +02:00
// Output status
$this -> statusMessage ( " Building database schema... " );
// Setup DB
$dbAdmin = new DatabaseAdmin ();
$dbAdmin -> setRequest ( $request );
$dbAdmin -> pushCurrent ();
$dbAdmin -> doInit ();
$dbAdmin -> doBuild ( true );
// Create default administrator user and group in database
// (not using Security::setDefaultAdmin())
2017-07-06 03:29:27 +02:00
$username = $config [ 'admin' ][ 'username' ];
$password = $config [ 'admin' ][ 'password' ];
$adminMember = DefaultAdminService :: singleton ()
-> findOrCreateAdmin (
$username ,
2017-09-26 03:57:16 +02:00
_t ( 'SilverStripe\\Security\\DefaultAdminService.DefaultAdminFirstname' , 'Default Admin' )
2017-07-06 03:29:27 +02:00
);
$adminMember -> Email = $username ;
$adminMember -> Password = $password ;
2017-06-22 12:50:45 +02:00
$adminMember -> PasswordEncryption = Security :: config () -> get ( 'encryption_algorithm' );
try {
$this -> statusMessage ( 'Creating default CMS admin account...' );
$adminMember -> write ();
} catch ( Exception $e ) {
$this -> statusMessage (
sprintf ( 'Warning: Default CMS admin account could not be created (error: %s)' , $e -> getMessage ())
);
}
2017-07-06 03:29:27 +02:00
$request -> getSession () -> set ( 'username' , $username );
$request -> getSession () -> set ( 'password' , $password );
2017-06-28 07:59:16 +02:00
$request -> getSession () -> save ( $request );
2017-06-22 12:50:45 +02:00
}, true );
// Check result of install
if ( ! $this -> errors ) {
if ( isset ( $_SERVER [ 'HTTP_HOST' ]) && $this -> hasRewritingCapability ()) {
$this -> statusMessage ( " Checking that friendly URLs work... " );
$this -> checkRewrite ();
} else {
$token = new ParameterConfirmationToken ( 'flush' , $request );
$params = http_build_query ( $token -> params ());
$destinationURL = 'index.php/' .
( $this -> checkModuleExists ( 'cms' ) ? " home/successfullyinstalled? $params " : " ? $params " );
echo <<< HTML
< li > SilverStripe successfully installed ; I am now redirecting you to your SilverStripe site ...</ li >
< script >
setTimeout ( function () {
window . location = " $destinationURL " ;
}, 2000 );
</ script >
< noscript >
< li >< a href = " $destinationURL " > Click here to access your site .</ a ></ li >
</ noscript >
HTML ;
}
}
return $this -> errors ;
}
2017-10-10 04:23:00 +02:00
protected function writeIndexPHP ()
{
$content = <<< 'PHP'
< ? php
use SilverStripe\Control\HTTPApplication ;
use SilverStripe\Control\HTTPRequestBuilder ;
use SilverStripe\Core\CoreKernel ;
use SilverStripe\Core\Startup\ErrorControlChainMiddleware ;
require __DIR__ . '/vendor/autoload.php' ;
// Build request and detect flush
$request = HTTPRequestBuilder :: createFromEnvironment ();
// Default application
$kernel = new CoreKernel ( BASE_PATH );
$app = new HTTPApplication ( $kernel );
$app -> addMiddleware ( new ErrorControlChainMiddleware ( $app ));
$response = $app -> handle ( $request );
$response -> output ();
PHP ;
$this -> writeToFile ( 'index.php' , $content );
}
2017-08-31 08:17:58 +02:00
/**
* Write all . env files
*
* @ param $config
*/
protected function writeConfigEnv ( $config )
{
if ( ! $config [ 'usingEnv' ]) {
return ;
}
$path = $this -> getBaseDir () . '.env' ;
$vars = [];
// Retain existing vars
2017-10-25 03:06:57 +02:00
$env = new EnvironmentLoader ();
2017-08-31 08:17:58 +02:00
if ( file_exists ( $path )) {
2017-10-25 03:06:57 +02:00
$vars = $env -> loadFile ( $path ) ? : [];
2017-08-31 08:17:58 +02:00
}
// Set base URL
if ( ! isset ( $vars [ 'SS_BASE_URL' ]) && isset ( $_SERVER [ 'HTTP_HOST' ])) {
$vars [ 'SS_BASE_URL' ] = 'http://' . $_SERVER [ 'HTTP_HOST' ] . BASE_URL ;
}
// Set DB env
if ( empty ( $config [ 'db' ][ 'database' ])) {
$vars [ 'SS_DATABASE_CHOOSE_NAME' ] = true ;
} else {
$vars [ 'SS_DATABASE_NAME' ] = $config [ 'db' ][ 'database' ];
}
$vars [ 'SS_DATABASE_CLASS' ] = $config [ 'db' ][ 'type' ];
if ( isset ( $config [ 'db' ][ 'server' ])) {
$vars [ 'SS_DATABASE_SERVER' ] = $config [ 'db' ][ 'server' ];
}
if ( isset ( $config [ 'db' ][ 'username' ])) {
$vars [ 'SS_DATABASE_USERNAME' ] = $config [ 'db' ][ 'username' ];
}
if ( isset ( $config [ 'db' ][ 'password' ])) {
$vars [ 'SS_DATABASE_PASSWORD' ] = $config [ 'db' ][ 'password' ];
}
if ( isset ( $config [ 'db' ][ 'path' ])) {
$vars [ 'SS_DATABASE_PATH' ] = $config [ 'db' ][ 'path' ];
// sqlite compat
$vars [ 'SS_SQLITE_DATABASE_PATH' ] = $config [ 'db' ][ 'path' ];
}
if ( isset ( $config [ 'db' ][ 'key' ])) {
$vars [ 'SS_DATABASE_KEY' ] = $config [ 'db' ][ 'key' ];
// sqlite compat
$vars [ 'SS_SQLITE_DATABASE_KEY' ] = $config [ 'db' ][ 'key' ];
}
// Write all env vars
$lines = [
'# Generated by SilverStripe Installer'
];
ksort ( $vars );
foreach ( $vars as $key => $value ) {
$lines [] = $key . '="' . addcslashes ( $value , '"' ) . '"' ;
}
$this -> writeToFile ( '.env' , implode ( " \n " , $lines ));
// Re-load env vars for installer access
2017-10-25 03:06:57 +02:00
$env -> loadFile ( $path );
2017-08-31 08:17:58 +02:00
}
/**
* Write all *. php files
*
* @ param array $config
*/
protected function writeConfigPHP ( $config )
{
if ( $config [ 'usingEnv' ]) {
$this -> writeToFile ( " mysite/_config.php " , " <?php \n " );
return ;
}
// Create databaseConfig
$lines = [];
foreach ( $config [ 'db' ] as $key => $value ) {
$lines [] = sprintf (
" '%s' => '%s' " ,
addslashes ( $key ),
addslashes ( $value )
);
}
$databaseConfigContent = implode ( " , \n " , $lines );
$this -> writeToFile ( " mysite/_config.php " , <<< PHP
< ? php
use SilverStripe\\ORM\\DB ;
DB :: setConfig ([
{ $databaseConfigContent }
]);
PHP
);
}
/**
* Write yml files
*
* @ param array $config
*/
protected function writeConfigYaml ( $config )
{
// Escape user input for safe insertion into PHP file
$locale = $this -> ymlString ( $config [ 'locale' ]);
// Set either specified, or no theme
if ( $config [ 'theme' ] && $config [ 'theme' ] !== 'tutorial' ) {
$theme = $this -> ymlString ( $config [ 'theme' ]);
$themeYML = <<< YML
- '$theme'
- '\$default'
YML ;
} else {
$themeYML = <<< YML
- '\$default'
YML ;
}
// Write theme.yml
$this -> writeToFile ( " mysite/_config/theme.yml " , <<< YML
---
Name : mytheme
---
SilverStripe\\View\\SSViewer :
themes :
$themeYML
SilverStripe\\i18n\\i18n :
default_locale : '$locale'
YML
);
}
/**
* Escape yml string
*
* @ param string $string
* @ return mixed
*/
protected function ymlString ( $string )
{
// just escape single quotes using ''
return str_replace ( " ' " , " '' " , $string );
}
/**
* Write file to given location
*
* @ param $filename
* @ param $content
* @ return bool
*/
2017-06-22 12:50:45 +02:00
public function writeToFile ( $filename , $content )
{
$base = $this -> getBaseDir ();
$this -> statusMessage ( " Setting up $base $filename " );
if (( @ $fh = fopen ( $base . $filename , 'wb' )) && fwrite ( $fh , $content ) && fclose ( $fh )) {
2017-08-31 08:17:58 +02:00
// Set permissions to writable
@ chmod ( $base . $filename , 0775 );
2017-06-22 12:50:45 +02:00
return true ;
}
$this -> error ( " Couldn't write to file $base $filename " );
return false ;
}
2017-08-31 08:17:58 +02:00
/**
* Ensure root . htaccess is setup
*/
2017-06-22 12:50:45 +02:00
public function createHtaccess ()
{
$start = " ### SILVERSTRIPE START ### \n " ;
$end = " \n ### SILVERSTRIPE END ### " ;
$base = dirname ( $_SERVER [ 'SCRIPT_NAME' ]);
if ( defined ( 'DIRECTORY_SEPARATOR' )) {
$base = str_replace ( DIRECTORY_SEPARATOR , '/' , $base );
} else {
$base = str_replace ( " \\ " , '/' , $base );
}
if ( $base != '.' ) {
$baseClause = " RewriteBase ' $base ' \n " ;
} else {
$baseClause = " " ;
}
if ( strpos ( strtolower ( php_sapi_name ()), " cgi " ) !== false ) {
$cgiClause = " RewriteRule .* - [E=HTTP_AUTHORIZATION:% { HTTP:Authorization}] \n " ;
} else {
$cgiClause = " " ;
}
$rewrite = <<< TEXT
# Deny access to templates (but allow from localhost)
< Files *. ss >
Order deny , allow
Deny from all
Allow from 127.0 . 0.1
</ Files >
# Deny access to IIS configuration
< Files web . config >
Order deny , allow
Deny from all
</ Files >
# Deny access to YAML configuration files which might include sensitive information
2017-10-03 01:20:49 +02:00
< Files ~ " \ .ya?ml $ " >
2017-06-22 12:50:45 +02:00
Order allow , deny
Deny from all
</ Files >
# Route errors to static pages automatically generated by SilverStripe
ErrorDocument 404 / assets / error - 404. html
ErrorDocument 500 / assets / error - 500. html
< IfModule mod_rewrite . c >
# Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
< IfModule mod_dir . c >
DirectoryIndex disabled
2017-11-08 00:12:10 +01:00
DirectorySlash On
2017-06-22 12:50:45 +02:00
</ IfModule >
SetEnv HTTP_MOD_REWRITE On
RewriteEngine On
$baseClause
$cgiClause
2017-10-02 15:53:35 +02:00
# Deny access to potentially sensitive files and folders
2017-10-03 13:23:17 +02:00
RewriteRule ^ vendor ( /| $ ) - [ F , L , NC ]
2017-10-02 15:53:35 +02:00
RewriteRule ^ \ . env - [ F , L , NC ]
RewriteRule silverstripe - cache ( /| $ ) - [ F , L , NC ]
RewriteRule composer\ . ( json | lock ) - [ F , L , NC ]
RewriteRule ( error | silverstripe | debug ) \ . log - [ F , L , NC ]
2017-10-02 13:30:24 +02:00
2017-06-22 12:50:45 +02:00
# Process through SilverStripe if no file with the requested name exists.
2017-10-02 15:53:35 +02:00
# Pass through the original path as a query parameter, and retain the existing parameters.
# Try finding framework in the vendor folder first
RewriteCond % { REQUEST_URI } ^ ( .* ) $
RewriteCond % { REQUEST_FILENAME } !- f
2017-10-03 13:23:17 +02:00
RewriteRule .* index . php
2017-06-22 12:50:45 +02:00
</ IfModule >
TEXT ;
if ( file_exists ( '.htaccess' )) {
$htaccess = file_get_contents ( '.htaccess' );
if ( strpos ( $htaccess , '### SILVERSTRIPE START ###' ) === false
&& strpos ( $htaccess , '### SILVERSTRIPE END ###' ) === false
) {
$htaccess .= " \n ### SILVERSTRIPE START ### \n ### SILVERSTRIPE END ### \n " ;
}
if ( strpos ( $htaccess , '### SILVERSTRIPE START ###' ) !== false
&& strpos ( $htaccess , '### SILVERSTRIPE END ###' ) !== false
) {
$start = substr ( $htaccess , 0 , strpos ( $htaccess , '### SILVERSTRIPE START ###' ))
. " ### SILVERSTRIPE START ### \n " ;
$end = " \n " . substr ( $htaccess , strpos ( $htaccess , '### SILVERSTRIPE END ###' ));
}
}
$this -> writeToFile ( '.htaccess' , $start . $rewrite . $end );
}
/**
* Writes basic configuration to the web . config for IIS
* so that rewriting capability can be use .
*/
public function createWebConfig ()
{
$content = <<< TEXT
< ? xml version = " 1.0 " encoding = " utf-8 " ?>
< configuration >
< system . webServer >
< security >
< requestFiltering >
< hiddenSegments applyToWebDAV = " false " >
< add segment = " silverstripe-cache " />
< add segment = " vendor " />
< add segment = " composer.json " />
< add segment = " composer.lock " />
</ hiddenSegments >
< fileExtensions allowUnlisted = " true " >
< add fileExtension = " .ss " allowed = " false " />
< add fileExtension = " .yml " allowed = " false " />
</ fileExtensions >
</ requestFiltering >
</ security >
< rewrite >
< rules >
< rule name = " SilverStripe Clean URLs " stopProcessing = " true " >
< match url = " ^(.*) $ " />
< conditions >
< add input = " { REQUEST_FILENAME} " matchType = " IsFile " negate = " true " />
</ conditions >
2017-10-03 13:23:17 +02:00
< action type = " Rewrite " url = " index.php " appendQueryString = " true " />
2017-06-22 12:50:45 +02:00
</ rule >
</ rules >
</ rewrite >
</ system . webServer >
</ configuration >
TEXT ;
$this -> writeToFile ( 'web.config' , $content );
}
public function checkRewrite ()
{
$token = new ParameterConfirmationToken ( 'flush' , new HTTPRequest ( 'GET' , '/' ));
$params = http_build_query ( $token -> params ());
$destinationURL = str_replace ( 'install.php' , '' , $_SERVER [ 'SCRIPT_NAME' ]) .
( $this -> checkModuleExists ( 'cms' ) ? " home/successfullyinstalled? $params " : " ? $params " );
echo <<< HTML
< li id = " ModRewriteResult " > Testing ...</ li >
< script >
if ( typeof $ == 'undefined' ) {
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. " ;
setTimeout ( function () {
window . location = " $destinationURL " ;
}, 10000 );
} else {
$ . ajax ({
method : 'get' ,
url : 'InstallerTest/testrewrite' ,
complete : function ( response ) {
var r = response . responseText . replace ( / [ ^ A - Z ] ? / g , " " );
if ( r === " OK " ) {
$ ( '#ModRewriteResult' ) . html ( " Friendly URLs set up successfully; I am now redirecting you to your SilverStripe site... " )
setTimeout ( function () {
window . location = " $destinationURL " ;
}, 2000 );
} else {
$ ( '#ModRewriteResult' ) . html ( " Friendly URLs are not working. This is most likely because a rewrite module isn't configured "
+ " correctly on your site. You may need to get your web host or server administrator to do this for you: "
+ " <ul> "
+ " <li><strong>mod_rewrite</strong> or other rewrite module is enabled on your web server</li> "
+ " <li><strong>AllowOverride All</strong> is set for the directory where SilverStripe is installed</li> "
+ " </ul> " );
}
}
});
}
</ script >
< noscript >
< li >< a href = " $destinationURL " > Click here </ a > to check friendly URLs are working . If you get a 404 then something is wrong .</ li >
</ noscript >
HTML ;
}
/**
* Show an installation status message .
* The output differs depending on whether this is CLI or web based
*
* @ param string $msg
*/
public function statusMessage ( $msg )
{
echo " <li> $msg </li> \n " ;
flush ();
}
2017-08-31 08:17:58 +02:00
/**
* @ param $config
*/
protected function sendInstallStats ( $config )
{
// Try to determine the database version from the helper
$dbType = $config [ 'db' ][ 'type' ];
$helper = $this -> getDatabaseConfigurationHelper ( $dbType );
if ( $helper ) {
$databaseVersion = $dbType . ': ' . $helper -> getDatabaseVersion ( $config [ 'db' ]);
} else {
$databaseVersion = $dbType ;
}
$args = http_build_query ( array_filter ([
'SilverStripe' => $config [ 'version' ],
'PHP' => phpversion (),
'Database' => $databaseVersion ,
'WebServer' => $this -> findWebserver (),
'ID' => empty ( $_SESSION [ 'StatsID' ]) ? null : $_SESSION [ 'StatsID' ]
]));
$url = " http://ss2stat.silverstripe.com/Installation/add? { $args } " ;
@ $_SESSION [ 'StatsID' ] = file_get_contents ( $url );
}
2017-06-22 12:50:45 +02:00
}