parent
306d801258
commit
de079c041d
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\ORM\DB;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -145,8 +144,6 @@ if(!$url) {
|
|||
|
||||
$_SERVER['REQUEST_URI'] = BASE_URL . '/' . $url;
|
||||
|
||||
// Direct away - this is the "main" function, that hands control to the apporopriate controller
|
||||
DataModel::set_inst(new DataModel());
|
||||
Director::direct($url, DataModel::inst());
|
||||
Director::direct($url);
|
||||
|
||||
|
||||
|
|
|
@ -82,12 +82,12 @@
|
|||
"SilverStripe\\Framework\\Tests\\Behaviour\\": "tests/behat/src/"
|
||||
},
|
||||
"files": [
|
||||
"src/Core/Constants.php",
|
||||
"src/Dev/PhpUnitShim.php"
|
||||
"src/includes/constants.php"
|
||||
]
|
||||
},
|
||||
"include-path": [
|
||||
"src/",
|
||||
"src/includes/",
|
||||
"thirdparty/"
|
||||
],
|
||||
"scripts": {
|
||||
|
|
|
@ -1335,6 +1335,7 @@ After (`mysite/_config/config.yml`):
|
|||
* `findAnAdministrator` use `DefaultAdminService::findOrCreateDefaultAdmin()` instead
|
||||
* `Member` methods deprecated:
|
||||
* `checkPassword`. Use Authenticator::checkPassword() instead
|
||||
* `RequestFilter` changed. $session and $dataModel variables removed from preRequest / postRequest
|
||||
|
||||
#### <a name="overview-general-removed"></a>General and Core Removed API
|
||||
|
||||
|
@ -1523,6 +1524,7 @@ The below methods have been added or had their functionality updated to `DBDate`
|
|||
|
||||
#### <a name="overview-orm-removed"></a>ORM Removed API
|
||||
|
||||
* `DataModel` removed
|
||||
* `DataObject::can*` methods no longer accept a member ID. These must now be passed a Member object or left null
|
||||
* `DataObject::db` removed and replaced with `DataObjectSchema::fieldSpec` and `DataObjectSchema::fieldSpecs`
|
||||
* `DataObject::manyManyComponent` moved to `DataObjectSchema`
|
||||
|
|
228
main.php
228
main.php
|
@ -1,226 +1,26 @@
|
|||
<?php
|
||||
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Core\Startup\ParameterConfirmationToken;
|
||||
use SilverStripe\Core\Startup\ErrorControlChain;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Control\Director;
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
************************************************************************************
|
||||
** **
|
||||
** If you can read this text in your browser then you don't have PHP installed. **
|
||||
** Please install PHP 5.5.0 or higher . **
|
||||
** Please install PHP 5.6.0 or higher **
|
||||
** **
|
||||
************************************************************************************
|
||||
************************************************************************************/
|
||||
|
||||
if (version_compare(phpversion(), '5.5.0', '<')) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error");
|
||||
echo str_replace('$PHPVersion', phpversion(), file_get_contents("Dev/Install/php5-required.html"));
|
||||
die();
|
||||
}
|
||||
use SilverStripe\Core\AppKernel;
|
||||
use SilverStripe\Core\HTTPApplication;
|
||||
use SilverStripe\Core\Startup\ErrorControlChainMiddleware;
|
||||
use SilverStripe\Core\Startup\OutputMiddleware;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
|
||||
/**
|
||||
* Main file that handles every page request.
|
||||
*
|
||||
* The main.php does a number of set-up activities for the request.
|
||||
*
|
||||
* - Includes the .env file in your webroot
|
||||
* - Gets an up-to-date manifest from {@link ManifestBuilder}
|
||||
* - Sets up error handlers with {@link Debug::loadErrorHandlers()}
|
||||
* - Calls {@link DB::connect()}, passing it the global variable $databaseConfig that should
|
||||
* be defined in an _config.php
|
||||
* - Sets up the default director rules using {@link Director::$rules}
|
||||
*
|
||||
* After that, it calls {@link Director::direct()}, which is responsible for doing most of the
|
||||
* real work.
|
||||
*
|
||||
* CONFIGURING THE WEBSERVER
|
||||
*
|
||||
* To use SilverStripe, every request that doesn't point directly to a file should be rewritten to
|
||||
* framework/main.php?url=(url). For example, http://www.example.com/about-us/rss would be rewritten
|
||||
* to http://www.example.com/framework/main.php?url=about-us/rss
|
||||
*
|
||||
* It's important that requests that point directly to a file aren't rewritten; otherwise, visitors
|
||||
* won't be able to download any CSS, JS, image files, or other downloads.
|
||||
*
|
||||
* On Apache, RewriteEngine can be used to do this.
|
||||
*
|
||||
* @see Director::direct()
|
||||
*/
|
||||
require __DIR__ . '/src/includes/autoload.php';
|
||||
|
||||
// require composers autoloader, unless it is already installed
|
||||
if(!class_exists('Composer\\Autoload\\ClassLoader', false)) {
|
||||
if (file_exists($autoloadPath = dirname(__DIR__) . '/vendor/autoload.php')) {
|
||||
require_once $autoloadPath;
|
||||
}
|
||||
else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// IIS will sometimes generate this.
|
||||
if(!empty($_SERVER['HTTP_X_ORIGINAL_URL'])) {
|
||||
$_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_ORIGINAL_URL'];
|
||||
}
|
||||
|
||||
// Enable the entity loader to be able to load XML in Zend_Locale_Data
|
||||
libxml_disable_entity_loader(false);
|
||||
|
||||
/**
|
||||
* Figure out the request URL
|
||||
*/
|
||||
global $url;
|
||||
|
||||
// Helper to safely parse and load a querystring fragment
|
||||
$parseQuery = function($query) {
|
||||
parse_str($query, $_GET);
|
||||
if ($_GET) $_REQUEST = array_merge((array)$_REQUEST, (array)$_GET);
|
||||
};
|
||||
|
||||
// Apache rewrite rules and IIS use this
|
||||
if (isset($_GET['url']) && php_sapi_name() !== 'cli-server') {
|
||||
|
||||
// Prevent injection of url= querystring argument by prioritising any leading url argument
|
||||
if(isset($_SERVER['QUERY_STRING']) &&
|
||||
preg_match('/^(?<url>url=[^&?]*)(?<query>.*[&?]url=.*)$/', $_SERVER['QUERY_STRING'], $results)
|
||||
) {
|
||||
$queryString = $results['query'].'&'.$results['url'];
|
||||
$parseQuery($queryString);
|
||||
}
|
||||
|
||||
$url = $_GET['url'];
|
||||
|
||||
// IIS includes get variables in url
|
||||
$i = strpos($url, '?');
|
||||
if($i !== false) {
|
||||
$url = substr($url, 0, $i);
|
||||
}
|
||||
|
||||
// Lighttpd and PHP 5.4's built-in webserver use this
|
||||
} else {
|
||||
// Get raw URL -- still needs to be decoded below (after parsing out query string).
|
||||
$url = $_SERVER['REQUEST_URI'];
|
||||
|
||||
// Querystring args need to be explicitly parsed
|
||||
if(strpos($url,'?') !== false) {
|
||||
list($url, $query) = explode('?',$url,2);
|
||||
$parseQuery($query);
|
||||
}
|
||||
|
||||
// Decode URL now that it has been separated from query string.
|
||||
$url = urldecode($url);
|
||||
|
||||
// Pass back to the webserver for files that exist
|
||||
if(php_sapi_name() === 'cli-server' && file_exists(BASE_PATH . $url) && is_file(BASE_PATH . $url)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove base folders from the URL if webroot is hosted in a subfolder
|
||||
if (substr(strtolower($url), 0, strlen(BASE_URL)) == strtolower(BASE_URL)) $url = substr($url, strlen(BASE_URL));
|
||||
|
||||
/**
|
||||
* Include SilverStripe's core code
|
||||
*/
|
||||
require_once('Core/Startup/ErrorControlChain.php');
|
||||
require_once('Core/Startup/ParameterConfirmationToken.php');
|
||||
|
||||
// Prepare tokens and execute chain
|
||||
$reloadToken = ParameterConfirmationToken::prepare_tokens(array('isTest', 'isDev', 'flush'));
|
||||
$chain = new ErrorControlChain();
|
||||
$chain
|
||||
->then(function($chain) use ($reloadToken) {
|
||||
// If no redirection is necessary then we can disable error supression
|
||||
if (!$reloadToken) $chain->setSuppression(false);
|
||||
|
||||
// Load in core
|
||||
require_once('Core/Core.php');
|
||||
|
||||
// Connect to database
|
||||
global $databaseConfig;
|
||||
if ($databaseConfig) DB::connect($databaseConfig);
|
||||
|
||||
// Check if a token is requesting a redirect
|
||||
if (!$reloadToken) return;
|
||||
|
||||
// Otherwise, we start up the session if needed
|
||||
if(!isset($_SESSION) && Session::request_contains_session_id()) {
|
||||
Session::start();
|
||||
}
|
||||
|
||||
// Next, check if we're in dev mode, or the database doesn't have any security data, or we are admin
|
||||
if (Director::isDev() || !Security::database_is_ready() || Permission::check('ADMIN')) {
|
||||
$reloadToken->reloadWithToken();
|
||||
return;
|
||||
}
|
||||
|
||||
// Fail and redirect the user to the login page
|
||||
$loginPage = Director::absoluteURL(Security::config()->login_url);
|
||||
$loginPage .= "?BackURL=" . urlencode($_SERVER['REQUEST_URI']);
|
||||
header('location: '.$loginPage, true, 302);
|
||||
die;
|
||||
})
|
||||
// Finally if a token was requested but there was an error while figuring out if it's allowed, do it anyway
|
||||
->thenIfErrored(function() use ($reloadToken){
|
||||
if ($reloadToken) {
|
||||
$reloadToken->reloadWithToken();
|
||||
}
|
||||
})
|
||||
->execute();
|
||||
|
||||
global $databaseConfig;
|
||||
|
||||
// Redirect to the installer if no database is selected
|
||||
if(!isset($databaseConfig) || !isset($databaseConfig['database']) || !$databaseConfig['database']) {
|
||||
|
||||
// Is there an _ss_environment.php file?
|
||||
if(file_exists(BASE_PATH . '/_ss_environment.php') || file_exists(dirname(BASE_PATH) . '/_ss_environment.php')) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error");
|
||||
$dv = new SilverStripe\Dev\DebugView();
|
||||
echo $dv->renderHeader();
|
||||
echo $dv->renderInfo(
|
||||
"Configuraton Error",
|
||||
Director::absoluteBaseURL()
|
||||
);
|
||||
echo $dv->renderParagraph(
|
||||
'You need to replace your _ss_environment.php file with a .env file, or with environment variables.<br><br>'
|
||||
. 'See the <a href="https://docs.silverstripe.org/en/4/getting_started/environment_management/">'
|
||||
. 'Environment Management</a> docs for more information.'
|
||||
);
|
||||
echo $dv->renderFooter();
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
if(!file_exists(BASE_PATH . '/install.php')) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error");
|
||||
die('SilverStripe Framework requires a $databaseConfig defined.');
|
||||
}
|
||||
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
|
||||
$s = (isset($_SERVER['SSL']) || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) ? 's' : '';
|
||||
$installURL = "http$s://" . $host . BASE_URL . '/install.php';
|
||||
|
||||
// The above dirname() will equate to "\" on Windows when installing directly from http://localhost (not using
|
||||
// a sub-directory), this really messes things up in some browsers. Let's get rid of the backslashes
|
||||
$installURL = str_replace('\\', '', $installURL);
|
||||
|
||||
header("Location: $installURL");
|
||||
die();
|
||||
}
|
||||
|
||||
// Direct away - this is the "main" function, that hands control to the appropriate controller
|
||||
DataModel::set_inst(new DataModel());
|
||||
Director::direct($url, DataModel::inst());
|
||||
// Default application
|
||||
$request = HTTPRequest::createFromEnvironment();
|
||||
$kernel = new AppKernel();
|
||||
$app = new HTTPApplication($kernel);
|
||||
$app->addMiddleware(new OutputMiddleware());
|
||||
$app->addMiddleware(new ErrorControlChainMiddleware($app, $request));
|
||||
$app->handle($request);
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @package framework
|
||||
* @subpackage core
|
||||
*
|
||||
* Alternative main.php file for servers that need the php5 extension
|
||||
*/
|
||||
include("main.php");
|
||||
?>
|
|
@ -3,9 +3,7 @@
|
|||
namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\Debug;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\Security\BasicAuth;
|
||||
use SilverStripe\Security\Member;
|
||||
|
@ -47,13 +45,6 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
|
|||
*/
|
||||
protected $action;
|
||||
|
||||
/**
|
||||
* The {@link Session} object for this controller.
|
||||
*
|
||||
* @var Session
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* Stack of current controllers. Controller::$controller_stack[0] is the current controller.
|
||||
*
|
||||
|
@ -152,16 +143,14 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
|
|||
* @todo setDataModel and setRequest are redundantly called in parent::handleRequest() - sort this out
|
||||
*
|
||||
* @param HTTPRequest $request
|
||||
* @param DataModel $model
|
||||
*/
|
||||
protected function beforeHandleRequest(HTTPRequest $request, DataModel $model)
|
||||
protected function beforeHandleRequest(HTTPRequest $request)
|
||||
{
|
||||
//Push the current controller to protect against weird session issues
|
||||
$this->pushCurrent();
|
||||
//Set up the internal dependencies (request, response, datamodel)
|
||||
//Set up the internal dependencies (request, response)
|
||||
$this->setRequest($request);
|
||||
$this->setResponse(new HTTPResponse());
|
||||
$this->setDataModel($model);
|
||||
//kick off the init functionality
|
||||
$this->doInit();
|
||||
}
|
||||
|
@ -192,24 +181,22 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
|
|||
* and end the method with $this->afterHandleRequest()
|
||||
*
|
||||
* @param HTTPRequest $request
|
||||
* @param DataModel $model
|
||||
*
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
public function handleRequest(HTTPRequest $request, DataModel $model)
|
||||
public function handleRequest(HTTPRequest $request)
|
||||
{
|
||||
if (!$request) {
|
||||
user_error("Controller::handleRequest() not passed a request!", E_USER_ERROR);
|
||||
}
|
||||
|
||||
//set up the controller for the incoming request
|
||||
$this->beforeHandleRequest($request, $model);
|
||||
$this->beforeHandleRequest($request);
|
||||
|
||||
//if the before handler manipulated the response in a way that we shouldn't proceed, then skip our request
|
||||
// handling
|
||||
if (!$this->getResponse()->isFinished()) {
|
||||
//retrieve the response for the request
|
||||
$response = parent::handleRequest($request, $model);
|
||||
$response = parent::handleRequest($request);
|
||||
|
||||
//prepare the response (we can receive an assortment of response types (strings/objects/HTTPResponses)
|
||||
$this->prepareResponse($response);
|
||||
|
@ -597,14 +584,6 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
|
|||
public function pushCurrent()
|
||||
{
|
||||
array_unshift(self::$controller_stack, $this);
|
||||
// Create a new session object
|
||||
if (!$this->session) {
|
||||
if (isset(self::$controller_stack[1])) {
|
||||
$this->session = self::$controller_stack[1]->getSession();
|
||||
} else {
|
||||
$this->session = Injector::inst()->create('SilverStripe\\Control\\Session', array());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -653,26 +632,6 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
|
|||
return $this->getResponse() && $this->getResponse()->getHeader('Location');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Session object representing this Controller's session.
|
||||
*
|
||||
* @return Session
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Session object.
|
||||
*
|
||||
* @param Session $session
|
||||
*/
|
||||
public function setSession(Session $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins two or more link segments together, putting a slash between them if necessary. Use this
|
||||
* for building the results of {@link Link()} methods. If either of the links have query strings,
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
|
||||
namespace SilverStripe\Control;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Kernel;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\ORM\ArrayLib;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\View\Requirements;
|
||||
use SilverStripe\View\Requirements_Backend;
|
||||
|
@ -120,112 +119,41 @@ class Director implements TemplateGlobalProvider
|
|||
*
|
||||
* @uses handleRequest() rule-lookup logic is handled by this.
|
||||
* @uses TestController::handleRequest() This handles the page logic for a Director::direct() call.
|
||||
* @param string $url
|
||||
* @param DataModel $model
|
||||
* @param HTTPRequest $request
|
||||
* @return HTTPResponse
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
public static function direct($url, DataModel $model)
|
||||
public static function direct(HTTPRequest $request)
|
||||
{
|
||||
// check allowed hosts
|
||||
if (getenv('SS_ALLOWED_HOSTS') && !Director::is_cli()) {
|
||||
$all_allowed_hosts = explode(',', getenv('SS_ALLOWED_HOSTS'));
|
||||
if (!in_array(static::host(), $all_allowed_hosts)) {
|
||||
throw new HTTPResponse_Exception('Invalid Host', 400);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Validate $_FILES array before merging it with $_POST
|
||||
foreach ($_FILES as $k => $v) {
|
||||
if (is_array($v['tmp_name'])) {
|
||||
$v = ArrayLib::array_values_recursive($v['tmp_name']);
|
||||
foreach ($v as $tmpFile) {
|
||||
if ($tmpFile && !is_uploaded_file($tmpFile)) {
|
||||
user_error("File upload '$k' doesn't appear to be a valid upload", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($v['tmp_name'] && !is_uploaded_file($v['tmp_name'])) {
|
||||
user_error("File upload '$k' doesn't appear to be a valid upload", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$req = new HTTPRequest(
|
||||
(isset($_SERVER['X-HTTP-Method-Override']))
|
||||
? $_SERVER['X-HTTP-Method-Override']
|
||||
: $_SERVER['REQUEST_METHOD'],
|
||||
$url,
|
||||
$_GET,
|
||||
ArrayLib::array_merge_recursive((array) $_POST, (array) $_FILES),
|
||||
@file_get_contents('php://input')
|
||||
);
|
||||
|
||||
$headers = self::extract_request_headers($_SERVER);
|
||||
foreach ($headers as $header => $value) {
|
||||
$req->addHeader($header, $value);
|
||||
}
|
||||
|
||||
// Initiate an empty session - doesn't initialize an actual PHP session until saved (see below)
|
||||
$session = Session::create(isset($_SESSION) ? $_SESSION : array());
|
||||
|
||||
// Only resume a session if its not started already, and a session identifier exists
|
||||
if (!isset($_SESSION) && Session::request_contains_session_id()) {
|
||||
$session->inst_start();
|
||||
}
|
||||
|
||||
$output = RequestProcessor::singleton()->preRequest($req, $session, $model);
|
||||
|
||||
// Pre-request
|
||||
$output = RequestProcessor::singleton()->preRequest($request);
|
||||
if ($output === false) {
|
||||
// @TODO Need to NOT proceed with the request in an elegant manner
|
||||
throw new HTTPResponse_Exception(_t('SilverStripe\\Control\\Director.INVALID_REQUEST', 'Invalid request'), 400);
|
||||
return new HTTPResponse(_t(__CLASS__.'.INVALID_REQUEST', 'Invalid request'), 400);
|
||||
}
|
||||
|
||||
$result = Director::handleRequest($req, $session, $model);
|
||||
// Generate output
|
||||
$result = static::handleRequest($request);
|
||||
|
||||
// Save session data. Note that inst_save() will start/resume the session if required.
|
||||
$session->inst_save();
|
||||
$request->getSession()->save();
|
||||
|
||||
// Return code for a redirection request
|
||||
if (is_string($result) && substr($result, 0, 9) == 'redirect:') {
|
||||
$url = substr($result, 9);
|
||||
|
||||
if (Director::is_cli()) {
|
||||
// on cli, follow SilverStripe redirects automatically
|
||||
Director::direct(
|
||||
str_replace(Director::absoluteBaseURL(), '', $url),
|
||||
DataModel::inst()
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
$response = new HTTPResponse();
|
||||
$response->redirect($url);
|
||||
$res = RequestProcessor::singleton()->postRequest($req, $response, $model);
|
||||
|
||||
if ($res !== false) {
|
||||
$response->output();
|
||||
}
|
||||
}
|
||||
// Handle a controller
|
||||
} elseif ($result) {
|
||||
if ($result instanceof HTTPResponse) {
|
||||
$response = $result;
|
||||
} else {
|
||||
$response = new HTTPResponse();
|
||||
$response->setBody($result);
|
||||
}
|
||||
|
||||
$res = RequestProcessor::singleton()->postRequest($req, $response, $model);
|
||||
if ($res !== false) {
|
||||
$response->output();
|
||||
} else {
|
||||
// @TODO Proper response here.
|
||||
throw new HTTPResponse_Exception("Invalid response");
|
||||
}
|
||||
|
||||
|
||||
//$controllerObj->getSession()->inst_save();
|
||||
// @todo: Refactor into CLIApplication
|
||||
if ($result->isRedirect() && static::is_cli()) {
|
||||
$url = Director::makeRelative($result->getHeader('Location'));
|
||||
$request = clone $request;
|
||||
$request->setUrl($url);
|
||||
return static::direct($request);
|
||||
}
|
||||
|
||||
// Post-request handling
|
||||
$postRequest = RequestProcessor::singleton()->postRequest($request, $result);
|
||||
if ($postRequest === false) {
|
||||
return new HTTPResponse(_t(__CLASS__ . '.REQUEST_ABORTED', 'Request aborted'), 500);
|
||||
}
|
||||
|
||||
// Return
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,7 +206,7 @@ class Director implements TemplateGlobalProvider
|
|||
}
|
||||
|
||||
if (!$session) {
|
||||
$session = Session::create([]);
|
||||
$session = new Session([]);
|
||||
}
|
||||
$cookieJar = $cookies instanceof Cookie_Backend
|
||||
? $cookies
|
||||
|
@ -340,15 +268,14 @@ class Director implements TemplateGlobalProvider
|
|||
|
||||
try {
|
||||
// Pre-request filtering
|
||||
$model = DataModel::inst();
|
||||
$requestProcessor = Injector::inst()->get(RequestProcessor::class);
|
||||
$output = $requestProcessor->preRequest($request, $session, $model);
|
||||
$output = $requestProcessor->preRequest($request);
|
||||
if ($output === false) {
|
||||
throw new HTTPResponse_Exception(_t('SilverStripe\\Control\\Director.INVALID_REQUEST', 'Invalid request'), 400);
|
||||
}
|
||||
|
||||
// Process request
|
||||
$result = Director::handleRequest($request, $session, $model);
|
||||
$result = Director::handleRequest($request);
|
||||
|
||||
// Ensure that the result is an HTTPResponse object
|
||||
if (is_string($result)) {
|
||||
|
@ -395,15 +322,14 @@ class Director implements TemplateGlobalProvider
|
|||
*
|
||||
* @skipUpgrade
|
||||
* @param HTTPRequest $request
|
||||
* @param Session $session
|
||||
* @param DataModel $model
|
||||
* @return HTTPResponse|string
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
protected static function handleRequest(HTTPRequest $request, Session $session, DataModel $model)
|
||||
protected static function handleRequest(HTTPRequest $request)
|
||||
{
|
||||
$rules = Director::config()->uninherited('rules');
|
||||
|
||||
foreach ($rules as $pattern => $controllerOptions) {
|
||||
// Normalise route rule
|
||||
if (is_string($controllerOptions)) {
|
||||
if (substr($controllerOptions, 0, 2) == '->') {
|
||||
$controllerOptions = array('Redirect' => substr($controllerOptions, 2));
|
||||
|
@ -412,7 +338,9 @@ class Director implements TemplateGlobalProvider
|
|||
}
|
||||
}
|
||||
|
||||
if (($arguments = $request->match($pattern, true)) !== false) {
|
||||
// Match pattern
|
||||
$arguments = $request->match($pattern, true);
|
||||
if ($arguments !== false) {
|
||||
$request->setRouteParams($controllerOptions);
|
||||
// controllerOptions provide some default arguments
|
||||
$arguments = array_merge($controllerOptions, $arguments);
|
||||
|
@ -424,24 +352,20 @@ class Director implements TemplateGlobalProvider
|
|||
|
||||
// Handle redirection
|
||||
if (isset($arguments['Redirect'])) {
|
||||
return "redirect:" . Director::absoluteURL($arguments['Redirect'], true);
|
||||
} else {
|
||||
// Find the controller name
|
||||
$controller = $arguments['Controller'];
|
||||
$controllerObj = Injector::inst()->create($controller);
|
||||
$controllerObj->setSession($session);
|
||||
// Redirection
|
||||
$response = new HTTPResponse();
|
||||
$response->redirect(static::absoluteURL($arguments['Redirect']));
|
||||
return $response;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $controllerObj->handleRequest($request, $model);
|
||||
} catch (HTTPResponse_Exception $responseException) {
|
||||
$result = $responseException->getResponse();
|
||||
}
|
||||
if (!is_object($result) || $result instanceof HTTPResponse) {
|
||||
return $result;
|
||||
}
|
||||
// Find the controller name
|
||||
$controller = $arguments['Controller'];
|
||||
$controllerObj = Injector::inst()->create($controller);
|
||||
|
||||
user_error("Bad result from url " . $request->getURL() . " handled by " .
|
||||
get_class($controllerObj)." controller: ".get_class($result), E_USER_WARNING);
|
||||
try {
|
||||
return $controllerObj->handleRequest($request);
|
||||
} catch (HTTPResponse_Exception $responseException) {
|
||||
return $responseException->getResponse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -852,36 +776,6 @@ class Director implements TemplateGlobalProvider
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a $_SERVER data array and extracts HTTP request headers.
|
||||
*
|
||||
* @param array $server
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function extract_request_headers(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a filesystem reference relative to the site root, return the full file-system path.
|
||||
*
|
||||
|
@ -1073,47 +967,7 @@ class Director implements TemplateGlobalProvider
|
|||
*/
|
||||
public static function is_cli()
|
||||
{
|
||||
return (php_sapi_name() == "cli");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the environment type of the current site.
|
||||
*
|
||||
* Typically, a SilverStripe site have a number of environments:
|
||||
* - Development environments, such a copy on your local machine.
|
||||
* - Test sites, such as the one you show the client before going live.
|
||||
* - The live site itself.
|
||||
*
|
||||
* The behaviour of these environments often varies slightly. For example, development sites may
|
||||
* have errors dumped to the screen, and order confirmation emails might be sent to the developer
|
||||
* instead of the client.
|
||||
*
|
||||
* To help with this, SilverStripe supports the notion of an environment type. The environment
|
||||
* type can be dev, test, or 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.
|
||||
*
|
||||
* Test mode can also be forced by putting ?isTest=1 in your URL, which will ask you to log in and
|
||||
* then push the site into test mode for the remainder of the session. Putting ?isTest=0 onto the URL
|
||||
* can turn it back.
|
||||
*
|
||||
* Generally speaking, these methods will be called from your _config.php file.
|
||||
*
|
||||
* Once the environment type is set, it can be checked with {@link Director::isDev()},
|
||||
* {@link Director::isTest()}, and {@link Director::isLive()}.
|
||||
*
|
||||
* @param string $environment
|
||||
*/
|
||||
public static function set_environment_type($environment)
|
||||
{
|
||||
if (!in_array($environment, ['dev', 'test', 'live'])) {
|
||||
throw new InvalidArgumentException(
|
||||
"Director::set_environment_type passed '$environment'. It should be passed dev, test, or live"
|
||||
);
|
||||
}
|
||||
self::$environment_type = $environment;
|
||||
return php_sapi_name() === "cli";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1124,22 +978,9 @@ class Director implements TemplateGlobalProvider
|
|||
*/
|
||||
public static function get_environment_type()
|
||||
{
|
||||
// Check saved session
|
||||
if ($env = self::session_environment()) {
|
||||
return $env;
|
||||
}
|
||||
|
||||
// Check set
|
||||
if (self::$environment_type) {
|
||||
return self::$environment_type;
|
||||
}
|
||||
|
||||
// Check getenv
|
||||
if ($env = getenv('SS_ENVIRONMENT_TYPE')) {
|
||||
return $env;
|
||||
}
|
||||
|
||||
return 'live';
|
||||
/** @var Kernel $kernel */
|
||||
$kernel = Injector::inst()->get(Kernel::class);
|
||||
return $kernel->getEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1175,37 +1016,6 @@ class Director implements TemplateGlobalProvider
|
|||
return self::get_environment_type() === 'test';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check or update any temporary environment specified in the session.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public static function session_environment()
|
||||
{
|
||||
// Set session from querystring
|
||||
if (isset($_GET['isDev'])) {
|
||||
if (isset($_SESSION)) {
|
||||
unset($_SESSION['isTest']); // In case we are changing from test mode
|
||||
$_SESSION['isDev'] = $_GET['isDev'];
|
||||
}
|
||||
return 'dev';
|
||||
} elseif (isset($_GET['isTest'])) {
|
||||
if (isset($_SESSION)) {
|
||||
unset($_SESSION['isDev']); // In case we are changing from dev mode
|
||||
$_SESSION['isTest'] = $_GET['isTest'];
|
||||
}
|
||||
return 'test';
|
||||
}
|
||||
// Check session
|
||||
if (isset($_SESSION['isDev']) && $_SESSION['isDev']) {
|
||||
return 'dev';
|
||||
} elseif (isset($_SESSION['isTest']) && $_SESSION['isTest']) {
|
||||
return 'test';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of strings of the method names of methods on the call that should be exposed
|
||||
* as global variables in the templates.
|
||||
|
|
|
@ -96,6 +96,72 @@ class Email extends ViewableData
|
|||
return \Swift_Validate::email($address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get send_all_emails_to
|
||||
*
|
||||
* @return array Keys are addresses, values are names
|
||||
*/
|
||||
public static function getSendAllEmailsTo()
|
||||
{
|
||||
return static::mergeConfiguredEmails('send_all_emails_to', 'SS_SEND_ALL_EMAILS_TO');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cc_all_emails_to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getCCAllEmailsTo()
|
||||
{
|
||||
return static::mergeConfiguredEmails('cc_all_emails_to', 'SS_CC_ALL_EMAILS_TO');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bcc_all_emails_to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getBCCAllEmailsTo()
|
||||
{
|
||||
return static::mergeConfiguredEmails('bcc_all_emails_to', 'SS_BCC_ALL_EMAILS_TO');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get send_all_emails_from
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getSendAllEmailsFrom()
|
||||
{
|
||||
return static::mergeConfiguredEmails('send_all_emails_from', 'SS_SEND_ALL_EMAILS_FROM');
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise email list from config merged with env vars
|
||||
*
|
||||
* @param string $config Config key
|
||||
* @param string $env Env variable key
|
||||
* @return array Array of email addresses
|
||||
*/
|
||||
protected static function mergeConfiguredEmails($config, $env)
|
||||
{
|
||||
// Normalise config list
|
||||
$normalised = [];
|
||||
$source = (array)static::config()->get($config);
|
||||
foreach ($source as $address => $name) {
|
||||
if ($address && !is_numeric($address)) {
|
||||
$normalised[$address] = $name;
|
||||
} elseif ($name) {
|
||||
$normalised[$name] = null;
|
||||
}
|
||||
}
|
||||
$extra = getenv($env);
|
||||
if ($extra) {
|
||||
$normalised[$extra] = null;
|
||||
}
|
||||
return $normalised;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an email-address to protect it from spambots.
|
||||
* At the moment only simple string substitutions,
|
||||
|
|
|
@ -11,36 +11,29 @@ class SwiftPlugin implements \Swift_Events_SendListener
|
|||
*/
|
||||
public function beforeSendPerformed(\Swift_Events_SendEvent $evt)
|
||||
{
|
||||
|
||||
/** @var \Swift_Message $message */
|
||||
$message = $evt->getMessage();
|
||||
$sendAllTo = Email::config()->send_all_emails_to;
|
||||
$ccAllTo = Email::config()->cc_all_emails_to;
|
||||
$bccAllTo = Email::config()->bcc_all_emails_to;
|
||||
$sendAllFrom = Email::config()->send_all_emails_from;
|
||||
|
||||
$sendAllTo = Email::getSendAllEmailsTo();
|
||||
if (!empty($sendAllTo)) {
|
||||
$this->setTo($message, $sendAllTo);
|
||||
}
|
||||
|
||||
$ccAllTo = Email::getCCAllEmailsTo();
|
||||
if (!empty($ccAllTo)) {
|
||||
if (!is_array($ccAllTo)) {
|
||||
$ccAllTo = array($ccAllTo => null);
|
||||
}
|
||||
foreach ($ccAllTo as $address => $name) {
|
||||
$message->addCc($address, $name);
|
||||
}
|
||||
}
|
||||
|
||||
$bccAllTo = Email::getBCCAllEmailsTo();
|
||||
if (!empty($bccAllTo)) {
|
||||
if (!is_array($bccAllTo)) {
|
||||
$bccAllTo = array($bccAllTo => null);
|
||||
}
|
||||
foreach ($bccAllTo as $address => $name) {
|
||||
$message->addBcc($address, $name);
|
||||
}
|
||||
}
|
||||
|
||||
$sendAllFrom = Email::getSendAllEmailsFrom();
|
||||
if (!empty($sendAllFrom)) {
|
||||
$this->setFrom($message, $sendAllFrom);
|
||||
}
|
||||
|
@ -48,7 +41,7 @@ class SwiftPlugin implements \Swift_Events_SendListener
|
|||
|
||||
/**
|
||||
* @param \Swift_Mime_Message $message
|
||||
* @param string $to
|
||||
* @param array|string $to
|
||||
*/
|
||||
protected function setTo($message, $to)
|
||||
{
|
||||
|
@ -70,7 +63,7 @@ class SwiftPlugin implements \Swift_Events_SendListener
|
|||
|
||||
/**
|
||||
* @param \Swift_Mime_Message $message
|
||||
* @param string $from
|
||||
* @param array|string $from
|
||||
*/
|
||||
protected function setFrom($message, $from)
|
||||
{
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\Core\Flushable;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
|
||||
/**
|
||||
|
@ -11,37 +10,17 @@ use SilverStripe\Core\ClassInfo;
|
|||
*/
|
||||
class FlushRequestFilter implements RequestFilter
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param HTTPRequest $request
|
||||
* @param Session $session
|
||||
* @param DataModel $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function preRequest(HTTPRequest $request, Session $session, DataModel $model)
|
||||
public function preRequest(HTTPRequest $request)
|
||||
{
|
||||
if (array_key_exists('flush', $request->getVars())) {
|
||||
foreach (ClassInfo::implementorsOf(Flushable::class) as $class) {
|
||||
$class::flush();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param HTTPRequest $request
|
||||
* @param HTTPResponse $response
|
||||
* @param DataModel $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response, DataModel $model)
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -125,6 +125,11 @@ class HTTPRequest implements ArrayAccess
|
|||
*/
|
||||
protected $unshiftedButParsedParts = 0;
|
||||
|
||||
/**
|
||||
* @var Session
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* Construct a HTTPRequest from a URL relative to the site root.
|
||||
*
|
||||
|
@ -138,12 +143,194 @@ class HTTPRequest implements ArrayAccess
|
|||
{
|
||||
$this->httpMethod = strtoupper(self::detect_method($httpMethod, $postVars));
|
||||
$this->setUrl($url);
|
||||
|
||||
$this->getVars = (array) $getVars;
|
||||
$this->postVars = (array) $postVars;
|
||||
$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
|
||||
$variables = static::variablesFromEnvironment();
|
||||
return self::createFromVariables($variables, @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
|
||||
* @return array
|
||||
*/
|
||||
protected static function variablesFromEnvironment()
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'_SERVER' => $_SERVER,
|
||||
'_GET' => $_GET,
|
||||
'_POST' => $_POST,
|
||||
'_FILES' => $_FILES,
|
||||
'_SESSION' => isset($_SESSION) ? $_SESSION : null,
|
||||
'_COOKIE' => $_COOKIE
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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($variables['_SESSION']);
|
||||
$request->setSession($session);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the setting of a URL
|
||||
*
|
||||
|
@ -435,21 +622,15 @@ class HTTPRequest implements ArrayAccess
|
|||
return $this->requestVar($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @param string $offset
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->getVars[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @param mixed $offset
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->getVars[$offset]);
|
||||
unset($this->postVars[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -866,4 +1047,22 @@ class HTTPRequest implements ArrayAccess
|
|||
return $origMethod;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Session $session
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(Session $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\ORM\DataModel;
|
||||
|
||||
/**
|
||||
* A request filter is an object that's executed before and after a
|
||||
* request occurs. By returning 'false' from the preRequest method,
|
||||
|
@ -14,24 +12,20 @@ use SilverStripe\ORM\DataModel;
|
|||
*/
|
||||
interface RequestFilter
|
||||
{
|
||||
|
||||
/**
|
||||
* Filter executed before a request processes
|
||||
*
|
||||
* @param HTTPRequest $request Request container object
|
||||
* @param Session $session Request session
|
||||
* @param DataModel $model Current DataModel
|
||||
* @return boolean Whether to continue processing other filters. Null or true will continue processing (optional)
|
||||
*/
|
||||
public function preRequest(HTTPRequest $request, Session $session, DataModel $model);
|
||||
public function preRequest(HTTPRequest $request);
|
||||
|
||||
/**
|
||||
* Filter executed AFTER a request
|
||||
*
|
||||
* @param HTTPRequest $request Request container object
|
||||
* @param HTTPResponse $response Response output object
|
||||
* @param DataModel $model Current DataModel
|
||||
* @return boolean Whether to continue processing other filters. Null or true will continue processing (optional)
|
||||
* @param HTTPResponse $response
|
||||
* @return bool Whether to continue processing other filters. Null or true will continue processing (optional)
|
||||
*/
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response, DataModel $model);
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ use InvalidArgumentException;
|
|||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Dev\Debug;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Security\PermissionFailureException;
|
||||
use SilverStripe\Security\Permission;
|
||||
|
@ -123,22 +122,9 @@ class RequestHandler extends ViewableData
|
|||
|
||||
$this->setRequest(new NullHTTPRequest());
|
||||
|
||||
// This will prevent bugs if setDataModel() isn't called.
|
||||
$this->model = DataModel::inst();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DataModel for this request.
|
||||
*
|
||||
* @param DataModel $model
|
||||
*/
|
||||
public function setDataModel($model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles URL requests.
|
||||
*
|
||||
|
@ -156,10 +142,9 @@ class RequestHandler extends ViewableData
|
|||
* customise the controller.
|
||||
*
|
||||
* @param HTTPRequest $request The object that is reponsible for distributing URL parsing
|
||||
* @param DataModel $model
|
||||
* @return HTTPResponse|RequestHandler|string|array
|
||||
*/
|
||||
public function handleRequest(HTTPRequest $request, DataModel $model)
|
||||
public function handleRequest(HTTPRequest $request)
|
||||
{
|
||||
// $handlerClass is used to step up the class hierarchy to implement url_handlers inheritance
|
||||
if ($this->brokenOnConstruct) {
|
||||
|
@ -170,7 +155,6 @@ class RequestHandler extends ViewableData
|
|||
}
|
||||
|
||||
$this->setRequest($request);
|
||||
$this->setDataModel($model);
|
||||
|
||||
$match = $this->findAction($request);
|
||||
|
||||
|
@ -237,7 +221,7 @@ class RequestHandler extends ViewableData
|
|||
if ($result instanceof HasRequestHandler) {
|
||||
$result = $result->getRequestHandler();
|
||||
}
|
||||
$returnValue = $result->handleRequest($request, $model);
|
||||
$returnValue = $result->handleRequest($request);
|
||||
|
||||
// Array results can be used to handle
|
||||
if (is_array($returnValue)) {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
|
||||
/**
|
||||
* Represents a request processer that delegates pre and post request handling to nested request filters
|
||||
|
@ -34,10 +33,10 @@ class RequestProcessor implements RequestFilter
|
|||
$this->filters = $filters;
|
||||
}
|
||||
|
||||
public function preRequest(HTTPRequest $request, Session $session, DataModel $model)
|
||||
public function preRequest(HTTPRequest $request)
|
||||
{
|
||||
foreach ($this->filters as $filter) {
|
||||
$res = $filter->preRequest($request, $session, $model);
|
||||
$res = $filter->preRequest($request);
|
||||
if ($res === false) {
|
||||
return false;
|
||||
}
|
||||
|
@ -45,10 +44,10 @@ class RequestProcessor implements RequestFilter
|
|||
return null;
|
||||
}
|
||||
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response, DataModel $model)
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response)
|
||||
{
|
||||
foreach ($this->filters as $filter) {
|
||||
$res = $filter->postRequest($request, $response, $model);
|
||||
$res = $filter->postRequest($request, $response);
|
||||
if ($res === false) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
|
||||
namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use BadMethodCallException;
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
|
||||
/**
|
||||
* Handles all manipulation of the session.
|
||||
|
@ -89,7 +87,7 @@ use SilverStripe\Dev\Deprecation;
|
|||
*/
|
||||
class Session
|
||||
{
|
||||
use Injectable;
|
||||
use Configurable;
|
||||
|
||||
/**
|
||||
* Set session timeout in seconds.
|
||||
|
@ -130,12 +128,23 @@ class Session
|
|||
private static $cookie_secure = false;
|
||||
|
||||
/**
|
||||
* Session data
|
||||
* Session data.
|
||||
* Will be null if session has not been started
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
protected $data = array();
|
||||
protected $data = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $changedData = array();
|
||||
|
||||
/**
|
||||
* Get user agent for this request
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function userAgent()
|
||||
{
|
||||
if (isset($_SERVER['HTTP_USER_AGENT'])) {
|
||||
|
@ -148,123 +157,75 @@ class Session
|
|||
/**
|
||||
* Start PHP session, then create a new Session object with the given start data.
|
||||
*
|
||||
* @param $data array|Session Can be an array of data (such as $_SESSION) or another Session object to clone.
|
||||
* @param array|null|Session $data Can be an array of data (such as $_SESSION) or another Session object to clone.
|
||||
* If null, this session is treated as unstarted.
|
||||
*/
|
||||
public function __construct($data)
|
||||
{
|
||||
if ($data instanceof Session) {
|
||||
$data = $data->inst_getAll();
|
||||
$data = $data->getAll();
|
||||
}
|
||||
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init this session instance before usage
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
$this->start();
|
||||
}
|
||||
|
||||
// Funny business detected!
|
||||
if (isset($this->data['HTTP_USER_AGENT'])) {
|
||||
if ($this->data['HTTP_USER_AGENT'] != $this->userAgent()) {
|
||||
// Funny business detected!
|
||||
$this->inst_clearAll();
|
||||
$this->inst_destroy();
|
||||
$this->inst_start();
|
||||
if ($this->data['HTTP_USER_AGENT'] !== $this->userAgent()) {
|
||||
$this->clearAll();
|
||||
$this->destroy();
|
||||
$this->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a value to a specific key in the session array
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $val
|
||||
* Destroy existing session and restart
|
||||
*/
|
||||
public static function add_to_array($name, $val)
|
||||
public function restart()
|
||||
{
|
||||
return self::current_session()->inst_addToArray($name, $val);
|
||||
$this->destroy();
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a key/value pair in the session
|
||||
* Determine if this session has started
|
||||
*
|
||||
* @param string $name Key
|
||||
* @param string|array $val Value
|
||||
* @return bool
|
||||
*/
|
||||
public static function set($name, $val)
|
||||
public function isStarted()
|
||||
{
|
||||
return self::current_session()->inst_set($name, $val);
|
||||
return isset($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a specific value by session key
|
||||
* Begin session
|
||||
*
|
||||
* @param string $name Key to lookup
|
||||
* @return mixed
|
||||
* @param string $sid
|
||||
*/
|
||||
public static function get($name)
|
||||
public function start($sid = null)
|
||||
{
|
||||
return self::current_session()->inst_get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the values in session
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_all()
|
||||
{
|
||||
return self::current_session()->inst_getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a given session key, value pair.
|
||||
*
|
||||
* @param string $name Key to lookup
|
||||
*/
|
||||
public static function clear($name)
|
||||
{
|
||||
return self::current_session()->inst_clear($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all the values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clear_all()
|
||||
{
|
||||
self::current_session()->inst_clearAll();
|
||||
self::$default_session = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all the values in our session to $_SESSION
|
||||
*/
|
||||
public static function save()
|
||||
{
|
||||
return self::current_session()->inst_save();
|
||||
}
|
||||
|
||||
protected static $default_session = null;
|
||||
|
||||
protected static function current_session()
|
||||
{
|
||||
if (Controller::has_curr()) {
|
||||
return Controller::curr()->getSession();
|
||||
} else {
|
||||
if (!self::$default_session) {
|
||||
self::$default_session = Injector::inst()->create('SilverStripe\\Control\\Session', isset($_SESSION) ? $_SESSION : array());
|
||||
}
|
||||
|
||||
return self::$default_session;
|
||||
if ($this->isStarted()) {
|
||||
throw new BadMethodCallException("Session has already started");
|
||||
}
|
||||
}
|
||||
|
||||
public function inst_start($sid = null)
|
||||
{
|
||||
$path = Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_path');
|
||||
$path = $this->config()->get('cookie_path');
|
||||
if (!$path) {
|
||||
$path = Director::baseURL();
|
||||
}
|
||||
$domain = Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_domain');
|
||||
$secure = Director::is_https() && Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_secure');
|
||||
$session_path = Config::inst()->get('SilverStripe\\Control\\Session', 'session_store_path');
|
||||
$timeout = Config::inst()->get('SilverStripe\\Control\\Session', 'timeout');
|
||||
$domain = $this->config()->get('cookie_domain');
|
||||
$secure = Director::is_https() && $this->config()->get('cookie_secure');
|
||||
$session_path = $this->config()->get('session_store_path');
|
||||
$timeout = $this->config()->get('timeout');
|
||||
|
||||
// Director::baseURL can return absolute domain names - this extracts the relevant parts
|
||||
// for the session otherwise we can get broken session cookies
|
||||
|
@ -300,6 +261,8 @@ class Session
|
|||
session_start();
|
||||
|
||||
$this->data = isset($_SESSION) ? $_SESSION : array();
|
||||
} else {
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
// Modify the timeout behaviour so it's the *inactive* time before the session expires.
|
||||
|
@ -310,28 +273,41 @@ class Session
|
|||
}
|
||||
}
|
||||
|
||||
public function inst_destroy($removeCookie = true)
|
||||
/**
|
||||
* Destroy this session
|
||||
*
|
||||
* @param bool $removeCookie
|
||||
*/
|
||||
public function destroy($removeCookie = true)
|
||||
{
|
||||
if (session_id()) {
|
||||
if ($removeCookie) {
|
||||
$path = Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_path') ?: Director::baseURL();
|
||||
$domain = Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_domain');
|
||||
$secure = Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_secure');
|
||||
|
||||
$path = $this->config()->get('cookie_path') ?: Director::baseURL();
|
||||
$domain = $this->config()->get('cookie_domain');
|
||||
$secure = $this->config()->get('cookie_secure');
|
||||
Cookie::force_expiry(session_name(), $path, $domain, $secure, true);
|
||||
}
|
||||
|
||||
session_destroy();
|
||||
|
||||
// Clean up the superglobal - session_destroy does not do it.
|
||||
// http://nz1.php.net/manual/en/function.session-destroy.php
|
||||
unset($_SESSION);
|
||||
$this->data = array();
|
||||
}
|
||||
// Clean up the superglobal - session_destroy does not do it.
|
||||
// http://nz1.php.net/manual/en/function.session-destroy.php
|
||||
unset($_SESSION);
|
||||
$this->data = null;
|
||||
}
|
||||
|
||||
public function inst_set($name, $val)
|
||||
/**
|
||||
* Set session value
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $val
|
||||
* @return $this
|
||||
*/
|
||||
public function set($name, $val)
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new BadMethodCallException("Session cannot be modified until it's started");
|
||||
}
|
||||
|
||||
// Quicker execution path for "."-free names
|
||||
if (strpos($name, '.') === false) {
|
||||
$this->data[$name] = $val;
|
||||
|
@ -360,10 +336,21 @@ class Session
|
|||
$diffVar = $val;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function inst_addToArray($name, $val)
|
||||
/**
|
||||
* Merge value with array
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function addToArray($name, $val)
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new BadMethodCallException("Session cannot be modified until it's started");
|
||||
}
|
||||
|
||||
$names = explode('.', $name);
|
||||
|
||||
// We still want to do this even if we have strict path checking for legacy code
|
||||
|
@ -379,8 +366,18 @@ class Session
|
|||
$diffVar[sizeof($var)-1] = $val;
|
||||
}
|
||||
|
||||
public function inst_get($name)
|
||||
/**
|
||||
* Get session value
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new BadMethodCallException("Session cannot be accessed until it's started");
|
||||
}
|
||||
|
||||
// Quicker execution path for "."-free names
|
||||
if (strpos($name, '.') === false) {
|
||||
if (isset($this->data[$name])) {
|
||||
|
@ -407,8 +404,18 @@ class Session
|
|||
}
|
||||
}
|
||||
|
||||
public function inst_clear($name)
|
||||
/**
|
||||
* Clear session value
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function clear($name)
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new BadMethodCallException("Session cannot be modified until it's started");
|
||||
}
|
||||
|
||||
$names = explode('.', $name);
|
||||
|
||||
// We still want to do this even if we have strict path checking for legacy code
|
||||
|
@ -418,7 +425,7 @@ class Session
|
|||
foreach ($names as $n) {
|
||||
// don't clear a record that doesn't exist
|
||||
if (!isset($var[$n])) {
|
||||
return;
|
||||
return $this;
|
||||
}
|
||||
$var = &$var[$n];
|
||||
}
|
||||
|
@ -432,38 +439,54 @@ class Session
|
|||
$var = null;
|
||||
$diffVar = null;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function inst_clearAll()
|
||||
/**
|
||||
* Clear all values
|
||||
*/
|
||||
public function clearAll()
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new BadMethodCallException("Session cannot be modified until it's started");
|
||||
}
|
||||
|
||||
if ($this->data && is_array($this->data)) {
|
||||
foreach (array_keys($this->data) as $key) {
|
||||
$this->inst_clear($key);
|
||||
$this->clear($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function inst_getAll()
|
||||
/**
|
||||
* Get all values
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function inst_finalize()
|
||||
/**
|
||||
* Set user agent key
|
||||
*/
|
||||
public function finalize()
|
||||
{
|
||||
$this->inst_set('HTTP_USER_AGENT', $this->userAgent());
|
||||
$this->set('HTTP_USER_AGENT', $this->userAgent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data to session
|
||||
* Only save the changes, so that anyone manipulating $_SESSION directly doesn't get burned.
|
||||
*/
|
||||
public function inst_save()
|
||||
public function save()
|
||||
{
|
||||
if ($this->changedData) {
|
||||
$this->inst_finalize();
|
||||
$this->finalize();
|
||||
|
||||
if (!isset($_SESSION)) {
|
||||
$this->inst_start();
|
||||
if (!$this->isStarted()) {
|
||||
$this->start();
|
||||
}
|
||||
|
||||
$this->recursivelyApply($this->changedData, $_SESSION);
|
||||
|
@ -493,55 +516,11 @@ class Session
|
|||
|
||||
/**
|
||||
* Return the changed data, for debugging purposes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function inst_changedData()
|
||||
public function changedData()
|
||||
{
|
||||
return $this->changedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the appropriate form message in session, with type. This will be shown once,
|
||||
* for the form specified.
|
||||
*
|
||||
* @param string $formname the form name you wish to use ( usually $form->FormName() )
|
||||
* @param string $message the message you wish to add to it
|
||||
* @param string $type the type of message
|
||||
*/
|
||||
public static function setFormMessage($formname, $message, $type)
|
||||
{
|
||||
Session::set("FormInfo.$formname.formError.message", $message);
|
||||
Session::set("FormInfo.$formname.formError.type", $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is there a session ID in the request?
|
||||
* @return bool
|
||||
*/
|
||||
public static function request_contains_session_id()
|
||||
{
|
||||
$secure = Director::is_https() && Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_secure');
|
||||
$name = $secure ? 'SECSESSID' : session_name();
|
||||
return isset($_COOKIE[$name]) || isset($_REQUEST[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize session.
|
||||
*
|
||||
* @param string $sid Start the session with a specific ID
|
||||
*/
|
||||
public static function start($sid = null)
|
||||
{
|
||||
self::current_session()->inst_start($sid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the active session.
|
||||
*
|
||||
* @param bool $removeCookie If set to TRUE, removes the user's cookie, FALSE does not remove
|
||||
*/
|
||||
public static function destroy($removeCookie = true)
|
||||
{
|
||||
self::current_session()->inst_destroy($removeCookie);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,413 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use SilverStripe\Config\Collections\CachedConfigCollection;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Core\Cache\ManifestCacheFactory;
|
||||
use SilverStripe\Core\Config\ConfigLoader;
|
||||
use SilverStripe\Core\Config\CoreConfigFactory;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Injector\SilverStripeServiceConfigurationLocator;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Core\Manifest\ClassManifest;
|
||||
use SilverStripe\Core\Manifest\ModuleLoader;
|
||||
use SilverStripe\Core\Manifest\ModuleManifest;
|
||||
use SilverStripe\Dev\DebugView;
|
||||
use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
|
||||
use SilverStripe\Logging\ErrorHandler;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\View\ThemeManifest;
|
||||
use SilverStripe\View\ThemeResourceLoader;
|
||||
|
||||
class AppKernel extends CoreKernel
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
// Initialise the dependency injector as soon as possible, as it is
|
||||
// subsequently used by some of the following code
|
||||
$injector = new Injector(array('locator' => SilverStripeServiceConfigurationLocator::class));
|
||||
$this->setContainer($injector);
|
||||
Injector::set_inst($injector);
|
||||
|
||||
// Manifest cache factory
|
||||
$manifestCacheFactory = $this->buildManifestCacheFactory();
|
||||
|
||||
// Class loader
|
||||
$classLoader = ClassLoader::inst();
|
||||
$classLoader->pushManifest(new ClassManifest(BASE_PATH, $manifestCacheFactory));
|
||||
$this->setClassLoader($classLoader);
|
||||
|
||||
// Module loader
|
||||
$moduleLoader = ModuleLoader::inst();
|
||||
$moduleManifest = new ModuleManifest(BASE_PATH, $manifestCacheFactory);
|
||||
$moduleLoader->pushManifest($moduleManifest);
|
||||
$this->setModuleLoader($moduleLoader);
|
||||
|
||||
// Config loader
|
||||
// @todo refactor CoreConfigFactory
|
||||
$configFactory = new CoreConfigFactory($manifestCacheFactory, $this->getEnvironment());
|
||||
$configManifest = $configFactory->createRoot();
|
||||
$configLoader = ConfigLoader::inst();
|
||||
$configLoader->pushManifest($configManifest);
|
||||
$this->setConfigLoader($configLoader);
|
||||
|
||||
// Load template manifest
|
||||
$themeResourceLoader = ThemeResourceLoader::inst();
|
||||
$themeResourceLoader->addSet('$default', new ThemeManifest(
|
||||
BASE_PATH,
|
||||
project(),
|
||||
$manifestCacheFactory
|
||||
));
|
||||
$this->setThemeResourceLoader($themeResourceLoader);
|
||||
}
|
||||
|
||||
public function getEnvironment()
|
||||
{
|
||||
// Check saved session
|
||||
$env = $this->sessionEnvironment();
|
||||
if ($env) {
|
||||
return $env;
|
||||
}
|
||||
|
||||
// Check set
|
||||
if ($this->enviroment) {
|
||||
return $this->enviroment;
|
||||
}
|
||||
|
||||
// Check getenv
|
||||
if ($env = getenv('SS_ENVIRONMENT_TYPE')) {
|
||||
return $env;
|
||||
}
|
||||
|
||||
return self::LIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check or update any temporary environment specified in the session.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function sessionEnvironment()
|
||||
{
|
||||
// Check isDev in querystring
|
||||
if (isset($_GET['isDev'])) {
|
||||
if (isset($_SESSION)) {
|
||||
unset($_SESSION['isTest']); // In case we are changing from test mode
|
||||
$_SESSION['isDev'] = $_GET['isDev'];
|
||||
}
|
||||
return self::DEV;
|
||||
}
|
||||
|
||||
// Check isTest in querystring
|
||||
if (isset($_GET['isTest'])) {
|
||||
if (isset($_SESSION)) {
|
||||
unset($_SESSION['isDev']); // In case we are changing from dev mode
|
||||
$_SESSION['isTest'] = $_GET['isTest'];
|
||||
}
|
||||
return self::TEST;
|
||||
}
|
||||
|
||||
// Check session
|
||||
if (!empty($_SESSION['isDev'])) {
|
||||
return self::DEV;
|
||||
}
|
||||
if (!empty($_SESSION['isTest'])) {
|
||||
return self::TEST;
|
||||
}
|
||||
|
||||
// no session environment
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->bootPHP();
|
||||
$this->bootManifests();
|
||||
$this->bootErrorHandling();
|
||||
$this->bootDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure database
|
||||
*
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
protected function bootDatabase()
|
||||
{
|
||||
// Check if a DB is named
|
||||
$name = $this->getDatabaseName();
|
||||
|
||||
// Gracefully fail if no DB is configured
|
||||
if (empty($name)) {
|
||||
$this->detectLegacyEnvironment();
|
||||
$this->redirectToInstaller();
|
||||
}
|
||||
|
||||
// Set default database config
|
||||
$databaseConfig = $this->getDatabaseConfig();
|
||||
$databaseConfig['database'] = $this->getDatabaseName();
|
||||
DB::setConfig($databaseConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there's a legacy _ss_environment.php file
|
||||
*
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
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')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build error response
|
||||
$dv = new DebugView();
|
||||
$body =
|
||||
$dv->renderHeader() .
|
||||
$dv->renderInfo(
|
||||
"Configuraton Error",
|
||||
Director::absoluteBaseURL()
|
||||
) .
|
||||
$dv->renderParagraph(
|
||||
'You need to replace your _ss_environment.php file with a .env file, or with environment variables.<br><br>'
|
||||
. 'See the <a href="https://docs.silverstripe.org/en/4/getting_started/environment_management/">'
|
||||
. 'Environment Management</a> docs for more information.'
|
||||
) .
|
||||
$dv->renderFooter();
|
||||
|
||||
// Raise error
|
||||
$response = new HTTPResponse($body, 500);
|
||||
throw new HTTPResponse_Exception($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* If missing configuration, redirect to install.php
|
||||
*/
|
||||
protected function redirectToInstaller()
|
||||
{
|
||||
// Error if installer not available
|
||||
if (!file_exists(BASE_PATH . '/install.php')) {
|
||||
throw new HTTPResponse_Exception(
|
||||
'SilverStripe Framework requires a $databaseConfig defined.',
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
// Redirect to installer
|
||||
$response = new HTTPResponse();
|
||||
$response->redirect(Director::absoluteURL('install.php'));
|
||||
throw new HTTPResponse_Exception($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load database config from environment
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDatabaseConfig()
|
||||
{
|
||||
// Check global config
|
||||
global $databaseConfig;
|
||||
if (!empty($databaseConfig)) {
|
||||
return $databaseConfig;
|
||||
}
|
||||
|
||||
/** @skipUpgrade */
|
||||
$databaseConfig = [
|
||||
"type" => getenv('SS_DATABASE_CLASS') ?: 'MySQLDatabase',
|
||||
"server" => getenv('SS_DATABASE_SERVER') ?: 'localhost',
|
||||
"username" => getenv('SS_DATABASE_USERNAME') ?: null,
|
||||
"password" => getenv('SS_DATABASE_PASSWORD') ?: null,
|
||||
];
|
||||
|
||||
// Set the port if called for
|
||||
$dbPort = getenv('SS_DATABASE_PORT');
|
||||
if ($dbPort) {
|
||||
$databaseConfig['port'] = $dbPort;
|
||||
}
|
||||
|
||||
// Set the timezone if called for
|
||||
$dbTZ = getenv('SS_DATABASE_TIMEZONE');
|
||||
if ($dbTZ) {
|
||||
$databaseConfig['timezone'] = $dbTZ;
|
||||
}
|
||||
|
||||
// For schema enabled drivers:
|
||||
$dbSchema = getenv('SS_DATABASE_SCHEMA');
|
||||
if ($dbSchema) {
|
||||
$databaseConfig["schema"] = $dbSchema;
|
||||
}
|
||||
|
||||
// For SQlite3 memory databases (mainly for testing purposes)
|
||||
$dbMemory = getenv('SS_DATABASE_MEMORY');
|
||||
if ($dbMemory) {
|
||||
$databaseConfig["memory"] = $dbMemory;
|
||||
}
|
||||
|
||||
// Allow database adapters to handle their own configuration
|
||||
DatabaseAdapterRegistry::autoconfigure();
|
||||
return $databaseConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name of database
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDatabaseName()
|
||||
{
|
||||
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'SS_';
|
||||
|
||||
// Check globals
|
||||
global $database;
|
||||
if (!empty($database)) {
|
||||
return $prefix.$database;
|
||||
}
|
||||
global $databaseConfig;
|
||||
if (!empty($databaseConfig['database'])) {
|
||||
return $databaseConfig['database']; // Note: Already includes prefix
|
||||
}
|
||||
|
||||
// Check environment
|
||||
$database = getenv('SS_DATABASE_NAME');
|
||||
if ($database) {
|
||||
return $prefix.$database;
|
||||
}
|
||||
|
||||
// Auto-detect name
|
||||
$chooseName = getenv('SS_DATABASE_CHOOSE_NAME');
|
||||
if ($chooseName) {
|
||||
// Find directory to build name from
|
||||
$loopCount = (int)$chooseName;
|
||||
$databaseDir = BASE_PATH;
|
||||
for ($i = 0; $i < $loopCount-1; $i++) {
|
||||
$databaseDir = dirname($databaseDir);
|
||||
}
|
||||
|
||||
// Build name
|
||||
$database = str_replace('.', '', basename($databaseDir));
|
||||
return $prefix.$database;
|
||||
}
|
||||
|
||||
// no DB name (may be optional for some connectors)
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise PHP with default variables
|
||||
*/
|
||||
protected function bootPHP()
|
||||
{
|
||||
if ($this->getEnvironment() === self::LIVE) {
|
||||
// limited to fatal errors and warnings in live mode
|
||||
error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE));
|
||||
} else {
|
||||
// Report all errors in dev / test mode
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
}
|
||||
|
||||
global $_increase_time_limit_max;
|
||||
$_increase_time_limit_max = -1;
|
||||
|
||||
/**
|
||||
* Ensure we have enough memory
|
||||
*/
|
||||
increase_memory_limit_to('64M');
|
||||
|
||||
/**
|
||||
* Ensure we don't run into xdebug's fairly conservative infinite recursion protection limit
|
||||
*/
|
||||
increase_xdebug_nesting_level_to(200);
|
||||
|
||||
/**
|
||||
* Set default encoding
|
||||
*/
|
||||
mb_http_output('UTF-8');
|
||||
mb_internal_encoding('UTF-8');
|
||||
mb_regex_encoding('UTF-8');
|
||||
|
||||
/**
|
||||
* Enable better garbage collection
|
||||
*/
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ManifestCacheFactory
|
||||
*/
|
||||
protected function buildManifestCacheFactory()
|
||||
{
|
||||
return new ManifestCacheFactory([
|
||||
'namespace' => 'manifestcache',
|
||||
'directory' => getTempFolder(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot all manifests
|
||||
*/
|
||||
protected function bootManifests()
|
||||
{
|
||||
// Regenerate the manifest if ?flush is set, or if the database is being built.
|
||||
// The coupling is a hack, but it removes an annoying bug where new classes
|
||||
// referenced in _config.php files can be referenced during the build process.
|
||||
$flush = isset($_GET['flush']) ||
|
||||
trim($_GET['url'], '/') === trim(BASE_URL . '/dev/build', '/');
|
||||
|
||||
// Setup autoloader
|
||||
$this->getClassLoader()->init(false, $flush);
|
||||
|
||||
// Find modules
|
||||
$this->getModuleLoader()->init(false, $flush);
|
||||
|
||||
// Flush config
|
||||
if ($flush) {
|
||||
$config = $this->getConfigLoader()->getManifest();
|
||||
if ($config instanceof CachedConfigCollection) {
|
||||
$config->setFlush($flush);
|
||||
}
|
||||
}
|
||||
|
||||
// After loading config, boot _config.php files
|
||||
$this->getModuleLoader()->getManifest()->activateConfig();
|
||||
|
||||
// Find default templates
|
||||
$defaultSet = $this->getThemeResourceLoader()->getSet('$default');
|
||||
if ($defaultSet instanceof ThemeManifest) {
|
||||
$defaultSet->init(false, $flush);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on error handling
|
||||
*/
|
||||
protected function bootErrorHandling()
|
||||
{
|
||||
// Register error handler
|
||||
$errorHandler = Injector::inst()->get(ErrorHandler::class);
|
||||
$errorHandler->start();
|
||||
|
||||
// Register error log file
|
||||
$errorLog = getenv('SS_ERROR_LOG');
|
||||
if ($errorLog) {
|
||||
$logger = Injector::inst()->get(LoggerInterface::class);
|
||||
if ($logger instanceof Logger) {
|
||||
$logger->pushHandler(new StreamHandler(BASE_PATH . '/' . $errorLog, Logger::WARNING));
|
||||
} else {
|
||||
user_error("SS_ERROR_LOG setting only works with Monolog, you are using another logger", E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
/**
|
||||
* Identifies a class as a root silverstripe application
|
||||
*/
|
||||
interface Application
|
||||
{
|
||||
/**
|
||||
* Get the kernel for this application
|
||||
*
|
||||
* @return Kernel
|
||||
*/
|
||||
public function getKernel();
|
||||
|
||||
/**
|
||||
* Invoke the application control chain
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function execute(callable $callback);
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace SilverStripe\Core\Config;
|
||||
|
||||
use BadMethodCallException;
|
||||
use SilverStripe\Config\Collections\ConfigCollectionInterface;
|
||||
|
||||
/**
|
||||
|
@ -36,6 +37,9 @@ class ConfigLoader
|
|||
*/
|
||||
public function getManifest()
|
||||
{
|
||||
if (empty($this->manifests)) {
|
||||
throw new BadMethodCallException("No config manifests available");
|
||||
}
|
||||
return $this->manifests[count($this->manifests) - 1];
|
||||
}
|
||||
|
||||
|
|
|
@ -2,22 +2,16 @@
|
|||
|
||||
namespace SilverStripe\Core\Config;
|
||||
|
||||
use Monolog\Handler\ErrorLogHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use SilverStripe\Config\Collections\CachedConfigCollection;
|
||||
use SilverStripe\Config\Collections\MemoryConfigCollection;
|
||||
use SilverStripe\Config\Transformer\PrivateStaticTransformer;
|
||||
use SilverStripe\Config\Transformer\YamlTransformer;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Cache\CacheFactory;
|
||||
use SilverStripe\Core\Config\Middleware\ExtensionMiddleware;
|
||||
use SilverStripe\Core\Config\Middleware\InheritanceMiddleware;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Core\Manifest\ModuleLoader;
|
||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
|
@ -26,19 +20,19 @@ use Symfony\Component\Finder\Finder;
|
|||
class CoreConfigFactory
|
||||
{
|
||||
/**
|
||||
* @var static
|
||||
* @var CacheFactory
|
||||
*/
|
||||
protected static $inst = null;
|
||||
protected $cacheFactory = null;
|
||||
|
||||
/**
|
||||
* @return static
|
||||
* @var string
|
||||
*/
|
||||
public static function inst()
|
||||
protected $environment = null;
|
||||
|
||||
public function __construct(CacheFactory $cacheFactory, $environment)
|
||||
{
|
||||
if (!self::$inst) {
|
||||
self::$inst = new static();
|
||||
}
|
||||
return self::$inst;
|
||||
$this->cacheFactory = $cacheFactory;
|
||||
$this->environment = $environment;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,20 +40,17 @@ class CoreConfigFactory
|
|||
* This will be an immutable cached config,
|
||||
* which conditionally generates a nested "core" config.
|
||||
*
|
||||
* @param bool $flush
|
||||
* @param CacheFactory $cacheFactory
|
||||
* @return CachedConfigCollection
|
||||
*/
|
||||
public function createRoot($flush, CacheFactory $cacheFactory)
|
||||
public function createRoot()
|
||||
{
|
||||
$instance = new CachedConfigCollection();
|
||||
|
||||
// Create config cache
|
||||
$cache = $cacheFactory->create(CacheInterface::class.'.configcache', [
|
||||
$cache = $this->cacheFactory->create(CacheInterface::class.'.configcache', [
|
||||
'namespace' => 'configcache'
|
||||
]);
|
||||
$instance->setCache($cache);
|
||||
$instance->setFlush($flush);
|
||||
|
||||
// Set collection creator
|
||||
$instance->setCollectionCreator(function () {
|
||||
|
@ -171,8 +162,7 @@ class CoreConfigFactory
|
|||
}
|
||||
)
|
||||
->addRule('environment', function ($env) {
|
||||
$current = Director::get_environment_type();
|
||||
return strtolower($current) === strtolower($env);
|
||||
return strtolower($this->environment) === strtolower($env);
|
||||
})
|
||||
->addRule('moduleexists', function ($module) {
|
||||
return ModuleLoader::inst()->getManifest()->moduleExists($module);
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Core\Config\ConfigLoader;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Core\Manifest\ModuleLoader;
|
||||
use SilverStripe\View\ThemeResourceLoader;
|
||||
|
||||
/**
|
||||
* Simple Kernel container
|
||||
*/
|
||||
class CoreKernel implements Kernel
|
||||
{
|
||||
/**
|
||||
* @var Injector
|
||||
*/
|
||||
protected $container = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $enviroment = null;
|
||||
|
||||
/**
|
||||
* @var ClassLoader
|
||||
*/
|
||||
protected $classLoader = null;
|
||||
|
||||
/**
|
||||
* @var ModuleLoader
|
||||
*/
|
||||
protected $moduleLoader = null;
|
||||
|
||||
/**
|
||||
* @var ConfigLoader
|
||||
*/
|
||||
protected $configLoader = null;
|
||||
|
||||
/**
|
||||
* @var ThemeResourceLoader
|
||||
*/
|
||||
protected $themeResourceLoader = null;
|
||||
|
||||
public function boot()
|
||||
{
|
||||
}
|
||||
|
||||
public function shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
public function nest()
|
||||
{
|
||||
// TODO: Implement nest() method.
|
||||
}
|
||||
|
||||
public function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function setContainer(Injector $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$container->registerService($this, Kernel::class);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClassLoader()
|
||||
{
|
||||
return $this->classLoader;
|
||||
}
|
||||
|
||||
public function setClassLoader(ClassLoader $classLoader)
|
||||
{
|
||||
$this->classLoader = $classLoader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getModuleLoader()
|
||||
{
|
||||
return $this->moduleLoader;
|
||||
}
|
||||
|
||||
public function setModuleLoader(ModuleLoader $moduleLoader)
|
||||
{
|
||||
$this->moduleLoader = $moduleLoader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEnvironment()
|
||||
{
|
||||
return $this->enviroment ?: self::LIVE;
|
||||
}
|
||||
|
||||
public function setEnvironment($environment)
|
||||
{
|
||||
if (!in_array($environment, [self::DEV, self::TEST, self::LIVE])) {
|
||||
throw new InvalidArgumentException(
|
||||
"Director::set_environment_type passed '$environment'. It should be passed dev, test, or live"
|
||||
);
|
||||
}
|
||||
$this->enviroment = $environment;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getConfigLoader()
|
||||
{
|
||||
return $this->configLoader;
|
||||
}
|
||||
|
||||
public function setConfigLoader($configLoader)
|
||||
{
|
||||
$this->configLoader = $configLoader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getThemeResourceLoader()
|
||||
{
|
||||
return $this->themeResourceLoader;
|
||||
}
|
||||
|
||||
public function setThemeResourceLoader($themeResourceLoader)
|
||||
{
|
||||
$this->themeResourceLoader = $themeResourceLoader;
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
|
||||
/**
|
||||
* Invokes the HTTP application within an ErrorControlChain
|
||||
*/
|
||||
class HTTPApplication implements Application
|
||||
{
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $middlewares = [];
|
||||
|
||||
/**
|
||||
* @return callable[]
|
||||
*/
|
||||
public function getMiddlewares()
|
||||
{
|
||||
return $this->middlewares;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable[] $middlewares
|
||||
* @return $this
|
||||
*/
|
||||
public function setMiddlewares($middlewares)
|
||||
{
|
||||
$this->middlewares = $middlewares;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $middleware
|
||||
* @return $this
|
||||
*/
|
||||
public function addMiddleware($middleware)
|
||||
{
|
||||
$this->middlewares[] = $middleware;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call middleware
|
||||
*
|
||||
* @param callable $last Last config to call
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
protected function callMiddleware($last)
|
||||
{
|
||||
// Reverse middlewares
|
||||
$next = $last;
|
||||
foreach (array_reverse($this->getMiddlewares()) as $middleware) {
|
||||
$next = function () use ($middleware, $next) {
|
||||
return call_user_func($middleware, $next);
|
||||
};
|
||||
}
|
||||
return call_user_func($next);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Kernel
|
||||
*/
|
||||
protected $kernel;
|
||||
|
||||
public function __construct(Kernel $kernel)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the kernel for this application
|
||||
*
|
||||
* @return Kernel
|
||||
*/
|
||||
public function getKernel()
|
||||
{
|
||||
return $this->kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the given HTTP request
|
||||
*
|
||||
* @param HTTPRequest $request
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
public function handle(HTTPRequest $request)
|
||||
{
|
||||
// Ensure boot is invoked
|
||||
return $this->execute(function () use ($request) {
|
||||
// Start session and execute
|
||||
$request->getSession()->init();
|
||||
return Director::direct($request);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely boot the application and execute the given main action
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
public function execute(callable $callback)
|
||||
{
|
||||
return $this->callMiddleware(function () use ($callback) {
|
||||
// Pre-request boot
|
||||
$this->getKernel()->boot();
|
||||
return call_user_func($callback);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -202,21 +202,18 @@ class Injector implements ContainerInterface
|
|||
{
|
||||
$this->injectMap = array();
|
||||
$this->serviceCache = array(
|
||||
'Injector' => $this,
|
||||
'Injector' => $this,
|
||||
);
|
||||
$this->specs = array(
|
||||
'Injector' => array('class' => 'SilverStripe\\Core\\Injector\\Injector')
|
||||
);
|
||||
|
||||
$this->specs = [
|
||||
'Injector' => ['class' => static::class]
|
||||
];
|
||||
$this->autoProperties = array();
|
||||
|
||||
|
||||
$creatorClass = isset($config['creator'])
|
||||
? $config['creator']
|
||||
: 'SilverStripe\\Core\\Injector\\InjectionCreator';
|
||||
: InjectionCreator::class;
|
||||
$locatorClass = isset($config['locator'])
|
||||
? $config['locator']
|
||||
: 'SilverStripe\\Core\\Injector\\SilverStripeServiceConfigurationLocator';
|
||||
: SilverStripeServiceConfigurationLocator::class;
|
||||
|
||||
$this->objectCreator = new $creatorClass;
|
||||
$this->configLocator = new $locatorClass;
|
||||
|
@ -860,7 +857,6 @@ class Injector implements ContainerInterface
|
|||
|
||||
$this->specs[$registerAt] = array('class' => get_class($service));
|
||||
$this->serviceCache[$registerAt] = $service;
|
||||
$this->inject($service);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,7 +51,7 @@ class SilverStripeServiceConfigurationLocator implements ServiceConfigurationLoc
|
|||
return $this->configs[$name];
|
||||
}
|
||||
|
||||
$config = Config::inst()->get('SilverStripe\\Core\\Injector\\Injector', $name);
|
||||
$config = Config::inst()->get(Injector::class, $name);
|
||||
$this->configs[$name] = $config;
|
||||
return $config;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
use SilverStripe\Core\Config\ConfigLoader;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Core\Manifest\ModuleLoader;
|
||||
use SilverStripe\View\ThemeResourceLoader;
|
||||
|
||||
/**
|
||||
* Represents the core state of a SilverStripe application
|
||||
* Based loosely on symfony/http-kernel's KernelInterface component
|
||||
*/
|
||||
interface Kernel
|
||||
{
|
||||
/**
|
||||
* Test environment
|
||||
*/
|
||||
const TEST = 'test';
|
||||
|
||||
/**
|
||||
* Dev environment
|
||||
*/
|
||||
const DEV = 'dev';
|
||||
|
||||
/**
|
||||
* Live (default) environment
|
||||
*/
|
||||
const LIVE = 'live';
|
||||
|
||||
/*
|
||||
* Boots the current kernel
|
||||
*/
|
||||
public function boot();
|
||||
|
||||
/**
|
||||
* Shutdowns the kernel.
|
||||
*/
|
||||
public function shutdown();
|
||||
|
||||
/**
|
||||
* Nests this kernel, all components, and returns the nested value.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function nest();
|
||||
|
||||
/**
|
||||
* @return Injector
|
||||
*/
|
||||
public function getContainer();
|
||||
|
||||
/**
|
||||
* Sets injector
|
||||
*
|
||||
* @param Injector $container
|
||||
* @return $this
|
||||
*/
|
||||
public function setContainer(Injector $container);
|
||||
|
||||
/**
|
||||
* @return ClassLoader
|
||||
*/
|
||||
public function getClassLoader();
|
||||
|
||||
/**
|
||||
* @param ClassLoader $classLoader
|
||||
* @return $this
|
||||
*/
|
||||
public function setClassLoader(ClassLoader $classLoader);
|
||||
|
||||
/**
|
||||
* @return ModuleLoader
|
||||
*/
|
||||
public function getModuleLoader();
|
||||
|
||||
/**
|
||||
* @param ModuleLoader $moduleLoader
|
||||
* @return $this
|
||||
*/
|
||||
public function setModuleLoader(ModuleLoader $moduleLoader);
|
||||
|
||||
/**
|
||||
* @return ConfigLoader
|
||||
*/
|
||||
public function getConfigLoader();
|
||||
|
||||
/**
|
||||
* @param ConfigLoader $configLoader
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfigLoader($configLoader);
|
||||
|
||||
/**
|
||||
* @return ThemeResourceLoader
|
||||
*/
|
||||
public function getThemeResourceLoader();
|
||||
|
||||
/**
|
||||
* @param ThemeResourceLoader $themeResourceLoader
|
||||
* @return $this
|
||||
*/
|
||||
public function setThemeResourceLoader($themeResourceLoader);
|
||||
|
||||
/**
|
||||
* One of dev, live, or test
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEnvironment();
|
||||
|
||||
/**
|
||||
* Sets new environment
|
||||
*
|
||||
* @param string $environment
|
||||
* @return $this
|
||||
*/
|
||||
public function setEnvironment($environment);
|
||||
}
|
|
@ -19,7 +19,9 @@ class ClassLoader
|
|||
private static $instance;
|
||||
|
||||
/**
|
||||
* @var array Map of 'instance' (ClassManifest) and other options.
|
||||
* Map of 'instance' (ClassManifest) and other options.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $manifests = array();
|
||||
|
||||
|
@ -113,6 +115,23 @@ class ClassLoader
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the class loader
|
||||
*
|
||||
* @param bool $includeTests
|
||||
* @param bool $forceRegen
|
||||
*/
|
||||
public function init($includeTests = false, $forceRegen = false)
|
||||
{
|
||||
foreach ($this->manifests as $manifest) {
|
||||
/** @var ClassManifest $instance */
|
||||
$instance = $manifest['instance'];
|
||||
$instance->init($includeTests, $forceRegen);
|
||||
}
|
||||
|
||||
$this->registerAutoloader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a class or interface name exists in the manifest.
|
||||
*
|
||||
|
|
|
@ -28,6 +28,13 @@ class ClassManifest
|
|||
*/
|
||||
protected $base;
|
||||
|
||||
/**
|
||||
* Used to build cache during boot
|
||||
*
|
||||
* @var CacheFactory
|
||||
*/
|
||||
protected $cacheFactory;
|
||||
|
||||
/**
|
||||
* Set if including test classes
|
||||
*
|
||||
|
@ -56,7 +63,7 @@ class ClassManifest
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $classes = array();
|
||||
protected $classes = array();
|
||||
|
||||
/**
|
||||
* List of root classes with no parent class
|
||||
|
@ -122,27 +129,30 @@ class ClassManifest
|
|||
* from the cache or re-scanning for classes.
|
||||
*
|
||||
* @param string $base The manifest base path.
|
||||
* @param bool $includeTests Include the contents of "tests" directories.
|
||||
* @param bool $forceRegen Force the manifest to be regenerated.
|
||||
* @param CacheFactory $cacheFactory Optional cache to use. Set to null to not cache.
|
||||
*/
|
||||
public function __construct(
|
||||
$base,
|
||||
$includeTests = false,
|
||||
$forceRegen = false,
|
||||
CacheFactory $cacheFactory = null
|
||||
) {
|
||||
public function __construct($base, CacheFactory $cacheFactory = null)
|
||||
{
|
||||
$this->base = $base;
|
||||
$this->tests = $includeTests;
|
||||
$this->cacheFactory = $cacheFactory;
|
||||
$this->cacheKey = 'manifest';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the class manifest
|
||||
*
|
||||
* @param bool $includeTests
|
||||
* @param bool $forceRegen
|
||||
*/
|
||||
public function init($includeTests = false, $forceRegen = false)
|
||||
{
|
||||
// build cache from factory
|
||||
if ($cacheFactory) {
|
||||
$this->cache = $cacheFactory->create(
|
||||
if ($this->cacheFactory) {
|
||||
$this->cache = $this->cacheFactory->create(
|
||||
CacheInterface::class.'.classmanifest',
|
||||
[ 'namespace' => 'classmanifest' . ($includeTests ? '_tests' : '') ]
|
||||
);
|
||||
}
|
||||
$this->cacheKey = 'manifest';
|
||||
|
||||
if (!$forceRegen && $this->cache && ($data = $this->cache->get($this->cacheKey))) {
|
||||
$this->classes = $data['classes'];
|
||||
|
|
|
@ -85,4 +85,17 @@ class ModuleLoader
|
|||
{
|
||||
return count($this->manifests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the module loader
|
||||
*
|
||||
* @param bool $includeTests
|
||||
* @param bool $forceRegen
|
||||
*/
|
||||
public function init($includeTests = false, $forceRegen = false)
|
||||
{
|
||||
foreach ($this->manifests as $manifest) {
|
||||
$manifest->init($includeTests, $forceRegen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,11 @@ class ModuleManifest
|
|||
protected $cacheKey;
|
||||
|
||||
/**
|
||||
* Whether `test` directories should be searched when searching for configuration
|
||||
* Factory to use to build cache
|
||||
*
|
||||
* @var bool
|
||||
* @var CacheFactory
|
||||
*/
|
||||
protected $includeTests;
|
||||
protected $cacheFactory;
|
||||
|
||||
/**
|
||||
* @var CacheInterface
|
||||
|
@ -87,19 +87,24 @@ class ModuleManifest
|
|||
* from the cache or re-scanning for classes.
|
||||
*
|
||||
* @param string $base The project base path.
|
||||
* @param bool $includeTests
|
||||
* @param bool $forceRegen Force the manifest to be regenerated.
|
||||
* @param CacheFactory $cacheFactory Cache factory to use
|
||||
*/
|
||||
public function __construct($base, $includeTests = false, $forceRegen = false, CacheFactory $cacheFactory = null)
|
||||
public function __construct($base, CacheFactory $cacheFactory = null)
|
||||
{
|
||||
$this->base = $base;
|
||||
$this->cacheKey = sha1($base).'_modules';
|
||||
$this->includeTests = $includeTests;
|
||||
$this->cacheKey = sha1($base) . '_modules';
|
||||
$this->cacheFactory = $cacheFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $includeTests
|
||||
* @param bool $forceRegen Force the manifest to be regenerated.
|
||||
*/
|
||||
public function init($includeTests = false, $forceRegen = false)
|
||||
{
|
||||
// build cache from factory
|
||||
if ($cacheFactory) {
|
||||
$this->cache = $cacheFactory->create(
|
||||
if ($this->cacheFactory) {
|
||||
$this->cache = $this->cacheFactory->create(
|
||||
CacheInterface::class.'.modulemanifest',
|
||||
[ 'namespace' => 'modulemanifest' . ($includeTests ? '_tests' : '') ]
|
||||
);
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Core\Startup;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Core\Application;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Security\Security;
|
||||
|
||||
/**
|
||||
* Decorates application bootstrapping with errorcontrolchain
|
||||
*/
|
||||
class ErrorControlChainMiddleware
|
||||
{
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $application = null;
|
||||
|
||||
/**
|
||||
* @var HTTPRequest
|
||||
*/
|
||||
protected $request = null;
|
||||
|
||||
/**
|
||||
* Build error control chain for an application
|
||||
*
|
||||
* @param Application $application
|
||||
* @param HTTPRequest $request
|
||||
*/
|
||||
public function __construct(Application $application, HTTPRequest $request)
|
||||
{
|
||||
$this->application = $application;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $next
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
public function __invoke(callable $next)
|
||||
{
|
||||
$result = null;
|
||||
|
||||
// Prepare tokens and execute chain
|
||||
$reloadToken = ParameterConfirmationToken::prepare_tokens(
|
||||
['isTest', 'isDev', 'flush'],
|
||||
$this->getRequest()
|
||||
);
|
||||
$chain = new ErrorControlChain();
|
||||
$chain
|
||||
->then(function () use ($chain, $reloadToken, $next, &$result) {
|
||||
// If no redirection is necessary then we can disable error supression
|
||||
if (!$reloadToken) {
|
||||
$chain->setSuppression(false);
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if a token is requesting a redirect
|
||||
if ($reloadToken) {
|
||||
$result = $this->safeReloadWithToken($reloadToken);
|
||||
} else {
|
||||
// If no reload necessary, process application
|
||||
$result = call_user_func($next);
|
||||
}
|
||||
} catch (HTTPResponse_Exception $exception) {
|
||||
$result = $exception->getResponse();
|
||||
}
|
||||
})
|
||||
// Finally if a token was requested but there was an error while figuring out if it's allowed, do it anyway
|
||||
->thenIfErrored(function () use ($reloadToken, &$result) {
|
||||
if ($reloadToken) {
|
||||
$result = $reloadToken->reloadWithToken();
|
||||
}
|
||||
})
|
||||
->execute();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload application with the given token, but only if either the user is authenticated,
|
||||
* or authentication is impossible.
|
||||
*
|
||||
* @param ParameterConfirmationToken $reloadToken
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
protected function safeReloadWithToken($reloadToken)
|
||||
{
|
||||
// Safe reload requires manual boot
|
||||
$this->getApplication()->getKernel()->boot();
|
||||
|
||||
// Ensure session is started
|
||||
$this->getRequest()->getSession()->init();
|
||||
|
||||
// Next, check if we're in dev mode, or the database doesn't have any security data, or we are admin
|
||||
if (Director::isDev() || !Security::database_is_ready() || Permission::check('ADMIN')) {
|
||||
return $reloadToken->reloadWithToken();
|
||||
}
|
||||
|
||||
// Fail and redirect the user to the login page
|
||||
$loginPage = Director::absoluteURL(Security::config()->get('login_url'));
|
||||
$loginPage .= "?BackURL=" . urlencode($this->getRequest()->getURL());
|
||||
$result = new HTTPResponse();
|
||||
$result->redirect($loginPage);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Application
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
return $this->application;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Application $application
|
||||
* @return $this
|
||||
*/
|
||||
public function setApplication(Application $application)
|
||||
{
|
||||
$this->application = $application;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HTTPRequest
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HTTPRequest $request
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(HTTPRequest $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Core\Startup;
|
||||
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
|
||||
/**
|
||||
* Emits response to the browser
|
||||
*/
|
||||
class OutputMiddleware
|
||||
{
|
||||
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 __invoke(callable $next)
|
||||
{
|
||||
/** @var HTTPResponse $response */
|
||||
$response = call_user_func($next);
|
||||
if ($response) {
|
||||
$response->output();
|
||||
} elseif ($this->defaultResponse) {
|
||||
echo $this->defaultResponse;
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
namespace SilverStripe\Core\Startup;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Security\RandomGenerator;
|
||||
|
||||
/**
|
||||
|
@ -25,6 +28,11 @@ class ParameterConfirmationToken
|
|||
*/
|
||||
protected $parameterName = null;
|
||||
|
||||
/**
|
||||
* @var HTTPRequest
|
||||
*/
|
||||
protected $request = null;
|
||||
|
||||
/**
|
||||
* The parameter given
|
||||
*
|
||||
|
@ -88,17 +96,19 @@ class ParameterConfirmationToken
|
|||
* Create a new ParameterConfirmationToken
|
||||
*
|
||||
* @param string $parameterName Name of the querystring parameter to check
|
||||
* @param HTTPRequest $request
|
||||
*/
|
||||
public function __construct($parameterName)
|
||||
public function __construct($parameterName, HTTPRequest $request)
|
||||
{
|
||||
// Store the parameter name
|
||||
$this->parameterName = $parameterName;
|
||||
$this->request = $request;
|
||||
|
||||
// Store the parameter value
|
||||
$this->parameter = isset($_GET[$parameterName]) ? $_GET[$parameterName] : null;
|
||||
$this->parameter = $request->getVar($parameterName);
|
||||
|
||||
// If the token provided is valid, mark it as such
|
||||
$token = isset($_GET[$parameterName.'token']) ? $_GET[$parameterName.'token'] : null;
|
||||
$token = $request->getVar($parameterName.'token');
|
||||
if ($this->checkToken($token)) {
|
||||
$this->token = $token;
|
||||
}
|
||||
|
@ -151,7 +161,7 @@ class ParameterConfirmationToken
|
|||
*/
|
||||
public function suppress()
|
||||
{
|
||||
unset($_GET[$this->parameterName]);
|
||||
$this->request->offsetUnset($this->parameterName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,81 +177,45 @@ class ParameterConfirmationToken
|
|||
);
|
||||
}
|
||||
|
||||
/** What to use instead of BASE_URL. Must not contain protocol or host. @var string */
|
||||
static public $alternateBaseURL = null;
|
||||
|
||||
protected function currentAbsoluteURL()
|
||||
/**
|
||||
* Get redirect url, excluding querystring
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function currentURL()
|
||||
{
|
||||
global $url;
|
||||
|
||||
// Are we http or https? Replicates Director::is_https() without its dependencies/
|
||||
$proto = 'http';
|
||||
// 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');
|
||||
}
|
||||
foreach ($headers as $header) {
|
||||
$headerCompareVal = ($header === 'HTTP_FRONT_END_HTTPS' ? 'on' : 'https');
|
||||
if (!empty($_SERVER[$header]) && strtolower($_SERVER[$header]) == $headerCompareVal) {
|
||||
$headerOverride = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($headerOverride) {
|
||||
$proto = 'https';
|
||||
} elseif ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
|
||||
$proto = 'https';
|
||||
} elseif (isset($_SERVER['SSL'])) {
|
||||
$proto = 'https';
|
||||
}
|
||||
|
||||
$parts = array_filter(array(
|
||||
// What's our host
|
||||
Director::host(),
|
||||
// SilverStripe base
|
||||
self::$alternateBaseURL !== null ? self::$alternateBaseURL : BASE_URL,
|
||||
// And URL including base script (eg: if it's index.php/page/url/)
|
||||
(defined('BASE_SCRIPT_URL') ? '/' . BASE_SCRIPT_URL : '') . $url,
|
||||
));
|
||||
|
||||
// Join together with protocol into our current absolute URL, avoiding duplicated "/" characters
|
||||
return "$proto://" . preg_replace('#/{2,}#', '/', implode('/', $parts));
|
||||
return Controller::join_links(
|
||||
BASE_URL,
|
||||
'/',
|
||||
$this->request->getURL(false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a reload of the request with the token included
|
||||
* This method will terminate the script with `die`
|
||||
*
|
||||
* @return HTTPResponse
|
||||
*/
|
||||
public function reloadWithToken()
|
||||
{
|
||||
$location = $this->currentAbsoluteURL();
|
||||
// Merge get params with current url
|
||||
$params = array_merge($this->request->getVars(), $this->params());
|
||||
$location = Controller::join_links(
|
||||
$this->currentURL(),
|
||||
'?'.http_build_query($params)
|
||||
);
|
||||
$locationJS = Convert::raw2js($location);
|
||||
$locationATT = Convert::raw2att($location);
|
||||
$body = <<<HTML
|
||||
<script>location.href='$locationJS';</script>
|
||||
<noscript><meta http-equiv="refresh" content="0; url=$locationATT"></noscript>
|
||||
You are being redirected. If you are not redirected soon, <a href="$locationATT">click here to continue the flush</a>
|
||||
HTML;
|
||||
|
||||
// What's our GET params (ensuring they include the original parameter + a new token)
|
||||
$params = array_merge($_GET, $this->params());
|
||||
unset($params['url']);
|
||||
|
||||
if ($params) {
|
||||
$location .= '?'.http_build_query($params);
|
||||
}
|
||||
|
||||
// And redirect
|
||||
if (headers_sent()) {
|
||||
echo "
|
||||
<script>location.href='$location';</script>
|
||||
<noscript><meta http-equiv='refresh' content='0; url=$location'></noscript>
|
||||
You are being redirected. If you are not redirected soon, <a href='$location'>click here to continue the flush</a>
|
||||
";
|
||||
} else {
|
||||
header('location: '.$location, true, 302);
|
||||
}
|
||||
die;
|
||||
// Build response
|
||||
$result = new HTTPResponse($body);
|
||||
$result->redirect($location);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,13 +223,14 @@ You are being redirected. If you are not redirected soon, <a href='$location'>cl
|
|||
* return the non-validated token with the highest priority
|
||||
*
|
||||
* @param array $keys List of token keys in ascending priority (low to high)
|
||||
* @param HTTPRequest $request
|
||||
* @return ParameterConfirmationToken The token container for the unvalidated $key given with the highest priority
|
||||
*/
|
||||
public static function prepare_tokens($keys)
|
||||
public static function prepare_tokens($keys, HTTPRequest $request)
|
||||
{
|
||||
$target = null;
|
||||
foreach ($keys as $key) {
|
||||
$token = new ParameterConfirmationToken($key);
|
||||
$token = new ParameterConfirmationToken($key, $request);
|
||||
// Validate this token
|
||||
if ($token->reloadRequired()) {
|
||||
$token->suppress();
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
|
@ -21,7 +21,7 @@ class DevBuildController extends Controller
|
|||
{
|
||||
if (Director::is_cli()) {
|
||||
$da = DatabaseAdmin::create();
|
||||
return $da->handleRequest($request, $this->model);
|
||||
return $da->handleRequest($request);
|
||||
} else {
|
||||
$renderer = DebugView::create();
|
||||
echo $renderer->renderHeader();
|
||||
|
@ -29,7 +29,7 @@ class DevBuildController extends Controller
|
|||
echo "<div class=\"build\">";
|
||||
|
||||
$da = DatabaseAdmin::create();
|
||||
$response = $da->handleRequest($request, $this->model);
|
||||
$response = $da->handleRequest($request);
|
||||
|
||||
echo "</div>";
|
||||
echo $renderer->renderFooter();
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
namespace SilverStripe\Dev;
|
||||
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use InvalidArgumentException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
|
||||
/**
|
||||
* A blueprint on how to create instances of a certain {@link DataObject} subclass.
|
||||
|
@ -94,7 +94,7 @@ class FixtureBlueprint
|
|||
try {
|
||||
$class = $this->class;
|
||||
$schema = DataObject::getSchema();
|
||||
$obj = DataModel::inst()->$class->newObject();
|
||||
$obj = Injector::inst()->create($class);
|
||||
|
||||
// If an ID is explicitly passed, then we'll sort out the initial write straight away
|
||||
// This is just in case field setters triggered by the population code in the next block
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>PHP 5.5.0 is required</title>
|
||||
<title>PHP 5.6.0 is required</title>
|
||||
<link rel="stylesheet" type="text/css" href="framework/src/Dev/Install/client/styles/install.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="BgContainer">
|
||||
<div id="Container">
|
||||
<div id="Header">
|
||||
<h1>PHP 5.5.0 required</h1>
|
||||
<h1>PHP 5.6.0 required</h1>
|
||||
<div class="left">
|
||||
<h3>To run SilverStripe, please install PHP 5.5.0 or greater.</h3>
|
||||
<h3>To run SilverStripe, please install PHP 5.6.0 or greater.</h3>
|
||||
|
||||
<p>We have detected that you are running PHP version <b>$PHPVersion</b>. In order to run SilverStripe,
|
||||
you must have PHP version 5.5.0 or higher.<p/>
|
||||
you must have PHP version 5.6.0 or higher.<p/>
|
||||
|
||||
<p>If you are running on a shared host, you may need to ask your hosting provider how to do this.</p>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
// Ensure this class can be autoloaded when installed without dev dependencies.
|
||||
// It's included by default through composer's autoloading.
|
||||
// class_exists() triggers PSR-4 autoloaders, which should discover if PHPUnit is installed.
|
||||
// TODO Factor out SapphireTest references from non-dev core code (avoid autoloading in the first place)
|
||||
namespace {
|
||||
|
||||
if (!class_exists('PHPUnit_Framework_TestCase')) {
|
||||
class PHPUnit_Framework_TestCase
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,25 +2,27 @@
|
|||
|
||||
namespace SilverStripe\Dev;
|
||||
|
||||
use Exception;
|
||||
use LogicException;
|
||||
use PHPUnit_Framework_TestCase;
|
||||
use SilverStripe\CMS\Controllers\RootURLController;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Cookie;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\Email\Email;
|
||||
use SilverStripe\Control\Email\Mailer;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\Tests\FakeController;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Config\ConfigLoader;
|
||||
use SilverStripe\Core\Config\CoreConfigFactory;
|
||||
use SilverStripe\Core\Config\DefaultConfig;
|
||||
use SilverStripe\Core\Config\Middleware\ExtensionMiddleware;
|
||||
use SilverStripe\Core\Extension;
|
||||
use SilverStripe\Core\Flushable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Manifest\ClassManifest;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Core\Manifest\ClassManifest;
|
||||
use SilverStripe\Core\Resettable;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
|
@ -28,22 +30,20 @@ use SilverStripe\ORM\SS_List;
|
|||
use SilverStripe\Security\IdentityStore;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\Security\Group;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\View\Requirements;
|
||||
use SilverStripe\View\SSViewer;
|
||||
use SilverStripe\View\ThemeResourceLoader;
|
||||
use SilverStripe\View\ThemeManifest;
|
||||
use PHPUnit_Framework_TestCase;
|
||||
use SilverStripe\View\ThemeResourceLoader;
|
||||
use Translatable;
|
||||
use LogicException;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Test case class for the Sapphire framework.
|
||||
|
@ -274,9 +274,6 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
|||
$resettable::reset();
|
||||
}
|
||||
|
||||
if (Controller::has_curr()) {
|
||||
Controller::curr()->setSession(Session::create(array()));
|
||||
}
|
||||
Security::clear_database_is_ready();
|
||||
|
||||
// Set up test routes
|
||||
|
@ -284,9 +281,6 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
|||
|
||||
$fixtureFiles = $this->getFixturePaths();
|
||||
|
||||
// Todo: this could be a special test model
|
||||
$this->model = DataModel::inst();
|
||||
|
||||
// Set up fixture
|
||||
if ($fixtureFiles || $this->usesDatabase) {
|
||||
if (!self::using_temp_db()) {
|
||||
|
|
|
@ -333,11 +333,23 @@ class Form extends ViewableData implements HasRequestHandler
|
|||
*/
|
||||
public function clearFormState()
|
||||
{
|
||||
Session::clear("FormInfo.{$this->FormName()}.result");
|
||||
Session::clear("FormInfo.{$this->FormName()}.data");
|
||||
$this
|
||||
->getSession()
|
||||
->clear("FormInfo.{$this->FormName()}.result")
|
||||
->clear("FormInfo.{$this->FormName()}.data");
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session for this form
|
||||
*
|
||||
* @return Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->getRequestHandler()->getRequest()->getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any form data stored in the session
|
||||
*
|
||||
|
@ -345,7 +357,7 @@ class Form extends ViewableData implements HasRequestHandler
|
|||
*/
|
||||
public function getSessionData()
|
||||
{
|
||||
return Session::get("FormInfo.{$this->FormName()}.data");
|
||||
return $this->getSession()->get("FormInfo.{$this->FormName()}.data");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -356,7 +368,7 @@ class Form extends ViewableData implements HasRequestHandler
|
|||
*/
|
||||
public function setSessionData($data)
|
||||
{
|
||||
Session::set("FormInfo.{$this->FormName()}.data", $data);
|
||||
$this->getSession()->set("FormInfo.{$this->FormName()}.data", $data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -367,7 +379,7 @@ class Form extends ViewableData implements HasRequestHandler
|
|||
*/
|
||||
public function getSessionValidationResult()
|
||||
{
|
||||
$resultData = Session::get("FormInfo.{$this->FormName()}.result");
|
||||
$resultData = $this->getSession()->get("FormInfo.{$this->FormName()}.result");
|
||||
if (isset($resultData)) {
|
||||
return unserialize($resultData);
|
||||
}
|
||||
|
@ -396,7 +408,7 @@ class Form extends ViewableData implements HasRequestHandler
|
|||
|
||||
// Serialise
|
||||
$resultData = $result ? serialize($result) : null;
|
||||
Session::set("FormInfo.{$this->FormName()}.result", $resultData);
|
||||
$this->getSession()->set("FormInfo.{$this->FormName()}.result", $resultData);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,23 +2,21 @@
|
|||
|
||||
namespace SilverStripe\Forms\GridField;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use SilverStripe\Control\HasRequestHandler;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Control\RequestHandler;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\RequestHandler;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\Form;
|
||||
use LogicException;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\View\HTML;
|
||||
|
||||
/**
|
||||
|
@ -910,7 +908,7 @@ class GridField extends FormField
|
|||
|
||||
foreach ($data as $dataKey => $dataValue) {
|
||||
if (preg_match('/^action_gridFieldAlterAction\?StateID=(.*)/', $dataKey, $matches)) {
|
||||
$stateChange = Session::get($matches[1]);
|
||||
$stateChange = $request->getSession()->get($matches[1]);
|
||||
$actionName = $stateChange['actionName'];
|
||||
|
||||
$arguments = array();
|
||||
|
@ -972,11 +970,10 @@ class GridField extends FormField
|
|||
* @todo copy less code from RequestHandler.
|
||||
*
|
||||
* @param HTTPRequest $request
|
||||
* @param DataModel $model
|
||||
* @return array|RequestHandler|HTTPResponse|string
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
public function handleRequest(HTTPRequest $request, DataModel $model)
|
||||
public function handleRequest(HTTPRequest $request)
|
||||
{
|
||||
if ($this->brokenOnConstruct) {
|
||||
user_error(
|
||||
|
@ -989,7 +986,6 @@ class GridField extends FormField
|
|||
}
|
||||
|
||||
$this->setRequest($request);
|
||||
$this->setDataModel($model);
|
||||
|
||||
$fieldData = $this->getRequest()->requestVar($this->getName());
|
||||
|
||||
|
@ -1038,7 +1034,7 @@ class GridField extends FormField
|
|||
if ($result instanceof HasRequestHandler) {
|
||||
$result = $result->getRequestHandler();
|
||||
}
|
||||
$returnValue = $result->handleRequest($request, $model);
|
||||
$returnValue = $result->handleRequest($request);
|
||||
|
||||
if (is_array($returnValue)) {
|
||||
throw new LogicException(
|
||||
|
@ -1066,7 +1062,7 @@ class GridField extends FormField
|
|||
}
|
||||
}
|
||||
|
||||
return parent::handleRequest($request, $model);
|
||||
return parent::handleRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,17 +2,16 @@
|
|||
|
||||
namespace SilverStripe\Forms\GridField;
|
||||
|
||||
use Closure;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\RequestHandler;
|
||||
use SilverStripe\Core\Extensible;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Extensible;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\Validator;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use Closure;
|
||||
use SilverStripe\Forms\Validator;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\Filterable;
|
||||
|
||||
/**
|
||||
|
@ -118,7 +117,7 @@ class GridFieldDetailForm implements GridField_URLHandler
|
|||
$this->setValidator($record->getCMSValidator());
|
||||
}
|
||||
|
||||
return $handler->handleRequest($request, DataModel::inst());
|
||||
return $handler->handleRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace SilverStripe\Forms\GridField;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\FormAction;
|
||||
|
@ -89,7 +90,9 @@ class GridField_FormAction extends FormAction
|
|||
|
||||
// Ensure $id doesn't contain only numeric characters
|
||||
$id = 'gf_' . substr(md5(serialize($state)), 0, 8);
|
||||
Session::set($id, $state);
|
||||
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($id, $state);
|
||||
$actionData['StateID'] = $id;
|
||||
|
||||
return array_merge(
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
|
||||
namespace SilverStripe\ORM;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use SilverStripe\Control\Cookie;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\Cookie;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\ORM\Connect\Database;
|
||||
use SilverStripe\ORM\Connect\DBConnector;
|
||||
use SilverStripe\ORM\Connect\DBSchemaManager;
|
||||
use SilverStripe\ORM\Connect\Query;
|
||||
use SilverStripe\ORM\Queries\SQLExpression;
|
||||
use SilverStripe\ORM\Connect\Database;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Global database interface, complete with static methods.
|
||||
|
@ -34,9 +34,19 @@ class DB
|
|||
|
||||
/**
|
||||
* The global database connection.
|
||||
*
|
||||
* @var Database
|
||||
*/
|
||||
private static $connections = array();
|
||||
protected static $connections = [];
|
||||
|
||||
/**
|
||||
* List of configurations for each connection
|
||||
*
|
||||
* @var array List of configs each in the $databaseConfig format
|
||||
*/
|
||||
protected static $configs = [];
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The last SQL query run.
|
||||
|
@ -77,6 +87,13 @@ class DB
|
|||
if (isset(self::$connections[$name])) {
|
||||
return self::$connections[$name];
|
||||
}
|
||||
|
||||
// lazy connect
|
||||
$config = static::getConfig($name);
|
||||
if ($config) {
|
||||
return static::connect($config, $name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -247,7 +264,7 @@ class DB
|
|||
}
|
||||
|
||||
/**
|
||||
* Connect to a database.
|
||||
* Specify connection to a database
|
||||
*
|
||||
* Given the database configuration, this method will create the correct
|
||||
* subclass of {@link SS_Database}.
|
||||
|
@ -259,14 +276,13 @@ class DB
|
|||
*/
|
||||
public static function connect($databaseConfig, $label = 'default')
|
||||
{
|
||||
|
||||
// This is used by the "testsession" module to test up a test session using an alternative name
|
||||
if ($name = self::get_alternative_database_name()) {
|
||||
$databaseConfig['database'] = $name;
|
||||
}
|
||||
|
||||
if (!isset($databaseConfig['type']) || empty($databaseConfig['type'])) {
|
||||
user_error("DB::connect: Not passed a valid database config", E_USER_ERROR);
|
||||
throw new InvalidArgumentException("DB::connect: Not passed a valid database config");
|
||||
}
|
||||
|
||||
self::$connection_attempted = true;
|
||||
|
@ -283,6 +299,30 @@ class DB
|
|||
return $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set config for a lazy-connected database
|
||||
*
|
||||
* @param array $databaseConfig
|
||||
* @param string $name
|
||||
*/
|
||||
public static function setConfig($databaseConfig, $name = 'default')
|
||||
{
|
||||
static::$configs[$name] = $databaseConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the named connection config
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getConfig($name)
|
||||
{
|
||||
if (isset(static::$configs[$name])) {
|
||||
return static::$configs[$name];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a database connection has been attempted.
|
||||
* In particular, it lets the caller know if we're still so early in the execution pipeline that
|
||||
|
|
|
@ -49,13 +49,6 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||
*/
|
||||
protected $dataQuery;
|
||||
|
||||
/**
|
||||
* The DataModel from which this DataList comes.
|
||||
*
|
||||
* @var DataModel
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Create a new DataList.
|
||||
* No querying is done on construction, but the initial query schema is set up.
|
||||
|
@ -70,16 +63,6 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DataModel
|
||||
*
|
||||
* @param DataModel $model
|
||||
*/
|
||||
public function setDataModel(DataModel $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dataClass name for this DataList, ie the DataObject ClassName
|
||||
*
|
||||
|
@ -796,7 +779,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||
$class = $row['RecordClassName'];
|
||||
}
|
||||
|
||||
$item = Injector::inst()->create($class, $row, false, $this->model, $this->getQueryParams());
|
||||
$item = Injector::inst()->create($class, $row, false, $this->getQueryParams());
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
@ -1119,7 +1102,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||
public function newObject($initialFields = null)
|
||||
{
|
||||
$class = $this->dataClass;
|
||||
return Injector::inst()->create($class, $initialFields, false, $this->model);
|
||||
return Injector::inst()->create($class, $initialFields, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\ORM;
|
||||
|
||||
/**
|
||||
* Representation of a DataModel - a collection of DataLists for each different
|
||||
* data type.
|
||||
*
|
||||
* Usage:
|
||||
* <code>
|
||||
* $model = new DataModel;
|
||||
* $mainMenu = $model->SiteTree->where('"ParentID" = 0 AND "ShowInMenus" = 1');
|
||||
* </code>
|
||||
*/
|
||||
class DataModel
|
||||
{
|
||||
|
||||
/**
|
||||
* @var DataModel
|
||||
*/
|
||||
protected static $inst;
|
||||
|
||||
/**
|
||||
* @var array $customDataLists
|
||||
*/
|
||||
protected $customDataLists = array();
|
||||
|
||||
/**
|
||||
* Get the global DataModel.
|
||||
*
|
||||
* @return DataModel
|
||||
*/
|
||||
public static function inst()
|
||||
{
|
||||
if (!self::$inst) {
|
||||
self::$inst = new self;
|
||||
}
|
||||
|
||||
return self::$inst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the global DataModel, used when data is requested from static
|
||||
* methods.
|
||||
*
|
||||
* @param DataModel $inst
|
||||
*/
|
||||
public static function set_inst(DataModel $inst)
|
||||
{
|
||||
self::$inst = $inst;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string
|
||||
*
|
||||
* @return DataList
|
||||
*/
|
||||
public function __get($class)
|
||||
{
|
||||
if (isset($this->customDataLists[$class])) {
|
||||
return clone $this->customDataLists[$class];
|
||||
} else {
|
||||
$list = DataList::create($class);
|
||||
$list->setDataModel($this);
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param DataList $item
|
||||
*/
|
||||
public function __set($class, $item)
|
||||
{
|
||||
$item = clone $item;
|
||||
$item->setDataModel($this);
|
||||
$this->customDataLists[$class] = $item;
|
||||
}
|
||||
}
|
|
@ -141,11 +141,6 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
*/
|
||||
public $destroyed = false;
|
||||
|
||||
/**
|
||||
* The DataModel from this this object comes
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Data stored in this objects database record. An array indexed by fieldname.
|
||||
*
|
||||
|
@ -289,10 +284,9 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
* for populating data on new records.
|
||||
* @param boolean $isSingleton This this to true if this is a singleton() object, a stub for calling methods.
|
||||
* Singletons don't have their defaults set.
|
||||
* @param DataModel $model
|
||||
* @param array $queryParams List of DataQuery params necessary to lazy load, or load related objects.
|
||||
*/
|
||||
public function __construct($record = null, $isSingleton = false, $model = null, $queryParams = array())
|
||||
public function __construct($record = null, $isSingleton = false, $queryParams = array())
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
|
@ -365,10 +359,6 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
HTTP::register_modification_date($record['LastEdited']);
|
||||
}
|
||||
|
||||
// this must be called before populateDefaults(), as field getters on a DataObject
|
||||
// may call getComponent() and others, which rely on $this->model being set.
|
||||
$this->model = $model ? $model : DataModel::inst();
|
||||
|
||||
// Must be called after parent constructor
|
||||
if (!$isSingleton && (!isset($this->record['ID']) || !$this->record['ID'])) {
|
||||
$this->populateDefaults();
|
||||
|
@ -378,17 +368,6 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
$this->changed = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DataModel
|
||||
* @param DataModel $model
|
||||
* @return DataObject $this
|
||||
*/
|
||||
public function setDataModel(DataModel $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy all of this objects dependant objects and local caches.
|
||||
* You'll need to call this to get the memory of an object that has components or extensions freed.
|
||||
|
@ -415,7 +394,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
$map = $this->toMap();
|
||||
unset($map['Created']);
|
||||
/** @var static $clone */
|
||||
$clone = Injector::inst()->create(static::class, $map, false, $this->model);
|
||||
$clone = Injector::inst()->create(static::class, $map, false, $this->getSourceQueryParams());
|
||||
$clone->ID = 0;
|
||||
|
||||
$clone->invokeWithExtensions('onBeforeDuplicate', $this, $doWrite, $manyMany);
|
||||
|
@ -1437,7 +1416,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
// - move the details of the delete code in the DataQuery system
|
||||
// - update the code to just delete the base table, and rely on cascading deletes in the DB to do the rest
|
||||
// obviously, that means getting requireTable() to configure cascading deletes ;-)
|
||||
$srcQuery = DataList::create(static::class, $this->model)
|
||||
$srcQuery = DataList::create(static::class)
|
||||
->filter('ID', $this->ID)
|
||||
->dataQuery()
|
||||
->query();
|
||||
|
@ -1520,7 +1499,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
}
|
||||
|
||||
if (empty($component)) {
|
||||
$component = $this->model->$class->newObject();
|
||||
$component = Injector::inst()->create($class);
|
||||
}
|
||||
} elseif ($class = $schema->belongsToComponent(static::class, $componentName)) {
|
||||
$joinField = $schema->getRemoteJoinField(static::class, $componentName, 'belongs_to', $polymorphic);
|
||||
|
@ -2827,9 +2806,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
. ' arguments');
|
||||
}
|
||||
|
||||
$result = DataList::create(get_called_class());
|
||||
$result->setDataModel(DataModel::inst());
|
||||
return $result;
|
||||
return DataList::create(get_called_class());
|
||||
}
|
||||
|
||||
if ($join) {
|
||||
|
@ -2847,7 +2824,6 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||
$result = $result->limit($limit);
|
||||
}
|
||||
|
||||
$result->setDataModel(DataModel::inst());
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class ManyManyThroughList extends RelationList
|
|||
if ($joinRow) {
|
||||
$joinClass = $this->manipulator->getJoinClass();
|
||||
$joinQueryParams = $this->manipulator->extractInheritableQueryParameters($this->dataQuery);
|
||||
$joinRecord = Injector::inst()->create($joinClass, $joinRow, false, $this->model, $joinQueryParams);
|
||||
$joinRecord = Injector::inst()->create($joinClass, $joinRow, false, $joinQueryParams);
|
||||
$record->setJoin($joinRecord, $joinAlias);
|
||||
}
|
||||
|
||||
|
|
|
@ -180,9 +180,12 @@ class BasicAuth
|
|||
*/
|
||||
public static function protect_entire_site($protect = true, $code = 'ADMIN', $message = null)
|
||||
{
|
||||
static::config()->set('entire_site_protected', $protect);
|
||||
static::config()->set('entire_site_protected_code', $code);
|
||||
static::config()->set('entire_site_protected_message', $message);
|
||||
static::config()
|
||||
->set('entire_site_protected', $protect)
|
||||
->set('entire_site_protected_code', $code);
|
||||
if ($message) {
|
||||
static::config()->set('entire_site_protected_message', $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,7 +200,6 @@ class BasicAuth
|
|||
$config = static::config();
|
||||
$request = Controller::curr()->getRequest();
|
||||
if ($config->get('entire_site_protected')) {
|
||||
/** @noinspection ExceptionsAnnotatingAndHandlingInspection */
|
||||
static::requireLogin(
|
||||
$request,
|
||||
$config->get('entire_site_protected_message'),
|
||||
|
|
|
@ -94,14 +94,14 @@ class CMSSecurity extends Security
|
|||
$message = parent::getLoginMessage($messageType);
|
||||
if ($message) {
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
|
||||
// Format
|
||||
return _t(
|
||||
return _t(
|
||||
__CLASS__.'.LOGIN_MESSAGE',
|
||||
'<p>Your session has timed out due to inactivity</p>'
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is a logged in member
|
||||
|
@ -187,7 +187,7 @@ PHP
|
|||
$controller = $this->getResponseController(_t(__CLASS__.'.SUCCESS', 'Success'));
|
||||
$backURLs = array(
|
||||
$this->getRequest()->requestVar('BackURL'),
|
||||
Session::get('BackURL'),
|
||||
$this->getRequest()->getSession()->get('BackURL'),
|
||||
Director::absoluteURL(AdminRootController::config()->get('url_base'), true),
|
||||
);
|
||||
$backURL = null;
|
||||
|
@ -201,7 +201,7 @@ PHP
|
|||
$controller = $controller->customise(array(
|
||||
'Content' => DBField::create_field(DBHTMLText::class, _t(
|
||||
__CLASS__.'.SUCCESSCONTENT',
|
||||
'<p>Login success. If you are not automatically redirected '.
|
||||
'<p>Login success. If you are not automatically redirected ' .
|
||||
'<a target="_top" href="{link}">click here</a></p>',
|
||||
'Login message displayed in the cms popup once a user has re-authenticated themselves',
|
||||
array('link' => Convert::raw2att($backURL))
|
||||
|
|
|
@ -275,14 +275,14 @@ class Member extends DataObject
|
|||
{
|
||||
Deprecation::notice('5.0', 'Use DefaultAdminService::findOrCreateDefaultAdmin() instead');
|
||||
return DefaultAdminService::singleton()->findOrCreateDefaultAdmin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the passed password matches the stored one (if the member is not locked out).
|
||||
*
|
||||
* @deprecated 4.0.0...5.0.0 Use Authenticator::checkPassword() instead
|
||||
*
|
||||
* @param string $password
|
||||
* @param string $password
|
||||
* @return ValidationResult
|
||||
*/
|
||||
public function checkPassword($password)
|
||||
|
@ -294,12 +294,12 @@ class Member extends DataObject
|
|||
$authenticators = Security::singleton()->getApplicableAuthenticators(Authenticator::CHECK_PASSWORD);
|
||||
foreach ($authenticators as $authenticator) {
|
||||
$authenticator->checkPassword($this, $password, $result);
|
||||
if (!$result->isValid()) {
|
||||
if (!$result->isValid()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this user is the currently configured default admin
|
||||
|
|
|
@ -28,7 +28,8 @@ class ChangePasswordForm extends Form
|
|||
*/
|
||||
public function __construct($controller, $name, $fields = null, $actions = null)
|
||||
{
|
||||
$backURL = $controller->getBackURL() ?: Session::get('BackURL');
|
||||
$backURL = $controller->getBackURL()
|
||||
?: $controller->getRequest()->getSession()->get('BackURL');
|
||||
|
||||
if (!$fields) {
|
||||
$fields = $this->getFormFields();
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace SilverStripe\Security\MemberAuthenticator;
|
|||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\RequestHandler;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
@ -79,7 +78,8 @@ class ChangePasswordHandler extends RequestHandler
|
|||
return $this->redirect($this->link);
|
||||
}
|
||||
|
||||
if (Session::get('AutoLoginHash')) {
|
||||
$session = $this->getRequest()->getSession();
|
||||
if ($session->get('AutoLoginHash')) {
|
||||
$message = DBField::create_field(
|
||||
'HTMLFragment',
|
||||
'<p>' . _t(
|
||||
|
@ -157,7 +157,7 @@ class ChangePasswordHandler extends RequestHandler
|
|||
}
|
||||
|
||||
// Store the hash for the change password form. Will be unset after reload within the ChangePasswordForm.
|
||||
Session::set('AutoLoginHash', $member->encryptWithUserSettings($token));
|
||||
$this->getRequest()->getSession()->set('AutoLoginHash', $member->encryptWithUserSettings($token));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,14 +214,15 @@ class ChangePasswordHandler extends RequestHandler
|
|||
return $this->redirectBackToForm();
|
||||
}
|
||||
|
||||
$session = $this->getRequest()->getSession();
|
||||
if (!$member) {
|
||||
if (Session::get('AutoLoginHash')) {
|
||||
$member = Member::member_from_autologinhash(Session::get('AutoLoginHash'));
|
||||
if ($session->get('AutoLoginHash')) {
|
||||
$member = Member::member_from_autologinhash($session->get('AutoLoginHash'));
|
||||
}
|
||||
|
||||
// The user is not logged in and no valid auto login hash is available
|
||||
if (!$member) {
|
||||
Session::clear('AutoLoginHash');
|
||||
$session->clear('AutoLoginHash');
|
||||
|
||||
return $this->redirect($this->addBackURLParam(Security::singleton()->Link('login')));
|
||||
}
|
||||
|
@ -278,7 +279,7 @@ class ChangePasswordHandler extends RequestHandler
|
|||
}
|
||||
|
||||
// TODO Add confirmation message to login redirect
|
||||
Session::clear('AutoLoginHash');
|
||||
$session->clear('AutoLoginHash');
|
||||
|
||||
// Redirect to backurl
|
||||
$backURL = $this->getBackURL();
|
||||
|
|
|
@ -143,7 +143,7 @@ class MemberLoginForm extends BaseLoginForm
|
|||
$emailField->setAttribute('autofocus', 'true');
|
||||
|
||||
if (Security::config()->get('remember_username')) {
|
||||
$emailField->setValue(Session::get('SessionForms.MemberLoginForm.Email'));
|
||||
$emailField->setValue($this->getSession()->get('SessionForms.MemberLoginForm.Email'));
|
||||
} else {
|
||||
// Some browsers won't respect this attribute unless it's added to the form
|
||||
$this->setAttribute('autocomplete', 'off');
|
||||
|
@ -195,7 +195,8 @@ class MemberLoginForm extends BaseLoginForm
|
|||
{
|
||||
parent::restoreFormState();
|
||||
|
||||
$forceMessage = Session::get('MemberLoginForm.force_message');
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$forceMessage = $session->get('MemberLoginForm.force_message');
|
||||
if (($member = Security::getCurrentUser()) && !$forceMessage) {
|
||||
$message = _t(
|
||||
'SilverStripe\\Security\\Member.LOGGEDINAS',
|
||||
|
@ -207,7 +208,7 @@ class MemberLoginForm extends BaseLoginForm
|
|||
|
||||
// Reset forced message
|
||||
if ($forceMessage) {
|
||||
Session::set('MemberLoginForm.force_message', false);
|
||||
$session->set('MemberLoginForm.force_message', false);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
namespace SilverStripe\Security\MemberAuthenticator;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Cookie;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Security\AuthenticationHandler;
|
||||
use SilverStripe\Security\Member;
|
||||
|
||||
|
@ -47,7 +47,7 @@ class SessionAuthenticationHandler implements AuthenticationHandler
|
|||
{
|
||||
// If ID is a bad ID it will be treated as if the user is not logged in, rather than throwing a
|
||||
// ValidationException
|
||||
$id = Session::get($this->getSessionVariable());
|
||||
$id = $request->getSession()->get($this->getSessionVariable());
|
||||
if (!$id) {
|
||||
return null;
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ class SessionAuthenticationHandler implements AuthenticationHandler
|
|||
public function logIn(Member $member, $persistent = false, HTTPRequest $request = null)
|
||||
{
|
||||
static::regenerateSessionId();
|
||||
Session::set($this->getSessionVariable(), $member->ID);
|
||||
$request = $request ?: Controller::curr()->getRequest();
|
||||
$request->getSession()->set($this->getSessionVariable(), $member->ID);
|
||||
|
||||
// This lets apache rules detect whether the user has logged in
|
||||
// @todo make this a setting on the authentication handler
|
||||
|
@ -102,6 +103,7 @@ class SessionAuthenticationHandler implements AuthenticationHandler
|
|||
*/
|
||||
public function logOut(HTTPRequest $request = null)
|
||||
{
|
||||
Session::clear($this->getSessionVariable());
|
||||
$request = $request ?: Controller::curr()->getRequest();
|
||||
$request->getSession()->clear($this->getSessionVariable());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ use SilverStripe\Dev\Deprecation;
|
|||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
@ -328,7 +327,7 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
{
|
||||
self::set_ignore_disallowed_actions(true);
|
||||
|
||||
if (!$controller) {
|
||||
if (!$controller && Controller::has_curr()) {
|
||||
$controller = Controller::curr();
|
||||
}
|
||||
|
||||
|
@ -357,7 +356,7 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
$messageSet = $configMessageSet;
|
||||
} else {
|
||||
$messageSet = array(
|
||||
'default' => _t(
|
||||
'default' => _t(
|
||||
'SilverStripe\\Security\\Security.NOTEPAGESECURED',
|
||||
"That page is secured. Enter your credentials below and we will send "
|
||||
. "you right along."
|
||||
|
@ -408,7 +407,7 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
|
||||
static::singleton()->setLoginMessage($message, ValidationResult::TYPE_WARNING);
|
||||
|
||||
Session::set("BackURL", $_SERVER['REQUEST_URI']);
|
||||
$controller->getRequest()->getSession()->set("BackURL", $_SERVER['REQUEST_URI']);
|
||||
|
||||
// TODO AccessLogEntry needs an extension to handle permission denied errors
|
||||
// Audit logging hook
|
||||
|
@ -569,6 +568,21 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getRequest()
|
||||
{
|
||||
// Support Security::singleton() where a request isn't always injected
|
||||
$request = parent::getRequest();
|
||||
if ($request) {
|
||||
return $request;
|
||||
}
|
||||
|
||||
if (Controller::has_curr() && Controller::curr() !== $this) {
|
||||
return Controller::curr()->getRequest();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the controller for handling the response to this request
|
||||
*
|
||||
|
@ -593,7 +607,6 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
$holderPage->ID = -1 * random_int(1, 10000000);
|
||||
|
||||
$controller = ModelAsController::controller_for($holderPage);
|
||||
$controller->setDataModel($this->model);
|
||||
$controller->doInit();
|
||||
|
||||
return $controller;
|
||||
|
@ -628,14 +641,15 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
*/
|
||||
protected function getLoginMessage(&$messageType = null)
|
||||
{
|
||||
$message = Session::get('Security.Message.message');
|
||||
$session = $this->getRequest()->getSession();
|
||||
$message = $session->get('Security.Message.message');
|
||||
$messageType = null;
|
||||
if (empty($message)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$messageType = Session::get('Security.Message.type');
|
||||
$messageCast = Session::get('Security.Message.cast');
|
||||
$messageType = $session->get('Security.Message.type');
|
||||
$messageCast = $session->get('Security.Message.cast');
|
||||
if ($messageCast !== ValidationResult::CAST_HTML) {
|
||||
$message = Convert::raw2xml($message);
|
||||
}
|
||||
|
@ -655,9 +669,12 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
$messageType = ValidationResult::TYPE_WARNING,
|
||||
$messageCast = ValidationResult::CAST_TEXT
|
||||
) {
|
||||
Session::set('Security.Message.message', $message);
|
||||
Session::set('Security.Message.type', $messageType);
|
||||
Session::set('Security.Message.cast', $messageCast);
|
||||
Controller::curr()
|
||||
->getRequest()
|
||||
->getSession()
|
||||
->set("Security.Message.message", $message)
|
||||
->set("Security.Message.type", $messageType)
|
||||
->set("Security.Message.cast", $messageCast);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -665,7 +682,10 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
*/
|
||||
public static function clearLoginMessage()
|
||||
{
|
||||
Session::clear('Security.Message');
|
||||
Controller::curr()
|
||||
->getRequest()
|
||||
->getSession()
|
||||
->clear("Security.Message");
|
||||
}
|
||||
|
||||
|
||||
|
@ -752,7 +772,7 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
// Process each of the handlers
|
||||
$results = array_map(
|
||||
function (RequestHandler $handler) {
|
||||
return $handler->handleRequest($this->getRequest(), DataModel::inst());
|
||||
return $handler->handleRequest($this->getRequest());
|
||||
},
|
||||
$handlers
|
||||
);
|
||||
|
@ -794,7 +814,7 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
*/
|
||||
protected function delegateToHandler(RequestHandler $handler, $title, array $templates = [])
|
||||
{
|
||||
$result = $handler->handleRequest($this->getRequest(), DataModel::inst());
|
||||
$result = $handler->handleRequest($this->getRequest());
|
||||
|
||||
// Return the customised controller - used to render in a Form
|
||||
// Post requests are expected to be login posts, so they'll be handled downstairs
|
||||
|
@ -958,7 +978,7 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
|
||||
$service = DefaultAdminService::singleton();
|
||||
return $service->findOrCreateDefaultAdmin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the default admin credentials
|
||||
|
@ -972,7 +992,6 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
DefaultAdminService::clearDefaultAdmin();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a default admin in dev-mode
|
||||
*
|
||||
|
@ -1092,7 +1111,7 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
|
||||
return [
|
||||
'password' => $encryptor->encrypt($password, $salt, $member),
|
||||
'salt' => $salt,
|
||||
'salt' => $salt,
|
||||
'algorithm' => $algorithm,
|
||||
'encryptor' => $encryptor
|
||||
];
|
||||
|
@ -1243,11 +1262,11 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||
public static function get_template_global_variables()
|
||||
{
|
||||
return [
|
||||
"LoginURL" => "login_url",
|
||||
"LogoutURL" => "logout_url",
|
||||
"LoginURL" => "login_url",
|
||||
"LogoutURL" => "logout_url",
|
||||
"LostPasswordURL" => "lost_password_url",
|
||||
"CurrentMember" => "getCurrentUser",
|
||||
"currentUser" => "getCurrentUser"
|
||||
"CurrentMember" => "getCurrentUser",
|
||||
"currentUser" => "getCurrentUser"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,7 +150,8 @@ class SecurityToken implements TemplateGlobalProvider
|
|||
*/
|
||||
public function getValue()
|
||||
{
|
||||
$value = Session::get($this->getName());
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$value = $session->get($this->getName());
|
||||
|
||||
// only regenerate if the token isn't already set in the session
|
||||
if (!$value) {
|
||||
|
@ -166,7 +167,8 @@ class SecurityToken implements TemplateGlobalProvider
|
|||
*/
|
||||
public function setValue($val)
|
||||
{
|
||||
Session::set($this->getName(), $val);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->getName(), $val);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
namespace SilverStripe\View;
|
||||
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\ORM\DataList;
|
||||
|
||||
class GenericTemplateGlobalProvider implements TemplateGlobalProvider
|
||||
{
|
||||
|
@ -61,8 +60,6 @@ class GenericTemplateGlobalProvider implements TemplateGlobalProvider
|
|||
*/
|
||||
public static function getDataList($className)
|
||||
{
|
||||
$list = new DataList($className);
|
||||
$list->setDataModel(DataModel::inst());
|
||||
return $list;
|
||||
return DataList::create($className);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,13 +21,6 @@ class ThemeManifest implements ThemeList
|
|||
*/
|
||||
protected $base;
|
||||
|
||||
/**
|
||||
* Include tests
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $tests;
|
||||
|
||||
/**
|
||||
* Path to application code
|
||||
*
|
||||
|
@ -56,39 +49,44 @@ class ThemeManifest implements ThemeList
|
|||
*/
|
||||
protected $themes = null;
|
||||
|
||||
/**
|
||||
* @var CacheFactory
|
||||
*/
|
||||
protected $cacheFactory= null;
|
||||
|
||||
/**
|
||||
* Constructs a new template manifest. The manifest is not actually built
|
||||
* or loaded from cache until needed.
|
||||
*
|
||||
* @param string $base The base path.
|
||||
* @param string $project Path to application code
|
||||
*
|
||||
* @param bool $includeTests Include tests in the manifest.
|
||||
* @param bool $forceRegen Force the manifest to be regenerated.
|
||||
* @param CacheFactory $cacheFactory Cache factory to generate backend cache with
|
||||
*/
|
||||
public function __construct(
|
||||
$base,
|
||||
$project,
|
||||
$includeTests = false,
|
||||
$forceRegen = false,
|
||||
CacheFactory $cacheFactory = null
|
||||
) {
|
||||
$this->base = $base;
|
||||
$this->tests = $includeTests;
|
||||
public function __construct($base, $project, CacheFactory $cacheFactory = null)
|
||||
{
|
||||
$this->base = $base;
|
||||
$this->project = $project;
|
||||
$this->cacheFactory = $cacheFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $includeTests Include tests in the manifest
|
||||
* @param bool $forceRegen Force the manifest to be regenerated.
|
||||
*/
|
||||
public function init($includeTests = false, $forceRegen = false)
|
||||
{
|
||||
// build cache from factory
|
||||
if ($cacheFactory) {
|
||||
$this->cache = $cacheFactory->create(
|
||||
if ($this->cacheFactory) {
|
||||
$this->cache = $this->cacheFactory->create(
|
||||
CacheInterface::class.'.thememanifest',
|
||||
[ 'namespace' => 'thememanifest' . ($includeTests ? '_tests' : '') ]
|
||||
);
|
||||
}
|
||||
$this->cacheKey = $this->getCacheKey();
|
||||
|
||||
if ($forceRegen) {
|
||||
$this->regenerate();
|
||||
$this->cacheKey = $this->getCacheKey($includeTests);
|
||||
if (!$forceRegen && $this->cache && ($data = $this->cache->get($this->cacheKey))) {
|
||||
$this->themes = $data;
|
||||
} else {
|
||||
$this->regenerate($includeTests);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,36 +102,37 @@ class ThemeManifest implements ThemeList
|
|||
* Generate a unique cache key to avoid manifest cache collisions.
|
||||
* We compartmentalise based on the base path, the given project, and whether
|
||||
* or not we intend to include tests.
|
||||
*
|
||||
* @param bool $includeTests
|
||||
* @return string
|
||||
*/
|
||||
public function getCacheKey()
|
||||
public function getCacheKey($includeTests = false)
|
||||
{
|
||||
return sha1(sprintf(
|
||||
"manifest-%s-%s-%u",
|
||||
$this->base,
|
||||
$this->project,
|
||||
$this->tests
|
||||
$includeTests
|
||||
));
|
||||
}
|
||||
|
||||
public function getThemes()
|
||||
{
|
||||
if ($this->themes === null) {
|
||||
$this->init();
|
||||
}
|
||||
return $this->themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerates the manifest by scanning the base path.
|
||||
*
|
||||
* @param bool $includeTests
|
||||
*/
|
||||
public function regenerate()
|
||||
public function regenerate($includeTests = false)
|
||||
{
|
||||
$finder = new ManifestFileFinder();
|
||||
$finder->setOptions(array(
|
||||
'include_themes' => false,
|
||||
'ignore_dirs' => array('node_modules', THEMES_DIR),
|
||||
'ignore_tests' => !$this->tests,
|
||||
'ignore_tests' => !$includeTests,
|
||||
'dir_callback' => array($this, 'handleDirectory')
|
||||
));
|
||||
|
||||
|
@ -172,16 +171,4 @@ class ThemeManifest implements ThemeList
|
|||
array_push($this->themes, $path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the manifest
|
||||
*/
|
||||
protected function init()
|
||||
{
|
||||
if ($this->cache && ($data = $this->cache->get($this->cacheKey))) {
|
||||
$this->themes = $data;
|
||||
} else {
|
||||
$this->regenerate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,172 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Configure SilverStripe from the environment variables.
|
||||
* Usage: Put "require_once('conf/ConfigureFromEnv.php');" into your _config.php file.
|
||||
* @deprecated 4.0...5.0
|
||||
*
|
||||
* If you include this file, you will be able to use the following variables to control
|
||||
* your site.
|
||||
*
|
||||
* Your database connection will be set up using these defines:
|
||||
* - SS_DATABASE_CLASS: The database class to use, MySQLDatabase, MSSQLDatabase, etc. defaults to
|
||||
* MySQLPDODatabase
|
||||
* - SS_DATABASE_SERVER: The database server to use, defaulting to localhost
|
||||
* - SS_DATABASE_USERNAME: The database username (mandatory)
|
||||
* - SS_DATABASE_PASSWORD: The database password (mandatory)
|
||||
* - SS_DATABASE_PORT: The database port
|
||||
* - SS_DATABASE_SUFFIX: A suffix to add to the database name.
|
||||
* - SS_DATABASE_PREFIX: A prefix to add to the database name.
|
||||
* - SS_DATABASE_TIMEZONE: Set the database timezone to something other than the system timezone.
|
||||
* - SS_DATABASE_MEMORY: Use in-memory state if possible. Useful for testing, currently only
|
||||
* supported by the SQLite database adapter.
|
||||
*
|
||||
* There is one more setting that is intended to be used by people who work on SilverStripe.
|
||||
* - SS_DATABASE_CHOOSE_NAME: Boolean/Int. If set, then the system will choose a default database name for you if
|
||||
* one isn't give in the $database variable. The database name will be "SS_" followed by the name of the folder
|
||||
* into which you have installed SilverStripe. If this is enabled, it means that the phpinstaller will work out of
|
||||
* the box without the installer needing to alter any files. This helps prevent accidental changes to the
|
||||
* environment.
|
||||
*
|
||||
* If SS_DATABASE_CHOOSE_NAME is an integer greater than one, then an ancestor folder will be used for the database
|
||||
* name. This is handy for a site that's hosted from /sites/examplesite/www or /buildbot/allmodules-2.3/build. If
|
||||
* it's 2, the parent folder will be chosen; if it's 3 the grandparent, and so on.
|
||||
*
|
||||
* You can configure the environment with this define:
|
||||
*
|
||||
* - SS_ENVIRONMENT_TYPE: The environment type: dev, test or live.
|
||||
*
|
||||
* You can configure the default admin with these defines:
|
||||
*
|
||||
* - SS_DEFAULT_ADMIN_USERNAME: The username of the default admin - this is a non-database user with administrative
|
||||
* privileges.
|
||||
* - SS_DEFAULT_ADMIN_PASSWORD: The password of the default admin.
|
||||
* - SS_USE_BASIC_AUTH: Protect the site with basic auth (good for test sites)
|
||||
*
|
||||
* Email:
|
||||
* - SS_SEND_ALL_EMAILS_TO: If you set this define, all emails will be redirected to this address.
|
||||
* - SS_SEND_ALL_EMAILS_FROM: If you set this define, all emails will be send from this address.
|
||||
* Placeholder empty file
|
||||
*/
|
||||
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use SilverStripe\Control\Email\Email;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
|
||||
use SilverStripe\Security\BasicAuth;
|
||||
use SilverStripe\Security\DefaultAdminService;
|
||||
|
||||
global $database;
|
||||
|
||||
// No database provided
|
||||
if (!isset($database) || !$database) {
|
||||
if (!($database = getenv('SS_DATABASE_NAME')) && $chooseName = getenv('SS_DATABASE_CHOOSE_NAME')) {
|
||||
$loopCount = (int)$chooseName;
|
||||
$databaseDir = BASE_PATH;
|
||||
for ($i=0; $i<$loopCount-1; $i++) {
|
||||
$databaseDir = dirname($databaseDir);
|
||||
}
|
||||
$database = getenv('SS_DATABASE_PREFIX') ?: 'SS_';
|
||||
$database .= basename($databaseDir);
|
||||
$database = str_replace('.', '', $database);
|
||||
}
|
||||
}
|
||||
|
||||
if ($dbUser = getenv('SS_DATABASE_USERNAME')) {
|
||||
global $databaseConfig;
|
||||
|
||||
// Checks if the database global is defined (if present, wraps with prefix and suffix)
|
||||
$databaseNameWrapper = function ($name) {
|
||||
if (!$name) {
|
||||
return '';
|
||||
} else {
|
||||
return (getenv('SS_DATABASE_PREFIX') ?: '')
|
||||
. $name
|
||||
. (getenv('SS_DATABASE_SUFFIX') ?: '');
|
||||
}
|
||||
};
|
||||
|
||||
/** @skipUpgrade */
|
||||
$databaseConfig = array(
|
||||
"type" => getenv('SS_DATABASE_CLASS') ?: 'MySQLPDODatabase',
|
||||
"server" => getenv('SS_DATABASE_SERVER') ?: 'localhost',
|
||||
"username" => $dbUser,
|
||||
"password" => getenv('SS_DATABASE_PASSWORD'),
|
||||
"database" => $databaseNameWrapper($database),
|
||||
);
|
||||
|
||||
// Set the port if called for
|
||||
if ($dbPort = getenv('SS_DATABASE_PORT')) {
|
||||
$databaseConfig['port'] = $dbPort;
|
||||
}
|
||||
|
||||
// Set the timezone if called for
|
||||
if ($dbTZ = getenv('SS_DATABASE_TIMEZONE')) {
|
||||
$databaseConfig['timezone'] = $dbTZ;
|
||||
}
|
||||
|
||||
// For schema enabled drivers:
|
||||
if ($dbSchema = getenv('SS_DATABASE_SCHEMA')) {
|
||||
$databaseConfig["schema"] = $dbSchema;
|
||||
}
|
||||
|
||||
// For SQlite3 memory databases (mainly for testing purposes)
|
||||
if ($dbMemory = getenv('SS_DATABASE_MEMORY')) {
|
||||
$databaseConfig["memory"] = $dbMemory;
|
||||
}
|
||||
}
|
||||
|
||||
if ($sendAllEmailsTo = getenv('SS_SEND_ALL_EMAILS_TO')) {
|
||||
Email::config()->send_all_emails_to = $sendAllEmailsTo;
|
||||
}
|
||||
if ($sendAllEmailsFrom = getenv('SS_SEND_ALL_EMAILS_FROM')) {
|
||||
Email::config()->send_all_emails_from = $sendAllEmailsFrom;
|
||||
}
|
||||
|
||||
if ($defaultAdminUser = getenv('SS_DEFAULT_ADMIN_USERNAME')) {
|
||||
if (!$defaultAdminPass = getenv('SS_DEFAULT_ADMIN_PASSWORD')) {
|
||||
user_error(
|
||||
"SS_DEFAULT_ADMIN_PASSWORD must be defined in your environment,"
|
||||
. "if SS_DEFAULT_ADMIN_USERNAME is defined. See "
|
||||
. "http://doc.silverstripe.org/framework/en/topics/environment-management for more information",
|
||||
E_USER_ERROR
|
||||
);
|
||||
} else {
|
||||
DefaultAdminService::setDefaultAdmin($defaultAdminUser, $defaultAdminPass);
|
||||
}
|
||||
}
|
||||
if ($useBasicAuth = getenv('SS_USE_BASIC_AUTH')) {
|
||||
BasicAuth::config()->entire_site_protected = $useBasicAuth;
|
||||
}
|
||||
|
||||
if ($errorLog = getenv('SS_ERROR_LOG')) {
|
||||
$logger = Injector::inst()->get(LoggerInterface::class);
|
||||
if ($logger instanceof Logger) {
|
||||
$logger->pushHandler(new StreamHandler(BASE_PATH . '/' . $errorLog, Logger::WARNING));
|
||||
} else {
|
||||
user_error("SS_ERROR_LOG setting only works with Monolog, you are using another logger", E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
// Allow database adapters to handle their own configuration
|
||||
DatabaseAdapterRegistry::autoconfigure();
|
||||
|
||||
unset(
|
||||
$envType,
|
||||
$chooseName,
|
||||
$loopCount,
|
||||
$databaseDir,
|
||||
$i,
|
||||
$databaseNameWrapper,
|
||||
$dbUser,
|
||||
$dbPort,
|
||||
$dbTZ,
|
||||
$dbSchema,
|
||||
$dbMemory,
|
||||
$sendAllEmailsTo,
|
||||
$sendAllEmailsFrom,
|
||||
$defaultAdminUser,
|
||||
$defaultAdminPass,
|
||||
$useBasicAuth,
|
||||
$errorLog,
|
||||
$logger
|
||||
);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
// Check PHP version
|
||||
if (version_compare(phpversion(), '5.6.0', '<')) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error");
|
||||
echo str_replace(
|
||||
'$PHPVersion',
|
||||
phpversion(),
|
||||
file_get_contents(__DIR__ . "/../Dev/Install/php5-required.html")
|
||||
);
|
||||
die();
|
||||
}
|
||||
|
||||
// Init composer autoload
|
||||
call_user_func(function () {
|
||||
$candidates = [
|
||||
__DIR__ . '/../../vendor/autoload.php',
|
||||
__DIR__ . '/../../../vendor/autoload.php',
|
||||
getcwd() . '/vendor/autoload.php',
|
||||
];
|
||||
foreach ($candidates as $candidate) {
|
||||
if (file_exists($candidate)) {
|
||||
require_once $candidate;
|
||||
return;
|
||||
}
|
||||
}
|
||||
die("Failed to include composer's autoloader, unable to continue");
|
||||
});
|
|
@ -27,6 +27,8 @@ use SilverStripe\Control\Util\IPUtils;
|
|||
* headers from the given client are trustworthy (e.g. from a reverse proxy).
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/functions.php';
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ENVIRONMENT CONFIG
|
||||
|
||||
|
@ -57,15 +59,17 @@ if (!defined('BASE_PATH')) {
|
|||
|
||||
// Allow a first class env var to be set that disables .env file loading
|
||||
if (!getenv('SS_IGNORE_DOT_ENV')) {
|
||||
foreach ([ BASE_PATH, dirname(BASE_PATH) ] as $path) {
|
||||
try {
|
||||
(new Dotenv($path))->load();
|
||||
} catch (InvalidPathException $e) {
|
||||
// no .env found - no big deal
|
||||
continue;
|
||||
call_user_func(function () {
|
||||
foreach ([BASE_PATH, dirname(BASE_PATH)] as $path) {
|
||||
try {
|
||||
(new Dotenv($path))->load();
|
||||
} catch (InvalidPathException $e) {
|
||||
// no .env found - no big deal
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -142,11 +146,7 @@ if (defined('CUSTOM_INCLUDE_PATH')) {
|
|||
set_include_path(CUSTOM_INCLUDE_PATH . PATH_SEPARATOR . get_include_path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the temporary folder if it wasn't defined yet
|
||||
*/
|
||||
require_once __DIR__ . '/TempPath.php';
|
||||
|
||||
// Define the temporary folder if it wasn't defined yet
|
||||
if (!defined('TEMP_FOLDER')) {
|
||||
define('TEMP_FOLDER', getTempFolder(BASE_PATH));
|
||||
}
|
|
@ -1,124 +1,8 @@
|
|||
<?php
|
||||
|
||||
use SilverStripe\Core\Cache\ManifestCacheFactory;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Config\CoreConfigFactory;
|
||||
use SilverStripe\Core\Config\ConfigLoader;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Injector\SilverStripeServiceConfigurationLocator;
|
||||
use SilverStripe\Core\Manifest\ClassManifest;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Manifest\ModuleLoader;
|
||||
use SilverStripe\Core\Manifest\ModuleManifest;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\Logging\ErrorHandler;
|
||||
|
||||
/**
|
||||
* This file is the Framework bootstrap. It will get your environment ready to call Director::direct().
|
||||
*
|
||||
* It takes care of:
|
||||
* - Checking of PHP memory limit
|
||||
* - Including all the files needed to get the manifest built
|
||||
* - Building and including the manifest
|
||||
*
|
||||
* @todo This file currently contains a lot of bits and pieces, and its various responsibilities should probably be
|
||||
* moved into different subsystems.
|
||||
* @todo A lot of this stuff is very order-dependent. This could be decoupled.
|
||||
*/
|
||||
|
||||
/**
|
||||
* All errors are reported, including E_STRICT by default *unless* the site is in
|
||||
* live mode, where reporting is limited to fatal errors and warnings (see later in this file)
|
||||
*/
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
global $_increase_time_limit_max;
|
||||
$_increase_time_limit_max = -1;
|
||||
|
||||
/**
|
||||
* Ensure we have enough memory
|
||||
*/
|
||||
increase_memory_limit_to('64M');
|
||||
|
||||
/**
|
||||
* Ensure we don't run into xdebug's fairly conservative infinite recursion protection limit
|
||||
*/
|
||||
increase_xdebug_nesting_level_to(200);
|
||||
|
||||
/**
|
||||
* Set default encoding
|
||||
*/
|
||||
mb_http_output('UTF-8');
|
||||
mb_internal_encoding('UTF-8');
|
||||
mb_regex_encoding('UTF-8');
|
||||
|
||||
/**
|
||||
* Enable better garbage collection
|
||||
*/
|
||||
gc_enable();
|
||||
|
||||
// Initialise the dependency injector as soon as possible, as it is
|
||||
// subsequently used by some of the following code
|
||||
$injector = new Injector(array('locator' => SilverStripeServiceConfigurationLocator::class));
|
||||
Injector::set_inst($injector);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MANIFEST
|
||||
|
||||
// Regenerate the manifest if ?flush is set, or if the database is being built.
|
||||
// The coupling is a hack, but it removes an annoying bug where new classes
|
||||
// referenced in _config.php files can be referenced during the build process.
|
||||
$requestURL = isset($_REQUEST['url']) ? trim($_REQUEST['url'], '/') : false;
|
||||
$flush = (isset($_GET['flush']) || $requestURL === trim(BASE_URL . '/dev/build', '/'));
|
||||
|
||||
// Manifest cache factory
|
||||
$manifestCacheFactory = new ManifestCacheFactory([
|
||||
'namespace' => 'manifestcache',
|
||||
'directory' => getTempFolder(),
|
||||
]);
|
||||
|
||||
// Build class manifest
|
||||
$manifest = new ClassManifest(BASE_PATH, false, $flush, $manifestCacheFactory);
|
||||
|
||||
// Register SilverStripe's class map autoload
|
||||
$loader = ClassLoader::inst();
|
||||
$loader->registerAutoloader();
|
||||
$loader->pushManifest($manifest);
|
||||
|
||||
// Init module manifest
|
||||
$moduleManifest = new ModuleManifest(BASE_PATH, false, $flush, $manifestCacheFactory);
|
||||
ModuleLoader::inst()->pushManifest($moduleManifest);
|
||||
|
||||
// Build config manifest
|
||||
$configManifest = CoreConfigFactory::inst()->createRoot($flush, $manifestCacheFactory);
|
||||
ConfigLoader::inst()->pushManifest($configManifest);
|
||||
|
||||
// After loading config, boot _config.php files
|
||||
ModuleLoader::inst()->getManifest()->activateConfig();
|
||||
|
||||
// Load template manifest
|
||||
SilverStripe\View\ThemeResourceLoader::inst()->addSet('$default', new SilverStripe\View\ThemeManifest(
|
||||
BASE_PATH,
|
||||
project(),
|
||||
false,
|
||||
$flush,
|
||||
$manifestCacheFactory
|
||||
));
|
||||
|
||||
// If in live mode, ensure deprecation, strict and notices are not reported
|
||||
if (Director::isLive()) {
|
||||
error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// POST-MANIFEST COMMANDS
|
||||
|
||||
/**
|
||||
* Load error handlers
|
||||
*/
|
||||
$errorHandler = Injector::inst()->get(ErrorHandler::class);
|
||||
$errorHandler->start();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HELPER FUNCTIONS
|
||||
|
@ -156,23 +40,23 @@ function project()
|
|||
}
|
||||
|
||||
/**
|
||||
* This is the main translator function. Returns the string defined by $entity according to the
|
||||
* currently set locale.
|
||||
*
|
||||
* Also supports pluralisation of strings. Pass in a `count` argument, as well as a
|
||||
* default value with `|` pipe-delimited options for each plural form.
|
||||
*
|
||||
* @param string $entity Entity that identifies the string. It must be in the form
|
||||
* "Namespace.Entity" where Namespace will be usually the class name where this
|
||||
* string is used and Entity identifies the string inside the namespace.
|
||||
* @param mixed $arg,... Additional arguments are parsed as such:
|
||||
* - Next string argument is a default. Pass in a `|` pipe-delimeted value with `{count}`
|
||||
* to do pluralisation.
|
||||
* - Any other string argument after default is context for i18nTextCollector
|
||||
* - Any array argument in any order is an injection parameter list. Pass in a `count`
|
||||
* injection parameter to pluralise.
|
||||
* @return string
|
||||
*/
|
||||
* This is the main translator function. Returns the string defined by $entity according to the
|
||||
* currently set locale.
|
||||
*
|
||||
* Also supports pluralisation of strings. Pass in a `count` argument, as well as a
|
||||
* default value with `|` pipe-delimited options for each plural form.
|
||||
*
|
||||
* @param string $entity Entity that identifies the string. It must be in the form
|
||||
* "Namespace.Entity" where Namespace will be usually the class name where this
|
||||
* string is used and Entity identifies the string inside the namespace.
|
||||
* @param mixed $arg,... Additional arguments are parsed as such:
|
||||
* - Next string argument is a default. Pass in a `|` pipe-delimeted value with `{count}`
|
||||
* to do pluralisation.
|
||||
* - Any other string argument after default is context for i18nTextCollector
|
||||
* - Any array argument in any order is an injection parameter list. Pass in a `count`
|
||||
* injection parameter to pluralise.
|
||||
* @return string
|
||||
*/
|
||||
function _t($entity, $arg = null)
|
||||
{
|
||||
// Pass args directly to handle deprecation
|
||||
|
@ -261,11 +145,11 @@ function translate_memstring($memString)
|
|||
{
|
||||
switch (strtolower(substr($memString, -1))) {
|
||||
case "k":
|
||||
return round(substr($memString, 0, -1)*1024);
|
||||
return round(substr($memString, 0, -1) * 1024);
|
||||
case "m":
|
||||
return round(substr($memString, 0, -1)*1024*1024);
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024);
|
||||
case "g":
|
||||
return round(substr($memString, 0, -1)*1024*1024*1024);
|
||||
return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
|
||||
default:
|
||||
return round($memString);
|
||||
}
|
||||
|
@ -322,3 +206,114 @@ 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;
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
// Connect to database
|
||||
use SilverStripe\ORM\DB;
|
||||
|
||||
require_once __DIR__ . '/../../src/Core/Core.php';
|
||||
require_once __DIR__ . '/../../src/Core/functions.php';
|
||||
require_once __DIR__ . '/../php/Control/FakeController.php';
|
||||
|
||||
// Bootstrap a mock project configuration
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
namespace SilverStripe\Control\Tests;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit_Framework_Error;
|
||||
use SilverStripe\Control\RequestHandler;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\Tests\ControllerTest\AccessBaseController;
|
||||
use SilverStripe\Control\Tests\ControllerTest\AccessSecuredController;
|
||||
use SilverStripe\Control\Tests\ControllerTest\AccessWildcardSecuredController;
|
||||
|
@ -15,13 +16,8 @@ use SilverStripe\Control\Tests\ControllerTest\IndexSecuredController;
|
|||
use SilverStripe\Control\Tests\ControllerTest\SubController;
|
||||
use SilverStripe\Control\Tests\ControllerTest\TestController;
|
||||
use SilverStripe\Control\Tests\ControllerTest\UnsecuredController;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\Dev\FunctionalTest;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\SSViewer;
|
||||
|
@ -539,7 +535,7 @@ class ControllerTest extends FunctionalTest
|
|||
/* Handle the request to create conditions where improperly passing the action to the viewer might fail */
|
||||
$controller = new ControllerTest\ContainerController();
|
||||
try {
|
||||
$controller->handleRequest($request, DataModel::inst());
|
||||
$controller->handleRequest($request);
|
||||
} catch (ControllerTest\SubController_Exception $e) {
|
||||
$this->fail($e->getMessage());
|
||||
}
|
||||
|
|
|
@ -5,9 +5,7 @@ namespace SilverStripe\Control\Tests\DirectorTest;
|
|||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\RequestFilter;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataModel;
|
||||
|
||||
class TestRequestFilter implements RequestFilter, TestOnly
|
||||
{
|
||||
|
@ -17,22 +15,24 @@ class TestRequestFilter implements RequestFilter, TestOnly
|
|||
public $failPre = false;
|
||||
public $failPost = false;
|
||||
|
||||
public function preRequest(HTTPRequest $request, Session $session, DataModel $model)
|
||||
public function preRequest(HTTPRequest $request)
|
||||
{
|
||||
++$this->preCalls;
|
||||
|
||||
if ($this->failPre) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response, DataModel $model)
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response)
|
||||
{
|
||||
++$this->postCalls;
|
||||
|
||||
if ($this->failPost) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function reset()
|
||||
|
|
|
@ -16,14 +16,11 @@ class FakeController extends Controller
|
|||
{
|
||||
parent::__construct();
|
||||
|
||||
$session = Injector::inst()->create(Session::class, isset($_SESSION) ? $_SESSION : array());
|
||||
$this->setSession($session);
|
||||
|
||||
$this->pushCurrent();
|
||||
|
||||
$session = new Session(isset($_SESSION) ? $_SESSION : array());
|
||||
$request = new HTTPRequest('GET', '/');
|
||||
$request->setSession($session);
|
||||
$this->setRequest($request);
|
||||
|
||||
$this->setResponse(new HTTPResponse());
|
||||
|
||||
$this->doInit();
|
||||
|
|
|
@ -134,7 +134,7 @@ class ParameterConfirmationTokenTest extends SapphireTest
|
|||
$_SERVER['HTTP_HOST'] = $host;
|
||||
ParameterConfirmationToken::$alternateBaseURL = $base;
|
||||
|
||||
$this->assertEquals('http://'.implode('/', $urlAnswer) . $urlSlash, $token->currentAbsoluteURL());
|
||||
$this->assertEquals('http://'.implode('/', $urlAnswer) . $urlSlash, $token->currentURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ use SilverStripe\Dev\TestOnly;
|
|||
class ParameterConfirmationTokenTest_Token extends ParameterConfirmationToken implements TestOnly
|
||||
{
|
||||
|
||||
public function currentAbsoluteURL()
|
||||
public function currentURL()
|
||||
{
|
||||
return parent::currentAbsoluteURL();
|
||||
return parent::currentURL();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,10 +118,10 @@ class GridFieldDeleteActionTest extends SapphireTest
|
|||
if (Security::getCurrentUser()) {
|
||||
Security::setCurrentUser(null);
|
||||
}
|
||||
$this->setExpectedException(ValidationException::class);
|
||||
$this->expectException(ValidationException::class);
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set(
|
||||
Controller::curr()->getRequest()->getSession()->set(
|
||||
$stateID,
|
||||
array(
|
||||
'grid' => '',
|
||||
|
|
|
@ -25,6 +25,7 @@ use SilverStripe\Forms\Tests\GridField\GridFieldTest\Permissions;
|
|||
use SilverStripe\Forms\Tests\GridField\GridFieldTest\Player;
|
||||
use SilverStripe\Forms\Tests\GridField\GridFieldTest\Team;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\Security\Group;
|
||||
use SilverStripe\Security\Member;
|
||||
|
||||
class GridFieldTest extends SapphireTest
|
||||
|
@ -115,9 +116,9 @@ class GridFieldTest extends SapphireTest
|
|||
public function testGridFieldModelClass()
|
||||
{
|
||||
$obj = new GridField('testfield', 'testfield', Member::get());
|
||||
$this->assertEquals('SilverStripe\\Security\\Member', $obj->getModelClass(), 'Should return Member');
|
||||
$obj->setModelClass('SilverStripe\\ORM\\DataModel');
|
||||
$this->assertEquals('SilverStripe\\ORM\\DataModel', $obj->getModelClass(), 'Should return Member');
|
||||
$this->assertEquals(Member::class, $obj->getModelClass(), 'Should return Member');
|
||||
$obj->setModelClass(Group::class);
|
||||
$this->assertEquals(Group::class, $obj->getModelClass(), 'Should return Group');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -79,15 +79,16 @@ class SecurityTest extends FunctionalTest
|
|||
$controller = new SecurityTest\NullController();
|
||||
$controller->setResponse(new HTTPResponse());
|
||||
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
Security::permissionFailure($controller, array('default' => 'Oops, not allowed'));
|
||||
$this->assertEquals('Oops, not allowed', Session::get('Security.Message.message'));
|
||||
$this->assertEquals('Oops, not allowed', $session->get('Security.Message.message'));
|
||||
|
||||
// Test that config values are used correctly
|
||||
Config::inst()->update(Security::class, 'default_message_set', 'stringvalue');
|
||||
Security::permissionFailure($controller);
|
||||
$this->assertEquals(
|
||||
'stringvalue',
|
||||
Session::get('Security.Message.message'),
|
||||
$session->get('Security.Message.message'),
|
||||
'Default permission failure message value was not present'
|
||||
);
|
||||
|
||||
|
@ -96,7 +97,7 @@ class SecurityTest extends FunctionalTest
|
|||
Security::permissionFailure($controller);
|
||||
$this->assertEquals(
|
||||
'arrayvalue',
|
||||
Session::get('Security.Message.message'),
|
||||
$session->get('Security.Message.message'),
|
||||
'Default permission failure message value was not present'
|
||||
);
|
||||
|
||||
|
@ -474,14 +475,14 @@ class SecurityTest extends FunctionalTest
|
|||
);
|
||||
}
|
||||
}
|
||||
$msg = _t(
|
||||
'SilverStripe\\Security\\Member.ERRORLOCKEDOUT2',
|
||||
'Your account has been temporarily disabled because of too many failed attempts at ' .
|
||||
'logging in. Please try again in {count} minutes.',
|
||||
null,
|
||||
array('count' => Member::config()->lock_out_delay_mins)
|
||||
);
|
||||
$this->assertHasMessage($msg);
|
||||
$msg = _t(
|
||||
'SilverStripe\\Security\\Member.ERRORLOCKEDOUT2',
|
||||
'Your account has been temporarily disabled because of too many failed attempts at ' .
|
||||
'logging in. Please try again in {count} minutes.',
|
||||
null,
|
||||
array('count' => Member::config()->lock_out_delay_mins)
|
||||
);
|
||||
$this->assertHasMessage($msg);
|
||||
|
||||
|
||||
$this->doTestLoginForm('testuser@example.com', '1nitialPassword');
|
||||
|
@ -563,14 +564,14 @@ class SecurityTest extends FunctionalTest
|
|||
$attempt = DataObject::get_one(
|
||||
LoginAttempt::class,
|
||||
array(
|
||||
'"LoginAttempt"."Email"' => 'testuser@example.com'
|
||||
'"LoginAttempt"."Email"' => 'testuser@example.com'
|
||||
)
|
||||
);
|
||||
$this->assertTrue(is_object($attempt));
|
||||
$member = DataObject::get_one(
|
||||
Member::class,
|
||||
array(
|
||||
'"Member"."Email"' => 'testuser@example.com'
|
||||
'"Member"."Email"' => 'testuser@example.com'
|
||||
)
|
||||
);
|
||||
$this->assertEquals($attempt->Status, 'Failure');
|
||||
|
|
Loading…
Reference in New Issue