Remove "url" query param reliance, use index.php

See https://github.com/silverstripe/silverstripe-framework/issues/7430
This commit is contained in:
Ingo Schommer 2017-10-03 12:23:17 +01:00 committed by Damian Mooyman
parent cc99b2ec19
commit 4a94dfe55b
9 changed files with 84 additions and 76 deletions

View File

@ -81,20 +81,32 @@ as a standard first point of upgrade.
#### Upgrade your rewrite rules
The location of SilverStripe's "entry file" has changed. Your project and server environment will need
to adjust the path to this file from `framework/main.php` to `vendor/silverstripe/framework/main.php`.
to adjust the path to this file from `framework/main.php` to `index.php`.
If you are running Apache, adjust your `.htaccess` file. For other webservers,
please consult the [installation guides](getting_started/installation/).
For websites served by Apache, here's an adjusted `.htaccess` excerpt:
The `index.php` file should already exist in your project,
but needs its content replaced:
```diff
+RewriteCond %{REQUEST_URI} !^/vendor/silverstripe/framework/main\.php
RewriteRule ^vendor(/|$) - [F,L,NC]
```php
<?php
# ...
use SilverStripe\Control\HTTPApplication;
use SilverStripe\Control\HTTPRequestBuilder;
use SilverStripe\Core\CoreKernel;
use SilverStripe\Core\Startup\ErrorControlChainMiddleware;
-RewriteRule .* framework/main.php?url=%1 [QSA]
+RewriteRule .* vendor/silverstripe/framework/main.php?url=%1 [QSA]
require __DIR__ . '/vendor/autoload.php';
// Build request and detect flush
$request = HTTPRequestBuilder::createFromEnvironment();
// Default application
$kernel = new CoreKernel(BASE_PATH);
$app = new HTTPApplication($kernel);
$app->addMiddleware(new ErrorControlChainMiddleware($app));
$response = $app->handle($request);
$response->output();
```
#### Upgrade references to renamed and namespaced classes

View File

@ -1,18 +0,0 @@
<?php
use SilverStripe\Control\HTTPApplication;
use SilverStripe\Control\HTTPRequestBuilder;
use SilverStripe\Core\CoreKernel;
use SilverStripe\Core\Startup\ErrorControlChainMiddleware;
require __DIR__ . '/src/includes/autoload.php';
// Build request and detect flush
$request = HTTPRequestBuilder::createFromEnvironment();
// Default application
$kernel = new CoreKernel(BASE_PATH);
$app = new HTTPApplication($kernel);
$app->addMiddleware(new ErrorControlChainMiddleware($app));
$response = $app->handle($request);
$response->output();

View File

@ -404,11 +404,7 @@ class HTTPRequest implements ArrayAccess
$url = ($this->getExtension()) ? $this->url . '.' . $this->getExtension() : $this->url;
if ($includeGetVars) {
// if we don't unset $vars['url'] we end up with /my/url?url=my/url&foo=bar etc
$vars = $this->getVars();
unset($vars['url']);
if (count($vars)) {
$url .= '?' . http_build_query($vars);
}

View File

@ -17,10 +17,16 @@ class HTTPRequestBuilder
{
// Clean and update live global variables
$variables = static::cleanEnvironment(Environment::getVariables());
Environment::setVariables($variables); // Currently necessary for SSViewer, etc to work
// Health-check prior to creating environment
return static::createFromVariables($variables, @file_get_contents('php://input'));
$req = static::createFromVariables($variables, @file_get_contents('php://input'));
// Normalise URL
$variables['_SERVER']['REQUEST_URI'] = $req->getURL();
Environment::setVariables($variables); // Currently necessary for SSViewer, etc to work
return $req;
}
/**
@ -32,9 +38,7 @@ class HTTPRequestBuilder
*/
public static function createFromVariables(array $variables, $input)
{
// Strip `url` out of querystring
$url = $variables['_GET']['url'];
unset($variables['_GET']['url']);
$url = self::getRequestUri($variables);
// Build request
$request = new HTTPRequest(
@ -100,7 +104,6 @@ class HTTPRequestBuilder
/**
* 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
@ -117,33 +120,6 @@ class HTTPRequestBuilder
$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']);
@ -156,4 +132,52 @@ class HTTPRequestBuilder
return $variables;
}
/**
* @param array $variables
* @return string
*/
protected static function getRequestUri(array $variables)
{
$server = $variables['_SERVER'];
$ruLen = strlen($server['REQUEST_URI']);
$snLen = strlen($server['SCRIPT_NAME']);
$isIIS = (strpos($server['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false);
// IIS will populate server variables using one of these two ways
if ($isIIS) {
if ($server['REQUEST_URI'] == $server['SCRIPT_NAME']) {
$url = "";
} elseif ($ruLen > $snLen && substr($server['REQUEST_URI'], 0, $snLen + 1) == ($server['SCRIPT_NAME'] . '/')) {
$url = substr($server['REQUEST_URI'], $snLen + 1);
$url = strtok($url, '?');
} else {
$url = $server['REQUEST_URI'];
if ($url[0] == '/') {
$url = substr($url, 1);
}
$url = strtok($url, '?');
}
// Apache will populate the server variables this way
} else {
// Remove query parameters (they're retained separately through $server['_GET']
$url = parse_url($server['REQUEST_URI'], PHP_URL_PATH);
// if ($ruLen > $snLen && substr($server['REQUEST_URI'], 0, $snLen + 1) == ($server['SCRIPT_NAME'] . '/')) {
// $url = substr($server['REQUEST_URI'], $snLen + 1);
// $url = strtok($url, '?');
// } else {
// $url = "";
// }
}
// 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));
}
return $url;
}
}

View File

@ -442,7 +442,7 @@ class ClassManifest
$finder = new ManifestFileFinder();
$finder->setOptions(array(
'name_regex' => '/^[^_].*\\.php$/',
'ignore_files' => array('index.php', 'main.php', 'cli-script.php'),
'ignore_files' => array('index.php', 'cli-script.php'),
'ignore_tests' => !$includeTests,
'file_callback' => function ($basename, $pathname, $depth) use ($includeTests, $finder) {
$this->handleFile($basename, $pathname, $includeTests);

View File

@ -15,7 +15,7 @@ use Exception;
* $chain = new ErrorControlChain();
* $chain->then($callback1)->then($callback2)->thenIfErrored($callback3)->execute();
*
* WARNING: This class is experimental and designed specifically for use pre-startup in main.php
* WARNING: This class is experimental and designed specifically for use pre-startup.
* It will likely be heavily refactored before the release of 3.2
*/
class ErrorControlChain

View File

@ -16,7 +16,7 @@ use SilverStripe\Security\RandomGenerator;
* established, this class takes care of allowing some other code of confirming the parameter,
* by generating a one-time-use token & redirecting with that token included in the redirected URL
*
* WARNING: This class is experimental and designed specifically for use pre-startup in main.php
* WARNING: This class is experimental and designed specifically for use pre-startup.
* It will likely be heavily refactored before the release of 3.2
*/
class ParameterConfirmationToken

View File

@ -439,12 +439,8 @@ ErrorDocument 500 /assets/error-500.html
$baseClause
$cgiClause
# Deny access to vendor, unless you're requesting main.php
# Not restricting to the start of the path to support RewriteBase
RewriteCond %{REQUEST_URI} !^/vendor/silverstripe/framework/main\.php
RewriteRule ^vendor(/|$) - [F,L,NC]
# Deny access to potentially sensitive files and folders
RewriteRule ^vendor(/|$) - [F,L,NC]
RewriteRule ^\.env - [F,L,NC]
RewriteRule silverstripe-cache(/|$) - [F,L,NC]
RewriteRule composer\.(json|lock) - [F,L,NC]
@ -455,7 +451,7 @@ ErrorDocument 500 /assets/error-500.html
# Try finding framework in the vendor folder first
RewriteCond %{REQUEST_URI} ^(.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* vendor/silverstripe/framework/main.php?url=%1 [QSA]
RewriteRule .* index.php
</IfModule>
TEXT;
@ -510,9 +506,8 @@ TEXT;
<match url="^(.*)$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="vendor/silverstripe/framework/main.php" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="vendor/silverstripe/framework/main.php?url={R:1}" appendQueryString="true" />
<action type="Rewrite" url="index.php" appendQueryString="true" />
</rule>
</rules>
</rewrite>

View File

@ -94,9 +94,8 @@ class DetailedErrorFormatter implements FormatterInterface
$httpRequest = null;
if (isset($_SERVER['REQUEST_URI'])) {
$httpRequest = $_SERVER['REQUEST_URI'];
} elseif (isset($_REQUEST['url'])) {
$httpRequest = $_REQUEST['url'];
}
if (isset($_SERVER['REQUEST_METHOD'])) {
$httpRequest = $_SERVER['REQUEST_METHOD'] . ' ' . $httpRequest;
}