mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API Replace SS_HOST with SS_BASE_URL
API Remove Director::$test_servers / $dev_servers API Remove MODULES_PATH / MODULES_DIR constants ENHANCEMENT Injector backtick syntax now supports environment variables as well as constants Fixes #6588
This commit is contained in:
parent
fdd9ad6dbc
commit
2548bfba1e
@ -83,8 +83,8 @@ SilverStripe core environment variables are listed here, though you're free to d
|
||||
| `SS_TRUSTED_PROXY_PROTOCOL_HEADER` | Used to define the proxy header to be used to determine HTTPS status |
|
||||
| `SS_TRUSTED_PROXY_IP_HEADER` | Used to define the proxy header to be used to determine request IPs |
|
||||
| `SS_TRUSTED_PROXY_HOST_HEADER` | Used to define the proxy header to be used to determine the requested host name |
|
||||
| `SS_TRUSTED_PROXY_IPS` | IP address or CIDR range to trust proxy headers from |
|
||||
| `SS_TRUSTED_PROXY_IPS` | IP address or CIDR range to trust proxy headers from. If left blank no proxy headers are trusted. Can be set to 'none' (trust none) or '*' (trust all) |
|
||||
| `SS_ALLOWED_HOSTS` | A comma deliminated list of hostnames the site is allowed to respond to |
|
||||
| `SS_MANIFESTCACHE` | The manifest cache to use (defaults to file based caching). Must be a CacheInterface or CacheFactory class name |
|
||||
| `SS_IGNORE_DOT_ENV` | If set the .env file will be ignored. This is good for live to mitigate any performance implications of loading the .env file |
|
||||
| `SS_HOST` | The hostname to use when it isn't determinable by other means (eg: for CLI commands) |
|
||||
| `SS_BASE_URL` | The url to use when it isn't determinable by other means (eg: for CLI commands) |
|
||||
|
@ -44,20 +44,12 @@ This currently only works on UNIX like systems, not on Windows.
|
||||
|
||||
Sometimes SilverStripe needs to know the URL of your site. For example, when sending an email or generating static
|
||||
files. When you're visiting the site in a web browser this is easy to work out, but when executing scripts on the
|
||||
command line, it has no way of knowing. To work this out, there are several ways to resolve this. You can set alternate
|
||||
base URLs, hosts, and protocol.
|
||||
command line, it has no way of knowing.
|
||||
|
||||
eg:
|
||||
|
||||
```yml
|
||||
SilverStripe\Control\Director:
|
||||
alternate_base_url: 'https://example.com/'
|
||||
```
|
||||
|
||||
Alternatively you can use the `SS_HOST` environment variable to set a fallback hostname:
|
||||
You can use the `SS_BASE_URL` environment variable to specify this.
|
||||
|
||||
```
|
||||
SS_HOST="localhost"
|
||||
SS_BASE_URL="http://localhost/base-url"
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
@ -141,7 +141,8 @@ For example, if you have the below `_ss_environment.php` file, your `.env` would
|
||||
SS_ENVIRONMENT_TYPE="dev"
|
||||
SS_DEFAULT_ADMIN_USERNAME="admin"
|
||||
SS_DEFAULT_ADMIN_PASSWORD="password"
|
||||
SS_HOST="localhost"
|
||||
SS_BASE_URL="http://localhost/"
|
||||
|
||||
### Database
|
||||
SS_DATABASE_CHOOSE_NAME="true"
|
||||
SS_DATABASE_CLASS="MySQLDatabase"
|
||||
@ -154,7 +155,7 @@ The removal of the `_ss_environment.php` file means that conditional logic is no
|
||||
variable set-up process. This generally encouraged bad practice and should be avoided. If you still require conditional
|
||||
logic early in the bootstrap, this is best placed in the `_config.php` files.
|
||||
|
||||
Note also that `$_FILE_TO_URL_MAPPING` has been removed and replaced with `SS_HOST` env var.
|
||||
Note also that `$_FILE_TO_URL_MAPPING` has been removed and replaced with `SS_BASE_URL` env var.
|
||||
|
||||
See [Environment Management docs](/getting-started/environment_management/) for full details.
|
||||
|
||||
@ -1200,6 +1201,19 @@ After (`mysite/_config/config.yml`):
|
||||
* `getsubtree()` -> moved to `CMSMain`
|
||||
* `updatetreenodes()` -> moved to `CMSMain`
|
||||
* `savetreenodes()` -> moved to `CMSMain`
|
||||
* Some `Director` API have been removed.
|
||||
* $dev_servers
|
||||
* $test_servers
|
||||
* $urlParams and setUrlParams()
|
||||
* `Director.alternate_host` removed. Use `Director.alternate_base_url` instead.
|
||||
* `Director.alternate_protocol` removed. Use `Director.alternate_base_url` instead.
|
||||
* Global enviromnent variables changed:
|
||||
* 'BlockUntrustedIPS' env setting has been removed.
|
||||
All IPs are untrusted unless `SS_TRUSTED_PROXY_IPS` is set to '*'
|
||||
See [Environment Management docs](/getting-started/environment_management/) for full details.
|
||||
* `MODULES_PATH` removed
|
||||
* `MODULES_DIR` removed
|
||||
* `SS_HOST` removed. Use `SS_BASE_URL` instead.
|
||||
|
||||
|
||||
#### <a name="overview-general-removed"></a>General and Core Removed API
|
||||
|
@ -57,8 +57,8 @@ Example `.env`:
|
||||
SS_DEFAULT_ADMIN_USERNAME="admin"
|
||||
SS_DEFAULT_ADMIN_PASSWORD="password"
|
||||
|
||||
# Basic CLI hostname
|
||||
SS_HOST="localhost";
|
||||
# Basic CLI request url default
|
||||
SS_BASE_URL="http://localhost/"
|
||||
|
||||
|
||||
You will also need to be assigned the following permissions. Contact one of the SS staff from
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace SilverStripe\Control;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
@ -54,62 +55,49 @@ class Director implements TemplateGlobalProvider
|
||||
const REQUEST = 'REQUEST';
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
static private $urlParams;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static private $rules = array();
|
||||
private static $rules = array();
|
||||
|
||||
/**
|
||||
* Set current page
|
||||
*
|
||||
* @internal
|
||||
* @var SiteTree
|
||||
*/
|
||||
private static $current_page;
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $alternate_base_folder;
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $dev_servers = array();
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $test_servers = array();
|
||||
|
||||
/**
|
||||
* Setting this explicitly specifies the protocol ("http" or "https") used, overriding the normal
|
||||
* behaviour of Director::is_https introspecting it from the request. False values imply default
|
||||
* introspection.
|
||||
* Force the base_url to a specific value.
|
||||
* If assigned, default_base_url and the value in the $_SERVER
|
||||
* global is ignored.
|
||||
* Supports back-ticked vars; E.g. '`SS_BASE_URL`'
|
||||
*
|
||||
* @config
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $alternate_protocol;
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $alternate_base_url;
|
||||
|
||||
/**
|
||||
* @config
|
||||
* Base url to populate if cannot be determined otherwise.
|
||||
* Supports back-ticked vars; E.g. '`SS_BASE_URL`'
|
||||
*
|
||||
* @config
|
||||
* @var string
|
||||
*/
|
||||
private static $default_base_url = '`SS_BASE_URL`';
|
||||
|
||||
/**
|
||||
* Assigned environment type
|
||||
*
|
||||
* @internal
|
||||
* @var string
|
||||
*/
|
||||
protected static $environment_type;
|
||||
@ -279,6 +267,7 @@ class Director implements TemplateGlobalProvider
|
||||
|
||||
// These are needed so that calling Director::test() does not muck with whoever is calling it.
|
||||
// Really, it's some inappropriate coupling and should be resolved by making less use of statics.
|
||||
$oldReadingMode = null;
|
||||
if (class_exists(Versioned::class)) {
|
||||
$oldReadingMode = Versioned::get_reading_mode();
|
||||
}
|
||||
@ -289,11 +278,11 @@ class Director implements TemplateGlobalProvider
|
||||
}
|
||||
|
||||
if (!$session) {
|
||||
$session = Injector::inst()->create('SilverStripe\\Control\\Session', array());
|
||||
$session = Session::create([]);
|
||||
}
|
||||
$cookieJar = $cookies instanceof Cookie_Backend
|
||||
? $cookies
|
||||
: Injector::inst()->createWithArgs('SilverStripe\\Control\\Cookie_Backend', array($cookies ?: array()));
|
||||
: Injector::inst()->createWithArgs(Cookie_Backend::class, array($cookies ?: []));
|
||||
|
||||
// Back up the current values of the superglobals
|
||||
$existingRequestVars = isset($_REQUEST) ? $_REQUEST : array();
|
||||
@ -308,37 +297,6 @@ class Director implements TemplateGlobalProvider
|
||||
Cookie::config()->update('report_errors', false);
|
||||
Requirements::set_backend(Requirements_Backend::create());
|
||||
|
||||
// Set callback to invoke prior to return
|
||||
$onCleanup = function () use (
|
||||
$existingRequestVars,
|
||||
$existingGetVars,
|
||||
$existingPostVars,
|
||||
$existingSessionVars,
|
||||
$existingCookies,
|
||||
$existingServer,
|
||||
$existingRequirementsBackend,
|
||||
$oldReadingMode
|
||||
) {
|
||||
// Restore the super globals
|
||||
$_REQUEST = $existingRequestVars;
|
||||
$_GET = $existingGetVars;
|
||||
$_POST = $existingPostVars;
|
||||
$_SESSION = $existingSessionVars;
|
||||
$_COOKIE = $existingCookies;
|
||||
$_SERVER = $existingServer;
|
||||
|
||||
Requirements::set_backend($existingRequirementsBackend);
|
||||
|
||||
// These are needed so that calling Director::test() does not muck with whoever is calling it.
|
||||
// Really, it's some inappropriate coupling and should be resolved by making less use of statics
|
||||
if (class_exists(Versioned::class)) {
|
||||
Versioned::set_reading_mode($oldReadingMode);
|
||||
}
|
||||
|
||||
Injector::unnest(); // Restore old CookieJar, etc
|
||||
Config::unnest();
|
||||
};
|
||||
|
||||
if (strpos($url, '#') !== false) {
|
||||
$url = substr($url, 0, strpos($url, '#'));
|
||||
}
|
||||
@ -370,7 +328,7 @@ class Director implements TemplateGlobalProvider
|
||||
$_POST = (array) $postVars;
|
||||
$_SESSION = $session ? $session->inst_getAll() : array();
|
||||
$_COOKIE = $cookieJar->getAll(false);
|
||||
Injector::inst()->registerService($cookieJar, 'SilverStripe\\Control\\Cookie_Backend');
|
||||
Injector::inst()->registerService($cookieJar, Cookie_Backend::class);
|
||||
$_SERVER['REQUEST_URI'] = Director::baseURL() . $urlWithQuerystring;
|
||||
|
||||
$request = new HTTPRequest($httpMethod, $url, $getVars, $postVars, $body);
|
||||
@ -380,16 +338,16 @@ class Director implements TemplateGlobalProvider
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Pre-request filtering
|
||||
// @see issue #2517
|
||||
$model = DataModel::inst();
|
||||
$output = Injector::inst()->get('SilverStripe\\Control\\RequestProcessor')->preRequest($request, $session, $model);
|
||||
$requestProcessor = Injector::inst()->get(RequestProcessor::class);
|
||||
$output = $requestProcessor->preRequest($request, $session, $model);
|
||||
if ($output === false) {
|
||||
$onCleanup();
|
||||
throw new HTTPResponse_Exception(_t('Director.INVALID_REQUEST', 'Invalid request'), 400);
|
||||
}
|
||||
|
||||
// TODO: Pass in the DataModel
|
||||
// Process request
|
||||
$result = Director::handleRequest($request, $session, $model);
|
||||
|
||||
// Ensure that the result is an HTTPResponse object
|
||||
@ -403,15 +361,33 @@ class Director implements TemplateGlobalProvider
|
||||
}
|
||||
}
|
||||
|
||||
$output = Injector::inst()->get('SilverStripe\\Control\\RequestProcessor')->postRequest($request, $result, $model);
|
||||
$output = $requestProcessor->postRequest($request, $result, $model);
|
||||
if ($output === false) {
|
||||
$onCleanup();
|
||||
throw new HTTPResponse_Exception("Invalid response");
|
||||
}
|
||||
|
||||
// Return valid response
|
||||
$onCleanup();
|
||||
return $result;
|
||||
} finally {
|
||||
// Restore the super globals
|
||||
$_REQUEST = $existingRequestVars;
|
||||
$_GET = $existingGetVars;
|
||||
$_POST = $existingPostVars;
|
||||
$_SESSION = $existingSessionVars;
|
||||
$_COOKIE = $existingCookies;
|
||||
$_SERVER = $existingServer;
|
||||
|
||||
Requirements::set_backend($existingRequirementsBackend);
|
||||
|
||||
// These are needed so that calling Director::test() does not muck with whoever is calling it.
|
||||
// Really, it's some inappropriate coupling and should be resolved by making less use of statics
|
||||
if (class_exists(Versioned::class)) {
|
||||
Versioned::set_reading_mode($oldReadingMode);
|
||||
}
|
||||
|
||||
Injector::unnest(); // Restore old CookieJar, etc
|
||||
Config::unnest();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -452,7 +428,6 @@ class Director implements TemplateGlobalProvider
|
||||
} else {
|
||||
// Find the controller name
|
||||
$controller = $arguments['Controller'];
|
||||
Director::$urlParams = $arguments;
|
||||
$controllerObj = Injector::inst()->create($controller);
|
||||
$controllerObj->setSession($session);
|
||||
|
||||
@ -475,16 +450,6 @@ class Director implements TemplateGlobalProvider
|
||||
return new HTTPResponse('No URL rule was matched', 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set url parameters (should only be called internally by RequestHandler->handleRequest()).
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
public static function setUrlParams($params)
|
||||
{
|
||||
Director::$urlParams = $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -562,60 +527,66 @@ class Director implements TemplateGlobalProvider
|
||||
/**
|
||||
* A helper to determine the current hostname used to access the site.
|
||||
* The following are used to determine the host (in order)
|
||||
* - Director.alternate_host
|
||||
* - Director.alternate_base_url (if it contains a domain name)
|
||||
* - Trusted proxy headers
|
||||
* - HTTP Host header
|
||||
* - SS_HOST env var
|
||||
* - SS_BASE_URL env var
|
||||
* - SERVER_NAME
|
||||
* - gethostname()
|
||||
*
|
||||
* @param bool $respectConfig Set to false to ignore config override
|
||||
* (Necessary for checking host pre-config)
|
||||
* @return string
|
||||
*/
|
||||
public static function host($respectConfig = true)
|
||||
public static function host()
|
||||
{
|
||||
$headerOverride = false;
|
||||
if (TRUSTED_PROXY) {
|
||||
$headers = (getenv('SS_TRUSTED_PROXY_HOST_HEADER')) ? array(getenv('SS_TRUSTED_PROXY_HOST_HEADER')) : null;
|
||||
if (!$headers) {
|
||||
// Backwards compatible defaults
|
||||
$headers = array('HTTP_X_FORWARDED_HOST');
|
||||
// Check if overridden by alternate_base_url
|
||||
if ($baseURL = self::config()->get('alternate_base_url')) {
|
||||
$baseURL = Injector::inst()->convertServiceProperty($baseURL);
|
||||
$host = parse_url($baseURL, PHP_URL_HOST);
|
||||
if ($host) {
|
||||
return $host;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate proxy-specific headers
|
||||
if (TRUSTED_PROXY) {
|
||||
// Check headers to validate
|
||||
$headers = getenv('SS_TRUSTED_PROXY_HOST_HEADER')
|
||||
? explode(',', getenv('SS_TRUSTED_PROXY_HOST_HEADER'))
|
||||
: ['HTTP_X_FORWARDED_HOST']; // Backwards compatible defaults
|
||||
foreach ($headers as $header) {
|
||||
if (!empty($_SERVER[$header])) {
|
||||
// Get the first host, in case there's multiple separated through commas
|
||||
$headerOverride = strtok($_SERVER[$header], ',');
|
||||
break;
|
||||
return strtok($_SERVER[$header], ',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($respectConfig) {
|
||||
if ($host = Director::config()->uninherited('alternate_host')) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
if ($baseURL = Director::config()->uninherited('alternate_base_url')) {
|
||||
if (preg_match('/^(http[^:]*:\/\/[^\/]+)(\/|$)/', $baseURL, $matches)) {
|
||||
return parse_url($baseURL, PHP_URL_HOST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($headerOverride) {
|
||||
return $headerOverride;
|
||||
}
|
||||
|
||||
// Check given header
|
||||
if (isset($_SERVER['HTTP_HOST'])) {
|
||||
return $_SERVER['HTTP_HOST'];
|
||||
}
|
||||
|
||||
if ($host = getenv('SS_HOST')) {
|
||||
// Check base url
|
||||
if ($baseURL = self::config()->uninherited('default_base_url')) {
|
||||
$baseURL = Injector::inst()->convertServiceProperty($baseURL);
|
||||
$host = parse_url($baseURL, PHP_URL_HOST);
|
||||
if ($host) {
|
||||
return $host;
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy ss4-alpha environment var
|
||||
/**
|
||||
* @todo remove at 4.0.0-beta1
|
||||
* @deprecated 4.0.0-beta1
|
||||
*/
|
||||
$legacyHostname = getenv('SS_HOST');
|
||||
if ($legacyHostname) {
|
||||
Deprecation::notice('4.0', 'SS_HOST will be removed in ss 4.0.0-beta1');
|
||||
return $legacyHostname;
|
||||
}
|
||||
|
||||
// Fail over to server_name (least reliable)
|
||||
return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : gethostname();
|
||||
}
|
||||
|
||||
@ -647,65 +618,74 @@ class Director implements TemplateGlobalProvider
|
||||
*/
|
||||
public static function is_https()
|
||||
{
|
||||
// Check override from alternate_base_url
|
||||
if ($baseURL = self::config()->uninherited('alternate_base_url')) {
|
||||
$baseURL = Injector::inst()->convertServiceProperty($baseURL);
|
||||
$protocol = parse_url($baseURL, PHP_URL_SCHEME);
|
||||
if ($protocol) {
|
||||
return $protocol === 'https';
|
||||
}
|
||||
}
|
||||
|
||||
// See https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
|
||||
// See https://support.microsoft.com/en-us/kb/307347
|
||||
$headerOverride = false;
|
||||
if (TRUSTED_PROXY) {
|
||||
$headers = (getenv('SS_TRUSTED_PROXY_PROTOCOL_HEADER')) ? array(getenv('SS_TRUSTED_PROXY_PROTOCOL_HEADER')) : null;
|
||||
if (!$headers) {
|
||||
// Backwards compatible defaults
|
||||
$headers = array('HTTP_X_FORWARDED_PROTO', 'HTTP_X_FORWARDED_PROTOCOL', 'HTTP_FRONT_END_HTTPS');
|
||||
}
|
||||
$headers = getenv('SS_TRUSTED_PROXY_PROTOCOL_HEADER')
|
||||
? explode(',', getenv('SS_TRUSTED_PROXY_PROTOCOL_HEADER'))
|
||||
: ['HTTP_X_FORWARDED_PROTO', 'HTTP_X_FORWARDED_PROTOCOL', 'HTTP_FRONT_END_HTTPS'];
|
||||
foreach ($headers as $header) {
|
||||
$headerCompareVal = ($header === 'HTTP_FRONT_END_HTTPS' ? 'on' : 'https');
|
||||
if (!empty($_SERVER[$header]) && strtolower($_SERVER[$header]) == $headerCompareVal) {
|
||||
$headerOverride = true;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($protocol = Config::inst()->get('SilverStripe\\Control\\Director', 'alternate_protocol')) {
|
||||
return ($protocol == 'https');
|
||||
} elseif ($headerOverride) {
|
||||
// Check common $_SERVER
|
||||
if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
|
||||
return true;
|
||||
} elseif ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
|
||||
return true;
|
||||
} elseif (isset($_SERVER['SSL'])) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (isset($_SERVER['SSL'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check default_base_url
|
||||
if ($baseURL = self::config()->uninherited('default_base_url')) {
|
||||
$baseURL = Injector::inst()->convertServiceProperty($baseURL);
|
||||
$protocol = parse_url($baseURL, PHP_URL_SCHEME);
|
||||
if ($protocol) {
|
||||
return $protocol === 'https';
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root URL for the site. It will be automatically calculated unless it is overridden
|
||||
* with {@link setBaseURL()}.
|
||||
* Return the root-relative url for the baseurl
|
||||
*
|
||||
* @return string
|
||||
* @return string Root-relative url with trailing slash.
|
||||
*/
|
||||
public static function baseURL()
|
||||
{
|
||||
$alternate = Config::inst()->get('SilverStripe\\Control\\Director', 'alternate_base_url');
|
||||
|
||||
// Check override base_url
|
||||
$alternate = self::config()->get('alternate_base_url');
|
||||
if ($alternate) {
|
||||
return $alternate;
|
||||
} else {
|
||||
$base = BASE_URL;
|
||||
|
||||
if ($base == '/' || $base == '/.' || $base == '\\') {
|
||||
$baseURL = '/';
|
||||
} else {
|
||||
$baseURL = $base . '/';
|
||||
$alternate = Injector::inst()->convertServiceProperty($alternate);
|
||||
return rtrim(parse_url($alternate, PHP_URL_PATH), '/') . '/';
|
||||
}
|
||||
|
||||
// Get env base url
|
||||
$baseURL = rtrim(BASE_URL, '/') . '/';
|
||||
|
||||
// Check if BASE_SCRIPT_URL is defined
|
||||
// e.g. `index.php/`
|
||||
if (defined('BASE_SCRIPT_URL')) {
|
||||
return $baseURL . BASE_SCRIPT_URL;
|
||||
}
|
||||
|
||||
return $baseURL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root filesystem folder for the site. It will be automatically calculated unless
|
||||
@ -1122,11 +1102,6 @@ class Director implements TemplateGlobalProvider
|
||||
* To help with this, SilverStripe supports the notion of an environment type. The environment
|
||||
* type can be dev, test, or live.
|
||||
*
|
||||
* You can set it explicitly with {@link Director::set_environment_type()}. Or you can use
|
||||
* {@link Director::$dev_servers} and {@link Director::$test_servers} to set it implicitly, based
|
||||
* on the value of $_SERVER['HTTP_HOST']. If the HTTP_HOST value is one of the servers listed,
|
||||
* then the environment type will be test or dev. Otherwise, the environment type will be live.
|
||||
*
|
||||
* Dev mode can also be forced by putting ?isDev=1 in your URL, which will ask you to log in and
|
||||
* then push the site into dev mode for the remainder of the session. Putting ?isDev=0 onto the URL
|
||||
* can turn it back.
|
||||
@ -1145,7 +1120,7 @@ class Director implements TemplateGlobalProvider
|
||||
public static function set_environment_type($environment)
|
||||
{
|
||||
if (!in_array($environment, ['dev', 'test', 'live'])) {
|
||||
throw new \InvalidArgumentException(
|
||||
throw new InvalidArgumentException(
|
||||
"Director::set_environment_type passed '$environment'. It should be passed dev, test, or live"
|
||||
);
|
||||
}
|
||||
@ -1175,14 +1150,6 @@ class Director implements TemplateGlobalProvider
|
||||
return $env;
|
||||
}
|
||||
|
||||
// Check if we are running on one of the test servers
|
||||
// Note: Bypass config for checking environment type
|
||||
if (in_array(static::host(false), self::$dev_servers)) {
|
||||
return 'dev';
|
||||
}
|
||||
if (in_array(static::host(false), self::$test_servers)) {
|
||||
return 'test';
|
||||
}
|
||||
return 'live';
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,9 @@
|
||||
<?php
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
use Dotenv\Exception\InvalidPathException;
|
||||
use SilverStripe\Control\Util\IPUtils;
|
||||
|
||||
/**
|
||||
* This file is the Framework constants bootstrap. It will prepare some basic common constants.
|
||||
*
|
||||
@ -12,8 +17,6 @@
|
||||
* See Director::baseFolder(). Can be overwritten by Config::inst()->update('Director', 'alternate_base_folder', ).
|
||||
* - TEMP_FOLDER: Absolute path to temporary folder, used for manifest and template caches. Example: "/var/tmp"
|
||||
* See getTempFolder(). No trailing slash.
|
||||
* - MODULES_DIR: Not used at the moment
|
||||
* - MODULES_PATH: Not used at the moment
|
||||
* - THEMES_DIR: Path relative to webroot, e.g. "themes"
|
||||
* - THEMES_PATH: Absolute filepath, e.g. "/var/www/my-webroot/themes"
|
||||
* - FRAMEWORK_DIR: Path relative to webroot, e.g. "framework"
|
||||
@ -33,66 +36,53 @@
|
||||
* or Client-IP HTTP headers can be trusted
|
||||
*/
|
||||
if (!defined('TRUSTED_PROXY')) {
|
||||
$trusted = true; // will be false by default in a future release
|
||||
|
||||
if (getenv('BlockUntrustedProxyHeaders') // Legacy setting (reverted from documentation)
|
||||
|| getenv('BlockUntrustedIPs') // Documented setting
|
||||
|| getenv('SS_TRUSTED_PROXY_IPS')
|
||||
) {
|
||||
$trusted = false;
|
||||
|
||||
if (getenv('SS_TRUSTED_PROXY_IPS') !== 'none') {
|
||||
if (getenv('SS_TRUSTED_PROXY_IPS') === '*') {
|
||||
$trusted = true;
|
||||
} elseif (isset($_SERVER['REMOTE_ADDR'])) {
|
||||
if (!class_exists('SilverStripe\\Control\\Util\\IPUtils')) {
|
||||
require_once 'Control/IPUtils.php';
|
||||
};
|
||||
$trusted = SilverStripe\Control\Util\IPUtils::checkIP($_SERVER['REMOTE_ADDR'], explode(',', getenv('SS_TRUSTED_PROXY_IPS')));
|
||||
define('TRUSTED_PROXY', call_user_func(function () {
|
||||
$trustedIPs = getenv('SS_TRUSTED_PROXY_IPS');
|
||||
if (empty($trustedIPs) || $trustedIPs === 'none') {
|
||||
return false;
|
||||
}
|
||||
if ($trustedIPs === '*') {
|
||||
return true;
|
||||
}
|
||||
// Validate IP address
|
||||
if (isset($_SERVER['REMOTE_ADDR'])) {
|
||||
return IPUtils::checkIP($_SERVER['REMOTE_ADDR'], explode(',', $trustedIPs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare whether or not the connecting server is a trusted proxy
|
||||
*/
|
||||
define('TRUSTED_PROXY', $trusted);
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define system paths
|
||||
*/
|
||||
// Determine BASE_PATH based on the composer autoloader
|
||||
if (!defined('BASE_PATH')) {
|
||||
define('BASE_PATH', call_user_func(function () {
|
||||
// Determine BASE_PATH based on the composer autoloader
|
||||
foreach (debug_backtrace() as $backtraceItem) {
|
||||
if (preg_match('#^(.*)\/vendor/composer/autoload_real.php#', $backtraceItem['file'], $matches)) {
|
||||
define('BASE_PATH', $matches[1]);
|
||||
break;
|
||||
if (isset($backtraceItem['file']) && preg_match(
|
||||
'#^(?<base>.*)(/|\\\\)vendor(/|\\\\)composer(/|\\\\)autoload_real.php#',
|
||||
$backtraceItem['file'],
|
||||
$matches
|
||||
)) {
|
||||
return realpath($matches['base']) ?: DIRECTORY_SEPARATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine BASE_PATH by assuming that this file is framework/src/Core/Constants.php
|
||||
if (!defined('BASE_PATH')) {
|
||||
// Determine BASE_PATH by assuming that this file is framework/src/Core/Constants.php
|
||||
// we can then determine the base path
|
||||
$candidateBasePath = rtrim(dirname(dirname(dirname(dirname(__FILE__)))), DIRECTORY_SEPARATOR);
|
||||
$candidateBasePath = rtrim(dirname(dirname(dirname(__DIR__))), DIRECTORY_SEPARATOR);
|
||||
// We can't have an empty BASE_PATH. Making it / means that double-slashes occur in places but that's benign.
|
||||
// This likely only happens on chrooted environemnts
|
||||
if ($candidateBasePath == '') {
|
||||
$candidateBasePath = DIRECTORY_SEPARATOR;
|
||||
}
|
||||
define('BASE_PATH', $candidateBasePath);
|
||||
return $candidateBasePath ?: DIRECTORY_SEPARATOR;
|
||||
}));
|
||||
}
|
||||
|
||||
// Allow a first class env var to be set that disables .env file loading
|
||||
if (!getenv('SS_IGNORE_DOT_ENV')) {
|
||||
foreach (array(
|
||||
BASE_PATH,
|
||||
dirname(BASE_PATH),
|
||||
) as $path) {
|
||||
foreach ([ BASE_PATH, dirname(BASE_PATH) ] as $path) {
|
||||
try {
|
||||
(new \Dotenv\Dotenv($path))->load();
|
||||
} catch (\Dotenv\Exception\InvalidPathException $e) {
|
||||
(new Dotenv($path))->load();
|
||||
} catch (InvalidPathException $e) {
|
||||
// no .env found - no big deal
|
||||
continue;
|
||||
}
|
||||
@ -101,48 +91,50 @@ if (!getenv('SS_IGNORE_DOT_ENV')) {
|
||||
}
|
||||
|
||||
if (!defined('BASE_URL')) {
|
||||
define('BASE_URL', call_user_func(function () {
|
||||
// Determine the base URL by comparing SCRIPT_NAME to SCRIPT_FILENAME and getting common elements
|
||||
// This tends not to work on CLI
|
||||
$path = realpath($_SERVER['SCRIPT_FILENAME']);
|
||||
if (substr($path, 0, strlen(BASE_PATH)) == BASE_PATH) {
|
||||
$urlSegmentToRemove = substr($path, strlen(BASE_PATH));
|
||||
if (substr($_SERVER['SCRIPT_NAME'], -strlen($urlSegmentToRemove)) == $urlSegmentToRemove) {
|
||||
$baseURL = substr($_SERVER['SCRIPT_NAME'], 0, -strlen($urlSegmentToRemove));
|
||||
define('BASE_URL', rtrim($baseURL, DIRECTORY_SEPARATOR));
|
||||
// Normalise slashes to '/' and rtrim('/')
|
||||
return rtrim(str_replace('\\', '/', $baseURL), '/');
|
||||
}
|
||||
}
|
||||
|
||||
// If that didn't work, failover to the old syntax. Hopefully this isn't necessary, and maybe
|
||||
// if can be phased out?
|
||||
if (!defined('BASE_URL')) {
|
||||
$dir = (strpos($_SERVER['SCRIPT_NAME'], 'index.php') !== false)
|
||||
? dirname($_SERVER['SCRIPT_NAME'])
|
||||
: dirname(dirname($_SERVER['SCRIPT_NAME']));
|
||||
define('BASE_URL', rtrim($dir, DIRECTORY_SEPARATOR));
|
||||
// Fall back to SS_BASE_URL
|
||||
$base = getenv('SS_BASE_URL');
|
||||
if ($base) {
|
||||
// Strip relative path from SS_BASE_URL
|
||||
return rtrim(parse_url($base, PHP_URL_PATH), '/');
|
||||
}
|
||||
|
||||
// Assume no base_url
|
||||
return '';
|
||||
}));
|
||||
}
|
||||
define('MODULES_DIR', 'modules');
|
||||
define('MODULES_PATH', BASE_PATH . '/' . MODULES_DIR);
|
||||
|
||||
define('THEMES_DIR', 'themes');
|
||||
define('THEMES_PATH', BASE_PATH . '/' . THEMES_DIR);
|
||||
define('THEMES_PATH', BASE_PATH . DIRECTORY_SEPARATOR . THEMES_DIR);
|
||||
|
||||
// Relies on this being in a subdir of the framework.
|
||||
// If it isn't, or is symlinked to a folder with a different name, you must define FRAMEWORK_DIR
|
||||
|
||||
define('FRAMEWORK_PATH', realpath(__DIR__ . '/../../'));
|
||||
if (strpos(FRAMEWORK_PATH, BASE_PATH) === 0) {
|
||||
define('FRAMEWORK_DIR', trim(substr(FRAMEWORK_PATH, strlen(BASE_PATH)), DIRECTORY_SEPARATOR));
|
||||
$frameworkDirSlashSuffix = FRAMEWORK_DIR ? FRAMEWORK_DIR . '/' : '';
|
||||
} else {
|
||||
if (strpos(FRAMEWORK_PATH, BASE_PATH) !== 0) {
|
||||
throw new Exception("Path error: FRAMEWORK_PATH " . FRAMEWORK_PATH . " not within BASE_PATH " . BASE_PATH);
|
||||
}
|
||||
|
||||
define('THIRDPARTY_DIR', $frameworkDirSlashSuffix . 'thirdparty');
|
||||
define('THIRDPARTY_PATH', FRAMEWORK_PATH . '/thirdparty');
|
||||
define('FRAMEWORK_DIR', trim(substr(FRAMEWORK_PATH, strlen(BASE_PATH)), DIRECTORY_SEPARATOR));
|
||||
define('THIRDPARTY_DIR', FRAMEWORK_DIR ? (FRAMEWORK_DIR . '/thirdparty') : 'thirdparty');
|
||||
define('THIRDPARTY_PATH', FRAMEWORK_PATH . DIRECTORY_SEPARATOR . 'thirdparty');
|
||||
|
||||
if (!defined('ASSETS_DIR')) {
|
||||
define('ASSETS_DIR', 'assets');
|
||||
}
|
||||
if (!defined('ASSETS_PATH')) {
|
||||
define('ASSETS_PATH', BASE_PATH . '/' . ASSETS_DIR);
|
||||
define('ASSETS_PATH', BASE_PATH . DIRECTORY_SEPARATOR . ASSETS_DIR);
|
||||
}
|
||||
|
||||
// Custom include path - deprecated
|
||||
@ -153,7 +145,7 @@ if (defined('CUSTOM_INCLUDE_PATH')) {
|
||||
/**
|
||||
* Define the temporary folder if it wasn't defined yet
|
||||
*/
|
||||
require_once 'Core/TempPath.php';
|
||||
require_once __DIR__ . '/TempPath.php';
|
||||
|
||||
if (!defined('TEMP_FOLDER')) {
|
||||
define('TEMP_FOLDER', getTempFolder(BASE_PATH));
|
||||
|
@ -527,7 +527,13 @@ class Injector
|
||||
|
||||
// Evaluate constants surrounded by back ticks
|
||||
if (preg_match('/^`(?<name>[^`]+)`$/', $value, $matches)) {
|
||||
$value = defined($matches['name']) ? constant($matches['name']) : null;
|
||||
if (getenv($matches['name']) !== false) {
|
||||
$value = getenv($matches['name']);
|
||||
} elseif (defined($matches['name'])) {
|
||||
$value = constant($matches['name']);
|
||||
} else {
|
||||
$value = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
@ -191,10 +191,31 @@ class DirectorTest extends SapphireTest
|
||||
Director::absoluteURL('subfolder/test')
|
||||
);
|
||||
|
||||
// absolute base URLS with subdirectory - You should end them in a /
|
||||
Director::config()->set('alternate_base_url', 'http://www.example.org/relativebase/');
|
||||
$_SERVER['REQUEST_URI'] = "http://www.example.org/relativebase/sub-page/";
|
||||
$this->assertEquals('/relativebase/', Director::baseURL()); // Non-absolute url
|
||||
$this->assertEquals('http://www.example.org/relativebase/', Director::absoluteBaseURL());
|
||||
$this->assertEquals('http://www.example.org/relativebase/sub-page/', Director::absoluteURL('', Director::REQUEST));
|
||||
$this->assertEquals('http://www.example.org/relativebase/', Director::absoluteURL('', Director::BASE));
|
||||
$this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::ROOT));
|
||||
$this->assertEquals(
|
||||
'http://www.example.org/relativebase/sub-page/subfolder/test',
|
||||
Director::absoluteURL('subfolder/test', Director::REQUEST)
|
||||
);
|
||||
$this->assertEquals(
|
||||
'http://www.example.org/subfolder/test',
|
||||
Director::absoluteURL('subfolder/test', Director::ROOT)
|
||||
);
|
||||
$this->assertEquals(
|
||||
'http://www.example.org/relativebase/subfolder/test',
|
||||
Director::absoluteURL('subfolder/test', Director::BASE)
|
||||
);
|
||||
|
||||
// absolute base URLs - you should end them in a /
|
||||
Director::config()->set('alternate_base_url', 'http://www.example.org/');
|
||||
$_SERVER['REQUEST_URI'] = "http://www.example.org/sub-page/";
|
||||
$this->assertEquals('http://www.example.org/', Director::baseURL());
|
||||
$this->assertEquals('/', Director::baseURL()); // Non-absolute url
|
||||
$this->assertEquals('http://www.example.org/', Director::absoluteBaseURL());
|
||||
$this->assertEquals('http://www.example.org/sub-page/', Director::absoluteURL('', Director::REQUEST));
|
||||
$this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::BASE));
|
||||
|
Loading…
Reference in New Issue
Block a user