mirror of
https://github.com/getgrav/grav.git
synced 2026-02-26 08:31:42 +01:00
Fixed multiple url() issues with streams
* Fixed `url()` returning wrong path if using stream with grav root path in it, eg: `user-data://shop` when Grav is in `/shop` * Fixed `url()` not returning a path to non-existing file (`user-data://shop` => `/user/data/shop`) if it is set to fail gracefully * Fixed `url()` returning false on unknown streams, such as `ftp://domain.com`, they should be treated as external URL
This commit is contained in:
@@ -8,6 +8,9 @@
|
||||
1. [](#bugfix)
|
||||
* Fixed some potential issues when `$grav['user']` is not set
|
||||
* Fixed error when calling `Media::add($name, null)`
|
||||
* Fixed `url()` returning wrong path if using stream with grav root path in it, eg: `user-data://shop` when Grav is in `/shop`
|
||||
* Fixed `url()` not returning a path to non-existing file (`user-data://shop` => `/user/data/shop`) if it is set to fail gracefully
|
||||
* Fixed `url()` returning false on unknown streams, such as `ftp://domain.com`, they should be treated as external URL
|
||||
|
||||
# v1.6.11
|
||||
## 06/21/2019
|
||||
|
||||
@@ -43,43 +43,80 @@ abstract class Utils
|
||||
}
|
||||
}
|
||||
|
||||
if (Grav::instance()['config']->get('system.absolute_urls', false)) {
|
||||
$domain = true;
|
||||
}
|
||||
$input = (string)$input;
|
||||
|
||||
if (Uri::isExternal($input)) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = Grav::instance()['uri'];
|
||||
$uri = $grav['uri'];
|
||||
|
||||
$root = $uri->rootUrl();
|
||||
$input = Utils::replaceFirstOccurrence($root, '', $input);
|
||||
|
||||
$input = ltrim((string)$input, '/');
|
||||
|
||||
if (Utils::contains((string)$input, '://')) {
|
||||
if (static::contains((string)$input, '://')) {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator = $grav['locator'];
|
||||
|
||||
$parts = Uri::parseUrl($input);
|
||||
|
||||
if ($parts) {
|
||||
try {
|
||||
$resource = $locator->findResource("{$parts['scheme']}://{$parts['host']}{$parts['path']}", false);
|
||||
} catch (\Exception $e) {
|
||||
return $fail_gracefully ? $input : false;
|
||||
if (is_array($parts)) {
|
||||
// Make sure we always have scheme, host, port and path.
|
||||
$scheme = $parts['scheme'] ?? '';
|
||||
$host = $parts['host'] ?? '';
|
||||
$port = $parts['port'] ?? '';
|
||||
$path = $parts['path'] ?? '';
|
||||
|
||||
if ($scheme && !$port) {
|
||||
// If URL has a scheme, we need to check if it's one of Grav streams.
|
||||
if (!$locator->schemeExists($scheme)) {
|
||||
// If scheme does not exists as a stream, assume it's external.
|
||||
return str_replace(' ', '%20', $input);
|
||||
}
|
||||
|
||||
// Attempt to find the resource (because of parse_url() we need to put host back to path).
|
||||
$resource = $locator->findResource("{$scheme}://{$host}{$path}", false);
|
||||
|
||||
if ($resource === false) {
|
||||
if (!$fail_gracefully) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return location where the file would be if it was saved.
|
||||
$resource = $locator->findResource("{$scheme}://{$host}{$path}", false, true);
|
||||
}
|
||||
|
||||
} elseif ($host || $port) {
|
||||
// If URL doesn't have scheme but has host or port, it is external.
|
||||
return str_replace(' ', '%20', $input);
|
||||
}
|
||||
|
||||
if ($resource && isset($parts['query'])) {
|
||||
$resource = $resource . '?' . $parts['query'];
|
||||
if (!empty($resource)) {
|
||||
// Add query string back.
|
||||
if (isset($parts['query'])) {
|
||||
$resource .= '?' . $parts['query'];
|
||||
}
|
||||
|
||||
// Add fragment back.
|
||||
if (isset($parts['fragment'])) {
|
||||
$resource .= '#' . $parts['fragment'];
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Not a valid URL (can still be a stream).
|
||||
$resource = $locator->findResource($input, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
$root = $uri->rootUrl();
|
||||
|
||||
if (static::startsWith($input, $root)) {
|
||||
$input = static::replaceFirstOccurrence($root, '', $input);
|
||||
}
|
||||
|
||||
$input = ltrim($input, '/');
|
||||
|
||||
$resource = $input;
|
||||
}
|
||||
|
||||
@@ -87,6 +124,8 @@ abstract class Utils
|
||||
return false;
|
||||
}
|
||||
|
||||
$domain = $domain ?: $grav['config']->get('system.absolute_urls', false);
|
||||
|
||||
return rtrim($uri->rootUrl($domain), '/') . '/' . ($resource ?? '');
|
||||
}
|
||||
|
||||
|
||||
@@ -382,30 +382,60 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
// Fail hard
|
||||
$this->assertSame(false, Utils::url('', true));
|
||||
$this->assertSame(false, Utils::url(''));
|
||||
$this->assertSame(false, Utils::url('foo://bar/baz'));
|
||||
$this->assertSame(false, Utils::url(new stdClass()));
|
||||
$this->assertSame(false, Utils::url(['foo','bar','baz']));
|
||||
$this->assertSame(false, Utils::url('user://does/not/exist'));
|
||||
|
||||
// Fail Gracefully
|
||||
$this->assertSame('/', Utils::url('/', false, true));
|
||||
$this->assertSame('/', Utils::url('', false, true));
|
||||
$this->assertSame('foo://bar/baz', Utils::url('foo://bar/baz', false, true));
|
||||
$this->assertSame('/', Utils::url(new stdClass(), false, true));
|
||||
$this->assertSame('/', Utils::url(['foo','bar','baz'], false, true));
|
||||
$this->assertSame('/user/does/not/exist', Utils::url('user://does/not/exist', false, true));
|
||||
|
||||
// Simple paths
|
||||
$this->assertSame('/', Utils::url('/'));
|
||||
$this->assertSame('http://testing.dev/', Utils::url('/', true));
|
||||
$this->assertSame('http://testing.dev/path1', Utils::url('/path1', true));
|
||||
$this->assertSame('/path1', Utils::url('/path1'));
|
||||
$this->assertSame('/path1/path2', Utils::url('/path1/path2'));
|
||||
$this->assertSame('/random/path1/path2', Utils::url('/random/path1/path2'));
|
||||
$this->assertSame('/foobar.jpg', Utils::url('/foobar.jpg'));
|
||||
$this->assertSame('/path1/foobar.jpg', Utils::url('/path1/foobar.jpg'));
|
||||
$this->assertSame('/path1/path2/foobar.jpg', Utils::url('/path1/path2/foobar.jpg'));
|
||||
$this->assertSame('/random/path1/path2/foobar.jpg', Utils::url('/random/path1/path2/foobar.jpg'));
|
||||
|
||||
// Simple paths with domain
|
||||
$this->assertSame('http://testing.dev/', Utils::url('/', true));
|
||||
$this->assertSame('http://testing.dev/path1', Utils::url('/path1', true));
|
||||
$this->assertSame('http://testing.dev/path1/path2', Utils::url('/path1/path2', true));
|
||||
$this->assertSame('http://testing.dev/random/path1/path2', Utils::url('/random/path1/path2', true));
|
||||
$this->assertSame('http://testing.dev/foobar.jpg', Utils::url('/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/path1/foobar.jpg', Utils::url('/path1/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/path1/path2/foobar.jpg', Utils::url('/path1/path2/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/random/path1/path2/foobar.jpg', Utils::url('/random/path1/path2/foobar.jpg', true));
|
||||
|
||||
// Relative paths from Grav root.
|
||||
$this->assertSame('/subdir', Utils::url('subdir'));
|
||||
$this->assertSame('/subdir/path1', Utils::url('subdir/path1'));
|
||||
$this->assertSame('/subdir/path1/path2', Utils::url('subdir/path1/path2'));
|
||||
$this->assertSame('/path1', Utils::url('path1'));
|
||||
$this->assertSame('/path1/path2', Utils::url('path1/path2'));
|
||||
$this->assertSame('/foobar.jpg', Utils::url('foobar.jpg'));
|
||||
$this->assertSame('http://testing.dev/foobar.jpg', Utils::url('foobar.jpg', true));
|
||||
|
||||
// Relative paths from Grav root with domain.
|
||||
$this->assertSame('http://testing.dev/foobar.jpg', Utils::url('foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/foobar.jpg', Utils::url('/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/path1/foobar.jpg', Utils::url('/path1/foobar.jpg', true));
|
||||
$this->assertSame('/foobar.jpg', Utils::url('/foobar.jpg'));
|
||||
$this->assertSame('/foobar.jpg', Utils::url('foobar.jpg'));
|
||||
$this->assertSame('/path1/foobar.jpg', Utils::url('/path1/foobar.jpg'));
|
||||
$this->assertSame('/path1/path2/foobar.jpg', Utils::url('/path1/path2/foobar.jpg'));
|
||||
|
||||
// All Non-existing streams should be treated as external URI / protocol.
|
||||
$this->assertSame('http://domain.com/path', Utils::url('http://domain.com/path'));
|
||||
$this->assertSame('ftp://domain.com/path', Utils::url('ftp://domain.com/path'));
|
||||
$this->assertSame('sftp://domain.com/path', Utils::url('sftp://domain.com/path'));
|
||||
$this->assertSame('ssh://domain.com', Utils::url('ssh://domain.com'));
|
||||
$this->assertSame('pop://domain.com', Utils::url('pop://domain.com'));
|
||||
$this->assertSame('foo://bar/baz', Utils::url('foo://bar/baz'));
|
||||
$this->assertSame('foo://bar/baz', Utils::url('foo://bar/baz', true));
|
||||
// $this->assertSame('mailto:joe@domain.com', Utils::url('mailto:joe@domain.com', true)); // FIXME <-
|
||||
}
|
||||
|
||||
public function testUrlWithRoot()
|
||||
@@ -415,31 +445,69 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
// Fail hard
|
||||
$this->assertSame(false, Utils::url('', true));
|
||||
$this->assertSame(false, Utils::url(''));
|
||||
$this->assertSame(false, Utils::url('foo://bar/baz'));
|
||||
$this->assertSame(false, Utils::url(new stdClass()));
|
||||
$this->assertSame(false, Utils::url(['foo','bar','baz']));
|
||||
$this->assertSame(false, Utils::url('user://does/not/exist'));
|
||||
|
||||
// Fail Gracefully
|
||||
$this->assertSame('/subdir/', Utils::url('/', false, true));
|
||||
$this->assertSame('/subdir/', Utils::url('', false, true));
|
||||
$this->assertSame('foo://bar/baz', Utils::url('foo://bar/baz', false, true));
|
||||
$this->assertSame('/subdir/', Utils::url(new stdClass(), false, true));
|
||||
$this->assertSame('/subdir/', Utils::url(['foo','bar','baz'], false, true));
|
||||
$this->assertSame('/subdir/user/does/not/exist', Utils::url('user://does/not/exist', false, true));
|
||||
|
||||
$this->assertSame('http://testing.dev/subdir/', Utils::url('/', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1', Utils::url('/path1', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1', Utils::url('/subdir/path1', true));
|
||||
// Simple paths
|
||||
$this->assertSame('/subdir/', Utils::url('/'));
|
||||
$this->assertSame('/subdir/path1', Utils::url('/path1'));
|
||||
$this->assertSame('/subdir/path1/path2', Utils::url('/path1/path2'));
|
||||
$this->assertSame('/subdir/path1/path2', Utils::url('/subdir/path1/path2'));
|
||||
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('/subdir/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/foobar.jpg', Utils::url('/path1/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/foobar.jpg', Utils::url('/subdir/path1/foobar.jpg', true));
|
||||
$this->assertSame('/subdir/random/path1/path2', Utils::url('/random/path1/path2'));
|
||||
$this->assertSame('/subdir/foobar.jpg', Utils::url('/foobar.jpg'));
|
||||
$this->assertSame('/subdir/foobar.jpg', Utils::url('foobar.jpg'));
|
||||
$this->assertSame('/subdir/foobar.jpg', Utils::url('/subdir/foobar.jpg'));
|
||||
$this->assertSame('/subdir/path1/foobar.jpg', Utils::url('/path1/foobar.jpg'));
|
||||
$this->assertSame('/subdir/path1/path2/foobar.jpg', Utils::url('/path1/path2/foobar.jpg'));
|
||||
$this->assertSame('/subdir/random/path1/path2/foobar.jpg', Utils::url('/random/path1/path2/foobar.jpg'));
|
||||
|
||||
// Simple paths with domain
|
||||
$this->assertSame('http://testing.dev/subdir/', Utils::url('/', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1', Utils::url('/path1', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/path2', Utils::url('/path1/path2', true));
|
||||
$this->assertSame('http://testing.dev/subdir/random/path1/path2', Utils::url('/random/path1/path2', true));
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/foobar.jpg', Utils::url('/path1/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/path2/foobar.jpg', Utils::url('/path1/path2/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/random/path1/path2/foobar.jpg', Utils::url('/random/path1/path2/foobar.jpg', true));
|
||||
|
||||
// Paths including the grav base.
|
||||
$this->assertSame('/subdir/', Utils::url('/subdir'));
|
||||
$this->assertSame('/subdir/path1', Utils::url('/subdir/path1'));
|
||||
$this->assertSame('/subdir/path1/path2', Utils::url('/subdir/path1/path2'));
|
||||
$this->assertSame('/subdir/foobar.jpg', Utils::url('/subdir/foobar.jpg'));
|
||||
$this->assertSame('/subdir/path1/foobar.jpg', Utils::url('/subdir/path1/foobar.jpg'));
|
||||
|
||||
// Relative paths from Grav root with domain.
|
||||
$this->assertSame('http://testing.dev/subdir/', Utils::url('/subdir', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1', Utils::url('/subdir/path1', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/path2', Utils::url('/subdir/path1/path2', true));
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('/subdir/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/foobar.jpg', Utils::url('/subdir/path1/foobar.jpg', true));
|
||||
|
||||
// Relative paths from Grav root.
|
||||
$this->assertSame('/subdir/subdir', Utils::url('subdir'));
|
||||
$this->assertSame('/subdir/subdir/path1', Utils::url('subdir/path1'));
|
||||
$this->assertSame('/subdir/subdir/path1/path2', Utils::url('subdir/path1/path2'));
|
||||
$this->assertSame('/subdir/path1', Utils::url('path1'));
|
||||
$this->assertSame('/subdir/path1/path2', Utils::url('path1/path2'));
|
||||
$this->assertSame('/subdir/foobar.jpg', Utils::url('foobar.jpg'));
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('foobar.jpg', true));
|
||||
|
||||
// All Non-existing streams should be treated as external URI / protocol.
|
||||
$this->assertSame('http://domain.com/path', Utils::url('http://domain.com/path'));
|
||||
$this->assertSame('ftp://domain.com/path', Utils::url('ftp://domain.com/path'));
|
||||
$this->assertSame('sftp://domain.com/path', Utils::url('sftp://domain.com/path'));
|
||||
$this->assertSame('ssh://domain.com', Utils::url('ssh://domain.com'));
|
||||
$this->assertSame('pop://domain.com', Utils::url('pop://domain.com'));
|
||||
$this->assertSame('foo://bar/baz', Utils::url('foo://bar/baz'));
|
||||
$this->assertSame('foo://bar/baz', Utils::url('foo://bar/baz', true));
|
||||
// $this->assertSame('mailto:joe@domain.com', Utils::url('mailto:joe@domain.com', true)); // FIXME <-
|
||||
}
|
||||
|
||||
public function testUrlWithStreams()
|
||||
|
||||
Reference in New Issue
Block a user