diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4c6182ad7..61715e9bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,14 @@
1. [](#improved)
* Make it possible to include debug bar also into non-HTML responses
+# v1.3.7
+## mm/dd/2017
+
+1. [](#bugfix)
+ * Regressionin Uri: `base_url_absolute` always has the port number (#1690)
+ * Uri: Prefer using REQUEST_SCHEME instead of HTTPS (#1698)
+ * Fixed routing paths with urlencoded spaces and non-latin letters (#1688)
+
# v1.3.6
## 10/12/2017
diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php
index 96411f7d9..781bccb72 100644
--- a/system/src/Grav/Common/Page/Page.php
+++ b/system/src/Grav/Common/Page/Page.php
@@ -135,7 +135,7 @@ class Page
$this->metadata();
$this->url();
$this->visible();
- $this->modularTwig($this->slug[0] == '_');
+ $this->modularTwig($this->slug[0] === '_');
$this->setPublishState();
$this->published();
$this->urlExtension();
@@ -517,17 +517,18 @@ class Page
// Return entire page content on wrong/ unknown format
if (!in_array($format, ['short', 'long'])) {
return $content;
- } elseif (($format === 'short') && isset($summary_size)) {
+ }
+ if (($format === 'short') && isset($summary_size)) {
// Use mb_strimwidth to slice the string
if (mb_strwidth($content, 'utf8') > $summary_size) {
return mb_substr($content, 0, $summary_size);
- } else {
- return $content;
}
+
+ return $content;
}
// Get summary size from site config's file
- if (is_null($size)) {
+ if ($size === null) {
$size = $config['size'];
}
@@ -535,7 +536,8 @@ class Page
if ($size === 0) {
return $content;
// Return calculated summary based on defaults
- } elseif (!is_numeric($size) || ($size < 0)) {
+ }
+ if (!is_numeric($size) || ($size < 0)) {
$size = 300;
}
@@ -726,10 +728,9 @@ class Page
if ($name) {
if (isset($this->content_meta[$name])) {
return $this->content_meta[$name];
- } else {
- return null;
}
+ return null;
}
return $this->content_meta;
@@ -825,27 +826,27 @@ class Page
*/
public function value($name, $default = null)
{
- if ($name == 'content') {
+ if ($name === 'content') {
return $this->raw_content;
}
- if ($name == 'route') {
+ if ($name === 'route') {
return $this->parent()->rawRoute();
}
- if ($name == 'order') {
+ if ($name === 'order') {
$order = $this->order();
return $order ? (int)$this->order() : '';
}
- if ($name == 'ordering') {
+ if ($name === 'ordering') {
return (bool)$this->order();
}
- if ($name == 'folder') {
+ if ($name === 'folder') {
return preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder);
}
- if ($name == 'slug') {
+ if ($name === 'slug') {
return $this->slug();
}
- if ($name == 'name') {
+ if ($name === 'name') {
$language = $this->language() ? '.' . $this->language() : '';
$name_val = str_replace($language . '.md', '', $this->name());
if ($this->modular()) {
@@ -854,30 +855,30 @@ class Page
return $name_val;
}
- if ($name == 'media') {
+ if ($name === 'media') {
return $this->media()->all();
}
- if ($name == 'media.file') {
+ if ($name === 'media.file') {
return $this->media()->files();
}
- if ($name == 'media.video') {
+ if ($name === 'media.video') {
return $this->media()->videos();
}
- if ($name == 'media.image') {
+ if ($name === 'media.image') {
return $this->media()->images();
}
- if ($name == 'media.audio') {
+ if ($name === 'media.audio') {
return $this->media()->audios();
}
$path = explode('.', $name);
$scope = array_shift($path);
- if ($name == 'frontmatter') {
+ if ($name === 'frontmatter') {
return $this->frontmatter;
}
- if ($scope == 'header') {
+ if ($scope === 'header') {
$current = $this->header();
foreach ($path as $field) {
if (is_object($current) && isset($current->{$field})) {
@@ -969,7 +970,7 @@ class Page
$this->_action = 'move';
- if ($this->route() == $parent->route()) {
+ if ($this->route() === $parent->route()) {
throw new Exception('Failed: Cannot set page parent to self');
}
if (Utils::startsWith($parent->rawRoute(), $this->rawRoute())) {
@@ -1029,12 +1030,12 @@ class Page
$edit_mode = isset($grav['admin']) ? $grav['config']->get('plugins.admin.edit_mode') : null;
// override if you only want 'normal' mode
- if (empty($fields) && ($edit_mode == 'auto' || $edit_mode == 'normal')) {
+ if (empty($fields) && ($edit_mode === 'auto' || $edit_mode === 'normal')) {
$blueprint = $pages->blueprints('default');
}
// override if you only want 'expert' mode
- if (!empty($fields) && $edit_mode == 'expert') {
+ if (!empty($fields) && $edit_mode === 'expert') {
$blueprint = $pages->blueprints('');
}
@@ -1459,9 +1460,9 @@ class Page
{
if (isset($this->debugger) && $this->debugger === false) {
return false;
- } else {
- return true;
}
+
+ return true;
}
/**
@@ -1502,7 +1503,7 @@ class Page
// Backward compatibility for nested arrays in metas
if (is_array($value)) {
foreach ($value as $property => $prop_value) {
- $prop_key = $key . ":" . $property;
+ $prop_key = $key . ':' . $property;
$this->metadata[$prop_key] = [
'name' => $prop_key,
'property' => $prop_key,
@@ -1517,7 +1518,7 @@ class Page
'http_equiv' => $key,
'content' => htmlspecialchars($value, ENT_QUOTES, 'UTF-8')
];
- } elseif ($key == 'charset') {
+ } elseif ($key === 'charset') {
$this->metadata[$key] = ['charset' => htmlspecialchars($value, ENT_QUOTES, 'UTF-8')];
} else {
// if it's a social metadata with separator, render as property
@@ -1552,7 +1553,7 @@ class Page
*/
public function slug($var = null)
{
- if ($var !== null && $var !== "") {
+ if ($var !== null && $var !== '') {
$this->slug = $var;
}
@@ -1679,7 +1680,7 @@ class Page
$url = rtrim($url, '/');
}
- return $url;
+ return Uri::filterPath($url);
}
/**
@@ -1702,7 +1703,7 @@ class Page
// calculate route based on parent slugs
$parent = $this->parent();
if (isset($parent)) {
- if ($this->hide_home_route && $parent->route() == $this->home_route) {
+ if ($this->hide_home_route && $parent->route() === $this->home_route) {
$baseRoute = '';
} else {
$baseRoute = (string)$parent->route();
@@ -1770,9 +1771,9 @@ class Page
if (!empty($this->routes) && isset($this->routes['aliases'])) {
return $this->routes['aliases'];
- } else {
- return [];
}
+
+ return [];
}
/**
@@ -2298,7 +2299,7 @@ class Page
$routes = Grav::instance()['pages']->routes();
if (isset($routes[$uri_path])) {
- if ($routes[$uri_path] == $this->path()) {
+ if ($routes[$uri_path] === $this->path()) {
return true;
}
@@ -2325,7 +2326,7 @@ class Page
$child_page = $pages->dispatch($uri->route())->parent();
if ($child_page) {
while (!$child_page->root()) {
- if ($this->path() == $child_page->path()) {
+ if ($this->path() === $child_page->path()) {
return true;
}
$child_page = $child_page->parent();
@@ -2344,7 +2345,7 @@ class Page
public function home()
{
$home = Grav::instance()['config']->get('system.home.alias');
- $is_home = ($this->route() == $home || $this->rawRoute() == $home);
+ $is_home = ($this->route() === $home || $this->rawRoute() === $home);
return $is_home;
}
@@ -2358,9 +2359,9 @@ class Page
{
if (!$this->parent && !$this->name && !$this->visible) {
return true;
- } else {
- return false;
}
+
+ return false;
}
/**
@@ -2587,7 +2588,7 @@ class Page
}
/**
- * @param string $value
+ * @param string|array $value
*
* @return mixed
* @internal
@@ -2605,7 +2606,7 @@ class Page
$params = (array)current($value);
} else {
$result = [];
- foreach ($value as $key => $val) {
+ foreach ((array)$value as $key => $val) {
if (is_int($key)) {
$result = $result + $this->evaluate($val)->toArray();
} else {
@@ -2711,7 +2712,7 @@ class Page
case 'root@':
case '@root':
- if (!empty($parts) && $parts[0] == 'descendants') {
+ if (!empty($parts) && $parts[0] === 'descendants') {
$results = $pages->all($pages->root())->nonModular()->published();
} else {
$results = $pages->root()->children()->nonModular()->published();
@@ -2824,11 +2825,11 @@ class Page
// Reorder all moved pages.
foreach ($siblings as $slug => $page) {
- $order = intval(trim($page->order(), '.'));
+ $order = (int)trim($page->order(), '.');
$counter++;
if ($order) {
- if ($page->path() == $this->path() && $this->folderExists()) {
+ if ($page->path() === $this->path() && $this->folderExists()) {
// Handle current page; we do want to change ordering number, but nothing else.
$this->order($counter);
$this->save(false);
@@ -2859,14 +2860,14 @@ class Page
}
if (is_dir($this->_original->path())) {
- if ($this->_action == 'move') {
+ if ($this->_action === 'move') {
Folder::move($this->_original->path(), $this->path());
- } elseif ($this->_action == 'copy') {
+ } elseif ($this->_action === 'copy') {
Folder::copy($this->_original->path(), $this->path());
}
}
- if ($this->name() != $this->_original->name()) {
+ if ($this->name() !== $this->_original->name()) {
$path = $this->path();
if (is_file($path . '/' . $this->_original->name())) {
rename($path . '/' . $this->_original->name(), $path . '/' . $this->name());
@@ -2889,7 +2890,7 @@ class Page
}
}
// publish if required, if not clear cache right before page is published
- if ($this->publishDate() && $this->publishDate() && $this->publishDate() > time()) {
+ if ($this->publishDate() && $this->publishDate() > time()) {
$this->published(false);
Grav::instance()['cache']->setLifeTime($this->publishDate());
}
diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php
index a59cee97d..f9f6a5240 100644
--- a/system/src/Grav/Common/Page/Pages.php
+++ b/system/src/Grav/Common/Page/Pages.php
@@ -16,12 +16,13 @@ use Grav\Common\Filesystem\Folder;
use Grav\Common\Grav;
use Grav\Common\Language\Language;
use Grav\Common\Taxonomy;
+use Grav\Common\Uri;
use Grav\Common\Utils;
use Grav\Plugin\Admin;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Whoops\Exception\ErrorException;
-use Collator as Collator;
+use Collator;
class Pages
{
@@ -152,7 +153,7 @@ class Pages
}
$path_append = rtrim($this->grav['pages']->base(), '/');
- if ($language->getDefault() != $lang || $config->get('system.languages.include_default_lang') === true) {
+ if ($language->getDefault() !== $lang || $config->get('system.languages.include_default_lang') === true) {
$path_append .= $lang ? '/' . $lang : '';
}
@@ -192,7 +193,7 @@ class Pages
return $this->homeUrl($lang, $absolute);
}
- return $this->baseUrl($lang, $absolute) . $route;
+ return $this->baseUrl($lang, $absolute) . Uri::filterPath($route);
}
/**
@@ -297,7 +298,7 @@ class Pages
$sort = $this->sort[$path][$order_by];
- if ($order_dir != 'asc') {
+ if ($order_dir !== 'asc') {
$sort = array_reverse($sort);
}
@@ -327,7 +328,7 @@ class Pages
$sort = $this->sort[$lookup][$orderBy];
- if ($orderDir != 'asc') {
+ if ($orderDir !== 'asc') {
$sort = array_reverse($sort);
}
@@ -345,10 +346,6 @@ class Pages
*/
public function get($path)
{
- if (!is_null($path) && !is_string($path)) {
- throw new \Exception();
- }
-
return isset($this->instances[(string)$path]) ? $this->instances[(string)$path] : null;
}
@@ -376,13 +373,13 @@ class Pages
*/
public function ancestor($route, $path = null)
{
- if (!is_null($path)) {
-
+ if ($path !== null) {
$page = $this->dispatch($route, true);
- if ($page->path() == $path) {
+ if ($page && $page->path() === $path) {
return $page;
- } elseif (!$page->parent()->root()) {
+ }
+ if ($page && !$page->parent()->root()) {
return $this->ancestor($page->parent()->route(), $path);
}
}
@@ -400,15 +397,14 @@ class Pages
*/
public function inherited($route, $field = null)
{
- if (!is_null($field)) {
+ if ($field !== null) {
$page = $this->dispatch($route, true);
- $ancestorField = $page->parent()->value('header.' . $field);
-
- if ($ancestorField !== null) {
+ if ($page && $page->parent()->value('header.' . $field) !== null) {
return $page->parent();
- } elseif (!$page->parent()->root()) {
+ }
+ if ($page && !$page->parent()->root()) {
return $this->inherited($page->parent()->route(), $field);
}
}
@@ -441,6 +437,8 @@ class Pages
*/
public function dispatch($route, $all = false, $redirect = true)
{
+ $route = urldecode($route);
+
// Fetch page if there's a defined route to it.
$page = isset($this->routes[$route]) ? $this->get($this->routes[$route]) : null;
// Try without trailing slash
@@ -499,7 +497,7 @@ class Pages
$pattern = '#^' . str_replace('/', '\/', ltrim($pattern, '^')) . '#';
try {
$found = preg_replace($pattern, $replace, $source_url);
- if ($found != $source_url) {
+ if ($found !== $source_url) {
$page = $this->dispatch($found, $all);
}
} catch (ErrorException $e) {
@@ -535,7 +533,7 @@ class Pages
*/
public function blueprints($type)
{
- if (!isset($this->blueprints)) {
+ if ($this->blueprints === null) {
$this->blueprints = new Blueprints(self::getTypes());
}
@@ -970,7 +968,7 @@ class Pages
* @throws \RuntimeException
* @internal
*/
- protected function recurse($directory, Page &$parent = null)
+ protected function recurse($directory, Page $parent = null)
{
$directory = rtrim($directory, DS);
$page = new Page;
@@ -1023,7 +1021,7 @@ class Pages
if ($found->isDir()) {
continue;
}
- $regex = '/^[^\.]*' . preg_quote($extension) . '$/';
+ $regex = '/^[^\.]*' . preg_quote($extension, '/') . '$/';
if (preg_match($regex, $found->getFilename())) {
$page_found = $found;
$page_extension = $extension;
@@ -1053,10 +1051,8 @@ class Pages
$name = $file->getFilename();
// Ignore all hidden files if set.
- if ($this->ignore_hidden) {
- if ($name && $name[0] == '.') {
- continue;
- }
+ if ($this->ignore_hidden && $name && $name[0] === '.') {
+ continue;
}
if ($file->isFile()) {
@@ -1096,7 +1092,7 @@ class Pages
}
// Override the modified time if modular
- if ($page->template() == 'modular') {
+ if ($page->template() === 'modular') {
foreach ($page->collection() as $child) {
$modified = $child->modified();
@@ -1174,6 +1170,7 @@ class Pages
* @param array $pages
* @param string $order_by
* @param array $manual
+ * @param int $sort_flags
*
* @throws \RuntimeException
* @internal
@@ -1249,7 +1246,7 @@ class Pages
}
// handle special case when order_by is random
- if ($order_by == 'random') {
+ if ($order_by === 'random') {
$list = $this->arrayShuffle($list);
} else {
// else just sort the list according to specified key
diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php
index 06cf8bc87..cb903fdc5 100644
--- a/system/src/Grav/Common/Uri.php
+++ b/system/src/Grav/Common/Uri.php
@@ -58,8 +58,12 @@ class Uri
protected function createFromEnvironment(array $env)
{
// Build scheme.
- $https = isset($env['HTTPS']) ? $env['HTTPS'] : '';
- $this->scheme = (empty($https) || strtolower($https) === 'off') ? 'http' : 'https';
+ if (isset($env['REQUEST_SCHEME'])) {
+ $this->scheme = $env['REQUEST_SCHEME'];
+ } else {
+ $https = isset($env['HTTPS']) ? $env['HTTPS'] : '';
+ $this->scheme = (empty($https) || strtolower($https) === 'off') ? 'http' : 'https';
+ }
// Build user and password.
$this->user = isset($env['PHP_AUTH_USER']) ? $env['PHP_AUTH_USER'] : null;
@@ -79,6 +83,9 @@ class Uri
// Build port.
$this->port = isset($env['SERVER_PORT']) ? (int)$env['SERVER_PORT'] : null;
+ if ($this->hasStandardPort()) {
+ $this->port = null;
+ }
// Build path.
$request_uri = isset($env['REQUEST_URI']) ? $env['REQUEST_URI'] : '';
@@ -107,6 +114,16 @@ class Uri
$this->reset();
}
+ /**
+ * Does this Uri use a standard port?
+ *
+ * @return bool
+ */
+ protected function hasStandardPort()
+ {
+ return ($this->scheme === 'http' && $this->port === 80) || ($this->scheme === 'https' && $this->port === 443);
+ }
+
/**
* @param string $url
*/
diff --git a/system/src/Grav/Console/Cli/InstallCommand.php b/system/src/Grav/Console/Cli/InstallCommand.php
index 461763643..53869fcc7 100644
--- a/system/src/Grav/Console/Cli/InstallCommand.php
+++ b/system/src/Grav/Console/Cli/InstallCommand.php
@@ -117,7 +117,7 @@ class InstallCommand extends ConsoleCommand
$this->destination = rtrim($this->destination, DS);
$path = $this->destination . DS . $data['path'];
if (!file_exists($path)) {
- exec('cd "' . $this->destination . '" && git clone -b ' . $data['branch'] . ' ' . $data['url'] . ' ' . $data['path'], $output, $return);
+ exec('cd "' . $this->destination . '" && git clone -b ' . $data['branch'] . ' --depth 1 ' . $data['url'] . ' ' . $data['path'], $output, $return);
if (!$return) {
$this->output->writeln('SUCCESS cloned ' . $data['url'] . ' -> ' . $path . '');
diff --git a/tests/unit/Grav/Common/UriTest.php b/tests/unit/Grav/Common/UriTest.php
index 398d12d2f..8ddb03f0b 100644
--- a/tests/unit/Grav/Common/UriTest.php
+++ b/tests/unit/Grav/Common/UriTest.php
@@ -371,6 +371,52 @@ class UriTest extends \Codeception\TestCase\Test
'extension' => null,
'addNonce' => 'http://localhost:8080/a/b/c/d/e/f/a/b/c/d/e/f/a/b/c/d/e/f/nonce:{{nonce}}',
],
+ 'http://localhost/this is the path/my page' => [
+ 'scheme' => 'http://',
+ 'user' => null,
+ 'password' => null,
+ 'host' => 'localhost',
+ 'port' => 80,
+ 'path' => '/this%20is%20the%20path/my%20page',
+ 'query' => '',
+ 'fragment' => null,
+
+ 'route' => '/this%20is%20the%20path/my%20page',
+ 'paths' => ['this%20is%20the%20path', 'my%20page'],
+ 'params' => null,
+ 'url' => '/this%20is%20the%20path/my%20page',
+ 'environment' => 'localhost',
+ 'basename' => 'my%20page',
+ 'base' => 'http://localhost',
+ 'currentPage' => 1,
+ 'rootUrl' => 'http://localhost',
+ 'extension' => null,
+ 'addNonce' => 'http://localhost/this%20is%20the%20path/my%20page/nonce:{{nonce}}',
+ '__toString' => 'http://localhost/this%20is%20the%20path/my%20page'
+ ],
+ 'http://localhost/pölöpölö/päläpälä' => [
+ 'scheme' => 'http://',
+ 'user' => null,
+ 'password' => null,
+ 'host' => 'localhost',
+ 'port' => 80,
+ 'path' => '/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4',
+ 'query' => '',
+ 'fragment' => null,
+
+ 'route' => '/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4',
+ 'paths' => ['p%C3%B6l%C3%B6p%C3%B6l%C3%B6', 'p%C3%A4l%C3%A4p%C3%A4l%C3%A4'],
+ 'params' => null,
+ 'url' => '/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4',
+ 'environment' => 'localhost',
+ 'basename' => 'p%C3%A4l%C3%A4p%C3%A4l%C3%A4',
+ 'base' => 'http://localhost',
+ 'currentPage' => 1,
+ 'rootUrl' => 'http://localhost',
+ 'extension' => null,
+ 'addNonce' => 'http://localhost/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4/nonce:{{nonce}}',
+ '__toString' => 'http://localhost/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4'
+ ],
// Query params tests.
'http://localhost:8080/grav/it/ueper?test=x&test2=y' => [
'scheme' => 'http://',