mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API Remove OutputMiddleware
API Move environment / global / ini management into Environment class API Move getTempFolder into TempFolder class API Implement HTTPRequestBuilder / CLIRequestBuilder BUG Restore SS_ALLOWED_HOSTS check in original location API CoreKernel now requires $basePath to be passed in API Refactor installer.php to use application to bootstrap API move memstring conversion globals to Convert BUG Fix error in CoreKernel nesting not un-nesting itself properly.
This commit is contained in:
parent
bba9791146
commit
12bd31f936
@ -1,19 +1,23 @@
|
||||
<?php
|
||||
|
||||
// CLI specific bootstrapping
|
||||
use SilverStripe\Control\CLIRequestBuilder;
|
||||
use SilverStripe\Core\AppKernel;
|
||||
use SilverStripe\Core\HTTPApplication;
|
||||
use SilverStripe\Core\Startup\OutputMiddleware;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
|
||||
require __DIR__ . '/src/includes/cli.php';
|
||||
require __DIR__ . '/src/includes/autoload.php';
|
||||
|
||||
// Ensure that people can't access this from a web-server
|
||||
if (!in_array(PHP_SAPI, ["cli", "cgi", "cgi-fcgi"])) {
|
||||
echo "cli-script.php can't be run from a web request, you have to run it on the command-line.";
|
||||
die();
|
||||
}
|
||||
|
||||
// Build request and detect flush
|
||||
$request = HTTPRequest::createFromEnvironment();
|
||||
$request = CLIRequestBuilder::createFromEnvironment();
|
||||
|
||||
// Default application
|
||||
$kernel = new AppKernel();
|
||||
$kernel = new AppKernel(BASE_PATH);
|
||||
$app = new HTTPApplication($kernel);
|
||||
$app->addMiddleware(new OutputMiddleware());
|
||||
$app->handle($request);
|
||||
$response = $app->handle($request);
|
||||
$response->output();
|
||||
|
@ -1248,6 +1248,7 @@ After (`mysite/_config/config.yml`):
|
||||
#### <a name="overview-general-api"></a>General and Core API Additions / Changes
|
||||
|
||||
* Minimum PHP version raised to 5.6 (with support for PHP 7.x)
|
||||
* Dropped support for PHP safe mode (removed php 5.4).
|
||||
* Once PHP versions become [unsupported by the PHP Project](http://php.net/supported-versions.php)),
|
||||
we drop support for those versions in the [next minor release](/contributing/release-process
|
||||
This means PHP 5.6 and PHP 7.0 support will become unsupported in Dec 2018.
|
||||
@ -1339,6 +1340,18 @@ After (`mysite/_config/config.yml`):
|
||||
|
||||
#### <a name="overview-general-removed"></a>General and Core Removed API
|
||||
|
||||
* Many global methods have been refactored into `Environment` or `Convert` class.
|
||||
* `increase_xdebug_nesting_level_to` removed (functionality has been inlined into `AppKernel`)
|
||||
* `set_increase_time_limit_max` moved to `Environment::setTimeLimitMax()`
|
||||
* `get_increase_time_limit_max` moved to `Environment::getTimeLimitMax()`
|
||||
* `set_increase_memory_limit_max` moved to `Environment::setMemoryLimitMax()`
|
||||
* `get_increase_memory_limit_max` moved to `Environment::getMemoryLimitMax()`
|
||||
* `increase_time_limit_to` moved to `Environment::increaseTimeLimitTo()`
|
||||
* `increase_memory_limit_to` moved to `Environment::increaseMemoryLimitTo()`
|
||||
* `translate_memstring` moved to `Convert::memstring2bytes`.
|
||||
* `getTempFolder` moved to `TempFolder::getTempFolder()`
|
||||
* `getTempParentFolder` removed.
|
||||
* `getTempFolderUsername` removed.
|
||||
* `CMSMain::buildbrokenlinks()` action is removed.
|
||||
* `Injector::unregisterAllObjects()` has been removed. Use `unregisterObjects` to unregister
|
||||
groups of objects limited by type instead.
|
||||
|
11
main.php
11
main.php
@ -1,19 +1,18 @@
|
||||
<?php
|
||||
|
||||
use SilverStripe\Control\HTTPRequestBuilder;
|
||||
use SilverStripe\Core\AppKernel;
|
||||
use SilverStripe\Core\HTTPApplication;
|
||||
use SilverStripe\Core\Startup\ErrorControlChainMiddleware;
|
||||
use SilverStripe\Core\Startup\OutputMiddleware;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
|
||||
require __DIR__ . '/src/includes/autoload.php';
|
||||
|
||||
// Build request and detect flush
|
||||
$request = HTTPRequest::createFromEnvironment();
|
||||
$request = HTTPRequestBuilder::createFromEnvironment();
|
||||
|
||||
// Default application
|
||||
$kernel = new AppKernel();
|
||||
$kernel = new AppKernel(BASE_PATH);
|
||||
$app = new HTTPApplication($kernel);
|
||||
$app->addMiddleware(new OutputMiddleware());
|
||||
$app->addMiddleware(new ErrorControlChainMiddleware($app));
|
||||
$app->handle($request);
|
||||
$response = $app->handle($request);
|
||||
$response->output();
|
||||
|
69
src/Control/CLIRequestBuilder.php
Normal file
69
src/Control/CLIRequestBuilder.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Control;
|
||||
|
||||
/**
|
||||
* CLI specific request building logic
|
||||
*/
|
||||
class CLIRequestBuilder extends HTTPRequestBuilder
|
||||
{
|
||||
protected static function cleanEnvironment(array $variables)
|
||||
{
|
||||
// Create all blank vars
|
||||
foreach (['_REQUEST', '_GET', '_POST', '_SESSION', '_SERVER', '_COOKIE', '_ENV', '_FILES'] as $key) {
|
||||
if (!isset($variables[$key])) {
|
||||
$variables[$key] = [];
|
||||
};
|
||||
}
|
||||
|
||||
// We update the $_SERVER variable to contain data consistent with the rest of the application.
|
||||
$variables['_SERVER'] = array_merge(array(
|
||||
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
||||
'HTTP_ACCEPT' => 'text/plain;q=0.5',
|
||||
'HTTP_ACCEPT_LANGUAGE' => '*;q=0.5',
|
||||
'HTTP_ACCEPT_ENCODING' => '',
|
||||
'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1;q=0.5',
|
||||
'SERVER_SIGNATURE' => 'Command-line PHP/' . phpversion(),
|
||||
'SERVER_SOFTWARE' => 'PHP/' . phpversion(),
|
||||
'SERVER_ADDR' => '127.0.0.1',
|
||||
'REMOTE_ADDR' => '127.0.0.1',
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'HTTP_USER_AGENT' => 'CLI',
|
||||
), $variables['_SERVER']);
|
||||
|
||||
/**
|
||||
* Process arguments and load them into the $_GET and $_REQUEST arrays
|
||||
* For example,
|
||||
* sake my/url somearg otherarg key=val --otherkey=val third=val&fourth=val
|
||||
*
|
||||
* Will result in the following get data:
|
||||
* args => array('somearg', 'otherarg'),
|
||||
* key => val
|
||||
* otherkey => val
|
||||
* third => val
|
||||
* fourth => val
|
||||
*/
|
||||
if (isset($variables['_SERVER']['argv'][2])) {
|
||||
$args = array_slice($variables['_SERVER']['argv'], 2);
|
||||
foreach ($args as $arg) {
|
||||
if (strpos($arg, '=') == false) {
|
||||
$variables['_GET']['args'][] = $arg;
|
||||
} else {
|
||||
$newItems = array();
|
||||
parse_str((substr($arg, 0, 2) == '--') ? substr($arg, 2) : $arg, $newItems);
|
||||
$variables['_GET'] = array_merge($variables['_GET'], $newItems);
|
||||
}
|
||||
}
|
||||
$_REQUEST = array_merge($_REQUEST, $variables['_GET']);
|
||||
}
|
||||
|
||||
// Set 'url' GET parameter
|
||||
if (isset($variables['_SERVER']['argv'][1])) {
|
||||
$variables['_GET']['url'] = $variables['_SERVER']['argv'][1];
|
||||
$variables['_SERVER']['REQUEST_URI'] = $variables['_SERVER']['argv'][1];
|
||||
}
|
||||
|
||||
// Parse rest of variables as standard
|
||||
return parent::cleanEnvironment($variables);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
use SilverStripe\Core\Environment;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Kernel;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
@ -122,6 +123,14 @@ class Director implements TemplateGlobalProvider
|
||||
*/
|
||||
public static function direct(HTTPRequest $request)
|
||||
{
|
||||
// check allowed hosts
|
||||
if (getenv('SS_ALLOWED_HOSTS') && !static::is_cli()) {
|
||||
$allowedHosts = explode(',', getenv('SS_ALLOWED_HOSTS'));
|
||||
if (!in_array(static::host(), $allowedHosts)) {
|
||||
return new HTTPResponse('Invalid Host', 400);
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-request
|
||||
$output = RequestProcessor::singleton()->preRequest($request);
|
||||
if ($output === false) {
|
||||
@ -231,9 +240,9 @@ class Director implements TemplateGlobalProvider
|
||||
};
|
||||
|
||||
// backup existing vars, and create new vars
|
||||
$existingVars = static::envToVars();
|
||||
$existingVars = Environment::getVariables();
|
||||
$finally[] = function () use ($existingVars) {
|
||||
static::varsToEnv($existingVars);
|
||||
Environment::setVariables($existingVars);
|
||||
};
|
||||
$newVars = $existingVars;
|
||||
|
||||
@ -307,7 +316,7 @@ class Director implements TemplateGlobalProvider
|
||||
$newVars['_REQUEST'] = array_merge($newVars['_GET'], $newVars['_POST']);
|
||||
|
||||
// Create new request
|
||||
$request = HTTPRequest::createFromVariables($newVars, $body);
|
||||
$request = HTTPRequestBuilder::createFromVariables($newVars, $body);
|
||||
if ($headers) {
|
||||
foreach ($headers as $k => $v) {
|
||||
$request->addHeader($k, $v);
|
||||
@ -315,7 +324,7 @@ class Director implements TemplateGlobalProvider
|
||||
}
|
||||
|
||||
// Apply new vars to environment
|
||||
static::varsToEnv($newVars);
|
||||
Environment::setVariables($newVars);
|
||||
|
||||
try {
|
||||
// Normal request handling
|
||||
@ -385,29 +394,6 @@ class Director implements TemplateGlobalProvider
|
||||
return new HTTPResponse('No URL rule was matched', 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract env vars prior to modification
|
||||
*
|
||||
* @return array List of all super globals
|
||||
*/
|
||||
public static function envToVars()
|
||||
{
|
||||
// Suppress return by-ref
|
||||
return array_merge($GLOBALS, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore a backed up or modified list of vars to $globals
|
||||
*
|
||||
* @param array $vars
|
||||
*/
|
||||
public static function varsToEnv(array $vars)
|
||||
{
|
||||
foreach ($vars as $key => $value) {
|
||||
$GLOBALS[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link SiteTree} object that is currently being viewed. If there is no SiteTree
|
||||
* object to return, then this will return the current controller.
|
||||
|
@ -23,7 +23,6 @@ use SilverStripe\ORM\ArrayLib;
|
||||
*/
|
||||
class HTTPRequest implements ArrayAccess
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@ -149,179 +148,6 @@ class HTTPRequest implements ArrayAccess
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create HTTPRequest instance from the current environment variables.
|
||||
* May throw errors if request is invalid.
|
||||
*
|
||||
* @throws HTTPResponse_Exception
|
||||
* @return static
|
||||
*/
|
||||
public static function createFromEnvironment()
|
||||
{
|
||||
// Health-check prior to creating environment
|
||||
static::validateEnvironment();
|
||||
return self::createFromVariables(Director::envToVars(), @file_get_contents('php://input'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a $_SERVER data array and extracts HTTP request headers.
|
||||
*
|
||||
* @param array $server
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function extractRequestHeaders(array $server)
|
||||
{
|
||||
$headers = array();
|
||||
foreach ($server as $key => $value) {
|
||||
if (substr($key, 0, 5) == 'HTTP_') {
|
||||
$key = substr($key, 5);
|
||||
$key = strtolower(str_replace('_', ' ', $key));
|
||||
$key = str_replace(' ', '-', ucwords($key));
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($server['CONTENT_TYPE'])) {
|
||||
$headers['Content-Type'] = $server['CONTENT_TYPE'];
|
||||
}
|
||||
if (isset($server['CONTENT_LENGTH'])) {
|
||||
$headers['Content-Length'] = $server['CONTENT_LENGTH'];
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up HTTP global vars for $_GET / $_REQUEST prior to bootstrapping
|
||||
* Will also populate the $_GET['url'] var safely
|
||||
*
|
||||
* @param array $variables
|
||||
* @return array Cleaned variables
|
||||
*/
|
||||
public static function cleanEnvironment(array $variables)
|
||||
{
|
||||
// IIS will sometimes generate this.
|
||||
if (!empty($variables['_SERVER']['HTTP_X_ORIGINAL_URL'])) {
|
||||
$variables['_SERVER']['REQUEST_URI'] = $variables['_SERVER']['HTTP_X_ORIGINAL_URL'];
|
||||
}
|
||||
|
||||
// Override REQUEST_METHOD
|
||||
if (isset($variables['_SERVER']['X-HTTP-Method-Override'])) {
|
||||
$variables['_SERVER']['REQUEST_METHOD'] = $variables['_SERVER']['X-HTTP-Method-Override'];
|
||||
}
|
||||
|
||||
// Prevent injection of url= querystring argument by prioritising any leading url argument
|
||||
if (isset($variables['_SERVER']['QUERY_STRING']) &&
|
||||
preg_match('/^(?<url>url=[^&?]*)(?<query>.*[&?]url=.*)$/', $variables['_SERVER']['QUERY_STRING'], $results)
|
||||
) {
|
||||
$queryString = $results['query'].'&'.$results['url'];
|
||||
parse_str($queryString, $variables['_GET']);
|
||||
}
|
||||
|
||||
// Decode url from REQUEST_URI if not passed via $_GET['url']
|
||||
if (!isset($variables['_GET']['url'])) {
|
||||
$url = $variables['_SERVER']['REQUEST_URI'];
|
||||
|
||||
// Querystring args need to be explicitly parsed
|
||||
if (strpos($url, '?') !== false) {
|
||||
list($url, $queryString) = explode('?', $url, 2);
|
||||
parse_str($queryString);
|
||||
}
|
||||
|
||||
// Ensure $_GET['url'] is set
|
||||
$variables['_GET']['url'] = urldecode($url);
|
||||
}
|
||||
|
||||
// Remove base folders from the URL if webroot is hosted in a subfolder
|
||||
if (substr(strtolower($variables['_GET']['url']), 0, strlen(BASE_URL)) === strtolower(BASE_URL)) {
|
||||
$variables['_GET']['url'] = substr($variables['_GET']['url'], strlen(BASE_URL));
|
||||
}
|
||||
|
||||
// Merge $_FILES into $_POST
|
||||
$variables['_POST'] = array_merge((array)$variables['_POST'], (array)$variables['_FILES']);
|
||||
|
||||
// Merge $_POST, $_GET, and $_COOKIE into $_REQUEST
|
||||
$variables['_REQUEST'] = array_merge(
|
||||
(array)$variables['_GET'],
|
||||
(array)$variables['_POST'],
|
||||
(array)$variables['_COOKIE']
|
||||
);
|
||||
|
||||
return $variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate environment vars prior to building HTTPRequest
|
||||
* Error conditions will raise HTTPResponse_Exceptions
|
||||
*
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
protected static function validateEnvironment()
|
||||
{
|
||||
// Validate $_FILES array before merging it with $_POST
|
||||
foreach ($_FILES as $key => $value) {
|
||||
if (is_array($value['tmp_name'])) {
|
||||
$tempFiles = ArrayLib::array_values_recursive($value['tmp_name']);
|
||||
} else {
|
||||
$tempFiles = [ $value['tmp_name'] ];
|
||||
}
|
||||
foreach ($tempFiles as $tmpFile) {
|
||||
if ($tmpFile && !is_uploaded_file($tmpFile)) {
|
||||
throw new HTTPResponse_Exception(
|
||||
"File upload '{$key}' doesn't appear to be a valid upload",
|
||||
400
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate hostname
|
||||
if (getenv('SS_ALLOWED_HOSTS') && !Director::is_cli()) {
|
||||
$all_allowed_hosts = explode(',', getenv('SS_ALLOWED_HOSTS'));
|
||||
if (!in_array(Director::host(), $all_allowed_hosts)) {
|
||||
throw new HTTPResponse_Exception('Invalid Host', 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build HTTPRequest from given variables
|
||||
*
|
||||
* @param array $variables
|
||||
* @param string $input Request body
|
||||
* @return HTTPRequest
|
||||
*/
|
||||
public static function createFromVariables(array $variables, $input)
|
||||
{
|
||||
$variables = static::cleanEnvironment($variables);
|
||||
|
||||
// Strip `url` out of querystring
|
||||
$url = $variables['_GET']['url'];
|
||||
unset($variables['_GET']['url']);
|
||||
|
||||
// Build request
|
||||
$request = new HTTPRequest(
|
||||
$variables['_SERVER']['REQUEST_METHOD'],
|
||||
$url,
|
||||
$variables['_GET'],
|
||||
$variables['_POST'],
|
||||
$input
|
||||
);
|
||||
|
||||
// Add headers
|
||||
$headers = static::extractRequestHeaders($variables['_SERVER']);
|
||||
foreach ($headers as $header => $value) {
|
||||
$request->addHeader($header, $value);
|
||||
}
|
||||
|
||||
// Initiate an empty session - doesn't initialize an actual PHP session (see HTTPApplication)
|
||||
$session = new Session(isset($variables['_SESSION']) ? $variables['_SESSION'] : null);
|
||||
$request->setSession($session);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the setting of a URL
|
||||
*
|
||||
|
146
src/Control/HTTPRequestBuilder.php
Normal file
146
src/Control/HTTPRequestBuilder.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\Core\Environment;
|
||||
|
||||
class HTTPRequestBuilder
|
||||
{
|
||||
/**
|
||||
* Create HTTPRequest instance from the current environment variables.
|
||||
* May throw errors if request is invalid.
|
||||
*
|
||||
* @throws HTTPResponse_Exception
|
||||
* @return HTTPRequest
|
||||
*/
|
||||
public static function createFromEnvironment()
|
||||
{
|
||||
// Health-check prior to creating environment
|
||||
return static::createFromVariables(Environment::getVariables(), @file_get_contents('php://input'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build HTTPRequest from given variables
|
||||
*
|
||||
* @param array $variables
|
||||
* @param string $input Request body
|
||||
* @return HTTPRequest
|
||||
*/
|
||||
public static function createFromVariables(array $variables, $input)
|
||||
{
|
||||
$variables = static::cleanEnvironment($variables);
|
||||
|
||||
// Strip `url` out of querystring
|
||||
$url = $variables['_GET']['url'];
|
||||
unset($variables['_GET']['url']);
|
||||
|
||||
// Build request
|
||||
$request = new HTTPRequest(
|
||||
$variables['_SERVER']['REQUEST_METHOD'],
|
||||
$url,
|
||||
$variables['_GET'],
|
||||
$variables['_POST'],
|
||||
$input
|
||||
);
|
||||
|
||||
// Add headers
|
||||
$headers = static::extractRequestHeaders($variables['_SERVER']);
|
||||
foreach ($headers as $header => $value) {
|
||||
$request->addHeader($header, $value);
|
||||
}
|
||||
|
||||
// Initiate an empty session - doesn't initialize an actual PHP session (see HTTPApplication)
|
||||
$session = new Session(isset($variables['_SESSION']) ? $variables['_SESSION'] : null);
|
||||
$request->setSession($session);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a $_SERVER data array and extracts HTTP request headers.
|
||||
*
|
||||
* @param array $server
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function extractRequestHeaders(array $server)
|
||||
{
|
||||
$headers = array();
|
||||
foreach ($server as $key => $value) {
|
||||
if (substr($key, 0, 5) == 'HTTP_') {
|
||||
$key = substr($key, 5);
|
||||
$key = strtolower(str_replace('_', ' ', $key));
|
||||
$key = str_replace(' ', '-', ucwords($key));
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($server['CONTENT_TYPE'])) {
|
||||
$headers['Content-Type'] = $server['CONTENT_TYPE'];
|
||||
}
|
||||
if (isset($server['CONTENT_LENGTH'])) {
|
||||
$headers['Content-Length'] = $server['CONTENT_LENGTH'];
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up HTTP global vars for $_GET / $_REQUEST prior to bootstrapping
|
||||
* Will also populate the $_GET['url'] var safely
|
||||
*
|
||||
* @param array $variables
|
||||
* @return array Cleaned variables
|
||||
*/
|
||||
protected static function cleanEnvironment(array $variables)
|
||||
{
|
||||
// IIS will sometimes generate this.
|
||||
if (!empty($variables['_SERVER']['HTTP_X_ORIGINAL_URL'])) {
|
||||
$variables['_SERVER']['REQUEST_URI'] = $variables['_SERVER']['HTTP_X_ORIGINAL_URL'];
|
||||
}
|
||||
|
||||
// Override REQUEST_METHOD
|
||||
if (isset($variables['_SERVER']['X-HTTP-Method-Override'])) {
|
||||
$variables['_SERVER']['REQUEST_METHOD'] = $variables['_SERVER']['X-HTTP-Method-Override'];
|
||||
}
|
||||
|
||||
// Prevent injection of url= querystring argument by prioritising any leading url argument
|
||||
if (isset($variables['_SERVER']['QUERY_STRING']) &&
|
||||
preg_match('/^(?<url>url=[^&?]*)(?<query>.*[&?]url=.*)$/', $variables['_SERVER']['QUERY_STRING'], $results)
|
||||
) {
|
||||
$queryString = $results['query'].'&'.$results['url'];
|
||||
parse_str($queryString, $variables['_GET']);
|
||||
}
|
||||
|
||||
// Decode url from REQUEST_URI if not passed via $_GET['url']
|
||||
if (!isset($variables['_GET']['url'])) {
|
||||
$url = $variables['_SERVER']['REQUEST_URI'];
|
||||
|
||||
// Querystring args need to be explicitly parsed
|
||||
if (strpos($url, '?') !== false) {
|
||||
list($url, $queryString) = explode('?', $url, 2);
|
||||
parse_str($queryString);
|
||||
}
|
||||
|
||||
// Ensure $_GET['url'] is set
|
||||
$variables['_GET']['url'] = urldecode($url);
|
||||
}
|
||||
|
||||
// Remove base folders from the URL if webroot is hosted in a subfolder
|
||||
if (substr(strtolower($variables['_GET']['url']), 0, strlen(BASE_URL)) === strtolower(BASE_URL)) {
|
||||
$variables['_GET']['url'] = substr($variables['_GET']['url'], strlen(BASE_URL));
|
||||
}
|
||||
|
||||
// Merge $_FILES into $_POST
|
||||
$variables['_POST'] = array_merge((array)$variables['_POST'], (array)$variables['_FILES']);
|
||||
|
||||
// Merge $_POST, $_GET, and $_COOKIE into $_REQUEST
|
||||
$variables['_REQUEST'] = array_merge(
|
||||
(array)$variables['_GET'],
|
||||
(array)$variables['_POST'],
|
||||
(array)$variables['_COOKIE']
|
||||
);
|
||||
|
||||
return $variables;
|
||||
}
|
||||
}
|
@ -28,8 +28,17 @@ use SilverStripe\View\ThemeResourceLoader;
|
||||
|
||||
class AppKernel extends CoreKernel
|
||||
{
|
||||
public function __construct()
|
||||
protected $basePath = null;
|
||||
|
||||
/**
|
||||
* Create a new kernel for this application
|
||||
*
|
||||
* @param string $basePath Path to base dir for this application
|
||||
*/
|
||||
public function __construct($basePath)
|
||||
{
|
||||
$this->basePath = $basePath;
|
||||
|
||||
// Initialise the dependency injector as soon as possible, as it is
|
||||
// subsequently used by some of the following code
|
||||
$injectorLoader = InjectorLoader::inst();
|
||||
@ -42,12 +51,12 @@ class AppKernel extends CoreKernel
|
||||
|
||||
// Class loader
|
||||
$classLoader = ClassLoader::inst();
|
||||
$classLoader->pushManifest(new ClassManifest(BASE_PATH, $manifestCacheFactory));
|
||||
$classLoader->pushManifest(new ClassManifest($basePath, $manifestCacheFactory));
|
||||
$this->setClassLoader($classLoader);
|
||||
|
||||
// Module loader
|
||||
$moduleLoader = ModuleLoader::inst();
|
||||
$moduleManifest = new ModuleManifest(BASE_PATH, $manifestCacheFactory);
|
||||
$moduleManifest = new ModuleManifest($basePath, $manifestCacheFactory);
|
||||
$moduleLoader->pushManifest($moduleManifest);
|
||||
$this->setModuleLoader($moduleLoader);
|
||||
|
||||
@ -62,7 +71,7 @@ class AppKernel extends CoreKernel
|
||||
// Load template manifest
|
||||
$themeResourceLoader = ThemeResourceLoader::inst();
|
||||
$themeResourceLoader->addSet('$default', new ThemeManifest(
|
||||
BASE_PATH,
|
||||
$basePath,
|
||||
project(),
|
||||
$manifestCacheFactory
|
||||
));
|
||||
@ -165,8 +174,8 @@ class AppKernel extends CoreKernel
|
||||
protected function detectLegacyEnvironment()
|
||||
{
|
||||
// Is there an _ss_environment.php file?
|
||||
if (!file_exists(BASE_PATH . '/_ss_environment.php') &&
|
||||
!file_exists(dirname(BASE_PATH) . '/_ss_environment.php')
|
||||
if (!file_exists($this->basePath . '/_ss_environment.php') &&
|
||||
!file_exists(dirname($this->basePath) . '/_ss_environment.php')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@ -197,7 +206,7 @@ class AppKernel extends CoreKernel
|
||||
protected function redirectToInstaller()
|
||||
{
|
||||
// Error if installer not available
|
||||
if (!file_exists(BASE_PATH . '/install.php')) {
|
||||
if (!file_exists($this->basePath . '/install.php')) {
|
||||
throw new HTTPResponse_Exception(
|
||||
'SilverStripe Framework requires a $databaseConfig defined.',
|
||||
500
|
||||
@ -290,7 +299,7 @@ class AppKernel extends CoreKernel
|
||||
if ($chooseName) {
|
||||
// Find directory to build name from
|
||||
$loopCount = (int)$chooseName;
|
||||
$databaseDir = BASE_PATH;
|
||||
$databaseDir = $this->basePath;
|
||||
for ($i = 0; $i < $loopCount-1; $i++) {
|
||||
$databaseDir = dirname($databaseDir);
|
||||
}
|
||||
@ -323,12 +332,15 @@ class AppKernel extends CoreKernel
|
||||
/**
|
||||
* Ensure we have enough memory
|
||||
*/
|
||||
increase_memory_limit_to('64M');
|
||||
Environment::increaseMemoryLimitTo('64M');
|
||||
|
||||
/**
|
||||
* Ensure we don't run into xdebug's fairly conservative infinite recursion protection limit
|
||||
*/
|
||||
increase_xdebug_nesting_level_to(200);
|
||||
// Ensure we don't run into xdebug's fairly conservative infinite recursion protection limit
|
||||
if (function_exists('xdebug_enable')) {
|
||||
$current = ini_get('xdebug.max_nesting_level');
|
||||
if ((int)$current < 200) {
|
||||
ini_set('xdebug.max_nesting_level', 200);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default encoding
|
||||
@ -350,7 +362,7 @@ class AppKernel extends CoreKernel
|
||||
{
|
||||
return new ManifestCacheFactory([
|
||||
'namespace' => 'manifestcache',
|
||||
'directory' => getTempFolder(),
|
||||
'directory' => TempFolder::getTempFolder($this->basePath),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -407,7 +419,7 @@ class AppKernel extends CoreKernel
|
||||
if ($errorLog) {
|
||||
$logger = Injector::inst()->get(LoggerInterface::class);
|
||||
if ($logger instanceof Logger) {
|
||||
$logger->pushHandler(new StreamHandler(BASE_PATH . '/' . $errorLog, Logger::WARNING));
|
||||
$logger->pushHandler(new StreamHandler($this->basePath . '/' . $errorLog, Logger::WARNING));
|
||||
} else {
|
||||
user_error("SS_ERROR_LOG setting only works with Monolog, you are using another logger", E_USER_WARNING);
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
|
||||
/**
|
||||
* Identifies a class as a root silverstripe application
|
||||
*/
|
||||
@ -13,4 +16,14 @@ interface Application
|
||||
* @return Kernel
|
||||
*/
|
||||
public function getKernel();
|
||||
|
||||
/**
|
||||
* Safely boot the application and execute the given main action
|
||||
*
|
||||
* @param HTTPRequest $request
|
||||
* @param callable $callback
|
||||
* @param bool $flush
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
public function execute(HTTPRequest $request, callable $callback, $flush = false);
|
||||
}
|
||||
|
@ -550,4 +550,47 @@ class Convert
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Turn a memory string, such as 512M into an actual number of bytes.
|
||||
*
|
||||
* @param string $memString A memory limit string, such as "64M"
|
||||
* @return float
|
||||
*/
|
||||
public static function memstring2bytes($memString)
|
||||
{
|
||||
switch (strtolower(substr($memString, -1))) {
|
||||
case "b":
|
||||
return round(substr($memString, 0, -1));
|
||||
case "k":
|
||||
return round(substr($memString, 0, -1) * 1024);
|
||||
case "m":
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024);
|
||||
case "g":
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
|
||||
default:
|
||||
return round($memString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $bytes
|
||||
* @param int $decimal decimal precision
|
||||
* @return string
|
||||
*/
|
||||
public static function bytes2memstring($bytes, $decimal = 0)
|
||||
{
|
||||
$scales = ['b','k','m','g'];
|
||||
// Get scale
|
||||
$scale = (int)floor(log($bytes, 1024));
|
||||
if (!isset($scales[$scale])) {
|
||||
$scale = 2;
|
||||
}
|
||||
|
||||
// Size
|
||||
$num = round($bytes / pow(1024, $scale), $decimal);
|
||||
return $num . $scales[$scale];
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,11 @@ class CoreKernel implements Kernel
|
||||
{
|
||||
$this->configLoader->activate();
|
||||
$this->injectorLoader->activate();
|
||||
|
||||
// Self register
|
||||
$this->getInjectorLoader()
|
||||
->getManifest()
|
||||
->registerService($this, Kernel::class);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
152
src/Core/Environment.php
Normal file
152
src/Core/Environment.php
Normal file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
/**
|
||||
* Look wrapper around global environment variables
|
||||
*/
|
||||
class Environment
|
||||
{
|
||||
/**
|
||||
* Set maximum limit allowed for increaseMemoryLimit
|
||||
*
|
||||
* @var float|null
|
||||
*/
|
||||
protected static $memoryLimitMax = null;
|
||||
|
||||
/**
|
||||
* Set maximum limited allowed for increaseTimeLimit
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
protected static $timeLimitMax = null;
|
||||
|
||||
/**
|
||||
* Extract env vars prior to modification
|
||||
*
|
||||
* @return array List of all super globals
|
||||
*/
|
||||
public static function getVariables()
|
||||
{
|
||||
// Suppress return by-ref
|
||||
return array_merge($GLOBALS, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore a backed up or modified list of vars to $globals
|
||||
*
|
||||
* @param array $vars
|
||||
*/
|
||||
public static function setVariables(array $vars)
|
||||
{
|
||||
foreach ($vars as $key => $value) {
|
||||
$GLOBALS[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the memory limit to the given level if it's currently too low.
|
||||
* Only increases up to the maximum defined in {@link set_increase_memory_limit_max()},
|
||||
* and defaults to the 'memory_limit' setting in the PHP configuration.
|
||||
*
|
||||
* @param string|float|int $memoryLimit A memory limit string, such as "64M". If omitted, unlimited memory will be set.
|
||||
* @return bool true indicates a successful change, false a denied change.
|
||||
*/
|
||||
public static function increaseMemoryLimitTo($memoryLimit = -1)
|
||||
{
|
||||
$memoryLimit = Convert::memstring2bytes($memoryLimit);
|
||||
$curLimit = Convert::memstring2bytes(ini_get('memory_limit'));
|
||||
|
||||
// Can't go higher than infinite
|
||||
if ($curLimit < 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check hard maximums
|
||||
$max = static::getMemoryLimitMax();
|
||||
if ($max > 0 && ($memoryLimit < 0 || $memoryLimit > $max)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increase the memory limit if it's too low
|
||||
if ($memoryLimit < 0) {
|
||||
ini_set('memory_limit', '-1');
|
||||
} elseif ($memoryLimit > $curLimit) {
|
||||
ini_set('memory_limit', Convert::bytes2memstring($memoryLimit));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum allowed value for {@link increase_memory_limit_to()}.
|
||||
* The same result can also be achieved through 'suhosin.memory_limit'
|
||||
* if PHP is running with the Suhosin system.
|
||||
*
|
||||
* @param string|float $memoryLimit Memory limit string or float value
|
||||
*/
|
||||
static function setMemoryLimitMax($memoryLimit)
|
||||
{
|
||||
if (isset($memoryLimit) && !is_numeric($memoryLimit)) {
|
||||
$memoryLimit = Convert::memstring2bytes($memoryLimit);
|
||||
}
|
||||
static::$memoryLimitMax = $memoryLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Memory limit in bytes
|
||||
*/
|
||||
public static function getMemoryLimitMax()
|
||||
{
|
||||
if (static::$memoryLimitMax === null) {
|
||||
return Convert::memstring2bytes(ini_get('memory_limit'));
|
||||
}
|
||||
return static::$memoryLimitMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the time limit of this script. By default, the time will be unlimited.
|
||||
* Only works if 'safe_mode' is off in the PHP configuration.
|
||||
* Only values up to {@link get_increase_time_limit_max()} are allowed.
|
||||
*
|
||||
* @param int $timeLimit The time limit in seconds. If omitted, no time limit will be set.
|
||||
* @return Boolean TRUE indicates a successful change, FALSE a denied change.
|
||||
*/
|
||||
public static function increaseTimeLimitTo($timeLimit = null)
|
||||
{
|
||||
// Check vs max limit
|
||||
$max = static::getTimeLimitMax();
|
||||
if ($max > 0 && $timeLimit > $max) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$timeLimit) {
|
||||
set_time_limit(0);
|
||||
} else {
|
||||
$currTimeLimit = ini_get('max_execution_time');
|
||||
// Only increase if its smaller
|
||||
if ($currTimeLimit > 0 && $currTimeLimit < $timeLimit) {
|
||||
set_time_limit($timeLimit);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum allowed value for {@link increase_timeLimit_to()};
|
||||
*
|
||||
* @param int $timeLimit Limit in seconds
|
||||
*/
|
||||
public static function setTimeLimitMax($timeLimit)
|
||||
{
|
||||
static::$timeLimitMax = $timeLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Int Limit in seconds
|
||||
*/
|
||||
public static function getTimeLimitMax()
|
||||
{
|
||||
return static::$timeLimitMax;
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Core\Startup;
|
||||
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Core\HTTPMiddleware;
|
||||
|
||||
/**
|
||||
* Emits response to the browser
|
||||
*/
|
||||
class OutputMiddleware implements HTTPMiddleware
|
||||
{
|
||||
protected $defaultResponse = null;
|
||||
|
||||
/**
|
||||
* Construct output middleware with a default response
|
||||
* (prevent WSOD)
|
||||
*
|
||||
* @param string $defaultResponse Provide default text to echo
|
||||
* if no response could be generated
|
||||
*/
|
||||
public function __construct($defaultResponse = null)
|
||||
{
|
||||
$this->defaultResponse = $defaultResponse;
|
||||
}
|
||||
|
||||
public function process(HTTPRequest $request, callable $delegate)
|
||||
{
|
||||
/** @var HTTPResponse $response */
|
||||
try {
|
||||
$response = call_user_func($delegate, $request);
|
||||
} catch (HTTPResponse_Exception $exception) {
|
||||
$response = $exception->getResponse();
|
||||
}
|
||||
if ($response) {
|
||||
$response->output();
|
||||
} elseif ($this->defaultResponse) {
|
||||
echo $this->defaultResponse;
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
117
src/Core/TempFolder.php
Normal file
117
src/Core/TempFolder.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Guesses location for temp folder
|
||||
*/
|
||||
class TempFolder
|
||||
{
|
||||
/**
|
||||
* Returns the temporary folder path that silverstripe should use for its cache files.
|
||||
*
|
||||
* @param string $base The base path to use for determining the temporary path
|
||||
* @return string Path to temp
|
||||
*/
|
||||
public static function getTempFolder($base)
|
||||
{
|
||||
$parent = static::getTempParentFolder($base);
|
||||
|
||||
// The actual temp folder is a subfolder of getTempParentFolder(), named by username
|
||||
$subfolder = $parent . DIRECTORY_SEPARATOR . static::getTempFolderUsername();
|
||||
|
||||
if (!@file_exists($subfolder)) {
|
||||
mkdir($subfolder);
|
||||
}
|
||||
|
||||
return $subfolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns as best a representation of the current username as we can glean.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getTempFolderUsername()
|
||||
{
|
||||
$user = getenv('APACHE_RUN_USER');
|
||||
if (!$user) {
|
||||
$user = getenv('USER');
|
||||
}
|
||||
if (!$user) {
|
||||
$user = getenv('USERNAME');
|
||||
}
|
||||
if (!$user && function_exists('posix_getpwuid') && function_exists('posix_getuid')) {
|
||||
$userDetails = posix_getpwuid(posix_getuid());
|
||||
$user = $userDetails['name'];
|
||||
}
|
||||
if (!$user) {
|
||||
$user = 'unknown';
|
||||
}
|
||||
$user = preg_replace('/[^A-Za-z0-9_\-]/', '', $user);
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent folder of the temp folder.
|
||||
* The temp folder will be a subfolder of this, named by username.
|
||||
* This structure prevents permission problems.
|
||||
*
|
||||
* @param string $base
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected static function getTempParentFolder($base)
|
||||
{
|
||||
// first, try finding a silverstripe-cache dir built off the base path
|
||||
$tempPath = $base . DIRECTORY_SEPARATOR . 'silverstripe-cache';
|
||||
if (@file_exists($tempPath)) {
|
||||
if ((fileperms($tempPath) & 0777) != 0777) {
|
||||
@chmod($tempPath, 0777);
|
||||
}
|
||||
return $tempPath;
|
||||
}
|
||||
|
||||
// failing the above, try finding a namespaced silverstripe-cache dir in the system temp
|
||||
$tempPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR .
|
||||
'silverstripe-cache-php' . preg_replace('/[^\w-\.+]+/', '-', PHP_VERSION) .
|
||||
str_replace(array(' ', '/', ':', '\\'), '-', $base);
|
||||
if (!@file_exists($tempPath)) {
|
||||
$oldUMask = umask(0);
|
||||
@mkdir($tempPath, 0777);
|
||||
umask($oldUMask);
|
||||
|
||||
// if the folder already exists, correct perms
|
||||
} else {
|
||||
if ((fileperms($tempPath) & 0777) != 0777) {
|
||||
@chmod($tempPath, 0777);
|
||||
}
|
||||
}
|
||||
|
||||
$worked = @file_exists($tempPath) && @is_writable($tempPath);
|
||||
|
||||
// failing to use the system path, attempt to create a local silverstripe-cache dir
|
||||
if (!$worked) {
|
||||
$tempPath = $base . DIRECTORY_SEPARATOR . 'silverstripe-cache';
|
||||
if (!@file_exists($tempPath)) {
|
||||
$oldUMask = umask(0);
|
||||
@mkdir($tempPath, 0777);
|
||||
umask($oldUMask);
|
||||
}
|
||||
|
||||
$worked = @file_exists($tempPath) && @is_writable($tempPath);
|
||||
}
|
||||
|
||||
if (!$worked) {
|
||||
throw new Exception(
|
||||
'Permission problem gaining access to a temp folder. ' .
|
||||
'Please create a folder named silverstripe-cache in the base folder ' .
|
||||
'of the installation and ensure it has the correct permissions'
|
||||
);
|
||||
}
|
||||
|
||||
return $tempPath;
|
||||
}
|
||||
}
|
@ -7,10 +7,10 @@ namespace SilverStripe\Core;
|
||||
*/
|
||||
class TestKernel extends AppKernel
|
||||
{
|
||||
public function __construct()
|
||||
public function __construct($basePath)
|
||||
{
|
||||
$this->setEnvironment(self::DEV);
|
||||
parent::__construct();
|
||||
parent::__construct($basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
1113
src/Dev/Install/InstallRequirements.php
Normal file
1113
src/Dev/Install/InstallRequirements.php
Normal file
@ -0,0 +1,1113 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Dev\Install;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Core\TempFolder;
|
||||
|
||||
/**
|
||||
* This class checks requirements
|
||||
* Each of the requireXXX functions takes an argument which gives a user description of the test.
|
||||
* It's an array of 3 parts:
|
||||
* $description[0] - The test catetgory
|
||||
* $description[1] - The test title
|
||||
* $description[2] - The test error to show, if it goes wrong
|
||||
*/
|
||||
class InstallRequirements
|
||||
{
|
||||
var $errors, $warnings, $tests;
|
||||
|
||||
/**
|
||||
* Check the database configuration. These are done one after another
|
||||
* starting with checking the database function exists in PHP, and
|
||||
* continuing onto more difficult checks like database permissions.
|
||||
*
|
||||
* @param array $databaseConfig The list of database parameters
|
||||
* @return boolean Validity of database configuration details
|
||||
*/
|
||||
public function checkDatabase($databaseConfig)
|
||||
{
|
||||
// Check if support is available
|
||||
if (!$this->requireDatabaseFunctions(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Database support",
|
||||
"Database support in PHP",
|
||||
$this->getDatabaseTypeNice($databaseConfig['type'])
|
||||
)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the server is available
|
||||
$usePath = !empty($databaseConfig['path']) && empty($databaseConfig['server']);
|
||||
if (!$this->requireDatabaseServer(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Database server",
|
||||
$usePath
|
||||
? "I couldn't write to path '$databaseConfig[path]'"
|
||||
: "I couldn't find a database server on '$databaseConfig[server]'",
|
||||
$usePath ? $databaseConfig['path'] : $databaseConfig['server']
|
||||
)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the connection credentials allow access to the server / database
|
||||
if (!$this->requireDatabaseConnection(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Database access credentials",
|
||||
"That username/password doesn't work"
|
||||
)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the necessary server version is available
|
||||
if (!$this->requireDatabaseVersion(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Database server version requirement",
|
||||
'',
|
||||
'Version ' . $this->getDatabaseConfigurationHelper($databaseConfig['type'])->getDatabaseVersion($databaseConfig)
|
||||
)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that database creation permissions are available
|
||||
if (!$this->requireDatabaseOrCreatePermissions(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Can I access/create the database",
|
||||
"I can't create new databases and the database '$databaseConfig[database]' doesn't exist"
|
||||
)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check alter permission (necessary to create tables etc)
|
||||
if (!$this->requireDatabaseAlterPermissions(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Can I ALTER tables",
|
||||
"I don't have permission to ALTER tables"
|
||||
)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success!
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkAdminConfig($adminConfig)
|
||||
{
|
||||
if (!$adminConfig['username']) {
|
||||
$this->error(array('', 'Please enter a username!'));
|
||||
}
|
||||
if (!$adminConfig['password']) {
|
||||
$this->error(array('', 'Please enter a password!'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the web server is IIS and version greater than the given version.
|
||||
*
|
||||
* @param int $fromVersion
|
||||
* @return bool
|
||||
*/
|
||||
public function isIIS($fromVersion = 7)
|
||||
{
|
||||
if (strpos($this->findWebserver(), 'IIS/') === false) {
|
||||
return false;
|
||||
}
|
||||
return substr(strstr($this->findWebserver(), '/'), -3, 1) >= $fromVersion;
|
||||
}
|
||||
|
||||
public function isApache()
|
||||
{
|
||||
if (strpos($this->findWebserver(), 'Apache') !== false) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the webserver software running on the PHP host.
|
||||
* @return string|boolean Server software or boolean FALSE
|
||||
*/
|
||||
public function findWebserver()
|
||||
{
|
||||
// Try finding from SERVER_SIGNATURE or SERVER_SOFTWARE
|
||||
if (!empty($_SERVER['SERVER_SIGNATURE'])) {
|
||||
$webserver = $_SERVER['SERVER_SIGNATURE'];
|
||||
} elseif (!empty($_SERVER['SERVER_SOFTWARE'])) {
|
||||
$webserver = $_SERVER['SERVER_SOFTWARE'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strip_tags(trim($webserver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check everything except the database
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
$this->errors = null;
|
||||
$isApache = $this->isApache();
|
||||
$isIIS = $this->isIIS();
|
||||
$webserver = $this->findWebserver();
|
||||
|
||||
$this->requirePHPVersion('5.5.0', '5.5.0', array(
|
||||
"PHP Configuration",
|
||||
"PHP5 installed",
|
||||
null,
|
||||
"PHP version " . phpversion()
|
||||
));
|
||||
|
||||
// Check that we can identify the root folder successfully
|
||||
$this->requireFile('framework/src/Dev/Install/config-form.html', array(
|
||||
"File permissions",
|
||||
"Does the webserver know where files are stored?",
|
||||
"The webserver isn't letting me identify where files are stored.",
|
||||
$this->getBaseDir()
|
||||
));
|
||||
|
||||
$this->requireModule('mysite', array(
|
||||
"File permissions",
|
||||
"mysite/ directory exists?",
|
||||
''
|
||||
));
|
||||
$this->requireModule('framework', array(
|
||||
"File permissions",
|
||||
"framework/ directory exists?",
|
||||
'',
|
||||
));
|
||||
|
||||
if ($isApache) {
|
||||
$this->checkApacheVersion(array(
|
||||
"Webserver Configuration",
|
||||
"Webserver is not Apache 1.x",
|
||||
"SilverStripe requires Apache version 2 or greater",
|
||||
$webserver
|
||||
));
|
||||
$this->requireWriteable('.htaccess', array("File permissions", "Is the .htaccess file writeable?", null));
|
||||
} elseif ($isIIS) {
|
||||
$this->requireWriteable('web.config', array("File permissions", "Is the web.config file writeable?", null));
|
||||
}
|
||||
|
||||
$this->requireWriteable('mysite/_config.php', array(
|
||||
"File permissions",
|
||||
"Is the mysite/_config.php file writeable?",
|
||||
null
|
||||
));
|
||||
|
||||
$this->requireWriteable('mysite/_config/config.yml', array(
|
||||
"File permissions",
|
||||
"Is the mysite/_config/config.yml file writeable?",
|
||||
null
|
||||
));
|
||||
|
||||
if (!$this->checkModuleExists('cms')) {
|
||||
$this->requireWriteable('mysite/code/RootURLController.php', array(
|
||||
"File permissions",
|
||||
"Is the mysite/code/RootURLController.php file writeable?",
|
||||
null
|
||||
));
|
||||
}
|
||||
$this->requireWriteable('assets', array("File permissions", "Is the assets/ directory writeable?", null));
|
||||
|
||||
try {
|
||||
$tempFolder = TempFolder::getTempFolder(BASE_PATH);
|
||||
} catch (Exception $e) {
|
||||
$tempFolder = false;
|
||||
}
|
||||
|
||||
$this->requireTempFolder(array('File permissions', 'Is a temporary directory available?', null, $tempFolder));
|
||||
if ($tempFolder) {
|
||||
// in addition to the temp folder being available, check it is writable
|
||||
$this->requireWriteable($tempFolder, array(
|
||||
"File permissions",
|
||||
sprintf("Is the temporary directory writeable?", $tempFolder),
|
||||
null
|
||||
), true);
|
||||
}
|
||||
|
||||
// Check for web server, unless we're calling the installer from the command-line
|
||||
$this->isRunningWebServer(array("Webserver Configuration", "Server software", "Unknown", $webserver));
|
||||
|
||||
if ($isApache) {
|
||||
$this->requireApacheRewriteModule('mod_rewrite', array(
|
||||
"Webserver Configuration",
|
||||
"URL rewriting support",
|
||||
"You need mod_rewrite to use friendly URLs with SilverStripe, but it is not enabled."
|
||||
));
|
||||
} elseif ($isIIS) {
|
||||
$this->requireIISRewriteModule('IIS_UrlRewriteModule', array(
|
||||
"Webserver Configuration",
|
||||
"URL rewriting support",
|
||||
"You need to enable the IIS URL Rewrite Module to use friendly URLs with SilverStripe, "
|
||||
. "but it is not installed or enabled. Download it for IIS 7 from http://www.iis.net/expand/URLRewrite"
|
||||
));
|
||||
} else {
|
||||
$this->warning(array(
|
||||
"Webserver Configuration",
|
||||
"URL rewriting support",
|
||||
"I can't tell whether any rewriting module is running. You may need to configure a rewriting rule yourself."
|
||||
));
|
||||
}
|
||||
|
||||
$this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
|
||||
"Webserver Configuration",
|
||||
"Recognised webserver",
|
||||
"You seem to be using an unsupported webserver. "
|
||||
. "The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."
|
||||
));
|
||||
|
||||
$this->requirePostSupport(array(
|
||||
"Webserver Configuration",
|
||||
"POST Support",
|
||||
'I can\'t find $_POST, make sure POST is enabled.'
|
||||
));
|
||||
|
||||
// Check for GD support
|
||||
if (!$this->requireFunction("imagecreatetruecolor", array(
|
||||
"PHP Configuration",
|
||||
"GD2 support",
|
||||
"PHP must have GD version 2."
|
||||
))
|
||||
) {
|
||||
$this->requireFunction("imagecreate", array(
|
||||
"PHP Configuration",
|
||||
"GD2 support",
|
||||
"GD support for PHP not included."
|
||||
));
|
||||
}
|
||||
|
||||
// Check for XML support
|
||||
$this->requireFunction('xml_set_object', array(
|
||||
"PHP Configuration",
|
||||
"XML support",
|
||||
"XML support not included in PHP."
|
||||
));
|
||||
$this->requireClass('DOMDocument', array(
|
||||
"PHP Configuration",
|
||||
"DOM/XML support",
|
||||
"DOM/XML support not included in PHP."
|
||||
));
|
||||
$this->requireFunction('simplexml_load_file', array(
|
||||
'PHP Configuration',
|
||||
'SimpleXML support',
|
||||
'SimpleXML support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for token_get_all
|
||||
$this->requireFunction('token_get_all', array(
|
||||
"PHP Configuration",
|
||||
"Tokenizer support",
|
||||
"Tokenizer support not included in PHP."
|
||||
));
|
||||
|
||||
// Check for CType support
|
||||
$this->requireFunction('ctype_digit', array(
|
||||
'PHP Configuration',
|
||||
'CType support',
|
||||
'CType support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for session support
|
||||
$this->requireFunction('session_start', array(
|
||||
'PHP Configuration',
|
||||
'Session support',
|
||||
'Session support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for iconv support
|
||||
$this->requireFunction('iconv', array(
|
||||
'PHP Configuration',
|
||||
'iconv support',
|
||||
'iconv support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for hash support
|
||||
$this->requireFunction('hash', array('PHP Configuration', 'hash support', 'hash support not included in PHP.'));
|
||||
|
||||
// Check for mbstring support
|
||||
$this->requireFunction('mb_internal_encoding', array(
|
||||
'PHP Configuration',
|
||||
'mbstring support',
|
||||
'mbstring support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for Reflection support
|
||||
$this->requireClass('ReflectionClass', array(
|
||||
'PHP Configuration',
|
||||
'Reflection support',
|
||||
'Reflection support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for Standard PHP Library (SPL) support
|
||||
$this->requireFunction('spl_classes', array(
|
||||
'PHP Configuration',
|
||||
'SPL support',
|
||||
'Standard PHP Library (SPL) not included in PHP.'
|
||||
));
|
||||
|
||||
$this->requireDateTimezone(array(
|
||||
'PHP Configuration',
|
||||
'date.timezone setting and validity',
|
||||
'date.timezone option in php.ini must be set correctly.',
|
||||
ini_get('date.timezone')
|
||||
));
|
||||
|
||||
$this->suggestClass('finfo', array(
|
||||
'PHP Configuration',
|
||||
'fileinfo support',
|
||||
'fileinfo should be enabled in PHP. SilverStripe uses it for MIME type detection of files. '
|
||||
. 'SilverStripe will still operate, but email attachments and sending files to browser '
|
||||
. '(e.g. export data to CSV) may not work correctly without finfo.'
|
||||
));
|
||||
|
||||
$this->suggestFunction('curl_init', array(
|
||||
'PHP Configuration',
|
||||
'curl support',
|
||||
'curl should be enabled in PHP. SilverStripe uses it for consuming web services'
|
||||
. ' via the RestfulService class and many modules rely on it.'
|
||||
));
|
||||
|
||||
$this->suggestClass('tidy', array(
|
||||
'PHP Configuration',
|
||||
'tidy support',
|
||||
'Tidy provides a library of code to clean up your html. '
|
||||
. 'SilverStripe will operate fine without tidy but HTMLCleaner will not be effective.'
|
||||
));
|
||||
|
||||
$this->suggestPHPSetting('asp_tags', array(false), array(
|
||||
'PHP Configuration',
|
||||
'asp_tags option',
|
||||
'This should be turned off as it can cause issues with SilverStripe'
|
||||
));
|
||||
$this->requirePHPSetting('magic_quotes_gpc', array(false), array(
|
||||
'PHP Configuration',
|
||||
'magic_quotes_gpc option',
|
||||
'This should be turned off, as it can cause issues with cookies. '
|
||||
. 'More specifically, unserializing data stored in cookies.'
|
||||
));
|
||||
$this->suggestPHPSetting('display_errors', array(false), array(
|
||||
'PHP Configuration',
|
||||
'display_errors option',
|
||||
'Unless you\'re in a development environment, this should be turned off, '
|
||||
. 'as it can expose sensitive data to website users.'
|
||||
));
|
||||
// on some weirdly configured webservers arg_separator.output is set to &
|
||||
// which will results in links like ?param=value&foo=bar which will not be i
|
||||
$this->suggestPHPSetting('arg_separator.output', array('&', ''), array(
|
||||
'PHP Configuration',
|
||||
'arg_separator.output option',
|
||||
'This option defines how URL parameters are concatenated. '
|
||||
. 'If not set to \'&\' this may cause issues with URL GET parameters'
|
||||
));
|
||||
|
||||
// always_populate_raw_post_data should be set to -1 if PHP < 7.0
|
||||
if (version_compare(PHP_VERSION, '7.0.0', '<')) {
|
||||
$this->suggestPHPSetting('always_populate_raw_post_data', ['-1'], [
|
||||
'PHP Configuration',
|
||||
'always_populate_raw_post_data option',
|
||||
'It\'s highly recommended to set this to \'-1\' in php 5.x, as $HTTP_RAW_POST_DATA is removed in php 7'
|
||||
]);
|
||||
}
|
||||
|
||||
// Check memory allocation
|
||||
$this->requireMemory(32 * 1024 * 1024, 64 * 1024 * 1024, array(
|
||||
"PHP Configuration",
|
||||
"Memory allocation (PHP config option 'memory_limit')",
|
||||
"SilverStripe needs a minimum of 32M allocated to PHP, but recommends 64M.",
|
||||
ini_get("memory_limit")
|
||||
));
|
||||
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
public function suggestPHPSetting($settingName, $settingValues, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
// special case for display_errors, check the original value before
|
||||
// it was changed at the start of this script.
|
||||
if ($settingName == 'display_errors') {
|
||||
global $originalDisplayErrorsValue;
|
||||
$val = $originalDisplayErrorsValue;
|
||||
} else {
|
||||
$val = ini_get($settingName);
|
||||
}
|
||||
|
||||
if (!in_array($val, $settingValues) && $val != $settingValues) {
|
||||
$this->warning($testDetails, "$settingName is set to '$val' in php.ini. $testDetails[2]");
|
||||
}
|
||||
}
|
||||
|
||||
public function requirePHPSetting($settingName, $settingValues, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
$val = ini_get($settingName);
|
||||
if (!in_array($val, $settingValues) && $val != $settingValues) {
|
||||
$this->error($testDetails, "$settingName is set to '$val' in php.ini. $testDetails[2]");
|
||||
}
|
||||
}
|
||||
|
||||
public function suggestClass($class, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
if (!class_exists($class)) {
|
||||
$this->warning($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function suggestFunction($class, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
if (!function_exists($class)) {
|
||||
$this->warning($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDateTimezone($testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
$result = ini_get('date.timezone') && in_array(ini_get('date.timezone'), timezone_identifiers_list());
|
||||
if (!$result) {
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireMemory($min, $recommended, $testDetails)
|
||||
{
|
||||
$_SESSION['forcemem'] = false;
|
||||
|
||||
$mem = $this->getPHPMemory();
|
||||
if ($mem < (64 * 1024 * 1024)) {
|
||||
ini_set('memory_limit', '64M');
|
||||
$mem = $this->getPHPMemory();
|
||||
$testDetails[3] = ini_get("memory_limit");
|
||||
}
|
||||
|
||||
$this->testing($testDetails);
|
||||
|
||||
if ($mem < $min && $mem > 0) {
|
||||
$message = $testDetails[2] . " You only have " . ini_get("memory_limit") . " allocated";
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
} elseif ($mem < $recommended && $mem > 0) {
|
||||
$message = $testDetails[2] . " You only have " . ini_get("memory_limit") . " allocated";
|
||||
$this->warning($testDetails, $message);
|
||||
return false;
|
||||
} elseif ($mem == 0) {
|
||||
$message = $testDetails[2] . " We can't determine how much memory you have allocated. "
|
||||
. "Install only if you're sure you've allocated at least 20 MB.";
|
||||
$this->warning($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getPHPMemory()
|
||||
{
|
||||
$memString = ini_get("memory_limit");
|
||||
|
||||
switch (strtolower(substr($memString, -1))) {
|
||||
case "k":
|
||||
return round(substr($memString, 0, -1) * 1024);
|
||||
|
||||
case "m":
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024);
|
||||
|
||||
case "g":
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
|
||||
|
||||
default:
|
||||
return round($memString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function listErrors()
|
||||
{
|
||||
if ($this->errors) {
|
||||
echo "<p>The following problems are preventing me from installing SilverStripe CMS:</p>\n\n";
|
||||
foreach ($this->errors as $error) {
|
||||
echo "<li>" . htmlentities(implode(", ", $error), ENT_COMPAT, 'UTF-8') . "</li>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function showTable($section = null)
|
||||
{
|
||||
if ($section) {
|
||||
$tests = $this->tests[$section];
|
||||
$id = strtolower(str_replace(' ', '_', $section));
|
||||
echo "<table id=\"{$id}_results\" class=\"testResults\" width=\"100%\">";
|
||||
foreach ($tests as $test => $result) {
|
||||
echo "<tr class=\"$result[0]\"><td>$test</td><td>"
|
||||
. nl2br(htmlentities($result[1], ENT_COMPAT, 'UTF-8')) . "</td></tr>";
|
||||
}
|
||||
echo "</table>";
|
||||
} else {
|
||||
foreach ($this->tests as $section => $tests) {
|
||||
$failedRequirements = 0;
|
||||
$warningRequirements = 0;
|
||||
|
||||
$output = "";
|
||||
|
||||
foreach ($tests as $test => $result) {
|
||||
if (isset($result['0'])) {
|
||||
switch ($result['0']) {
|
||||
case 'error':
|
||||
$failedRequirements++;
|
||||
break;
|
||||
case 'warning':
|
||||
$warningRequirements++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$output .= "<tr class=\"$result[0]\"><td>$test</td><td>"
|
||||
. nl2br(htmlentities($result[1], ENT_COMPAT, 'UTF-8')) . "</td></tr>";
|
||||
}
|
||||
$className = "good";
|
||||
$text = "All Requirements Pass";
|
||||
$pluralWarnings = ($warningRequirements == 1) ? 'Warning' : 'Warnings';
|
||||
|
||||
if ($failedRequirements > 0) {
|
||||
$className = "error";
|
||||
$pluralWarnings = ($warningRequirements == 1) ? 'Warning' : 'Warnings';
|
||||
|
||||
$text = $failedRequirements . ' Failed and ' . $warningRequirements . ' ' . $pluralWarnings;
|
||||
} elseif ($warningRequirements > 0) {
|
||||
$className = "warning";
|
||||
$text = "All Requirements Pass but " . $warningRequirements . ' ' . $pluralWarnings;
|
||||
}
|
||||
|
||||
echo "<h5 class='requirement $className'>$section <a href='#'>Show All Requirements</a> <span>$text</span></h5>";
|
||||
echo "<table class=\"testResults\">";
|
||||
echo $output;
|
||||
echo "</table>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function requireFunction($funcName, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
if (!function_exists($funcName)) {
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requireClass($className, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
if (!class_exists($className)) {
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the given class doesn't exist
|
||||
*
|
||||
* @param array $classNames
|
||||
* @param array $testDetails
|
||||
* @return bool
|
||||
*/
|
||||
public function requireNoClasses($classNames, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$badClasses = array();
|
||||
foreach ($classNames as $className) {
|
||||
if (class_exists($className)) {
|
||||
$badClasses[] = $className;
|
||||
}
|
||||
}
|
||||
if ($badClasses) {
|
||||
$message = $testDetails[2] . ". The following classes are at fault: " . implode(', ', $badClasses);
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkApacheVersion($testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
$is1pointx = preg_match('#Apache[/ ]1\.#', $testDetails[3]);
|
||||
if ($is1pointx) {
|
||||
$this->error($testDetails);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requirePHPVersion($recommendedVersion, $requiredVersion, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
$installedVersion = phpversion();
|
||||
|
||||
if (version_compare($installedVersion, $requiredVersion, '<')) {
|
||||
$message = "SilverStripe requires PHP version $requiredVersion or later.\n
|
||||
PHP version $installedVersion is currently installed.\n
|
||||
While SilverStripe requires at least PHP version $requiredVersion, upgrading to $recommendedVersion or later is recommended.\n
|
||||
If you are installing SilverStripe on a shared web server, please ask your web hosting provider to upgrade PHP for you.";
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version_compare($installedVersion, $recommendedVersion, '<')) {
|
||||
$message = "PHP version $installedVersion is currently installed.\n
|
||||
Upgrading to at least PHP version $recommendedVersion is recommended.\n
|
||||
SilverStripe should run, but you may run into issues. Future releases may require a later version of PHP.\n";
|
||||
$this->warning($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a module exists
|
||||
*
|
||||
* @param string $dirname
|
||||
* @return bool
|
||||
*/
|
||||
public function checkModuleExists($dirname)
|
||||
{
|
||||
$path = $this->getBaseDir() . $dirname;
|
||||
return file_exists($path) && ($dirname == 'mysite' || file_exists($path . '/_config.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as {@link requireFile()} but does additional checks
|
||||
* to ensure the module directory is intact.
|
||||
*
|
||||
* @param string $dirname
|
||||
* @param array $testDetails
|
||||
*/
|
||||
public function requireModule($dirname, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$path = $this->getBaseDir() . $dirname;
|
||||
if (!file_exists($path)) {
|
||||
$testDetails[2] .= " Directory '$path' not found. Please make sure you have uploaded the SilverStripe files to your webserver correctly.";
|
||||
$this->error($testDetails);
|
||||
} elseif (!file_exists($path . '/_config.php') && $dirname != 'mysite') {
|
||||
$testDetails[2] .= " Directory '$path' exists, but is missing files. Please make sure you have uploaded "
|
||||
. "the SilverStripe files to your webserver correctly.";
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireFile($filename, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$filename = $this->getBaseDir() . $filename;
|
||||
if (!file_exists($filename)) {
|
||||
$testDetails[2] .= " (file '$filename' not found)";
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireWriteable($filename, $testDetails, $absolute = false)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
if ($absolute) {
|
||||
$filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
|
||||
} else {
|
||||
$filename = $this->getBaseDir() . str_replace('/', DIRECTORY_SEPARATOR, $filename);
|
||||
}
|
||||
|
||||
if (file_exists($filename)) {
|
||||
$isWriteable = is_writeable($filename);
|
||||
} else {
|
||||
$isWriteable = is_writeable(dirname($filename));
|
||||
}
|
||||
|
||||
if (!$isWriteable) {
|
||||
if (function_exists('posix_getgroups')) {
|
||||
$userID = posix_geteuid();
|
||||
$user = posix_getpwuid($userID);
|
||||
|
||||
$currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename));
|
||||
$currentOwner = posix_getpwuid($currentOwnerID);
|
||||
|
||||
$testDetails[2] .= "User '$user[name]' needs to be able to write to this file:\n$filename\n\nThe "
|
||||
. "file is currently owned by '$currentOwner[name]'. ";
|
||||
|
||||
if ($user['name'] == $currentOwner['name']) {
|
||||
$testDetails[2] .= "We recommend that you make the file writeable.";
|
||||
} else {
|
||||
$groups = posix_getgroups();
|
||||
$groupList = array();
|
||||
foreach ($groups as $group) {
|
||||
$groupInfo = posix_getgrgid($group);
|
||||
if (in_array($currentOwner['name'], $groupInfo['members'])) {
|
||||
$groupList[] = $groupInfo['name'];
|
||||
}
|
||||
}
|
||||
if ($groupList) {
|
||||
$testDetails[2] .= " We recommend that you make the file group-writeable "
|
||||
. "and change the group to one of these groups:\n - " . implode("\n - ", $groupList)
|
||||
. "\n\nFor example:\nchmod g+w $filename\nchgrp " . $groupList[0] . " $filename";
|
||||
} else {
|
||||
$testDetails[2] .= " There is no user-group that contains both the web-server user and the "
|
||||
. "owner of this file. Change the ownership of the file, create a new group, or "
|
||||
. "temporarily make the file writeable by everyone during the install process.";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$testDetails[2] .= "The webserver user needs to be able to write to this file:\n$filename";
|
||||
}
|
||||
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireTempFolder($testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
try {
|
||||
$tempFolder = TempFolder::getTempFolder(BASE_PATH);
|
||||
} catch (Exception $e) {
|
||||
$tempFolder = false;
|
||||
}
|
||||
|
||||
if (!$tempFolder) {
|
||||
$testDetails[2] = "Permission problem gaining access to a temp directory. " .
|
||||
"Please create a folder named silverstripe-cache in the base directory " .
|
||||
"of the installation and ensure it has the adequate permissions.";
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireApacheModule($moduleName, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
if (!in_array($moduleName, apache_get_modules())) {
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function testApacheRewriteExists($moduleName = 'mod_rewrite')
|
||||
{
|
||||
if (function_exists('apache_get_modules') && in_array($moduleName, apache_get_modules())) {
|
||||
return true;
|
||||
}
|
||||
if (isset($_SERVER['HTTP_MOD_REWRITE']) && $_SERVER['HTTP_MOD_REWRITE'] == 'On') {
|
||||
return true;
|
||||
}
|
||||
if (isset($_SERVER['REDIRECT_HTTP_MOD_REWRITE']) && $_SERVER['REDIRECT_HTTP_MOD_REWRITE'] == 'On') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function testIISRewriteModuleExists($moduleName = 'IIS_UrlRewriteModule')
|
||||
{
|
||||
if (isset($_SERVER[$moduleName]) && $_SERVER[$moduleName]) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireApacheRewriteModule($moduleName, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
if ($this->testApacheRewriteExists()) {
|
||||
return true;
|
||||
} else {
|
||||
$this->warning($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the web server has any rewriting capability.
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasRewritingCapability()
|
||||
{
|
||||
return ($this->testApacheRewriteExists() || $this->testIISRewriteModuleExists());
|
||||
}
|
||||
|
||||
public function requireIISRewriteModule($moduleName, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
if ($this->testIISRewriteModuleExists()) {
|
||||
return true;
|
||||
} else {
|
||||
$this->warning($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDatabaseTypeNice($databaseClass)
|
||||
{
|
||||
return substr($databaseClass, 0, -8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of a helper class for the specific database.
|
||||
*
|
||||
* @param string $databaseClass e.g. MySQLDatabase or MSSQLDatabase
|
||||
* @return DatabaseConfigurationHelper
|
||||
*/
|
||||
public function getDatabaseConfigurationHelper($databaseClass)
|
||||
{
|
||||
return DatabaseAdapterRegistry::getDatabaseConfigurationHelper($databaseClass);
|
||||
}
|
||||
|
||||
public function requireDatabaseFunctions($databaseConfig, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
if (!$helper) {
|
||||
$this->error($testDetails, "Couldn't load database helper code for " . $databaseConfig['type']);
|
||||
return false;
|
||||
}
|
||||
$result = $helper->requireDatabaseFunctions($databaseConfig);
|
||||
if ($result) {
|
||||
return true;
|
||||
} else {
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDatabaseConnection($databaseConfig, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
$result = $helper->requireDatabaseConnection($databaseConfig);
|
||||
if ($result['success']) {
|
||||
return true;
|
||||
} else {
|
||||
$testDetails[2] .= ": " . $result['error'];
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDatabaseVersion($databaseConfig, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
if (method_exists($helper, 'requireDatabaseVersion')) {
|
||||
$result = $helper->requireDatabaseVersion($databaseConfig);
|
||||
if ($result['success']) {
|
||||
return true;
|
||||
} else {
|
||||
$testDetails[2] .= $result['error'];
|
||||
$this->warning($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Skipped test because this database has no required version
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requireDatabaseServer($databaseConfig, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
$result = $helper->requireDatabaseServer($databaseConfig);
|
||||
if ($result['success']) {
|
||||
return true;
|
||||
} else {
|
||||
$message = $testDetails[2] . ": " . $result['error'];
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDatabaseOrCreatePermissions($databaseConfig, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
$result = $helper->requireDatabaseOrCreatePermissions($databaseConfig);
|
||||
if ($result['success']) {
|
||||
if ($result['alreadyExists']) {
|
||||
$testDetails[3] = "Database $databaseConfig[database]";
|
||||
} else {
|
||||
$testDetails[3] = "Able to create a new database";
|
||||
}
|
||||
$this->testing($testDetails);
|
||||
return true;
|
||||
} else {
|
||||
if (empty($result['cannotCreate'])) {
|
||||
$message = $testDetails[2] . ". Please create the database manually.";
|
||||
} else {
|
||||
$message = $testDetails[2] . " (user '$databaseConfig[username]' doesn't have CREATE DATABASE permissions.)";
|
||||
}
|
||||
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDatabaseAlterPermissions($databaseConfig, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
$result = $helper->requireDatabaseAlterPermissions($databaseConfig);
|
||||
if ($result['success']) {
|
||||
return true;
|
||||
} else {
|
||||
$message = "Silverstripe cannot alter tables. This won't prevent installation, however it may "
|
||||
. "cause issues if you try to run a /dev/build once installed.";
|
||||
$this->warning($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireServerVariables($varNames, $testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
$missing = array();
|
||||
|
||||
foreach ($varNames as $varName) {
|
||||
if (!isset($_SERVER[$varName]) || !$_SERVER[$varName]) {
|
||||
$missing[] = '$_SERVER[' . $varName . ']';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$missing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$message = $testDetails[2] . " (the following PHP variables are missing: " . implode(", ", $missing) . ")";
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function requirePostSupport($testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
|
||||
if (!isset($_POST)) {
|
||||
$this->error($testDetails);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isRunningWebServer($testDetails)
|
||||
{
|
||||
$this->testing($testDetails);
|
||||
if ($testDetails[3]) {
|
||||
return true;
|
||||
} else {
|
||||
$this->warning($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Must be PHP4 compatible
|
||||
var $baseDir;
|
||||
|
||||
public function getBaseDir()
|
||||
{
|
||||
return BASE_PATH . '/';
|
||||
}
|
||||
|
||||
public function testing($testDetails)
|
||||
{
|
||||
if (!$testDetails) {
|
||||
return;
|
||||
}
|
||||
|
||||
$section = $testDetails[0];
|
||||
$test = $testDetails[1];
|
||||
|
||||
$message = "OK";
|
||||
if (isset($testDetails[3])) {
|
||||
$message .= " ($testDetails[3])";
|
||||
}
|
||||
|
||||
$this->tests[$section][$test] = array("good", $message);
|
||||
}
|
||||
|
||||
public function error($testDetails, $message = null)
|
||||
{
|
||||
if (!is_array($testDetails)) {
|
||||
throw new InvalidArgumentException("Invalid error");
|
||||
}
|
||||
$section = $testDetails[0];
|
||||
$test = $testDetails[1];
|
||||
if (!$message && isset($testDetails[2])) {
|
||||
$message = $testDetails[2];
|
||||
}
|
||||
|
||||
$this->tests[$section][$test] = array("error", $message);
|
||||
$this->errors[] = $testDetails;
|
||||
}
|
||||
|
||||
public function warning($testDetails, $message = null)
|
||||
{
|
||||
if (!is_array($testDetails)) {
|
||||
throw new InvalidArgumentException("Invalid warning");
|
||||
}
|
||||
$section = $testDetails[0];
|
||||
$test = $testDetails[1];
|
||||
if (!$message && isset($testDetails[2])) {
|
||||
$message = $testDetails[2];
|
||||
}
|
||||
|
||||
$this->tests[$section][$test] = array("warning", $message);
|
||||
$this->warnings[] = $testDetails;
|
||||
}
|
||||
|
||||
public function hasErrors()
|
||||
{
|
||||
return sizeof($this->errors);
|
||||
}
|
||||
|
||||
public function hasWarnings()
|
||||
{
|
||||
return sizeof($this->warnings);
|
||||
}
|
||||
}
|
501
src/Dev/Install/Installer.php
Normal file
501
src/Dev/Install/Installer.php
Normal file
@ -0,0 +1,501 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Dev\Install;
|
||||
|
||||
use Exception;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Core\AppKernel;
|
||||
use SilverStripe\Core\HTTPApplication;
|
||||
use SilverStripe\Core\Kernel;
|
||||
use SilverStripe\Core\Startup\ParameterConfirmationToken;
|
||||
use SilverStripe\ORM\DatabaseAdmin;
|
||||
use SilverStripe\Security\DefaultAdminService;
|
||||
use SilverStripe\Security\Security;
|
||||
|
||||
class Installer extends InstallRequirements
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
// Cache the baseDir value
|
||||
$this->getBaseDir();
|
||||
}
|
||||
|
||||
protected function installHeader()
|
||||
{
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Installing SilverStripe...</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="framework/src/Dev/Install/client/styles/install.css"/>
|
||||
<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"> </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();
|
||||
|
||||
$webserver = $this->findWebserver();
|
||||
$isIIS = $this->isIIS();
|
||||
$isApache = $this->isApache();
|
||||
|
||||
flush();
|
||||
|
||||
if (isset($config['stats'])) {
|
||||
if (file_exists(FRAMEWORK_PATH . '/silverstripe_version')) {
|
||||
$silverstripe_version = file_get_contents(FRAMEWORK_PATH . '/silverstripe_version');
|
||||
} else {
|
||||
$silverstripe_version = "unknown";
|
||||
}
|
||||
|
||||
$phpVersion = urlencode(phpversion());
|
||||
$encWebserver = urlencode($webserver);
|
||||
$dbType = $config['db']['type'];
|
||||
|
||||
// Try to determine the database version from the helper
|
||||
$databaseVersion = $config['db']['type'];
|
||||
$helper = $this->getDatabaseConfigurationHelper($dbType);
|
||||
if ($helper && method_exists($helper, 'getDatabaseVersion')) {
|
||||
$versionConfig = $config['db'][$dbType];
|
||||
$versionConfig['type'] = $dbType;
|
||||
$databaseVersion = urlencode($dbType . ': ' . $helper->getDatabaseVersion($versionConfig));
|
||||
}
|
||||
|
||||
$url = "http://ss2stat.silverstripe.com/Installation/add?SilverStripe=$silverstripe_version&PHP=$phpVersion&Database=$databaseVersion&WebServer=$encWebserver";
|
||||
|
||||
if (isset($_SESSION['StatsID']) && $_SESSION['StatsID']) {
|
||||
$url .= '&ID=' . $_SESSION['StatsID'];
|
||||
}
|
||||
|
||||
@$_SESSION['StatsID'] = file_get_contents($url);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Escape user input for safe insertion into PHP file
|
||||
$theme = isset($_POST['template']) ? addcslashes($_POST['template'], "\'") : 'simple';
|
||||
$locale = isset($_POST['locale']) ? addcslashes($_POST['locale'], "\'") : 'en_US';
|
||||
$type = addcslashes($config['db']['type'], "\'");
|
||||
$dbConfig = $config['db'][$type];
|
||||
foreach ($dbConfig as &$configValue) {
|
||||
$configValue = addcslashes($configValue, "\\\'");
|
||||
}
|
||||
if (!isset($dbConfig['path'])) {
|
||||
$dbConfig['path'] = '';
|
||||
}
|
||||
if (!$dbConfig) {
|
||||
echo "<p style=\"color: red\">Bad config submitted</p><pre>";
|
||||
print_r($config);
|
||||
echo "</pre>";
|
||||
die();
|
||||
}
|
||||
|
||||
// Write the config file
|
||||
global $usingEnv;
|
||||
if ($usingEnv) {
|
||||
$this->statusMessage("Setting up 'mysite/_config.php' for use with environment variables...");
|
||||
$this->writeToFile("mysite/_config.php", <<<PHP
|
||||
<?php
|
||||
|
||||
global \$project;
|
||||
\$project = 'mysite';
|
||||
|
||||
global \$database;
|
||||
\$database = '{$dbConfig['database']}';
|
||||
|
||||
require_once('conf/ConfigureFromEnv.php');
|
||||
|
||||
PHP
|
||||
);
|
||||
} else {
|
||||
$this->statusMessage("Setting up 'mysite/_config.php'...");
|
||||
// Create databaseConfig
|
||||
$lines = array(
|
||||
$lines[] = "\t'type' => '$type'"
|
||||
);
|
||||
foreach ($dbConfig as $key => $value) {
|
||||
$lines[] = "\t'{$key}' => '$value'";
|
||||
}
|
||||
$databaseConfigContent = implode(",\n", $lines);
|
||||
$this->writeToFile("mysite/_config.php", <<<PHP
|
||||
<?php
|
||||
|
||||
global \$project;
|
||||
\$project = 'mysite';
|
||||
|
||||
global \$databaseConfig;
|
||||
\$databaseConfig = array(
|
||||
{$databaseConfigContent}
|
||||
);
|
||||
|
||||
PHP
|
||||
);
|
||||
}
|
||||
|
||||
$this->statusMessage("Setting up 'mysite/_config/config.yml'");
|
||||
$this->writeToFile("mysite/_config/config.yml", <<<YML
|
||||
---
|
||||
Name: mysite
|
||||
---
|
||||
# YAML configuration for SilverStripe
|
||||
# See http://doc.silverstripe.org/framework/en/topics/configuration
|
||||
# Caution: Indentation through two spaces, not tabs
|
||||
SilverStripe\\View\\SSViewer:
|
||||
themes:
|
||||
- '$theme'
|
||||
- '\$default'
|
||||
SilverStripe\\i18n\\i18n:
|
||||
default_locale: '$locale'
|
||||
YML
|
||||
);
|
||||
|
||||
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->statusMessage("Setting up '.htaccess' file...");
|
||||
$this->createHtaccess();
|
||||
} elseif ($isIIS) {
|
||||
$this->statusMessage("Setting up 'web.config' file...");
|
||||
$this->createWebConfig();
|
||||
}
|
||||
}
|
||||
|
||||
// Mock request
|
||||
$session = new Session(isset($_SESSION) ? $_SESSION : array());
|
||||
$request = new HTTPRequest('GET', '/');
|
||||
$request->setSession($session);
|
||||
|
||||
// Install kernel (fix to dev)
|
||||
$kernel = new AppKernel(BASE_PATH);
|
||||
$kernel->setEnvironment(Kernel::DEV);
|
||||
$app = new HTTPApplication($kernel);
|
||||
|
||||
// Build db within HTTPApplication
|
||||
$app->execute($request, function (HTTPRequest $request) use ($config) {
|
||||
// Start session and execute
|
||||
$request->getSession()->init();
|
||||
|
||||
// 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())
|
||||
$adminMember = DefaultAdminService::singleton()->findOrCreateDefaultAdmin();
|
||||
$adminMember->Email = $config['admin']['username'];
|
||||
$adminMember->Password = $config['admin']['password'];
|
||||
$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())
|
||||
);
|
||||
}
|
||||
|
||||
$request->getSession()->set('username', $config['admin']['username']);
|
||||
$request->getSession()->set('password', $config['admin']['password']);
|
||||
$request->getSession()->save();
|
||||
}, 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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
$this->error("Couldn't write to file $base$filename");
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
<Files *.yml>
|
||||
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
|
||||
</IfModule>
|
||||
|
||||
SetEnv HTTP_MOD_REWRITE On
|
||||
RewriteEngine On
|
||||
$baseClause
|
||||
$cgiClause
|
||||
|
||||
# Deny access to potentially sensitive files and folders
|
||||
RewriteRule ^vendor(/|$) - [F,L,NC]
|
||||
RewriteRule silverstripe-cache(/|$) - [F,L,NC]
|
||||
RewriteRule composer\.(json|lock) - [F,L,NC]
|
||||
|
||||
# Process through SilverStripe if no file with the requested name exists.
|
||||
# Pass through the original path as a query parameter, and retain the existing parameters.
|
||||
RewriteCond %{REQUEST_URI} ^(.*)$
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule .* framework/main.php?url=%1 [QSA]
|
||||
</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>
|
||||
<action type="Rewrite" url="framework/main.php?url={R:1}" appendQueryString="true" />
|
||||
</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;
|
||||
}
|
||||
|
||||
public function var_export_array_nokeys($array)
|
||||
{
|
||||
$retval = "array(\n";
|
||||
foreach ($array as $item) {
|
||||
$retval .= "\t'";
|
||||
$retval .= trim($item);
|
||||
$retval .= "',\n";
|
||||
}
|
||||
$retval .= ")";
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
@ -24,4 +24,4 @@ if (version_compare(phpversion(), '5.5.0', '<')) {
|
||||
die();
|
||||
}
|
||||
|
||||
include(__DIR__ . '/install.php5');
|
||||
include(__DIR__ . '/install5.php');
|
||||
|
@ -1,1767 +0,0 @@
|
||||
<?php
|
||||
|
||||
/************************************************************************************
|
||||
************************************************************************************
|
||||
** **
|
||||
** If you can read this text in your browser then you don't have PHP installed. **
|
||||
** Please install PHP 5.5.0 or higher. **
|
||||
** **
|
||||
************************************************************************************
|
||||
************************************************************************************/
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Core\Startup\ParameterConfirmationToken;
|
||||
use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
|
||||
use SilverStripe\Dev\Install\DatabaseConfigurationHelper;
|
||||
use SilverStripe\ORM\DatabaseAdmin;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Security\DefaultAdminService;
|
||||
|
||||
/**
|
||||
* SilverStripe CMS Installer
|
||||
* This installer doesn't use any of the fancy SilverStripe stuff in case it's unsupported.
|
||||
*/
|
||||
|
||||
// speed up mysql_connect timeout if the server can't be found
|
||||
ini_set('mysql.connect_timeout', 5);
|
||||
// Don't die half was through installation; that does more harm than good
|
||||
ini_set('max_execution_time', 0);
|
||||
|
||||
// set display_errors php setting to on to force installer to avoid blank screen of death.
|
||||
// get the original value so it can be used in PHP requirement checks later in this script.
|
||||
$originalDisplayErrorsValue = ini_get('display_errors');
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
// Attempt to start a session so that the username and password can be sent back to the user.
|
||||
if(function_exists('session_start') && !session_id()) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// require composers autoloader
|
||||
$autoloadPaths = [
|
||||
__DIR__ . '/../../../vendor/autoload.php', // framework/vendor
|
||||
__DIR__ . '/../../../../vendor/autoload.php', // root vendor
|
||||
];
|
||||
$included = false;
|
||||
foreach($autoloadPaths as $path) {
|
||||
if (file_exists($path)) {
|
||||
$included = true;
|
||||
require_once $path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$included) {
|
||||
if (!headers_sent()) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error");
|
||||
header('Content-Type: text/plain');
|
||||
}
|
||||
echo "Failed to include composer's autoloader, unable to continue\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$usingEnv = !empty($_REQUEST['useEnv']);
|
||||
|
||||
require_once __DIR__ . '/DatabaseConfigurationHelper.php';
|
||||
require_once __DIR__ . '/DatabaseAdapterRegistry.php';
|
||||
|
||||
// Set default locale, but try and sniff from the user agent
|
||||
$defaultLocale = 'en_US';
|
||||
$locales = array(
|
||||
'af_ZA' => 'Afrikaans (South Africa)',
|
||||
'ar_EG' => 'Arabic (Egypt)',
|
||||
'hy_AM' => 'Armenian (Armenia)',
|
||||
'ast_ES' => 'Asturian (Spain)',
|
||||
'az_AZ' => 'Azerbaijani (Azerbaijan)',
|
||||
'bs_BA' => 'Bosnian (Bosnia and Herzegovina)',
|
||||
'bg_BG' => 'Bulgarian (Bulgaria)',
|
||||
'ca_ES' => 'Catalan (Spain)',
|
||||
'zh_CN' => 'Chinese (China)',
|
||||
'zh_TW' => 'Chinese (Taiwan)',
|
||||
'hr_HR' => 'Croatian (Croatia)',
|
||||
'cs_CZ' => 'Czech (Czech Republic)',
|
||||
'da_DK' => 'Danish (Denmark)',
|
||||
'nl_NL' => 'Dutch (Netherlands)',
|
||||
'en_GB' => 'English (United Kingdom)',
|
||||
'en_US' => 'English (United States)',
|
||||
'eo_XX' => 'Esperanto',
|
||||
'et_EE' => 'Estonian (Estonia)',
|
||||
'fo_FO' => 'Faroese (Faroe Islands)',
|
||||
'fi_FI' => 'Finnish (Finland)',
|
||||
'fr_FR' => 'French (France)',
|
||||
'de_DE' => 'German (Germany)',
|
||||
'el_GR' => 'Greek (Greece)',
|
||||
'he_IL' => 'Hebrew (Israel)',
|
||||
'hu_HU' => 'Hungarian (Hungary)',
|
||||
'is_IS' => 'Icelandic (Iceland)',
|
||||
'id_ID' => 'Indonesian (Indonesia)',
|
||||
'it_IT' => 'Italian (Italy)',
|
||||
'ja_JP' => 'Japanese (Japan)',
|
||||
'km_KH' => 'Khmer (Cambodia)',
|
||||
'lc_XX' => 'LOLCAT',
|
||||
'lv_LV' => 'Latvian (Latvia)',
|
||||
'lt_LT' => 'Lithuanian (Lithuania)',
|
||||
'ms_MY' => 'Malay (Malaysia)',
|
||||
'mi_NZ' => 'Maori (New Zealand)',
|
||||
'ne_NP' => 'Nepali (Nepal)',
|
||||
'nb_NO' => 'Norwegian',
|
||||
'fa_IR' => 'Persian (Iran)',
|
||||
'pl_PL' => 'Polish (Poland)',
|
||||
'pt_BR' => 'Portuguese (Brazil)',
|
||||
'pa_IN' => 'Punjabi (India)',
|
||||
'ro_RO' => 'Romanian (Romania)',
|
||||
'ru_RU' => 'Russian (Russia)',
|
||||
'sr_RS' => 'Serbian (Serbia)',
|
||||
'si_LK' => 'Sinhalese (Sri Lanka)',
|
||||
'sk_SK' => 'Slovak (Slovakia)',
|
||||
'sl_SI' => 'Slovenian (Slovenia)',
|
||||
'es_AR' => 'Spanish (Argentina)',
|
||||
'es_MX' => 'Spanish (Mexico)',
|
||||
'es_ES' => 'Spanish (Spain)',
|
||||
'sv_SE' => 'Swedish (Sweden)',
|
||||
'th_TH' => 'Thai (Thailand)',
|
||||
'tr_TR' => 'Turkish (Turkey)',
|
||||
'uk_UA' => 'Ukrainian (Ukraine)',
|
||||
'uz_UZ' => 'Uzbek (Uzbekistan)',
|
||||
'vi_VN' => 'Vietnamese (Vietnam)',
|
||||
);
|
||||
|
||||
// Discover which databases are available
|
||||
DatabaseAdapterRegistry::autodiscover();
|
||||
|
||||
// Determine which external database modules are USABLE
|
||||
$databaseClasses = DatabaseAdapterRegistry::get_adapters();
|
||||
foreach($databaseClasses as $class => $details) {
|
||||
$helper = DatabaseAdapterRegistry::getDatabaseConfigurationHelper($class);
|
||||
$databaseClasses[$class]['hasModule'] = !empty($helper);
|
||||
}
|
||||
|
||||
// Load database config
|
||||
if(isset($_REQUEST['db'])) {
|
||||
if(isset($_REQUEST['db']['type'])) {
|
||||
$type = $_REQUEST['db']['type'];
|
||||
} else {
|
||||
if ($type = getenv('SS_DATABASE_CLASS')) {
|
||||
$_REQUEST['db']['type'] = $type;
|
||||
} elseif( $databaseClasses['MySQLPDODatabase']['supported'] ) {
|
||||
$type = $_REQUEST['db']['type'] = 'MySQLPDODatabase';
|
||||
} elseif( $databaseClasses['MySQLDatabase']['supported'] ) {
|
||||
$type = $_REQUEST['db']['type'] = 'MySQLDatabase';
|
||||
} else {
|
||||
// handle error
|
||||
}
|
||||
}
|
||||
|
||||
// Disabled inputs don't submit anything - we need to use the environment (except the database name)
|
||||
if($usingEnv) {
|
||||
$_REQUEST['db'][$type] = $databaseConfig = array(
|
||||
"type" => getenv('SS_DATABASE_CLASS') ?: $type,
|
||||
"server" => getenv('SS_DATABASE_SERVER') ?: "localhost",
|
||||
"username" => getenv('SS_DATABASE_USERNAME') ?: "root",
|
||||
"password" => getenv('SS_DATABASE_PASSWORD') ?: "",
|
||||
"database" => $_REQUEST['db'][$type]['database'],
|
||||
);
|
||||
|
||||
} else {
|
||||
// Normal behaviour without the environment
|
||||
$databaseConfig = $_REQUEST['db'][$type];
|
||||
$databaseConfig['type'] = $type;
|
||||
}
|
||||
} else {
|
||||
if($type = getenv('SS_DATABASE_CLASS')) {
|
||||
$_REQUEST['db']['type'] = $type;
|
||||
} elseif( $databaseClasses['MySQLPDODatabase']['supported'] ) {
|
||||
$type = $_REQUEST['db']['type'] = 'MySQLPDODatabase';
|
||||
} elseif( $databaseClasses['MySQLDatabase']['supported'] ) {
|
||||
$type = $_REQUEST['db']['type'] = 'MySQLDatabase';
|
||||
} else {
|
||||
// handle error
|
||||
}
|
||||
$_REQUEST['db'][$type] = $databaseConfig = array(
|
||||
"type" => $type,
|
||||
"server" => getenv('SS_DATABASE_SERVER') ?: "localhost",
|
||||
"username" => getenv('SS_DATABASE_USERNAME') ?: "root",
|
||||
"password" => getenv('SS_DATABASE_PASSWORD') ?: "",
|
||||
"database" => isset($_SERVER['argv'][2]) ? $_SERVER['argv'][2] : "SS_mysite",
|
||||
);
|
||||
}
|
||||
|
||||
if(isset($_REQUEST['admin'])) {
|
||||
// Disabled inputs don't submit anything - we need to use the environment (except the database name)
|
||||
if($usingEnv) {
|
||||
$_REQUEST['admin'] = $adminConfig = array(
|
||||
'username' => getenv('SS_DEFAULT_ADMIN_USERNAME') ?: 'admin',
|
||||
'password' => getenv('SS_DEFAULT_ADMIN_PASSWORD') ?: '',
|
||||
);
|
||||
} else {
|
||||
$adminConfig = $_REQUEST['admin'];
|
||||
}
|
||||
} else {
|
||||
$_REQUEST['admin'] = $adminConfig = array(
|
||||
'username' => getenv('SS_DEFAULT_ADMIN_USERNAME') ?: 'admin',
|
||||
'password' => getenv('SS_DEFAULT_ADMIN_PASSWORD') ?: '',
|
||||
);
|
||||
}
|
||||
|
||||
$alreadyInstalled = false;
|
||||
if(file_exists('mysite/_config.php')) {
|
||||
// Find the $database variable in the relevant config file without having to execute the config file
|
||||
if(preg_match("/\\\$database\s*=\s*[^\n\r]+[\n\r]/", file_get_contents("mysite/_config.php"), $parts)) {
|
||||
eval($parts[0]);
|
||||
if(!empty($database)) {
|
||||
$alreadyInstalled = true;
|
||||
}
|
||||
// Assume that if $databaseConfig is defined in mysite/_config.php, then a non-environment-based installation has
|
||||
// already gone ahead
|
||||
} else if(preg_match("/\\\$databaseConfig\s*=\s*[^\n\r]+[\n\r]/", file_get_contents("mysite/_config.php"), $parts)) {
|
||||
$alreadyInstalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(file_exists(FRAMEWORK_NAME . '/silverstripe_version')) {
|
||||
$silverstripe_version = file_get_contents(FRAMEWORK_NAME . '/silverstripe_version');
|
||||
} else {
|
||||
$silverstripe_version = "unknown";
|
||||
}
|
||||
|
||||
// Check requirements
|
||||
$req = new InstallRequirements();
|
||||
$req->check();
|
||||
|
||||
$webserverConfigFile = '';
|
||||
if($req->isIIS()) {
|
||||
$webserverConfigFile = 'web.config';
|
||||
} else {
|
||||
$webserverConfigFile = '.htaccess';
|
||||
}
|
||||
|
||||
if($req->hasErrors()) {
|
||||
$hasErrorOtherThanDatabase = true;
|
||||
$phpIniLocation = php_ini_loaded_file();
|
||||
}
|
||||
|
||||
if($databaseConfig) {
|
||||
$dbReq = new InstallRequirements();
|
||||
$dbReq->checkDatabase($databaseConfig);
|
||||
}
|
||||
|
||||
if($adminConfig) {
|
||||
$adminReq = new InstallRequirements();
|
||||
$adminReq->checkAdminConfig($adminConfig);
|
||||
}
|
||||
|
||||
// Actual processor
|
||||
$installFromCli = (isset($_SERVER['argv'][1]) && $_SERVER['argv'][1] == 'install');
|
||||
|
||||
// CLI-install error message. exit(1) will halt any makefile.
|
||||
if($installFromCli && ($req->hasErrors() || $dbReq->hasErrors())) {
|
||||
echo "Cannot install due to errors:\n";
|
||||
$req->listErrors();
|
||||
$dbReq->listErrors();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if((isset($_REQUEST['go']) || $installFromCli) && !$req->hasErrors() && !$dbReq->hasErrors() && $adminConfig['username'] && $adminConfig['password']) {
|
||||
// Confirm before reinstalling
|
||||
if(!$installFromCli && $alreadyInstalled) {
|
||||
include(__DIR__ . '/config-form.html');
|
||||
|
||||
} else {
|
||||
$inst = new Installer();
|
||||
if($_REQUEST) $inst->install($_REQUEST);
|
||||
else $inst->install(array(
|
||||
'db' => $databaseConfig,
|
||||
'admin' => $adminConfig,
|
||||
));
|
||||
}
|
||||
|
||||
// Show the config form
|
||||
} else {
|
||||
include(__DIR__ . '/config-form.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* This class checks requirements
|
||||
* Each of the requireXXX functions takes an argument which gives a user description of the test.
|
||||
* It's an array of 3 parts:
|
||||
* $description[0] - The test catetgory
|
||||
* $description[1] - The test title
|
||||
* $description[2] - The test error to show, if it goes wrong
|
||||
*/
|
||||
class InstallRequirements {
|
||||
var $errors, $warnings, $tests;
|
||||
|
||||
/**
|
||||
* Check the database configuration. These are done one after another
|
||||
* starting with checking the database function exists in PHP, and
|
||||
* continuing onto more difficult checks like database permissions.
|
||||
*
|
||||
* @param array $databaseConfig The list of database parameters
|
||||
* @return boolean Validity of database configuration details
|
||||
*/
|
||||
public function checkDatabase($databaseConfig) {
|
||||
// Check if support is available
|
||||
if(!$this->requireDatabaseFunctions(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Database support",
|
||||
"Database support in PHP",
|
||||
$this->getDatabaseTypeNice($databaseConfig['type'])
|
||||
)
|
||||
)) return false;
|
||||
|
||||
// Check if the server is available
|
||||
$usePath = !empty($databaseConfig['path']) && empty($databaseConfig['server']);
|
||||
if(!$this->requireDatabaseServer(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Database server",
|
||||
$usePath
|
||||
? "I couldn't write to path '$databaseConfig[path]'"
|
||||
: "I couldn't find a database server on '$databaseConfig[server]'",
|
||||
$usePath ? $databaseConfig['path'] : $databaseConfig['server']
|
||||
)
|
||||
)) return false;
|
||||
|
||||
// Check if the connection credentials allow access to the server / database
|
||||
if(!$this->requireDatabaseConnection(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Database access credentials",
|
||||
"That username/password doesn't work"
|
||||
)
|
||||
)) return false;
|
||||
|
||||
// Check the necessary server version is available
|
||||
if(!$this->requireDatabaseVersion(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Database server version requirement",
|
||||
'',
|
||||
'Version ' . $this->getDatabaseConfigurationHelper($databaseConfig['type'])->getDatabaseVersion($databaseConfig)
|
||||
)
|
||||
)) return false;
|
||||
|
||||
// Check that database creation permissions are available
|
||||
if(!$this->requireDatabaseOrCreatePermissions(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Can I access/create the database",
|
||||
"I can't create new databases and the database '$databaseConfig[database]' doesn't exist"
|
||||
)
|
||||
)) return false;
|
||||
|
||||
// Check alter permission (necessary to create tables etc)
|
||||
if(!$this->requireDatabaseAlterPermissions(
|
||||
$databaseConfig,
|
||||
array(
|
||||
"Database Configuration",
|
||||
"Can I ALTER tables",
|
||||
"I don't have permission to ALTER tables"
|
||||
)
|
||||
)) return false;
|
||||
|
||||
// Success!
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkAdminConfig($adminConfig) {
|
||||
if(!$adminConfig['username']) {
|
||||
$this->error(array('', 'Please enter a username!'));
|
||||
}
|
||||
if(!$adminConfig['password']) {
|
||||
$this->error(array('', 'Please enter a password!'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the web server is IIS and version greater than the given version.
|
||||
*
|
||||
* @param int $fromVersion
|
||||
* @return bool
|
||||
*/
|
||||
public function isIIS($fromVersion = 7) {
|
||||
if(strpos($this->findWebserver(), 'IIS/') === false) {
|
||||
return false;
|
||||
}
|
||||
return substr(strstr($this->findWebserver(), '/'), -3, 1) >= $fromVersion;
|
||||
}
|
||||
|
||||
public function isApache() {
|
||||
if(strpos($this->findWebserver(), 'Apache') !== false) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the webserver software running on the PHP host.
|
||||
* @return string|boolean Server software or boolean FALSE
|
||||
*/
|
||||
public function findWebserver() {
|
||||
// Try finding from SERVER_SIGNATURE or SERVER_SOFTWARE
|
||||
if(!empty($_SERVER['SERVER_SIGNATURE'])) {
|
||||
$webserver = $_SERVER['SERVER_SIGNATURE'];
|
||||
} elseif(!empty($_SERVER['SERVER_SOFTWARE'])) {
|
||||
$webserver = $_SERVER['SERVER_SOFTWARE'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strip_tags(trim($webserver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check everything except the database
|
||||
*/
|
||||
public function check() {
|
||||
$this->errors = null;
|
||||
$isApache = $this->isApache();
|
||||
$isIIS = $this->isIIS();
|
||||
$webserver = $this->findWebserver();
|
||||
|
||||
$this->requirePHPVersion('5.5.0', '5.5.0', array(
|
||||
"PHP Configuration",
|
||||
"PHP5 installed",
|
||||
null,
|
||||
"PHP version " . phpversion()
|
||||
));
|
||||
|
||||
// Check that we can identify the root folder successfully
|
||||
$this->requireFile(FRAMEWORK_NAME . '/src/Dev/Install/config-form.html', array("File permissions",
|
||||
"Does the webserver know where files are stored?",
|
||||
"The webserver isn't letting me identify where files are stored.",
|
||||
$this->getBaseDir()
|
||||
));
|
||||
|
||||
$this->requireModule('mysite', array("File permissions", "mysite/ directory exists?"));
|
||||
$this->requireModule(FRAMEWORK_NAME, array("File permissions", FRAMEWORK_NAME . "/ directory exists?"));
|
||||
|
||||
if($isApache) {
|
||||
$this->checkApacheVersion(array(
|
||||
"Webserver Configuration",
|
||||
"Webserver is not Apache 1.x", "SilverStripe requires Apache version 2 or greater",
|
||||
$webserver
|
||||
));
|
||||
$this->requireWriteable('.htaccess', array("File permissions", "Is the .htaccess file writeable?", null));
|
||||
} elseif($isIIS) {
|
||||
$this->requireWriteable('web.config', array("File permissions", "Is the web.config file writeable?", null));
|
||||
}
|
||||
|
||||
$this->requireWriteable('mysite/_config.php', array(
|
||||
"File permissions",
|
||||
"Is the mysite/_config.php file writeable?",
|
||||
null
|
||||
));
|
||||
|
||||
$this->requireWriteable('mysite/_config/config.yml', array(
|
||||
"File permissions",
|
||||
"Is the mysite/_config/config.yml file writeable?",
|
||||
null
|
||||
));
|
||||
|
||||
if(!$this->checkModuleExists('cms')) {
|
||||
$this->requireWriteable('mysite/code/RootURLController.php', array(
|
||||
"File permissions",
|
||||
"Is the mysite/code/RootURLController.php file writeable?",
|
||||
null
|
||||
));
|
||||
}
|
||||
$this->requireWriteable('assets', array("File permissions", "Is the assets/ directory writeable?", null));
|
||||
|
||||
try {
|
||||
$tempFolder = getTempFolder();
|
||||
} catch(Exception $e) {
|
||||
$tempFolder = false;
|
||||
}
|
||||
|
||||
$this->requireTempFolder(array('File permissions', 'Is a temporary directory available?', null, $tempFolder));
|
||||
if($tempFolder) {
|
||||
// in addition to the temp folder being available, check it is writable
|
||||
$this->requireWriteable($tempFolder, array(
|
||||
"File permissions",
|
||||
sprintf("Is the temporary directory writeable?", $tempFolder),
|
||||
null
|
||||
), true);
|
||||
}
|
||||
|
||||
// Check for web server, unless we're calling the installer from the command-line
|
||||
$this->isRunningWebServer(array("Webserver Configuration", "Server software", "Unknown", $webserver));
|
||||
|
||||
if($isApache) {
|
||||
$this->requireApacheRewriteModule('mod_rewrite', array(
|
||||
"Webserver Configuration",
|
||||
"URL rewriting support",
|
||||
"You need mod_rewrite to use friendly URLs with SilverStripe, but it is not enabled."
|
||||
));
|
||||
} elseif($isIIS) {
|
||||
$this->requireIISRewriteModule('IIS_UrlRewriteModule', array(
|
||||
"Webserver Configuration",
|
||||
"URL rewriting support",
|
||||
"You need to enable the IIS URL Rewrite Module to use friendly URLs with SilverStripe, "
|
||||
. "but it is not installed or enabled. Download it for IIS 7 from http://www.iis.net/expand/URLRewrite"
|
||||
));
|
||||
} else {
|
||||
$this->warning(array(
|
||||
"Webserver Configuration",
|
||||
"URL rewriting support",
|
||||
"I can't tell whether any rewriting module is running. You may need to configure a rewriting rule yourself."));
|
||||
}
|
||||
|
||||
$this->requireServerVariables(array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'), array(
|
||||
"Webserver Configuration",
|
||||
"Recognised webserver",
|
||||
"You seem to be using an unsupported webserver. "
|
||||
. "The server variables SCRIPT_NAME, HTTP_HOST, SCRIPT_FILENAME need to be set."
|
||||
));
|
||||
|
||||
$this->requirePostSupport(array(
|
||||
"Webserver Configuration",
|
||||
"POST Support",
|
||||
'I can\'t find $_POST, make sure POST is enabled.'
|
||||
));
|
||||
|
||||
// Check for GD support
|
||||
if(!$this->requireFunction("imagecreatetruecolor", array(
|
||||
"PHP Configuration",
|
||||
"GD2 support",
|
||||
"PHP must have GD version 2."
|
||||
))) {
|
||||
$this->requireFunction("imagecreate", array(
|
||||
"PHP Configuration",
|
||||
"GD2 support",
|
||||
"GD support for PHP not included."
|
||||
));
|
||||
}
|
||||
|
||||
// Check for XML support
|
||||
$this->requireFunction('xml_set_object', array(
|
||||
"PHP Configuration",
|
||||
"XML support",
|
||||
"XML support not included in PHP."
|
||||
));
|
||||
$this->requireClass('DOMDocument', array(
|
||||
"PHP Configuration",
|
||||
"DOM/XML support",
|
||||
"DOM/XML support not included in PHP."
|
||||
));
|
||||
$this->requireFunction('simplexml_load_file', array(
|
||||
'PHP Configuration',
|
||||
'SimpleXML support',
|
||||
'SimpleXML support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for token_get_all
|
||||
$this->requireFunction('token_get_all', array(
|
||||
"PHP Configuration",
|
||||
"Tokenizer support",
|
||||
"Tokenizer support not included in PHP."
|
||||
));
|
||||
|
||||
// Check for CType support
|
||||
$this->requireFunction('ctype_digit', array(
|
||||
'PHP Configuration',
|
||||
'CType support',
|
||||
'CType support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for session support
|
||||
$this->requireFunction('session_start', array(
|
||||
'PHP Configuration',
|
||||
'Session support',
|
||||
'Session support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for iconv support
|
||||
$this->requireFunction('iconv', array(
|
||||
'PHP Configuration',
|
||||
'iconv support',
|
||||
'iconv support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for hash support
|
||||
$this->requireFunction('hash', array('PHP Configuration', 'hash support', 'hash support not included in PHP.'));
|
||||
|
||||
// Check for mbstring support
|
||||
$this->requireFunction('mb_internal_encoding', array(
|
||||
'PHP Configuration',
|
||||
'mbstring support',
|
||||
'mbstring support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for Reflection support
|
||||
$this->requireClass('ReflectionClass', array(
|
||||
'PHP Configuration',
|
||||
'Reflection support',
|
||||
'Reflection support not included in PHP.'
|
||||
));
|
||||
|
||||
// Check for Standard PHP Library (SPL) support
|
||||
$this->requireFunction('spl_classes', array(
|
||||
'PHP Configuration',
|
||||
'SPL support',
|
||||
'Standard PHP Library (SPL) not included in PHP.'
|
||||
));
|
||||
|
||||
$this->requireDateTimezone(array(
|
||||
'PHP Configuration',
|
||||
'date.timezone setting and validity',
|
||||
'date.timezone option in php.ini must be set correctly.',
|
||||
ini_get('date.timezone')
|
||||
));
|
||||
|
||||
$this->suggestClass('finfo', array(
|
||||
'PHP Configuration',
|
||||
'fileinfo support',
|
||||
'fileinfo should be enabled in PHP. SilverStripe uses it for MIME type detection of files. '
|
||||
. 'SilverStripe will still operate, but email attachments and sending files to browser '
|
||||
. '(e.g. export data to CSV) may not work correctly without finfo.'
|
||||
));
|
||||
|
||||
$this->suggestFunction('curl_init', array(
|
||||
'PHP Configuration',
|
||||
'curl support',
|
||||
'curl should be enabled in PHP. SilverStripe uses it for consuming web services'
|
||||
. ' via the RestfulService class and many modules rely on it.'
|
||||
));
|
||||
|
||||
$this->suggestClass('tidy', array(
|
||||
'PHP Configuration',
|
||||
'tidy support',
|
||||
'Tidy provides a library of code to clean up your html. '
|
||||
. 'SilverStripe will operate fine without tidy but HTMLCleaner will not be effective.'
|
||||
));
|
||||
|
||||
$this->suggestPHPSetting('asp_tags', array(false), array(
|
||||
'PHP Configuration',
|
||||
'asp_tags option',
|
||||
'This should be turned off as it can cause issues with SilverStripe'
|
||||
));
|
||||
$this->requirePHPSetting('magic_quotes_gpc', array(false), array(
|
||||
'PHP Configuration',
|
||||
'magic_quotes_gpc option',
|
||||
'This should be turned off, as it can cause issues with cookies. '
|
||||
. 'More specifically, unserializing data stored in cookies.'
|
||||
));
|
||||
$this->suggestPHPSetting('display_errors', array(false), array(
|
||||
'PHP Configuration',
|
||||
'display_errors option',
|
||||
'Unless you\'re in a development environment, this should be turned off, '
|
||||
. 'as it can expose sensitive data to website users.'
|
||||
));
|
||||
// on some weirdly configured webservers arg_separator.output is set to &
|
||||
// which will results in links like ?param=value&foo=bar which will not be i
|
||||
$this->suggestPHPSetting('arg_separator.output', array('&', ''), array(
|
||||
'PHP Configuration',
|
||||
'arg_separator.output option',
|
||||
'This option defines how URL parameters are concatenated. '
|
||||
. 'If not set to \'&\' this may cause issues with URL GET parameters'
|
||||
));
|
||||
|
||||
// always_populate_raw_post_data should be set to -1 if PHP < 7.0
|
||||
if (version_compare(PHP_VERSION, '7.0.0', '<')) {
|
||||
$this->suggestPHPSetting('always_populate_raw_post_data', ['-1'], [
|
||||
'PHP Configuration',
|
||||
'always_populate_raw_post_data option',
|
||||
'It\'s highly recommended to set this to \'-1\' in php 5.x, as $HTTP_RAW_POST_DATA is removed in php 7'
|
||||
]);
|
||||
}
|
||||
|
||||
// Check memory allocation
|
||||
$this->requireMemory(32 * 1024 * 1024, 64 * 1024 * 1024, array(
|
||||
"PHP Configuration",
|
||||
"Memory allocation (PHP config option 'memory_limit')",
|
||||
"SilverStripe needs a minimum of 32M allocated to PHP, but recommends 64M.",
|
||||
ini_get("memory_limit")
|
||||
));
|
||||
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
public function suggestPHPSetting($settingName, $settingValues, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
// special case for display_errors, check the original value before
|
||||
// it was changed at the start of this script.
|
||||
if($settingName == 'display_errors') {
|
||||
global $originalDisplayErrorsValue;
|
||||
$val = $originalDisplayErrorsValue;
|
||||
} else {
|
||||
$val = ini_get($settingName);
|
||||
}
|
||||
|
||||
if(!in_array($val, $settingValues) && $val != $settingValues) {
|
||||
$this->warning($testDetails, "$settingName is set to '$val' in php.ini. $testDetails[2]");
|
||||
}
|
||||
}
|
||||
|
||||
public function requirePHPSetting($settingName, $settingValues, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
$val = ini_get($settingName);
|
||||
if(!in_array($val, $settingValues) && $val != $settingValues) {
|
||||
$this->error($testDetails, "$settingName is set to '$val' in php.ini. $testDetails[2]");
|
||||
}
|
||||
}
|
||||
|
||||
public function suggestClass($class, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
if(!class_exists($class)) {
|
||||
$this->warning($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function suggestFunction($class, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
if(!function_exists($class)) {
|
||||
$this->warning($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDateTimezone($testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
$result = ini_get('date.timezone') && in_array(ini_get('date.timezone'), timezone_identifiers_list());
|
||||
if(!$result) {
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireMemory($min, $recommended, $testDetails) {
|
||||
$_SESSION['forcemem'] = false;
|
||||
|
||||
$mem = $this->getPHPMemory();
|
||||
if($mem < (64 * 1024 * 1024)) {
|
||||
ini_set('memory_limit', '64M');
|
||||
$mem = $this->getPHPMemory();
|
||||
$testDetails[3] = ini_get("memory_limit");
|
||||
}
|
||||
|
||||
$this->testing($testDetails);
|
||||
|
||||
if($mem < $min && $mem > 0) {
|
||||
$message = $testDetails[2] . " You only have " . ini_get("memory_limit") . " allocated";
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
} else if($mem < $recommended && $mem > 0) {
|
||||
$message = $testDetails[2] . " You only have " . ini_get("memory_limit") . " allocated";
|
||||
$this->warning($testDetails, $message);
|
||||
return false;
|
||||
} elseif($mem == 0) {
|
||||
$message = $testDetails[2] . " We can't determine how much memory you have allocated. "
|
||||
. "Install only if you're sure you've allocated at least 20 MB.";
|
||||
$this->warning($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getPHPMemory() {
|
||||
$memString = ini_get("memory_limit");
|
||||
|
||||
switch(strtolower(substr($memString, -1))) {
|
||||
case "k":
|
||||
return round(substr($memString, 0, -1) * 1024);
|
||||
|
||||
case "m":
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024);
|
||||
|
||||
case "g":
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
|
||||
|
||||
default:
|
||||
return round($memString);
|
||||
}
|
||||
}
|
||||
|
||||
public function listErrors() {
|
||||
if($this->errors) {
|
||||
echo "<p>The following problems are preventing me from installing SilverStripe CMS:</p>\n\n";
|
||||
foreach($this->errors as $error) {
|
||||
echo "<li>" . htmlentities(implode(", ", $error), ENT_COMPAT, 'UTF-8') . "</li>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function showTable($section = null) {
|
||||
if($section) {
|
||||
$tests = $this->tests[$section];
|
||||
$id = strtolower(str_replace(' ', '_', $section));
|
||||
echo "<table id=\"{$id}_results\" class=\"testResults\" width=\"100%\">";
|
||||
foreach($tests as $test => $result) {
|
||||
echo "<tr class=\"$result[0]\"><td>$test</td><td>"
|
||||
. nl2br(htmlentities($result[1], ENT_COMPAT, 'UTF-8')) . "</td></tr>";
|
||||
}
|
||||
echo "</table>";
|
||||
|
||||
} else {
|
||||
foreach($this->tests as $section => $tests) {
|
||||
$failedRequirements = 0;
|
||||
$warningRequirements = 0;
|
||||
|
||||
$output = "";
|
||||
|
||||
foreach($tests as $test => $result) {
|
||||
if(isset($result['0'])) {
|
||||
switch($result['0']) {
|
||||
case 'error':
|
||||
$failedRequirements++;
|
||||
break;
|
||||
case 'warning':
|
||||
$warningRequirements++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$output .= "<tr class=\"$result[0]\"><td>$test</td><td>"
|
||||
. nl2br(htmlentities($result[1], ENT_COMPAT, 'UTF-8')) . "</td></tr>";
|
||||
}
|
||||
$className = "good";
|
||||
$text = "All Requirements Pass";
|
||||
$pluralWarnings = ($warningRequirements == 1) ? 'Warning' : 'Warnings';
|
||||
|
||||
if($failedRequirements > 0) {
|
||||
$className = "error";
|
||||
$pluralWarnings = ($warningRequirements == 1) ? 'Warning' : 'Warnings';
|
||||
|
||||
$text = $failedRequirements . ' Failed and ' . $warningRequirements . ' ' . $pluralWarnings;
|
||||
} else if($warningRequirements > 0) {
|
||||
$className = "warning";
|
||||
$text = "All Requirements Pass but " . $warningRequirements . ' ' . $pluralWarnings;
|
||||
}
|
||||
|
||||
echo "<h5 class='requirement $className'>$section <a href='#'>Show All Requirements</a> <span>$text</span></h5>";
|
||||
echo "<table class=\"testResults\">";
|
||||
echo $output;
|
||||
echo "</table>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function requireFunction($funcName, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
if(!function_exists($funcName)) {
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requireClass($className, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
if(!class_exists($className)) {
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the given class doesn't exist
|
||||
*
|
||||
* @param array $classNames
|
||||
* @param array $testDetails
|
||||
* @return bool
|
||||
*/
|
||||
public function requireNoClasses($classNames, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$badClasses = array();
|
||||
foreach($classNames as $className) {
|
||||
if(class_exists($className)) {
|
||||
$badClasses[] = $className;
|
||||
}
|
||||
}
|
||||
if($badClasses) {
|
||||
$message = $testDetails[2] . ". The following classes are at fault: " . implode(', ', $badClasses);
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkApacheVersion($testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
$is1pointx = preg_match('#Apache[/ ]1\.#', $testDetails[3]);
|
||||
if($is1pointx) {
|
||||
$this->error($testDetails);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requirePHPVersion($recommendedVersion, $requiredVersion, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
$installedVersion = phpversion();
|
||||
|
||||
if(version_compare($installedVersion, $requiredVersion, '<')) {
|
||||
$message = "SilverStripe requires PHP version $requiredVersion or later.\n
|
||||
PHP version $installedVersion is currently installed.\n
|
||||
While SilverStripe requires at least PHP version $requiredVersion, upgrading to $recommendedVersion or later is recommended.\n
|
||||
If you are installing SilverStripe on a shared web server, please ask your web hosting provider to upgrade PHP for you.";
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(version_compare($installedVersion, $recommendedVersion, '<')) {
|
||||
$message = "PHP version $installedVersion is currently installed.\n
|
||||
Upgrading to at least PHP version $recommendedVersion is recommended.\n
|
||||
SilverStripe should run, but you may run into issues. Future releases may require a later version of PHP.\n";
|
||||
$this->warning($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a module exists
|
||||
*
|
||||
* @param string $dirname
|
||||
* @return bool
|
||||
*/
|
||||
public function checkModuleExists($dirname) {
|
||||
$path = $this->getBaseDir() . $dirname;
|
||||
return file_exists($path) && ($dirname == 'mysite' || file_exists($path . '/_config.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as {@link requireFile()} but does additional checks
|
||||
* to ensure the module directory is intact.
|
||||
*
|
||||
* @param string $dirname
|
||||
* @param array $testDetails
|
||||
*/
|
||||
public function requireModule($dirname, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$path = $this->getBaseDir() . $dirname;
|
||||
if(!file_exists($path)) {
|
||||
$testDetails[2] .= " Directory '$path' not found. Please make sure you have uploaded the SilverStripe files to your webserver correctly.";
|
||||
$this->error($testDetails);
|
||||
} elseif(!file_exists($path . '/_config.php') && $dirname != 'mysite') {
|
||||
$testDetails[2] .= " Directory '$path' exists, but is missing files. Please make sure you have uploaded "
|
||||
. "the SilverStripe files to your webserver correctly.";
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireFile($filename, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$filename = $this->getBaseDir() . $filename;
|
||||
if(!file_exists($filename)) {
|
||||
$testDetails[2] .= " (file '$filename' not found)";
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireWriteable($filename, $testDetails, $absolute = false) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
if($absolute) {
|
||||
$filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
|
||||
} else {
|
||||
$filename = $this->getBaseDir() . str_replace('/', DIRECTORY_SEPARATOR, $filename);
|
||||
}
|
||||
|
||||
if(file_exists($filename)) $isWriteable = is_writeable($filename);
|
||||
else $isWriteable = is_writeable(dirname($filename));
|
||||
|
||||
if(!$isWriteable) {
|
||||
if(function_exists('posix_getgroups')) {
|
||||
$userID = posix_geteuid();
|
||||
$user = posix_getpwuid($userID);
|
||||
|
||||
$currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename));
|
||||
$currentOwner = posix_getpwuid($currentOwnerID);
|
||||
|
||||
$testDetails[2] .= "User '$user[name]' needs to be able to write to this file:\n$filename\n\nThe "
|
||||
. "file is currently owned by '$currentOwner[name]'. ";
|
||||
|
||||
if($user['name'] == $currentOwner['name']) {
|
||||
$testDetails[2] .= "We recommend that you make the file writeable.";
|
||||
} else {
|
||||
|
||||
$groups = posix_getgroups();
|
||||
$groupList = array();
|
||||
foreach($groups as $group) {
|
||||
$groupInfo = posix_getgrgid($group);
|
||||
if(in_array($currentOwner['name'], $groupInfo['members'])) $groupList[] = $groupInfo['name'];
|
||||
}
|
||||
if($groupList) {
|
||||
$testDetails[2] .= " We recommend that you make the file group-writeable "
|
||||
. "and change the group to one of these groups:\n - " . implode("\n - ", $groupList)
|
||||
. "\n\nFor example:\nchmod g+w $filename\nchgrp " . $groupList[0] . " $filename";
|
||||
} else {
|
||||
$testDetails[2] .= " There is no user-group that contains both the web-server user and the "
|
||||
. "owner of this file. Change the ownership of the file, create a new group, or "
|
||||
. "temporarily make the file writeable by everyone during the install process.";
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$testDetails[2] .= "The webserver user needs to be able to write to this file:\n$filename";
|
||||
}
|
||||
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireTempFolder($testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
try {
|
||||
$tempFolder = getTempFolder();
|
||||
} catch(Exception $e) {
|
||||
$tempFolder = false;
|
||||
}
|
||||
|
||||
if(!$tempFolder) {
|
||||
$testDetails[2] = "Permission problem gaining access to a temp directory. " .
|
||||
"Please create a folder named silverstripe-cache in the base directory " .
|
||||
"of the installation and ensure it has the adequate permissions.";
|
||||
$this->error($testDetails);
|
||||
}
|
||||
}
|
||||
|
||||
public function requireApacheModule($moduleName, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
if(!in_array($moduleName, apache_get_modules())) {
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function testApacheRewriteExists($moduleName = 'mod_rewrite') {
|
||||
if(function_exists('apache_get_modules') && in_array($moduleName, apache_get_modules())) {
|
||||
return true;
|
||||
} elseif(isset($_SERVER['HTTP_MOD_REWRITE']) && $_SERVER['HTTP_MOD_REWRITE'] == 'On') {
|
||||
return true;
|
||||
} elseif(isset($_SERVER['REDIRECT_HTTP_MOD_REWRITE']) && $_SERVER['REDIRECT_HTTP_MOD_REWRITE'] == 'On') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function testIISRewriteModuleExists($moduleName = 'IIS_UrlRewriteModule') {
|
||||
if(isset($_SERVER[$moduleName]) && $_SERVER[$moduleName]) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireApacheRewriteModule($moduleName, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
if($this->testApacheRewriteExists()) {
|
||||
return true;
|
||||
} else {
|
||||
$this->warning($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the web server has any rewriting capability.
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasRewritingCapability() {
|
||||
return ($this->testApacheRewriteExists() || $this->testIISRewriteModuleExists());
|
||||
}
|
||||
|
||||
public function requireIISRewriteModule($moduleName, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
if($this->testIISRewriteModuleExists()) {
|
||||
return true;
|
||||
} else {
|
||||
$this->warning($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDatabaseTypeNice($databaseClass) {
|
||||
return substr($databaseClass, 0, -8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of a helper class for the specific database.
|
||||
*
|
||||
* @param string $databaseClass e.g. MySQLDatabase or MSSQLDatabase
|
||||
* @return DatabaseConfigurationHelper
|
||||
*/
|
||||
public function getDatabaseConfigurationHelper($databaseClass) {
|
||||
return DatabaseAdapterRegistry::getDatabaseConfigurationHelper($databaseClass);
|
||||
}
|
||||
|
||||
public function requireDatabaseFunctions($databaseConfig, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
if (!$helper) {
|
||||
$this->error($testDetails, "Couldn't load database helper code for ". $databaseConfig['type']);
|
||||
return false;
|
||||
}
|
||||
$result = $helper->requireDatabaseFunctions($databaseConfig);
|
||||
if($result) {
|
||||
return true;
|
||||
} else {
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDatabaseConnection($databaseConfig, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
$result = $helper->requireDatabaseConnection($databaseConfig);
|
||||
if($result['success']) {
|
||||
return true;
|
||||
} else {
|
||||
$testDetails[2] .= ": " . $result['error'];
|
||||
$this->error($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDatabaseVersion($databaseConfig, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
if(method_exists($helper, 'requireDatabaseVersion')) {
|
||||
$result = $helper->requireDatabaseVersion($databaseConfig);
|
||||
if($result['success']) {
|
||||
return true;
|
||||
} else {
|
||||
$testDetails[2] .= $result['error'];
|
||||
$this->warning($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Skipped test because this database has no required version
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requireDatabaseServer($databaseConfig, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
$result = $helper->requireDatabaseServer($databaseConfig);
|
||||
if($result['success']) {
|
||||
return true;
|
||||
} else {
|
||||
$message = $testDetails[2] . ": " . $result['error'];
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDatabaseOrCreatePermissions($databaseConfig, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
$result = $helper->requireDatabaseOrCreatePermissions($databaseConfig);
|
||||
if($result['success']) {
|
||||
if($result['alreadyExists']) {
|
||||
$testDetails[3] = "Database $databaseConfig[database]";
|
||||
} else {
|
||||
$testDetails[3] = "Able to create a new database";
|
||||
}
|
||||
$this->testing($testDetails);
|
||||
return true;
|
||||
} else {
|
||||
if(empty($result['cannotCreate'])) {
|
||||
$message = $testDetails[2] . ". Please create the database manually.";
|
||||
} else {
|
||||
$message = $testDetails[2] . " (user '$databaseConfig[username]' doesn't have CREATE DATABASE permissions.)";
|
||||
}
|
||||
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireDatabaseAlterPermissions($databaseConfig, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$helper = $this->getDatabaseConfigurationHelper($databaseConfig['type']);
|
||||
$result = $helper->requireDatabaseAlterPermissions($databaseConfig);
|
||||
if ($result['success']) {
|
||||
return true;
|
||||
} else {
|
||||
$message = "Silverstripe cannot alter tables. This won't prevent installation, however it may "
|
||||
. "cause issues if you try to run a /dev/build once installed.";
|
||||
$this->warning($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireServerVariables($varNames, $testDetails) {
|
||||
$this->testing($testDetails);
|
||||
$missing = array();
|
||||
|
||||
foreach($varNames as $varName) {
|
||||
if(!isset($_SERVER[$varName]) || !$_SERVER[$varName]) {
|
||||
$missing[] = '$_SERVER[' . $varName . ']';
|
||||
}
|
||||
}
|
||||
|
||||
if(!$missing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$message = $testDetails[2] . " (the following PHP variables are missing: " . implode(", ", $missing) . ")";
|
||||
$this->error($testDetails, $message);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function requirePostSupport($testDetails) {
|
||||
$this->testing($testDetails);
|
||||
|
||||
if(!isset($_POST)) {
|
||||
$this->error($testDetails);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isRunningWebServer($testDetails) {
|
||||
$this->testing($testDetails);
|
||||
if($testDetails[3]) {
|
||||
return true;
|
||||
} else {
|
||||
$this->warning($testDetails);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Must be PHP4 compatible
|
||||
var $baseDir;
|
||||
|
||||
public function getBaseDir() {
|
||||
// Cache the value so that when the installer mucks with SCRIPT_FILENAME half way through, this method
|
||||
// still returns the correct value.
|
||||
if(!$this->baseDir) $this->baseDir = realpath(dirname($_SERVER['SCRIPT_FILENAME'])) . DIRECTORY_SEPARATOR;
|
||||
return $this->baseDir;
|
||||
}
|
||||
|
||||
public function testing($testDetails) {
|
||||
if(!$testDetails) return;
|
||||
|
||||
$section = $testDetails[0];
|
||||
$test = $testDetails[1];
|
||||
|
||||
$message = "OK";
|
||||
if(isset($testDetails[3])) $message .= " ($testDetails[3])";
|
||||
|
||||
$this->tests[$section][$test] = array("good", $message);
|
||||
}
|
||||
|
||||
public function error($testDetails, $message = null) {
|
||||
if (!is_array($testDetails)) {
|
||||
throw new InvalidArgumentException("Invalid error");
|
||||
}
|
||||
$section = $testDetails[0];
|
||||
$test = $testDetails[1];
|
||||
if (!$message && isset($testDetails[2])) {
|
||||
$message = $testDetails[2];
|
||||
}
|
||||
|
||||
$this->tests[$section][$test] = array("error", $message);
|
||||
$this->errors[] = $testDetails;
|
||||
}
|
||||
|
||||
public function warning($testDetails, $message = null) {
|
||||
if (!is_array($testDetails)) {
|
||||
throw new InvalidArgumentException("Invalid warning");
|
||||
}
|
||||
$section = $testDetails[0];
|
||||
$test = $testDetails[1];
|
||||
if (!$message && isset($testDetails[2])) {
|
||||
$message = $testDetails[2];
|
||||
}
|
||||
|
||||
$this->tests[$section][$test] = array("warning", $message);
|
||||
$this->warnings[] = $testDetails;
|
||||
}
|
||||
|
||||
public function hasErrors() {
|
||||
return sizeof($this->errors);
|
||||
}
|
||||
|
||||
public function hasWarnings() {
|
||||
return sizeof($this->warnings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Installer extends InstallRequirements {
|
||||
public function __construct() {
|
||||
// Cache the baseDir value
|
||||
$this->getBaseDir();
|
||||
}
|
||||
|
||||
public function install($config) {
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Installing SilverStripe...</title>
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo FRAMEWORK_NAME; ?>/src/Dev/Install/client/styles/install.css"/>
|
||||
<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"> </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
|
||||
|
||||
$webserver = $this->findWebserver();
|
||||
$isIIS = $this->isIIS();
|
||||
$isApache = $this->isApache();
|
||||
|
||||
flush();
|
||||
|
||||
if(isset($config['stats'])) {
|
||||
if(file_exists(FRAMEWORK_NAME . '/silverstripe_version')) {
|
||||
$silverstripe_version = file_get_contents(FRAMEWORK_NAME . '/silverstripe_version');
|
||||
} else {
|
||||
$silverstripe_version = "unknown";
|
||||
}
|
||||
|
||||
$phpVersion = urlencode(phpversion());
|
||||
$encWebserver = urlencode($webserver);
|
||||
$dbType = $config['db']['type'];
|
||||
|
||||
// Try to determine the database version from the helper
|
||||
$databaseVersion = $config['db']['type'];
|
||||
$helper = $this->getDatabaseConfigurationHelper($dbType);
|
||||
if($helper && method_exists($helper, 'getDatabaseVersion')) {
|
||||
$versionConfig = $config['db'][$dbType];
|
||||
$versionConfig['type'] = $dbType;
|
||||
$databaseVersion = urlencode($dbType . ': ' . $helper->getDatabaseVersion($versionConfig));
|
||||
}
|
||||
|
||||
$url = "http://ss2stat.silverstripe.com/Installation/add?SilverStripe=$silverstripe_version&PHP=$phpVersion&Database=$databaseVersion&WebServer=$encWebserver";
|
||||
|
||||
if(isset($_SESSION['StatsID']) && $_SESSION['StatsID']) {
|
||||
$url .= '&ID=' . $_SESSION['StatsID'];
|
||||
}
|
||||
|
||||
@$_SESSION['StatsID'] = file_get_contents($url);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Escape user input for safe insertion into PHP file
|
||||
$theme = isset($_POST['template']) ? addcslashes($_POST['template'], "\'") : 'simple';
|
||||
$locale = isset($_POST['locale']) ? addcslashes($_POST['locale'], "\'") : 'en_US';
|
||||
$type = addcslashes($config['db']['type'], "\'");
|
||||
$dbConfig = $config['db'][$type];
|
||||
foreach ($dbConfig as &$configValue) {
|
||||
$configValue = addcslashes($configValue, "\\\'");
|
||||
}
|
||||
if(!isset($dbConfig['path'])) $dbConfig['path'] = '';
|
||||
if(!$dbConfig) {
|
||||
echo "<p style=\"color: red\">Bad config submitted</p><pre>";
|
||||
print_r($config);
|
||||
echo "</pre>";
|
||||
die();
|
||||
}
|
||||
|
||||
// Write the config file
|
||||
global $usingEnv;
|
||||
if($usingEnv) {
|
||||
$this->statusMessage("Setting up 'mysite/_config.php' for use with environment variables...");
|
||||
$this->writeToFile("mysite/_config.php", <<<PHP
|
||||
<?php
|
||||
|
||||
global \$project;
|
||||
\$project = 'mysite';
|
||||
|
||||
global \$database;
|
||||
\$database = '{$dbConfig['database']}';
|
||||
|
||||
require_once('conf/ConfigureFromEnv.php');
|
||||
|
||||
PHP
|
||||
);
|
||||
|
||||
} else {
|
||||
$this->statusMessage("Setting up 'mysite/_config.php'...");
|
||||
// Create databaseConfig
|
||||
$lines = array(
|
||||
$lines[] = "\t'type' => '$type'"
|
||||
);
|
||||
foreach($dbConfig as $key => $value) {
|
||||
$lines[] = "\t'{$key}' => '$value'";
|
||||
}
|
||||
$databaseConfigContent = implode(",\n", $lines);
|
||||
$this->writeToFile("mysite/_config.php", <<<PHP
|
||||
<?php
|
||||
|
||||
global \$project;
|
||||
\$project = 'mysite';
|
||||
|
||||
global \$databaseConfig;
|
||||
\$databaseConfig = array(
|
||||
{$databaseConfigContent}
|
||||
);
|
||||
|
||||
PHP
|
||||
);
|
||||
}
|
||||
|
||||
$this->statusMessage("Setting up 'mysite/_config/config.yml'");
|
||||
$this->writeToFile("mysite/_config/config.yml", <<<YML
|
||||
---
|
||||
Name: mysite
|
||||
---
|
||||
# YAML configuration for SilverStripe
|
||||
# See http://doc.silverstripe.org/framework/en/topics/configuration
|
||||
# Caution: Indentation through two spaces, not tabs
|
||||
SilverStripe\\View\\SSViewer:
|
||||
themes:
|
||||
- '$theme'
|
||||
- '\$default'
|
||||
SilverStripe\\i18n\\i18n:
|
||||
default_locale: '$locale'
|
||||
YML
|
||||
);
|
||||
|
||||
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->statusMessage("Setting up '.htaccess' file...");
|
||||
$this->createHtaccess();
|
||||
} elseif($isIIS) {
|
||||
$this->statusMessage("Setting up 'web.config' file...");
|
||||
$this->createWebConfig();
|
||||
}
|
||||
}
|
||||
|
||||
// Load the SilverStripe runtime
|
||||
$_SERVER['SCRIPT_FILENAME'] = dirname(realpath($_SERVER['SCRIPT_FILENAME'])) . '/' . FRAMEWORK_NAME . '/main.php';
|
||||
chdir(FRAMEWORK_NAME);
|
||||
|
||||
// Rebuild the manifest
|
||||
$_GET['flush'] = true;
|
||||
// Show errors as if you're in development mode
|
||||
$_SESSION['isDev'] = 1;
|
||||
|
||||
$this->statusMessage("Building database schema...");
|
||||
|
||||
require_once 'Core/Core.php';
|
||||
|
||||
// Build database
|
||||
$request = new HTTPRequest('GET', '/');
|
||||
$request->setSession(new Session([]));
|
||||
$con = new Controller();
|
||||
$con->setRequest($request);
|
||||
$con->pushCurrent();
|
||||
|
||||
global $databaseConfig;
|
||||
DB::connect($databaseConfig);
|
||||
|
||||
$dbAdmin = new DatabaseAdmin();
|
||||
$dbAdmin->doInit();
|
||||
|
||||
$dbAdmin->doBuild(true);
|
||||
|
||||
// Create default administrator user and group in database
|
||||
// (not using Security::setDefaultAdmin())
|
||||
$adminMember = DefaultAdminService::singleton()->findOrCreateDefaultAdmin();
|
||||
$adminMember->Email = $config['admin']['username'];
|
||||
$adminMember->Password = $config['admin']['password'];
|
||||
$adminMember->PasswordEncryption = Security::config()->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())
|
||||
);
|
||||
}
|
||||
|
||||
$_SESSION['username'] = $config['admin']['username'];
|
||||
$_SESSION['password'] = $config['admin']['password'];
|
||||
|
||||
if(!$this->errors) {
|
||||
if(isset($_SERVER['HTTP_HOST']) && $this->hasRewritingCapability()) {
|
||||
$this->statusMessage("Checking that friendly URLs work...");
|
||||
$this->checkRewrite();
|
||||
} else {
|
||||
require_once 'Core/Startup/ParameterConfirmationToken.php';
|
||||
$token = new ParameterConfirmationToken('flush');
|
||||
$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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
$this->error("Couldn't write to file $base$filename");
|
||||
return false;
|
||||
}
|
||||
|
||||
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 = "";
|
||||
$modulePath = FRAMEWORK_NAME;
|
||||
$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
|
||||
<Files *.yml>
|
||||
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
|
||||
</IfModule>
|
||||
|
||||
SetEnv HTTP_MOD_REWRITE On
|
||||
RewriteEngine On
|
||||
$baseClause
|
||||
$cgiClause
|
||||
|
||||
# Deny access to potentially sensitive files and folders
|
||||
RewriteRule ^vendor(/|$) - [F,L,NC]
|
||||
RewriteRule silverstripe-cache(/|$) - [F,L,NC]
|
||||
RewriteRule composer\.(json|lock) - [F,L,NC]
|
||||
|
||||
# Process through SilverStripe if no file with the requested name exists.
|
||||
# Pass through the original path as a query parameter, and retain the existing parameters.
|
||||
RewriteCond %{REQUEST_URI} ^(.*)$
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule .* $modulePath/main.php?url=%1 [QSA]
|
||||
</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() {
|
||||
$modulePath = FRAMEWORK_NAME;
|
||||
$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>
|
||||
<action type="Rewrite" url="$modulePath/main.php?url={R:1}" appendQueryString="true" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
TEXT;
|
||||
|
||||
$this->writeToFile('web.config', $content);
|
||||
}
|
||||
|
||||
public function checkRewrite() {
|
||||
require_once 'Core/Startup/ParameterConfirmationToken.php';
|
||||
$token = new ParameterConfirmationToken('flush');
|
||||
$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;
|
||||
}
|
||||
|
||||
public function var_export_array_nokeys($array) {
|
||||
$retval = "array(\n";
|
||||
foreach($array as $item) {
|
||||
$retval .= "\t'";
|
||||
$retval .= trim($item);
|
||||
$retval .= "',\n";
|
||||
}
|
||||
$retval .= ")";
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
265
src/Dev/Install/install5.php
Executable file
265
src/Dev/Install/install5.php
Executable file
@ -0,0 +1,265 @@
|
||||
<?php
|
||||
|
||||
/************************************************************************************
|
||||
************************************************************************************
|
||||
** **
|
||||
** If you can read this text in your browser then you don't have PHP installed. **
|
||||
** Please install PHP 5.5.0 or higher. **
|
||||
** **
|
||||
************************************************************************************
|
||||
************************************************************************************/
|
||||
|
||||
namespace SilverStripe\Dev\Install;
|
||||
|
||||
/**
|
||||
* SilverStripe CMS SilverStripe\Dev\Install\Installer
|
||||
* This installer doesn't use any of the fancy SilverStripe stuff in case it's unsupported.
|
||||
*/
|
||||
|
||||
// speed up mysql_connect timeout if the server can't be found
|
||||
ini_set('mysql.connect_timeout', 5);
|
||||
// Don't die half was through installation; that does more harm than good
|
||||
ini_set('max_execution_time', 0);
|
||||
|
||||
// set display_errors php setting to on to force installer to avoid blank screen of death.
|
||||
// get the original value so it can be used in PHP requirement checks later in this script.
|
||||
$originalDisplayErrorsValue = ini_get('display_errors');
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
// Attempt to start a session so that the username and password can be sent back to the user.
|
||||
if (function_exists('session_start') && !session_id()) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// require composers autoloader
|
||||
require __DIR__ . '/../../includes/autoload.php';
|
||||
|
||||
$usingEnv = !empty($_REQUEST['useEnv']);
|
||||
|
||||
// Set default locale, but try and sniff from the user agent
|
||||
$defaultLocale = 'en_US';
|
||||
$locales = array(
|
||||
'af_ZA' => 'Afrikaans (South Africa)',
|
||||
'ar_EG' => 'Arabic (Egypt)',
|
||||
'hy_AM' => 'Armenian (Armenia)',
|
||||
'ast_ES' => 'Asturian (Spain)',
|
||||
'az_AZ' => 'Azerbaijani (Azerbaijan)',
|
||||
'bs_BA' => 'Bosnian (Bosnia and Herzegovina)',
|
||||
'bg_BG' => 'Bulgarian (Bulgaria)',
|
||||
'ca_ES' => 'Catalan (Spain)',
|
||||
'zh_CN' => 'Chinese (China)',
|
||||
'zh_TW' => 'Chinese (Taiwan)',
|
||||
'hr_HR' => 'Croatian (Croatia)',
|
||||
'cs_CZ' => 'Czech (Czech Republic)',
|
||||
'da_DK' => 'Danish (Denmark)',
|
||||
'nl_NL' => 'Dutch (Netherlands)',
|
||||
'en_GB' => 'English (United Kingdom)',
|
||||
'en_US' => 'English (United States)',
|
||||
'eo_XX' => 'Esperanto',
|
||||
'et_EE' => 'Estonian (Estonia)',
|
||||
'fo_FO' => 'Faroese (Faroe Islands)',
|
||||
'fi_FI' => 'Finnish (Finland)',
|
||||
'fr_FR' => 'French (France)',
|
||||
'de_DE' => 'German (Germany)',
|
||||
'el_GR' => 'Greek (Greece)',
|
||||
'he_IL' => 'Hebrew (Israel)',
|
||||
'hu_HU' => 'Hungarian (Hungary)',
|
||||
'is_IS' => 'Icelandic (Iceland)',
|
||||
'id_ID' => 'Indonesian (Indonesia)',
|
||||
'it_IT' => 'Italian (Italy)',
|
||||
'ja_JP' => 'Japanese (Japan)',
|
||||
'km_KH' => 'Khmer (Cambodia)',
|
||||
'lc_XX' => 'LOLCAT',
|
||||
'lv_LV' => 'Latvian (Latvia)',
|
||||
'lt_LT' => 'Lithuanian (Lithuania)',
|
||||
'ms_MY' => 'Malay (Malaysia)',
|
||||
'mi_NZ' => 'Maori (New Zealand)',
|
||||
'ne_NP' => 'Nepali (Nepal)',
|
||||
'nb_NO' => 'Norwegian',
|
||||
'fa_IR' => 'Persian (Iran)',
|
||||
'pl_PL' => 'Polish (Poland)',
|
||||
'pt_BR' => 'Portuguese (Brazil)',
|
||||
'pa_IN' => 'Punjabi (India)',
|
||||
'ro_RO' => 'Romanian (Romania)',
|
||||
'ru_RU' => 'Russian (Russia)',
|
||||
'sr_RS' => 'Serbian (Serbia)',
|
||||
'si_LK' => 'Sinhalese (Sri Lanka)',
|
||||
'sk_SK' => 'Slovak (Slovakia)',
|
||||
'sl_SI' => 'Slovenian (Slovenia)',
|
||||
'es_AR' => 'Spanish (Argentina)',
|
||||
'es_MX' => 'Spanish (Mexico)',
|
||||
'es_ES' => 'Spanish (Spain)',
|
||||
'sv_SE' => 'Swedish (Sweden)',
|
||||
'th_TH' => 'Thai (Thailand)',
|
||||
'tr_TR' => 'Turkish (Turkey)',
|
||||
'uk_UA' => 'Ukrainian (Ukraine)',
|
||||
'uz_UZ' => 'Uzbek (Uzbekistan)',
|
||||
'vi_VN' => 'Vietnamese (Vietnam)',
|
||||
);
|
||||
|
||||
// Discover which databases are available
|
||||
DatabaseAdapterRegistry::autodiscover();
|
||||
|
||||
// Determine which external database modules are USABLE
|
||||
$databaseClasses = DatabaseAdapterRegistry::get_adapters();
|
||||
foreach ($databaseClasses as $class => $details) {
|
||||
$helper = DatabaseAdapterRegistry::getDatabaseConfigurationHelper($class);
|
||||
$databaseClasses[$class]['hasModule'] = !empty($helper);
|
||||
}
|
||||
|
||||
// Load database config
|
||||
if (isset($_REQUEST['db'])) {
|
||||
if (isset($_REQUEST['db']['type'])) {
|
||||
$type = $_REQUEST['db']['type'];
|
||||
} else {
|
||||
if ($type = getenv('SS_DATABASE_CLASS')) {
|
||||
$_REQUEST['db']['type'] = $type;
|
||||
} elseif ($databaseClasses['MySQLPDODatabase']['supported']) {
|
||||
$type = $_REQUEST['db']['type'] = 'MySQLPDODatabase';
|
||||
} elseif ($databaseClasses['MySQLDatabase']['supported']) {
|
||||
$type = $_REQUEST['db']['type'] = 'MySQLDatabase';
|
||||
} else {
|
||||
// handle error
|
||||
}
|
||||
}
|
||||
|
||||
// Disabled inputs don't submit anything - we need to use the environment (except the database name)
|
||||
if ($usingEnv) {
|
||||
$_REQUEST['db'][$type] = $databaseConfig = array(
|
||||
"type" => getenv('SS_DATABASE_CLASS') ?: $type,
|
||||
"server" => getenv('SS_DATABASE_SERVER') ?: "localhost",
|
||||
"username" => getenv('SS_DATABASE_USERNAME') ?: "root",
|
||||
"password" => getenv('SS_DATABASE_PASSWORD') ?: "",
|
||||
"database" => $_REQUEST['db'][$type]['database'],
|
||||
);
|
||||
} else {
|
||||
// Normal behaviour without the environment
|
||||
$databaseConfig = $_REQUEST['db'][$type];
|
||||
$databaseConfig['type'] = $type;
|
||||
}
|
||||
} else {
|
||||
if ($type = getenv('SS_DATABASE_CLASS')) {
|
||||
$_REQUEST['db']['type'] = $type;
|
||||
} elseif ($databaseClasses['MySQLPDODatabase']['supported']) {
|
||||
$type = $_REQUEST['db']['type'] = 'MySQLPDODatabase';
|
||||
} elseif ($databaseClasses['MySQLDatabase']['supported']) {
|
||||
$type = $_REQUEST['db']['type'] = 'MySQLDatabase';
|
||||
} else {
|
||||
// handle error
|
||||
}
|
||||
$_REQUEST['db'][$type] = $databaseConfig = array(
|
||||
"type" => $type,
|
||||
"server" => getenv('SS_DATABASE_SERVER') ?: "localhost",
|
||||
"username" => getenv('SS_DATABASE_USERNAME') ?: "root",
|
||||
"password" => getenv('SS_DATABASE_PASSWORD') ?: "",
|
||||
"database" => isset($_SERVER['argv'][2]) ? $_SERVER['argv'][2] : "SS_mysite",
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['admin'])) {
|
||||
// Disabled inputs don't submit anything - we need to use the environment (except the database name)
|
||||
if ($usingEnv) {
|
||||
$_REQUEST['admin'] = $adminConfig = array(
|
||||
'username' => getenv('SS_DEFAULT_ADMIN_USERNAME') ?: 'admin',
|
||||
'password' => getenv('SS_DEFAULT_ADMIN_PASSWORD') ?: '',
|
||||
);
|
||||
} else {
|
||||
$adminConfig = $_REQUEST['admin'];
|
||||
}
|
||||
} else {
|
||||
$_REQUEST['admin'] = $adminConfig = array(
|
||||
'username' => getenv('SS_DEFAULT_ADMIN_USERNAME') ?: 'admin',
|
||||
'password' => getenv('SS_DEFAULT_ADMIN_PASSWORD') ?: '',
|
||||
);
|
||||
}
|
||||
|
||||
$alreadyInstalled = false;
|
||||
if (file_exists('mysite/_config.php')) {
|
||||
// Find the $database variable in the relevant config file without having to execute the config file
|
||||
if (preg_match("/\\\$database\s*=\s*[^\n\r]+[\n\r]/", file_get_contents("mysite/_config.php"), $parts)) {
|
||||
eval($parts[0]);
|
||||
if (!empty($database)) {
|
||||
$alreadyInstalled = true;
|
||||
}
|
||||
// Assume that if $databaseConfig is defined in mysite/_config.php, then a non-environment-based installation has
|
||||
// already gone ahead
|
||||
} elseif (preg_match(
|
||||
"/\\\$databaseConfig\s*=\s*[^\n\r]+[\n\r]/",
|
||||
file_get_contents("mysite/_config.php"),
|
||||
$parts
|
||||
)) {
|
||||
$alreadyInstalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists(FRAMEWORK_NAME . '/silverstripe_version')) {
|
||||
$silverstripe_version = file_get_contents(FRAMEWORK_NAME . '/silverstripe_version');
|
||||
} else {
|
||||
$silverstripe_version = "unknown";
|
||||
}
|
||||
|
||||
// Check requirements
|
||||
$req = new InstallRequirements();
|
||||
$req->check();
|
||||
|
||||
$webserverConfigFile = '';
|
||||
if ($req->isIIS()) {
|
||||
$webserverConfigFile = 'web.config';
|
||||
} else {
|
||||
$webserverConfigFile = '.htaccess';
|
||||
}
|
||||
|
||||
if ($req->hasErrors()) {
|
||||
$hasErrorOtherThanDatabase = true;
|
||||
$phpIniLocation = php_ini_loaded_file();
|
||||
}
|
||||
|
||||
$dbReq = new InstallRequirements();
|
||||
if ($databaseConfig) {
|
||||
$dbReq->checkDatabase($databaseConfig);
|
||||
}
|
||||
|
||||
$adminReq = new InstallRequirements();
|
||||
if ($adminConfig) {
|
||||
$adminReq->checkAdminConfig($adminConfig);
|
||||
}
|
||||
|
||||
// Actual processor
|
||||
$installFromCli = (isset($_SERVER['argv'][1]) && $_SERVER['argv'][1] == 'install');
|
||||
|
||||
// CLI-install error message. exit(1) will halt any makefile.
|
||||
if ($installFromCli && ($req->hasErrors() || $dbReq->hasErrors())) {
|
||||
echo "Cannot install due to errors:\n";
|
||||
$req->listErrors();
|
||||
$dbReq->listErrors();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((isset($_REQUEST['go']) || $installFromCli)
|
||||
&& !$req->hasErrors()
|
||||
&& !$dbReq->hasErrors()
|
||||
&& $adminConfig['username']
|
||||
&& $adminConfig['password']
|
||||
) {
|
||||
// Confirm before reinstalling
|
||||
if (!$installFromCli && $alreadyInstalled) {
|
||||
include(__DIR__ . '/config-form.html');
|
||||
} else {
|
||||
$inst = new Installer();
|
||||
if ($_REQUEST) {
|
||||
$inst->install($_REQUEST);
|
||||
} else {
|
||||
$inst->install(array(
|
||||
'db' => $databaseConfig,
|
||||
'admin' => $adminConfig,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Show the config form
|
||||
} else {
|
||||
include(__DIR__ . '/config-form.html');
|
||||
}
|
||||
|
@ -894,7 +894,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
$request->setSession($session);
|
||||
|
||||
// Test application
|
||||
$kernel = new TestKernel();
|
||||
$kernel = new TestKernel(BASE_PATH);
|
||||
$app = new HTTPApplication($kernel);
|
||||
|
||||
// Custom application
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace SilverStripe\Dev\State;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Environment;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
|
||||
/**
|
||||
@ -24,21 +25,21 @@ class GlobalsTestState implements TestState
|
||||
|
||||
public function setUp(SapphireTest $test)
|
||||
{
|
||||
$this->vars = Director::envToVars();
|
||||
$this->vars = Environment::getVariables();
|
||||
}
|
||||
|
||||
public function tearDown(SapphireTest $test)
|
||||
{
|
||||
Director::varsToEnv($this->vars);
|
||||
Environment::setVariables($this->vars);
|
||||
}
|
||||
|
||||
public function setUpOnce($class)
|
||||
{
|
||||
$this->staticVars = Director::envToVars();
|
||||
$this->staticVars = Environment::getVariables();
|
||||
}
|
||||
|
||||
public function tearDownOnce($class)
|
||||
{
|
||||
Director::varsToEnv($this->staticVars);
|
||||
Environment::setVariables($this->staticVars);
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ class DatabaseAdmin extends Controller
|
||||
increase_time_limit_to(600);
|
||||
|
||||
// Get all our classes
|
||||
ClassLoader::inst()->getManifest()->regenerate();
|
||||
ClassLoader::inst()->getManifest()->regenerate(false);
|
||||
|
||||
$url = $this->getReturnURL();
|
||||
if ($url) {
|
||||
|
@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
// Mock HTTP globals in CLI environment
|
||||
|
||||
// Ensure that people can't access this from a web-server
|
||||
if (PHP_SAPI != "cli" && PHP_SAPI != "cgi" && PHP_SAPI != "cgi-fcgi") {
|
||||
echo "cli-script.php can't be run from a web request, you have to run it on the command-line.";
|
||||
die();
|
||||
}
|
||||
|
||||
// We update the $_SERVER variable to contain data consistent with the rest of the application.
|
||||
$_SERVER = array_merge(array(
|
||||
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
||||
'HTTP_ACCEPT' => 'text/plain;q=0.5',
|
||||
'HTTP_ACCEPT_LANGUAGE' => '*;q=0.5',
|
||||
'HTTP_ACCEPT_ENCODING' => '',
|
||||
'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1;q=0.5',
|
||||
'SERVER_SIGNATURE' => 'Command-line PHP/' . phpversion(),
|
||||
'SERVER_SOFTWARE' => 'PHP/' . phpversion(),
|
||||
'SERVER_ADDR' => '127.0.0.1',
|
||||
'REMOTE_ADDR' => '127.0.0.1',
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'HTTP_USER_AGENT' => 'CLI',
|
||||
), $_SERVER);
|
||||
|
||||
/**
|
||||
* Process arguments and load them into the $_GET and $_REQUEST arrays
|
||||
* For example,
|
||||
* sake my/url somearg otherarg key=val --otherkey=val third=val&fourth=val
|
||||
*
|
||||
* Will result in the following get data:
|
||||
* args => array('somearg', 'otherarg'),
|
||||
* key => val
|
||||
* otherkey => val
|
||||
* third => val
|
||||
* fourth => val
|
||||
*/
|
||||
if (isset($_SERVER['argv'][2])) {
|
||||
call_user_func(function () {
|
||||
$args = array_slice($_SERVER['argv'], 2);
|
||||
if (!isset($_GET)) {
|
||||
$_GET = array();
|
||||
}
|
||||
if (!isset($_REQUEST)) {
|
||||
$_REQUEST = array();
|
||||
}
|
||||
foreach ($args as $arg) {
|
||||
if (strpos($arg, '=') == false) {
|
||||
$_GET['args'][] = $arg;
|
||||
} else {
|
||||
$newItems = array();
|
||||
parse_str((substr($arg, 0, 2) == '--') ? substr($arg, 2) : $arg, $newItems);
|
||||
$_GET = array_merge($_GET, $newItems);
|
||||
}
|
||||
}
|
||||
$_REQUEST = array_merge($_REQUEST, $_GET);
|
||||
});
|
||||
}
|
||||
|
||||
// Set 'url' GET parameter
|
||||
if (isset($_SERVER['argv'][1])) {
|
||||
$_REQUEST['url'] = $_SERVER['argv'][1];
|
||||
$_GET['url'] = $_SERVER['argv'][1];
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
use Dotenv\Dotenv;
|
||||
use Dotenv\Exception\InvalidPathException;
|
||||
use SilverStripe\Control\Util\IPUtils;
|
||||
use SilverStripe\Core\TempFolder;
|
||||
|
||||
/**
|
||||
* This file is the Framework constants bootstrap. It will prepare some basic common constants.
|
||||
@ -148,5 +149,5 @@ if (defined('CUSTOM_INCLUDE_PATH')) {
|
||||
|
||||
// Define the temporary folder if it wasn't defined yet
|
||||
if (!defined('TEMP_FOLDER')) {
|
||||
define('TEMP_FOLDER', getTempFolder(BASE_PATH));
|
||||
define('TEMP_FOLDER', TempFolder::getTempFolder(BASE_PATH));
|
||||
}
|
||||
|
@ -62,258 +62,3 @@ function _t($entity, $arg = null)
|
||||
// Pass args directly to handle deprecation
|
||||
return call_user_func_array([i18n::class, '_t'], func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the memory limit to the given level if it's currently too low.
|
||||
* Only increases up to the maximum defined in {@link set_increase_memory_limit_max()},
|
||||
* and defaults to the 'memory_limit' setting in the PHP configuration.
|
||||
*
|
||||
* @param string|int $memoryLimit A memory limit string, such as "64M". If omitted, unlimited memory will be set.
|
||||
* @return Boolean TRUE indicates a successful change, FALSE a denied change.
|
||||
*/
|
||||
function increase_memory_limit_to($memoryLimit = -1)
|
||||
{
|
||||
$curLimit = ini_get('memory_limit');
|
||||
|
||||
// Can't go higher than infinite
|
||||
if ($curLimit == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check hard maximums
|
||||
$max = get_increase_memory_limit_max();
|
||||
|
||||
if ($max && $max != -1 && translate_memstring($memoryLimit) > translate_memstring($max)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increase the memory limit if it's too low
|
||||
if ($memoryLimit == -1 || translate_memstring($memoryLimit) > translate_memstring($curLimit)) {
|
||||
ini_set('memory_limit', $memoryLimit);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$_increase_memory_limit_max = ini_get('memory_limit');
|
||||
|
||||
/**
|
||||
* Set the maximum allowed value for {@link increase_memory_limit_to()}.
|
||||
* The same result can also be achieved through 'suhosin.memory_limit'
|
||||
* if PHP is running with the Suhosin system.
|
||||
*
|
||||
* @param string $memoryLimit Memory limit string
|
||||
*/
|
||||
function set_increase_memory_limit_max($memoryLimit)
|
||||
{
|
||||
global $_increase_memory_limit_max;
|
||||
$_increase_memory_limit_max = $memoryLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Memory limit string
|
||||
*/
|
||||
function get_increase_memory_limit_max()
|
||||
{
|
||||
global $_increase_memory_limit_max;
|
||||
return $_increase_memory_limit_max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the XDebug parameter max_nesting_level, which limits how deep recursion can go.
|
||||
* Only does anything if (a) xdebug is installed and (b) the new limit is higher than the existing limit
|
||||
*
|
||||
* @param int $limit - The new limit to increase to
|
||||
*/
|
||||
function increase_xdebug_nesting_level_to($limit)
|
||||
{
|
||||
if (function_exists('xdebug_enable')) {
|
||||
$current = ini_get('xdebug.max_nesting_level');
|
||||
if ((int)$current < $limit) {
|
||||
ini_set('xdebug.max_nesting_level', $limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a memory string, such as 512M into an actual number of bytes.
|
||||
*
|
||||
* @param string $memString A memory limit string, such as "64M"
|
||||
* @return float
|
||||
*/
|
||||
function translate_memstring($memString)
|
||||
{
|
||||
switch (strtolower(substr($memString, -1))) {
|
||||
case "k":
|
||||
return round(substr($memString, 0, -1) * 1024);
|
||||
case "m":
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024);
|
||||
case "g":
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
|
||||
default:
|
||||
return round($memString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the time limit of this script. By default, the time will be unlimited.
|
||||
* Only works if 'safe_mode' is off in the PHP configuration.
|
||||
* Only values up to {@link get_increase_time_limit_max()} are allowed.
|
||||
*
|
||||
* @param int $timeLimit The time limit in seconds. If omitted, no time limit will be set.
|
||||
* @return Boolean TRUE indicates a successful change, FALSE a denied change.
|
||||
*/
|
||||
function increase_time_limit_to($timeLimit = null)
|
||||
{
|
||||
$max = get_increase_time_limit_max();
|
||||
if ($max != -1 && $max != null && $timeLimit > $max) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ini_get('safe_mode')) {
|
||||
if (!$timeLimit) {
|
||||
set_time_limit(0);
|
||||
return true;
|
||||
} else {
|
||||
$currTimeLimit = ini_get('max_execution_time');
|
||||
// Only increase if its smaller
|
||||
if ($currTimeLimit && $currTimeLimit < $timeLimit) {
|
||||
set_time_limit($timeLimit);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum allowed value for {@link increase_timeLimit_to()};
|
||||
*
|
||||
* @param int $timeLimit Limit in seconds
|
||||
*/
|
||||
function set_increase_time_limit_max($timeLimit)
|
||||
{
|
||||
global $_increase_time_limit_max;
|
||||
$_increase_time_limit_max = $timeLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Int Limit in seconds
|
||||
*/
|
||||
function get_increase_time_limit_max()
|
||||
{
|
||||
global $_increase_time_limit_max;
|
||||
return $_increase_time_limit_max;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the temporary folder path that silverstripe should use for its cache files.
|
||||
*
|
||||
* @param string $base The base path to use for determining the temporary path
|
||||
* @return string Path to temp
|
||||
*/
|
||||
function getTempFolder($base = null)
|
||||
{
|
||||
$parent = getTempParentFolder($base);
|
||||
|
||||
// The actual temp folder is a subfolder of getTempParentFolder(), named by username
|
||||
$subfolder = $parent . DIRECTORY_SEPARATOR . getTempFolderUsername();
|
||||
|
||||
if (!@file_exists($subfolder)) {
|
||||
mkdir($subfolder);
|
||||
}
|
||||
|
||||
return $subfolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns as best a representation of the current username as we can glean.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getTempFolderUsername()
|
||||
{
|
||||
$user = getenv('APACHE_RUN_USER');
|
||||
if (!$user) {
|
||||
$user = getenv('USER');
|
||||
}
|
||||
if (!$user) {
|
||||
$user = getenv('USERNAME');
|
||||
}
|
||||
if (!$user && function_exists('posix_getpwuid') && function_exists('posix_getuid')) {
|
||||
$userDetails = posix_getpwuid(posix_getuid());
|
||||
$user = $userDetails['name'];
|
||||
}
|
||||
if (!$user) {
|
||||
$user = 'unknown';
|
||||
}
|
||||
$user = preg_replace('/[^A-Za-z0-9_\-]/', '', $user);
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent folder of the temp folder.
|
||||
* The temp folder will be a subfolder of this, named by username.
|
||||
* This structure prevents permission problems.
|
||||
*
|
||||
* @param string $base
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function getTempParentFolder($base = null)
|
||||
{
|
||||
if (!$base && defined('BASE_PATH')) {
|
||||
$base = BASE_PATH;
|
||||
}
|
||||
|
||||
// first, try finding a silverstripe-cache dir built off the base path
|
||||
$tempPath = $base . DIRECTORY_SEPARATOR . 'silverstripe-cache';
|
||||
if (@file_exists($tempPath)) {
|
||||
if ((fileperms($tempPath) & 0777) != 0777) {
|
||||
@chmod($tempPath, 0777);
|
||||
}
|
||||
return $tempPath;
|
||||
}
|
||||
|
||||
// failing the above, try finding a namespaced silverstripe-cache dir in the system temp
|
||||
$tempPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR .
|
||||
'silverstripe-cache-php' . preg_replace('/[^\w-\.+]+/', '-', PHP_VERSION) .
|
||||
str_replace(array(' ', '/', ':', '\\'), '-', $base);
|
||||
if (!@file_exists($tempPath)) {
|
||||
$oldUMask = umask(0);
|
||||
@mkdir($tempPath, 0777);
|
||||
umask($oldUMask);
|
||||
|
||||
// if the folder already exists, correct perms
|
||||
} else {
|
||||
if ((fileperms($tempPath) & 0777) != 0777) {
|
||||
@chmod($tempPath, 0777);
|
||||
}
|
||||
}
|
||||
|
||||
$worked = @file_exists($tempPath) && @is_writable($tempPath);
|
||||
|
||||
// failing to use the system path, attempt to create a local silverstripe-cache dir
|
||||
if (!$worked) {
|
||||
$tempPath = $base . DIRECTORY_SEPARATOR . 'silverstripe-cache';
|
||||
if (!@file_exists($tempPath)) {
|
||||
$oldUMask = umask(0);
|
||||
@mkdir($tempPath, 0777);
|
||||
umask($oldUMask);
|
||||
}
|
||||
|
||||
$worked = @file_exists($tempPath) && @is_writable($tempPath);
|
||||
}
|
||||
|
||||
if (!$worked) {
|
||||
throw new Exception(
|
||||
'Permission problem gaining access to a temp folder. ' .
|
||||
'Please create a folder named silverstripe-cache in the base folder ' .
|
||||
'of the installation and ensure it has the correct permissions'
|
||||
);
|
||||
}
|
||||
|
||||
return $tempPath;
|
||||
}
|
||||
|
@ -2,35 +2,64 @@
|
||||
|
||||
namespace SilverStripe\Core\Tests;
|
||||
|
||||
use SilverStripe\Core\Environment;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
|
||||
class MemoryLimitTest extends SapphireTest
|
||||
{
|
||||
protected $origMemLimitMax;
|
||||
protected $origTimeLimitMax;
|
||||
protected $origMemLimit;
|
||||
protected $origTimeLimit;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// see http://www.hardened-php.net/suhosin/configuration.html#suhosin.memory_limit
|
||||
if (in_array('suhosin', get_loaded_extensions())) {
|
||||
$this->markTestSkipped("This test cannot be run with suhosin installed");
|
||||
} else {
|
||||
$this->origMemLimit = ini_get('memory_limit');
|
||||
$this->origTimeLimit = ini_get('max_execution_time');
|
||||
$this->origMemLimitMax = Environment::getMemoryLimitMax();
|
||||
$this->origTimeLimitMax = Environment::getTimeLimitMax();
|
||||
Environment::setMemoryLimitMax(null);
|
||||
Environment::setTimeLimitMax(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
if (!in_array('suhosin', get_loaded_extensions())) {
|
||||
ini_set('memory_limit', $this->origMemLimit);
|
||||
set_time_limit($this->origTimeLimit);
|
||||
Environment::setMemoryLimitMax($this->origMemLimitMax);
|
||||
Environment::setTimeLimitMax($this->origTimeLimitMax);
|
||||
}
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testIncreaseMemoryLimitTo()
|
||||
{
|
||||
if (!$this->canChangeMemory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ini_set('memory_limit', '64M');
|
||||
|
||||
// It can go up
|
||||
increase_memory_limit_to('128M');
|
||||
Environment::increaseMemoryLimitTo('128M');
|
||||
$this->assertEquals('128M', ini_get('memory_limit'));
|
||||
|
||||
// But not down
|
||||
increase_memory_limit_to('64M');
|
||||
Environment::increaseMemoryLimitTo('64M');
|
||||
$this->assertEquals('128M', ini_get('memory_limit'));
|
||||
|
||||
// Test the different kinds of syntaxes
|
||||
increase_memory_limit_to(1024*1024*200);
|
||||
Environment::increaseMemoryLimitTo(1024*1024*200);
|
||||
$this->assertEquals(1024*1024*200, ini_get('memory_limit'));
|
||||
|
||||
increase_memory_limit_to('409600K');
|
||||
Environment::increaseMemoryLimitTo('409600K');
|
||||
$this->assertEquals('409600K', ini_get('memory_limit'));
|
||||
|
||||
increase_memory_limit_to('1G');
|
||||
Environment::increaseMemoryLimitTo('1G');
|
||||
|
||||
// If memory limit was left at 409600K, that means that the current testbox doesn't have
|
||||
// 1G of memory available. That's okay; let's not report a failure for that.
|
||||
@ -39,80 +68,31 @@ class MemoryLimitTest extends SapphireTest
|
||||
}
|
||||
|
||||
// No argument means unlimited
|
||||
increase_memory_limit_to();
|
||||
Environment::increaseMemoryLimitTo();
|
||||
$this->assertEquals(-1, ini_get('memory_limit'));
|
||||
}
|
||||
|
||||
public function testIncreaseTimeLimitTo()
|
||||
{
|
||||
if (!$this->canChangeMemory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't change time limit
|
||||
if (!set_time_limit(6000)) {
|
||||
return;
|
||||
$this->markTestSkipped("Cannot change time limit");
|
||||
}
|
||||
|
||||
// It can go up
|
||||
$this->assertTrue(increase_time_limit_to(7000));
|
||||
$this->assertTrue(Environment::increaseTimeLimitTo(7000));
|
||||
$this->assertEquals(7000, ini_get('max_execution_time'));
|
||||
|
||||
// But not down
|
||||
$this->assertTrue(increase_time_limit_to(5000));
|
||||
$this->assertTrue(Environment::increaseTimeLimitTo(5000));
|
||||
$this->assertEquals(7000, ini_get('max_execution_time'));
|
||||
|
||||
// 0/nothing means infinity
|
||||
$this->assertTrue(increase_time_limit_to());
|
||||
$this->assertTrue(Environment::increaseTimeLimitTo());
|
||||
$this->assertEquals(0, ini_get('max_execution_time'));
|
||||
|
||||
// Can't go down from there
|
||||
$this->assertTrue(increase_time_limit_to(10000));
|
||||
$this->assertTrue(Environment::increaseTimeLimitTo(10000));
|
||||
$this->assertEquals(0, ini_get('max_execution_time'));
|
||||
}
|
||||
|
||||
|
||||
///////////////////
|
||||
|
||||
private $origMemLimit, $origTimeLimit;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->origMemLimit = ini_get('memory_limit');
|
||||
$this->origTimeLimit = ini_get('max_execution_time');
|
||||
$this->origMemLimitMax = get_increase_memory_limit_max();
|
||||
$this->origTimeLimitMax = get_increase_time_limit_max();
|
||||
set_increase_memory_limit_max(-1);
|
||||
set_increase_time_limit_max(-1);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
ini_set('memory_limit', $this->origMemLimit);
|
||||
set_time_limit($this->origTimeLimit);
|
||||
set_increase_memory_limit_max($this->origMemLimitMax);
|
||||
set_increase_time_limit_max($this->origTimeLimitMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines wether the environment generally allows
|
||||
* to change the memory limits, which is not always the case.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
protected function canChangeMemory()
|
||||
{
|
||||
$exts = get_loaded_extensions();
|
||||
// see http://www.hardened-php.net/suhosin/configuration.html#suhosin.memory_limit
|
||||
if (in_array('suhosin', $exts)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can't change memory limit in safe mode
|
||||
if (ini_get('safe_mode')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user