We have detected that you are running PHP version $PHPVersion. In order to run SilverStripe, - you must have PHP version 5.5.0 or higher.
+ you must have PHP version 5.6.0 or higher.If you are running on a shared host, you may need to ask your hosting provider how to do this.
Your session has timed out due to inactivity
' - ); - } + ); + } /** * 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', - 'Login success. If you are not automatically redirected '. + '
Login success. If you are not automatically redirected ' . 'click here
', 'Login message displayed in the cms popup once a user has re-authenticated themselves', array('link' => Convert::raw2att($backURL)) diff --git a/src/Security/Member.php b/src/Security/Member.php index e11c76d56..20d42116d 100644 --- a/src/Security/Member.php +++ b/src/Security/Member.php @@ -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 diff --git a/src/Security/MemberAuthenticator/ChangePasswordForm.php b/src/Security/MemberAuthenticator/ChangePasswordForm.php index 5969c1f46..4a2efa6cf 100644 --- a/src/Security/MemberAuthenticator/ChangePasswordForm.php +++ b/src/Security/MemberAuthenticator/ChangePasswordForm.php @@ -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(); diff --git a/src/Security/MemberAuthenticator/ChangePasswordHandler.php b/src/Security/MemberAuthenticator/ChangePasswordHandler.php index 755153bcf..af67f570c 100644 --- a/src/Security/MemberAuthenticator/ChangePasswordHandler.php +++ b/src/Security/MemberAuthenticator/ChangePasswordHandler.php @@ -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', '' . _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(); diff --git a/src/Security/MemberAuthenticator/MemberLoginForm.php b/src/Security/MemberAuthenticator/MemberLoginForm.php index b56fe8f25..472ac9c74 100644 --- a/src/Security/MemberAuthenticator/MemberLoginForm.php +++ b/src/Security/MemberAuthenticator/MemberLoginForm.php @@ -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; diff --git a/src/Security/MemberAuthenticator/SessionAuthenticationHandler.php b/src/Security/MemberAuthenticator/SessionAuthenticationHandler.php index e88c68489..152518b77 100644 --- a/src/Security/MemberAuthenticator/SessionAuthenticationHandler.php +++ b/src/Security/MemberAuthenticator/SessionAuthenticationHandler.php @@ -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()); } } diff --git a/src/Security/Security.php b/src/Security/Security.php index 3d1bff936..cfdc50edc 100644 --- a/src/Security/Security.php +++ b/src/Security/Security.php @@ -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" ]; } } diff --git a/src/Security/SecurityToken.php b/src/Security/SecurityToken.php index d54c659f1..12c90a84a 100644 --- a/src/Security/SecurityToken.php +++ b/src/Security/SecurityToken.php @@ -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); } /** diff --git a/src/View/GenericTemplateGlobalProvider.php b/src/View/GenericTemplateGlobalProvider.php index 6df21bfc9..b16fcb020 100644 --- a/src/View/GenericTemplateGlobalProvider.php +++ b/src/View/GenericTemplateGlobalProvider.php @@ -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); } } diff --git a/src/View/ThemeManifest.php b/src/View/ThemeManifest.php index 597f6604d..a2fa87195 100644 --- a/src/View/ThemeManifest.php +++ b/src/View/ThemeManifest.php @@ -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(); - } - } } diff --git a/src/conf/ConfigureFromEnv.php b/src/conf/ConfigureFromEnv.php index c49141375..aadf2a7bd 100644 --- a/src/conf/ConfigureFromEnv.php +++ b/src/conf/ConfigureFromEnv.php @@ -1,172 +1,7 @@ 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 -); diff --git a/src/conf/_manifest_exclude b/src/includes/_manifest_exclude similarity index 100% rename from src/conf/_manifest_exclude rename to src/includes/_manifest_exclude diff --git a/src/includes/autoload.php b/src/includes/autoload.php new file mode 100644 index 000000000..1de9618ab --- /dev/null +++ b/src/includes/autoload.php @@ -0,0 +1,28 @@ +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)); } diff --git a/src/Core/Core.php b/src/includes/functions.php similarity index 51% rename from src/Core/Core.php rename to src/includes/functions.php index 3cf52008e..2411f3073 100644 --- a/src/Core/Core.php +++ b/src/includes/functions.php @@ -1,124 +1,8 @@ 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; +} diff --git a/tests/bootstrap/phpunit.php b/tests/bootstrap/phpunit.php index 6eef9bab7..2cf6401d9 100644 --- a/tests/bootstrap/phpunit.php +++ b/tests/bootstrap/phpunit.php @@ -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 diff --git a/tests/php/Control/ControllerTest.php b/tests/php/Control/ControllerTest.php index 43c911d24..8c426669a 100644 --- a/tests/php/Control/ControllerTest.php +++ b/tests/php/Control/ControllerTest.php @@ -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()); } diff --git a/tests/php/Control/DirectorTest/TestRequestFilter.php b/tests/php/Control/DirectorTest/TestRequestFilter.php index d3c041049..01bff2e52 100644 --- a/tests/php/Control/DirectorTest/TestRequestFilter.php +++ b/tests/php/Control/DirectorTest/TestRequestFilter.php @@ -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() diff --git a/tests/php/Control/FakeController.php b/tests/php/Control/FakeController.php index 237235525..bd1918209 100644 --- a/tests/php/Control/FakeController.php +++ b/tests/php/Control/FakeController.php @@ -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(); diff --git a/tests/php/Core/Startup/ParameterConfirmationTokenTest.php b/tests/php/Core/Startup/ParameterConfirmationTokenTest.php index d4af7eade..9744bd8da 100644 --- a/tests/php/Core/Startup/ParameterConfirmationTokenTest.php +++ b/tests/php/Core/Startup/ParameterConfirmationTokenTest.php @@ -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()); } } } diff --git a/tests/php/Core/Startup/ParameterConfirmationTokenTest/ParameterConfirmationTokenTest_Token.php b/tests/php/Core/Startup/ParameterConfirmationTokenTest/ParameterConfirmationTokenTest_Token.php index f6f4ac7c7..2f550548e 100644 --- a/tests/php/Core/Startup/ParameterConfirmationTokenTest/ParameterConfirmationTokenTest_Token.php +++ b/tests/php/Core/Startup/ParameterConfirmationTokenTest/ParameterConfirmationTokenTest_Token.php @@ -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(); } } diff --git a/tests/php/Forms/GridField/GridFieldDeleteActionTest.php b/tests/php/Forms/GridField/GridFieldDeleteActionTest.php index 5456f32c0..4f2bd36ac 100644 --- a/tests/php/Forms/GridField/GridFieldDeleteActionTest.php +++ b/tests/php/Forms/GridField/GridFieldDeleteActionTest.php @@ -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' => '', diff --git a/tests/php/Forms/GridField/GridFieldTest.php b/tests/php/Forms/GridField/GridFieldTest.php index 302bad239..df3717faf 100644 --- a/tests/php/Forms/GridField/GridFieldTest.php +++ b/tests/php/Forms/GridField/GridFieldTest.php @@ -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'); } /** diff --git a/tests/php/Security/SecurityTest.php b/tests/php/Security/SecurityTest.php index 029565661..6bfcf5206 100644 --- a/tests/php/Security/SecurityTest.php +++ b/tests/php/Security/SecurityTest.php @@ -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');