mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge 3.1 into 3.2
Conflicts: admin/javascript/LeftAndMain.js control/HTTPRequest.php docs/en/00_Getting_Started/00_Server_Requirements.md
This commit is contained in:
commit
a0812f987a
@ -176,7 +176,7 @@ jQuery.noConflict();
|
|||||||
var msg = (xhr.getResponseHeader('X-Status')) ? xhr.getResponseHeader('X-Status') : xhr.statusText,
|
var msg = (xhr.getResponseHeader('X-Status')) ? xhr.getResponseHeader('X-Status') : xhr.statusText,
|
||||||
reathenticate = xhr.getResponseHeader('X-Reauthenticate'),
|
reathenticate = xhr.getResponseHeader('X-Reauthenticate'),
|
||||||
msgType = (xhr.status < 200 || xhr.status > 399) ? 'bad' : 'good',
|
msgType = (xhr.status < 200 || xhr.status > 399) ? 'bad' : 'good',
|
||||||
ignoredMessages = ['OK'];
|
ignoredMessages = ['OK', 'success'];
|
||||||
|
|
||||||
// Enable reauthenticate dialog if requested
|
// Enable reauthenticate dialog if requested
|
||||||
if(reathenticate) {
|
if(reathenticate) {
|
||||||
@ -911,8 +911,11 @@ jQuery.noConflict();
|
|||||||
sessionStates = sessionData ? JSON.parse(sessionData) : false;
|
sessionStates = sessionData ? JSON.parse(sessionData) : false;
|
||||||
|
|
||||||
this.find('.cms-tabset, .ss-tabset').each(function() {
|
this.find('.cms-tabset, .ss-tabset').each(function() {
|
||||||
var index, tabset = $(this), tabsetId = tabset.attr('id'), tab,
|
var index,
|
||||||
forcedTab = tabset.find('.ss-tabs-force-active');
|
tabset = $(this),
|
||||||
|
tabsetId = tabset.attr('id'),
|
||||||
|
tab,
|
||||||
|
forcedTab = tabset.children('ul').children('li.ss-tabs-force-active');
|
||||||
|
|
||||||
if(!tabset.data('tabs')){
|
if(!tabset.data('tabs')){
|
||||||
return; // don't act on uninit'ed controls
|
return; // don't act on uninit'ed controls
|
||||||
@ -921,18 +924,18 @@ jQuery.noConflict();
|
|||||||
// The tabs may have changed, notify the widget that it should update its internal state.
|
// The tabs may have changed, notify the widget that it should update its internal state.
|
||||||
tabset.tabs('refresh');
|
tabset.tabs('refresh');
|
||||||
|
|
||||||
// Make sure the intended tab is selected.
|
// Make sure the intended tab is selected. Only force the tab on the correct tabset though
|
||||||
if(forcedTab.length) {
|
if(forcedTab.length) {
|
||||||
index = forcedTab.index();
|
index = forcedTab.first().index();
|
||||||
} else if(overrideStates && overrideStates[tabsetId]) {
|
} else if(overrideStates && overrideStates[tabsetId]) {
|
||||||
tab = tabset.find(overrideStates[tabsetId].tabSelector);
|
tab = tabset.find(overrideStates[tabsetId].tabSelector);
|
||||||
if(tab.length){
|
if(tab.length){
|
||||||
index = tab.index();
|
index = tab.index();
|
||||||
}
|
}
|
||||||
} else if(sessionStates) {
|
} else if(sessionStates) {
|
||||||
$.each(sessionStates, function(i, sessionState) {
|
$.each(sessionStates, function(i, state) {
|
||||||
if(tabset.is('#' + sessionState.id)){
|
if(tabsetId == state.id){
|
||||||
index = sessionState.selected;
|
index = state.selected;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -671,7 +671,7 @@ class SS_HTTPRequest implements ArrayAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($headerOverrideIP) {
|
if ($headerOverrideIP) {
|
||||||
return $headerOverrideIP;
|
return $this->getIPFromHeaderValue($headerOverrideIP);
|
||||||
} elseif(isset($_SERVER['REMOTE_ADDR'])) {
|
} elseif(isset($_SERVER['REMOTE_ADDR'])) {
|
||||||
return $_SERVER['REMOTE_ADDR'];
|
return $_SERVER['REMOTE_ADDR'];
|
||||||
} else {
|
} else {
|
||||||
@ -679,6 +679,28 @@ class SS_HTTPRequest implements ArrayAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract an IP address from a header value that has been obtained. Accepts single IP or comma separated string of
|
||||||
|
* IPs
|
||||||
|
*
|
||||||
|
* @param string $headerValue The value from a trusted header
|
||||||
|
* @return string The IP address
|
||||||
|
*/
|
||||||
|
protected function getIPFromHeaderValue($headerValue) {
|
||||||
|
if (strpos($headerValue, ',') !== false) {
|
||||||
|
//sometimes the IP from a load balancer could be "x.x.x.x, y.y.y.y, z.z.z.z" so we need to find the most
|
||||||
|
// likely candidate
|
||||||
|
$ips = explode(',', $headerValue);
|
||||||
|
foreach ($ips as $ip) {
|
||||||
|
$ip = trim($ip);
|
||||||
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $headerValue;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all mimetypes from the HTTP "Accept" header
|
* Returns all mimetypes from the HTTP "Accept" header
|
||||||
* as an array.
|
* as an array.
|
||||||
|
@ -67,9 +67,21 @@ class ErrorControlChain {
|
|||||||
$this->error = (bool)$error;
|
$this->error = (bool)$error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether errors are suppressed or not
|
||||||
|
* Notes:
|
||||||
|
* - Errors cannot be suppressed if not handling errors.
|
||||||
|
* - Errors cannot be un-suppressed if original mode dis-allowed visible errors
|
||||||
|
*
|
||||||
|
* @param bool $suppression
|
||||||
|
*/
|
||||||
public function setSuppression($suppression) {
|
public function setSuppression($suppression) {
|
||||||
$this->suppression = (bool)$suppression;
|
$this->suppression = (bool)$suppression;
|
||||||
if ($this->handleFatalErrors) ini_set('display_errors', !$suppression);
|
// Don't modify errors unless handling fatal errors, and if errors were
|
||||||
|
// originally allowed to be displayed.
|
||||||
|
if ($this->handleFatalErrors && $this->originalDisplayErrors) {
|
||||||
|
ini_set('display_errors', !$suppression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,7 +179,7 @@ class ErrorControlChain {
|
|||||||
$this->handleFatalErrors = true;
|
$this->handleFatalErrors = true;
|
||||||
|
|
||||||
$this->originalDisplayErrors = ini_get('display_errors');
|
$this->originalDisplayErrors = ini_get('display_errors');
|
||||||
ini_set('display_errors', !$this->suppression);
|
$this->setSuppression($this->suppression);
|
||||||
|
|
||||||
$this->step();
|
$this->step();
|
||||||
}
|
}
|
||||||
|
@ -194,8 +194,8 @@ class ParameterConfirmationToken {
|
|||||||
$_SERVER['HTTP_HOST'],
|
$_SERVER['HTTP_HOST'],
|
||||||
// SilverStripe base
|
// SilverStripe base
|
||||||
self::$alternateBaseURL !== null ? self::$alternateBaseURL : BASE_URL,
|
self::$alternateBaseURL !== null ? self::$alternateBaseURL : BASE_URL,
|
||||||
// And URL
|
// And URL including base script (eg: if it's index.php/page/url/)
|
||||||
$url
|
(defined('BASE_SCRIPT_URL') ? '/' . BASE_SCRIPT_URL : '') . $url,
|
||||||
));
|
));
|
||||||
|
|
||||||
// Join together with protocol into our current absolute URL, avoiding duplicated "/" characters
|
// Join together with protocol into our current absolute URL, avoiding duplicated "/" characters
|
||||||
|
@ -10,10 +10,10 @@
|
|||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* $parser = new CSVParser('myfile.csv');
|
* $parser = new CSVParser('myfile.csv');
|
||||||
* $parser->mapColumns(
|
* $parser->mapColumns(array(
|
||||||
* 'first name' => 'FirstName'
|
* 'first name' => 'FirstName'
|
||||||
* 'lastname' => 'Surname',
|
* 'lastname' => 'Surname',
|
||||||
* 'last name' => 'Surname'
|
* 'last name' => 'Surname',
|
||||||
* ));
|
* ));
|
||||||
* foreach($parser as $row) {
|
* foreach($parser as $row) {
|
||||||
* // $row is a map of column name => column value
|
* // $row is a map of column name => column value
|
||||||
|
@ -8,7 +8,7 @@ Our web-based [PHP installer](installation/) can check if you meet the requireme
|
|||||||
|
|
||||||
## Web server software requirements
|
## Web server software requirements
|
||||||
|
|
||||||
* PHP 5.3.3+
|
* PHP 5.3.3+, <7
|
||||||
* We recommend using a PHP accelerator or opcode cache, such as [xcache](http://xcache.lighttpd.net/) or [WinCache](http://www.iis.net/download/wincacheforphp).
|
* We recommend using a PHP accelerator or opcode cache, such as [xcache](http://xcache.lighttpd.net/) or [WinCache](http://www.iis.net/download/wincacheforphp).
|
||||||
* Allocate at least 48MB of memory to each PHP process. (SilverStripe can be resource hungry for some intensive operations.)
|
* Allocate at least 48MB of memory to each PHP process. (SilverStripe can be resource hungry for some intensive operations.)
|
||||||
* Required modules: dom, gd2, fileinfo, hash, iconv, mbstring, mysqli (or other database driver), session, simplexml, tokenizer, xml.
|
* Required modules: dom, gd2, fileinfo, hash, iconv, mbstring, mysqli (or other database driver), session, simplexml, tokenizer, xml.
|
||||||
@ -23,7 +23,7 @@ Our web-based [PHP installer](installation/) can check if you meet the requireme
|
|||||||
* MySQL 5.0+
|
* MySQL 5.0+
|
||||||
* PostgreSQL 8.3+ (requires ["postgresql" module](http://silverstripe.org/postgresql-module))
|
* PostgreSQL 8.3+ (requires ["postgresql" module](http://silverstripe.org/postgresql-module))
|
||||||
* SQL Server 2008+ (requires ["mssql" module](http://silverstripe.org/microsoft-sql-server-database/))
|
* SQL Server 2008+ (requires ["mssql" module](http://silverstripe.org/microsoft-sql-server-database/))
|
||||||
* Support for `[Oracle](http://www.silverstripe.org/oracle-database-module/)` and [SQLite](http://silverstripe.org/sqlite-database/) is not commercially supported, but is under development by our open source community.
|
* Support for [Oracle](http://www.silverstripe.org/oracle-database-module/) and [SQLite](http://silverstripe.org/sqlite-database/) is not commercially supported, but is under development by our open source community.
|
||||||
* One of the following web server products:
|
* One of the following web server products:
|
||||||
* Apache 2.0+ with mod_rewrite and "AllowOverride All" set
|
* Apache 2.0+ with mod_rewrite and "AllowOverride All" set
|
||||||
* IIS 7+
|
* IIS 7+
|
||||||
@ -34,6 +34,11 @@ Our web-based [PHP installer](installation/) can check if you meet the requireme
|
|||||||
* Microsoft Windows XP SP3, Vista, Windows 7, Server 2008, Server 2008 R2
|
* Microsoft Windows XP SP3, Vista, Windows 7, Server 2008, Server 2008 R2
|
||||||
* Mac OS X 10.4+
|
* Mac OS X 10.4+
|
||||||
|
|
||||||
|
### Why doesn't SilverStripe 3 work with PHP 7?
|
||||||
|
Unfortunately, SilverStripe has classes named the same as PHP reserved words, such as "Int" and "Float". This means that
|
||||||
|
we are unable to make SilverStripe 3 support PHP 7 without breaking backward compatibility. SilverStripe 4 will work
|
||||||
|
with PHP 7 and will be released in 2016. Until then, we recommend that you use PHP 5.6.
|
||||||
|
|
||||||
## Web server hardware requirements
|
## Web server hardware requirements
|
||||||
|
|
||||||
Hardware requirements vary widely depending on the traffic to your website, the complexity of its logic (i.e., PHP), and
|
Hardware requirements vary widely depending on the traffic to your website, the complexity of its logic (i.e., PHP), and
|
||||||
|
@ -30,7 +30,7 @@ directly calling methods that they shouldn't.
|
|||||||
'cmsrestrictedaction' => 'CMS_ACCESS_CMSMain',
|
'cmsrestrictedaction' => 'CMS_ACCESS_CMSMain',
|
||||||
|
|
||||||
// complexaction can only be accessed if $this->canComplexAction() returns true.
|
// complexaction can only be accessed if $this->canComplexAction() returns true.
|
||||||
'complexaction' '->canComplexAction'
|
'complexaction' => '->canComplexAction',
|
||||||
|
|
||||||
// complexactioncheck can only be accessed if $this->canComplexAction("MyRestrictedAction", false, 42) is true.
|
// complexactioncheck can only be accessed if $this->canComplexAction("MyRestrictedAction", false, 42) is true.
|
||||||
'complexactioncheck' => '->canComplexAction("MyRestrictedAction", false, 42)',
|
'complexactioncheck' => '->canComplexAction("MyRestrictedAction", false, 42)',
|
||||||
@ -200,4 +200,4 @@ execution. This behavior can be used to implement permission checks.
|
|||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
* [api:Controller]
|
* [api:Controller]
|
||||||
|
@ -254,4 +254,23 @@ class HTTPRequestTest extends SapphireTest {
|
|||||||
$this->assertEquals('home?test=1', $req->getURL(true));
|
$this->assertEquals('home?test=1', $req->getURL(true));
|
||||||
$this->assertEquals('home', $req->getURL());
|
$this->assertEquals('home', $req->getURL());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetIPFromHeaderValue() {
|
||||||
|
$req = new SS_HTTPRequest('GET', '/');
|
||||||
|
$reflectionMethod = new ReflectionMethod($req, 'getIPFromHeaderValue');
|
||||||
|
$reflectionMethod->setAccessible(true);
|
||||||
|
|
||||||
|
$headers = array(
|
||||||
|
'80.79.208.21, 149.126.76.1, 10.51.0.68' => '80.79.208.21',
|
||||||
|
'52.19.19.103, 10.51.0.49' => '52.19.19.103',
|
||||||
|
'10.51.0.49, 52.19.19.103' => '52.19.19.103',
|
||||||
|
'10.51.0.49' => '10.51.0.49',
|
||||||
|
'127.0.0.1, 10.51.0.49' => '127.0.0.1',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($headers as $header => $ip) {
|
||||||
|
$this->assertEquals($ip, $reflectionMethod->invoke($req, $header));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,11 @@ require_once '$classpath';
|
|||||||
|
|
||||||
class ErrorControlChainTest extends SapphireTest {
|
class ErrorControlChainTest extends SapphireTest {
|
||||||
|
|
||||||
|
protected $displayErrors = null;
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
|
$this->displayErrors = (bool)ini_get('display_errors');
|
||||||
|
|
||||||
// Check we can run PHP at all
|
// Check we can run PHP at all
|
||||||
$null = is_writeable('/dev/null') ? '/dev/null' : 'NUL';
|
$null = is_writeable('/dev/null') ? '/dev/null' : 'NUL';
|
||||||
exec("php -v 2> $null", $out, $rv);
|
exec("php -v 2> $null", $out, $rv);
|
||||||
@ -76,8 +80,48 @@ class ErrorControlChainTest extends SapphireTest {
|
|||||||
parent::setUp();
|
parent::setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function tearDown() {
|
||||||
|
if($this->displayErrors !== null) {
|
||||||
|
ini_set('display_errors', $this->displayErrors);
|
||||||
|
$this->displayErrors = null;
|
||||||
|
}
|
||||||
|
parent::tearDown(); // TODO: Change the autogenerated stub
|
||||||
|
}
|
||||||
|
|
||||||
function testErrorSuppression() {
|
function testErrorSuppression() {
|
||||||
|
|
||||||
|
// Errors disabled by default
|
||||||
|
ini_set('display_errors', false);
|
||||||
|
$chain = new ErrorControlChain();
|
||||||
|
$whenNotSuppressed = null;
|
||||||
|
$whenSuppressed = null;
|
||||||
|
$chain->then(function($chain) use(&$whenNotSuppressed, &$whenSuppressed) {
|
||||||
|
$chain->setSuppression(true);
|
||||||
|
$whenSuppressed = ini_get('display_errors');
|
||||||
|
$chain->setSuppression(false);
|
||||||
|
$whenNotSuppressed = ini_get('display_errors');
|
||||||
|
})->execute();
|
||||||
|
|
||||||
|
// Disabled errors never un-disable
|
||||||
|
$this->assertFalse((bool)$whenNotSuppressed);
|
||||||
|
$this->assertFalse((bool)$whenSuppressed);
|
||||||
|
|
||||||
|
// Errors enabled by default
|
||||||
|
ini_set('display_errors', true);
|
||||||
|
$chain = new ErrorControlChain();
|
||||||
|
$whenNotSuppressed = null;
|
||||||
|
$whenSuppressed = null;
|
||||||
|
$chain->then(function($chain) use(&$whenNotSuppressed, &$whenSuppressed) {
|
||||||
|
$chain->setSuppression(true);
|
||||||
|
$whenSuppressed = ini_get('display_errors');
|
||||||
|
$chain->setSuppression(false);
|
||||||
|
$whenNotSuppressed = ini_get('display_errors');
|
||||||
|
})->execute();
|
||||||
|
|
||||||
|
// Errors can be suppressed an un-suppressed when initially enabled
|
||||||
|
$this->assertTrue((bool)$whenNotSuppressed);
|
||||||
|
$this->assertFalse((bool)$whenSuppressed);
|
||||||
|
|
||||||
// Fatal error
|
// Fatal error
|
||||||
|
|
||||||
$chain = new ErrorControlChainTest_Chain();
|
$chain = new ErrorControlChainTest_Chain();
|
||||||
|
Loading…
Reference in New Issue
Block a user