Skip to content
Permalink
Browse files

Start refactoring URL handling to use PSR7 implementation.

Convert the internals of URL handling in the request class to use
the UriInterface implementation in diactoros. This will let us remove
a bunch of code from `Request` and replace it with code from diactoros
and our own ServerRequestFactory.

There are still a bunch of rough edges. Particularily around how the
base URL and webroot directory are being handled.
  • Loading branch information...
markstory committed Sep 12, 2016
1 parent fd101cd commit dbc5d413cc341dd1af198d4f4cd2050ae2bd0a54
Showing with 81 additions and 23 deletions.
  1. +42 −11 src/Http/ServerRequestFactory.php
  2. +38 −11 src/Network/Request.php
  3. +1 −1 tests/TestCase/Network/RequestTest.php
@@ -39,7 +39,7 @@ public static function fromGlobals(
array $files = null
) {
$request = parent::fromGlobals($server, $query, $body, $cookies, $files);
list($base, $webroot) = static::getBase($request);
list($base, $webroot) = static::getBase($request->getUri(), $request->getServerParams());
$sessionConfig = (array)Configure::read('Session') + [
'defaults' => 'php',
@@ -51,26 +51,59 @@ public static function fromGlobals(
->withAttribute('session', $session);
if ($base) {
$request = static::updatePath($base, $request);
$request = static::updatePath($base, $request->getUri());
}
return $request;
}
/**
* Create a new Uri instance from the provided server data.
*
* @param array $server Array of server data to build the Uri from.
* $_SERVER will be added into the $server parameter.
* @return \Psr\Http\Message\UriInterface New instance.
*/
public static function createUri(array $server = [])
{
$server += $_SERVER;
$server = static::normalizeServer($server);
$headers = static::marshalHeaders($server);
$uri = static::marshalUriFromServer($server, $headers);
list($base, $webroot) = static::getBase($uri, $server);
// Look in PATH_INFO first, as this is the exact value we need prepared
// by PHP.
$pathInfo = Hash::get($server, 'PATH_INFO');
if ($pathInfo) {
$uri = $uri->withPath($pathInfo);
} else {
$uri = static::updatePath($base, $uri);
}
// TODO Find an alternate solution to this.
$uri->base = $base;
$uri->webroot = $webroot;
return $uri;
}
/**
* Updates the request URI to remove the base directory.
*
* @param string $base The base path to remove.
* @param \Psr\Http\Message\ServerRequestInterface $request The request to modify.
* @return \Psr\Http\Message\ServerRequestInterface The modified request.
* @param \Psr\Http\Message\UriInterface $uri The uri to update.
* @return \Psr\Http\Message\ServerRequestInterface The modified Uri instance.
*/
protected static function updatePath($base, $request)
protected static function updatePath($base, $uri)
{
$uri = $request->getUri();
$path = $uri->getPath();
if (strlen($base) > 0 && strpos($path, $base) === 0) {
$path = substr($path, strlen($base));
}
if ($path === '/index.php' && $uri->getQuery()) {
$path = $uri->getQuery();

This comment has been minimized.

Copy link
@pmacko

pmacko Oct 2, 2017

Why? url /index.php?o=12&uu=1 allways throws "A route matching "o=12&uu=1" could not be found."

  • $path is replaced with query

This comment has been minimized.

Copy link
@markstory

markstory Oct 2, 2017

Author Member

This is to support webserver setups without URL rewriting if I remember correctly. You could try removing this code and seeing if any tests fail.

}
if (empty($path) || $path === '/' || $path === '//' || $path === '/index.php') {
$path = '/';
}
@@ -81,8 +114,7 @@ protected static function updatePath($base, $request)
) {
$path = '/';
}
return $request->withUri($uri->withPath($path));
return $uri->withPath($path);
}
/**
@@ -93,10 +125,9 @@ protected static function updatePath($base, $request)
* @param \Psr\Http\Message\ServerRequestInterface $request The request.
* @return array An array containing the [baseDir, webroot]
*/
protected static function getBase($request)
protected static function getBase($uri, $server)
{
$path = $request->getUri()->getPath();
$server = $request->getServerParams();
$path = $uri->getPath();
$base = $webroot = $baseUrl = null;
$config = Configure::read('App');
@@ -17,11 +17,13 @@
use ArrayAccess;
use BadMethodCallException;
use Cake\Core\Configure;
use Cake\Http\ServerRequestFactory;
use Cake\Network\Exception\MethodNotAllowedException;
use Cake\Utility\Hash;
use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
use Zend\Diactoros\PhpInputStream;
use Zend\Diactoros\Stream;
use Zend\Diactoros\UploadedFile;
@@ -203,7 +205,10 @@ class Request implements ArrayAccess
*/
public static function createFromGlobals()
{
list($base, $webroot) = static::_base();
$uri = ServerRequestFactory::createUri($_SERVER);
$base = $uri->base;
$webroot = $uri->webroot;
$sessionConfig = (array)Configure::read('Session') + [
'defaults' => 'php',
'cookiePath' => $webroot
@@ -215,11 +220,11 @@ public static function createFromGlobals()
'files' => $_FILES,
'cookies' => $_COOKIE,
'environment' => $_SERVER + $_ENV,
'uri' => $uri,
'base' => $base,
'webroot' => $webroot,
'session' => Session::create($sessionConfig)
];
$config['url'] = static::_url($config);
return new static($config);
}
@@ -237,6 +242,7 @@ public static function createFromGlobals()
* - `cookies` Cookies for this request.
* - `environment` $_SERVER and $_ENV data.
* - `url` The URL without the base path for the request.
* - `uri` The PSR7 UriInterface object. If null, one will be created.
* - `base` The base URL for the request.
* - `webroot` The webroot directory for the request.
* - `input` The data that would come from php://input this is useful for simulating
@@ -258,6 +264,7 @@ public function __construct($config = [])
'cookies' => [],
'environment' => [],
'url' => '',
'uri' => null,
'base' => '',
'webroot' => '',
'input' => null,
@@ -284,12 +291,32 @@ protected function _setConfig($config)
]);
}
$this->url = $config['url'];
$this->base = $config['base'];
$this->_environment = $config['environment'];
$this->cookies = $config['cookies'];
$this->here = $this->base . '/' . $this->url;
if (isset($config['uri']) && $config['uri'] instanceof UriInterface) {
$uri = $config['uri'];
} else {
$uri = ServerRequestFactory::createUri($config['environment']);
}
// Extract a query string from config[url] if present.
// This is required for backwards compatbility and keeping
// UriInterface implementations happy.
$querystr = '';
if (strpos($config['url'], '?') !== false) {
list($config['url'], $querystr) = explode('?', $config['url']);
}
if ($config['url']) {
$uri = $uri->withPath('/' . $config['url']);
}
$this->uri = $uri;
$this->base = $config['base'];
$this->webroot = $config['webroot'];
$this->_environment = $config['environment'];
$this->url = substr($uri->getPath(), 1);
$this->here = $this->base . '/' . $this->url;
if (isset($config['input'])) {
$stream = new Stream('php://memory', 'rw');
@@ -302,7 +329,7 @@ protected function _setConfig($config)
$config['post'] = $this->_processPost($config['post']);
$this->data = $this->_processFiles($config['post'], $config['files']);
$this->query = $this->_processGet($config['query']);
$this->query = $this->_processGet($config['query'], $querystr);
$this->params = $config['params'];
$this->_session = $config['session'];
}
@@ -347,17 +374,17 @@ protected function _processPost($data)
/**
* Process the GET parameters and move things into the object.
*
* @param string $queryString A query string from the URL if provided
* @param array $query The array to which the parsed keys/values are being added.
* @return array An array containing the parsed querystring keys/values.
*/
protected function _processGet($query)
protected function _processGet($query, $queryString = '')
{
$unsetUrl = '/' . str_replace(['.', ' '], '_', urldecode($this->url));
unset($query[$unsetUrl]);
unset($query[$this->base . $unsetUrl]);
if (strpos($this->url, '?') !== false) {
list(, $querystr) = explode('?', $this->url);
parse_str($querystr, $queryArgs);
if (strlen($queryString)) {
parse_str($queryString, $queryArgs);
$query += $queryArgs;
}
@@ -169,7 +169,7 @@ public function testQueryStringParsingFromInputUrl()
$request = new Request(['url' => 'some/path?one=something&two=else']);
$expected = ['one' => 'something', 'two' => 'else'];
$this->assertEquals($expected, $request->query);
$this->assertEquals('some/path?one=something&two=else', $request->url);
$this->assertEquals('some/path', $request->url);
}
/**

0 comments on commit dbc5d41

Please sign in to comment.
You can’t perform that action at this time.