From 40563ed2f8ae4e46c75acab8429a5516cd1f0adb Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Sat, 13 Apr 2019 12:21:54 -0600 Subject: [PATCH 01/10] Better Utils::normalizePath() logic #2216 --- CHANGELOG.md | 6 ++++ system/src/Grav/Common/Utils.php | 50 ++++++++++++++++++---------- tests/unit/Grav/Common/UtilsTest.php | 14 ++++++-- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45e8c5d52..6dec33462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v1.6.4 +## mm/dd/2019 + +1. [](#bugfix) + * Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216) + # v1.6.3 ## 04/12/2019 diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index c5728b56f..f233bf13f 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -20,7 +20,9 @@ abstract class Utils { protected static $nonces = []; - protected const ROOTURL_REGEX = '{^(\/*)}'; + protected const ROOTURL_REGEX = '{^((?:http[s]?:\/\/[^\/]+)|(?:\/\/[^\/]+))(.*)}'; + + // ^((?:http[s]?:)?[\/]?(?:\/)) /** * Simple helper method to make getting a Grav URL easier @@ -784,31 +786,43 @@ abstract class Utils */ public static function normalizePath($path) { - - if (Uri::isExternal($path)) { - return $path; + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + if ($locator->isStream($path)) { + $path = $locator->findResource($path); } $root = ''; preg_match(self::ROOTURL_REGEX, $path, $matches); if ($matches) { - $root = $matches[0]; + $root = $matches[1]; + $path = $matches[2]; } - $clean_path = static::replaceFirstOccurrence($root, '', $path); - $segments = explode('/', trim($clean_path, '/')); - $ret = []; - foreach ($segments as $segment) { - if (($segment === '.') || $segment === '') { - continue; - } - if ($segment === '..') { - array_pop($ret); - } else { - $ret[] = $segment; - } + if (Utils::startsWith($path,'/')) { + $root .= '/'; + $path = ltrim($path, '/'); } - $normalized = $root . implode('/', $ret); + +// $path = ltrim(static::replaceFirstOccurrence($root, '', $path), '/'); + + if (Utils::contains($path, '..')) { + $segments = explode('/', trim($path, '/')); + $ret = []; + foreach ($segments as $segment) { + if (($segment === '.') || $segment === '') { + continue; + } + if ($segment === '..') { + array_pop($ret); + } else { + $ret[] = $segment; + } + } + $path = implode('/', $ret); + } + + $normalized = $root . $path; return $normalized; } diff --git a/tests/unit/Grav/Common/UtilsTest.php b/tests/unit/Grav/Common/UtilsTest.php index 6c034bafd..f3b2a9707 100644 --- a/tests/unit/Grav/Common/UtilsTest.php +++ b/tests/unit/Grav/Common/UtilsTest.php @@ -224,9 +224,19 @@ class UtilsTest extends \Codeception\TestCase\Test $this->assertEquals('test', Utils::normalizePath('../test')); $this->assertEquals('/test', Utils::normalizePath('/../test')); $this->assertEquals('/test2', Utils::normalizePath('/test/../test2')); - $this->assertEquals('/test/test2', Utils::normalizePath('/test/./test2')); + $this->assertEquals('/test3', Utils::normalizePath('/test/../test2/../test3')); + + $this->assertEquals('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css')); + $this->assertEquals('//use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/all.css')); + $this->assertEquals('//use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot')); + + $this->assertEquals('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css')); + $this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/all.css')); + $this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot')); + $this->assertEquals('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css')); - $this->assertEquals('//something.com/../test/test2', Utils::normalizePath('//something.com/../test/test2')); + $this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/all.css')); + $this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot')); } public function testIsFunctionDisabled() From 08423df547a8791d3a930a0b1fa815a249b2a050 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Sat, 13 Apr 2019 12:27:19 -0600 Subject: [PATCH 02/10] code tidy --- system/src/Grav/Common/Utils.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index f233bf13f..e15894a2e 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -786,12 +786,14 @@ abstract class Utils */ public static function normalizePath($path) { + // Resolve any streams /** @var UniformResourceLocator $locator */ $locator = Grav::instance()['locator']; if ($locator->isStream($path)) { $path = $locator->findResource($path); } + // Set root properly for any URLs $root = ''; preg_match(self::ROOTURL_REGEX, $path, $matches); if ($matches) { @@ -799,13 +801,13 @@ abstract class Utils $path = $matches[2]; } + // Strip off leading / to ensure explode is accurate if (Utils::startsWith($path,'/')) { $root .= '/'; $path = ltrim($path, '/'); } -// $path = ltrim(static::replaceFirstOccurrence($root, '', $path), '/'); - + // If there are any relative paths (..) handle those if (Utils::contains($path, '..')) { $segments = explode('/', trim($path, '/')); $ret = []; @@ -822,6 +824,7 @@ abstract class Utils $path = implode('/', $ret); } + // Stick everything back together $normalized = $root . $path; return $normalized; } From 8fd7a5aebe34e4e5f31c769e7aac1e25bdc618df Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Sat, 13 Apr 2019 13:18:13 -0600 Subject: [PATCH 03/10] Fixes #2445 pipeline excluded assets with cache on --- CHANGELOG.md | 1 + system/src/Grav/Common/Assets.php | 30 ++++++++++------- system/src/Grav/Common/Assets/BaseAsset.php | 6 ++++ system/src/Grav/Common/Assets/Pipeline.php | 33 ++++--------------- .../Common/Assets/Traits/AssetUtilsTrait.php | 6 +--- 5 files changed, 32 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dec33462..5fd5ffa57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## mm/dd/2019 1. [](#bugfix) + * Rework logic to pull out excluded files from pipeline more reliably [#2445](https://github.com/getgrav/grav/issues/2445) * Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216) # v1.6.3 diff --git a/system/src/Grav/Common/Assets.php b/system/src/Grav/Common/Assets.php index 6c3cf20b9..af54b26bb 100644 --- a/system/src/Grav/Common/Assets.php +++ b/system/src/Grav/Common/Assets.php @@ -45,8 +45,10 @@ class Assets extends PropertyObject // Config Options protected $css_pipeline; + protected $css_pipeline_include_externals; protected $css_pipeline_before_excludes; protected $js_pipeline; + protected $js_pipeline_include_externals; protected $js_pipeline_before_excludes; protected $pipeline_options = []; @@ -264,6 +266,21 @@ class Assets extends PropertyObject protected function filterAssets($assets, $key, $value, $sort = false) { $results = array_filter($assets, function($asset) use ($key, $value) { + + if ($key === 'position' && $value === 'pipeline') { + + $type = $asset->getType(); + + if ($asset->getRemote() && $this->{$type . '_pipeline_include_externals'} === false) { + if ($this->{$type . '_pipeline_before_excludes'}) { + $asset->setPosition('after'); + } else { + $asset->setPosition('before'); + } + return false; + } + + } if ($asset[$key] === $value) return true; return false; }); @@ -292,11 +309,9 @@ class Assets extends PropertyObject $before_output = ''; $pipeline_output = ''; $after_output = ''; - $no_pipeline = []; $assets = 'assets_' . $type; $pipeline_enabled = $type . '_pipeline'; - $before_excludes = $type . '_pipeline_before_excludes'; $render_pipeline = 'render' . ucfirst($type); $group_assets = $this->filterAssets($this->$assets, 'group', $group); @@ -309,22 +324,13 @@ class Assets extends PropertyObject $options = array_merge($this->pipeline_options, ['timestamp' => $this->timestamp]); $pipeline = new Pipeline($options); - $pipeline_output = $pipeline->$render_pipeline($pipeline_assets, $group, $attributes, $no_pipeline); + $pipeline_output = $pipeline->$render_pipeline($pipeline_assets, $group, $attributes); } else { foreach ($pipeline_assets as $asset) { $pipeline_output .= $asset->render(); } } - // Handle stuff that couldn't be pipelined - if (!empty($no_pipeline)) { - if ($this->{$before_excludes}) { - $after_assets = array_merge($after_assets, $no_pipeline); - } else { - $before_assets = array_merge($before_assets, $no_pipeline); - } - } - // Before Pipeline foreach ($before_assets as $asset) { $before_output .= $asset->render(); diff --git a/system/src/Grav/Common/Assets/BaseAsset.php b/system/src/Grav/Common/Assets/BaseAsset.php index 802367c7f..98f0f0560 100644 --- a/system/src/Grav/Common/Assets/BaseAsset.php +++ b/system/src/Grav/Common/Assets/BaseAsset.php @@ -129,6 +129,12 @@ abstract class BaseAsset extends PropertyObject return $this->remote; } + public function setPosition($position) + { + $this->position = $position; + return $this; + } + /** * diff --git a/system/src/Grav/Common/Assets/Pipeline.php b/system/src/Grav/Common/Assets/Pipeline.php index 9557030cb..b009585c8 100644 --- a/system/src/Grav/Common/Assets/Pipeline.php +++ b/system/src/Grav/Common/Assets/Pipeline.php @@ -50,9 +50,6 @@ class Pipeline extends PropertyObject protected $query; protected $asset; - protected $css_pipeline_include_externals; - protected $js_pipeline_include_externals; - /** * Closure used by the pipeline to fetch assets. * @@ -91,11 +88,10 @@ class Pipeline extends PropertyObject * @param array $assets * @param string $group * @param array $attributes - * @param array $no_pipeline * * @return bool|string URL or generated content if available, else false */ - public function renderCss($assets, $group, $attributes = [], &$no_pipeline = []) + public function renderCss($assets, $group, $attributes = []) { // temporary list of assets to pipeline $inline_group = false; @@ -119,21 +115,13 @@ class Pipeline extends PropertyObject if (file_exists($this->assets_dir . $file)) { $buffer = file_get_contents($this->assets_dir . $file) . "\n"; } else { - - foreach ($assets as $id => $asset) { - if ($this->css_pipeline_include_externals === false && $asset->getRemote()) { - $no_pipeline[$id] = $asset; - unset($assets[$id]); - } - } - //if nothing found get out of here! - if (empty($assets) && empty($no_pipeline)) { + if (empty($assets)) { return false; } // Concatenate files - $buffer = $this->gatherLinks($assets, self::CSS_ASSET, $no_pipeline); + $buffer = $this->gatherLinks($assets, self::CSS_ASSET); // Minify if required if ($this->shouldMinify('css')) { @@ -164,11 +152,10 @@ class Pipeline extends PropertyObject * @param array $assets * @param string $group * @param array $attributes - * @param array $no_pipeline * * @return bool|string URL or generated content if available, else false */ - public function renderJs($assets, $group, $attributes = [], &$no_pipeline = []) + public function renderJs($assets, $group, $attributes = []) { // temporary list of assets to pipeline $inline_group = false; @@ -192,21 +179,13 @@ class Pipeline extends PropertyObject if (file_exists($this->assets_dir . $file)) { $buffer = file_get_contents($this->assets_dir . $file) . "\n"; } else { - - foreach ($assets as $id => $asset) { - if ($this->js_pipeline_include_externals === false && $asset->getRemote()) { - $no_pipeline[$id] = $asset; - unset($assets[$id]); - } - } - //if nothing found get out of here! - if (empty($assets) && empty($no_pipeline)) { + if (empty($assets)) { return false; } // Concatenate files - $buffer = $this->gatherLinks($assets, self::JS_ASSET, $no_pipeline); + $buffer = $this->gatherLinks($assets, self::JS_ASSET); // Minify if required if ($this->shouldMinify('js')) { diff --git a/system/src/Grav/Common/Assets/Traits/AssetUtilsTrait.php b/system/src/Grav/Common/Assets/Traits/AssetUtilsTrait.php index c478b1aae..0a1d149de 100644 --- a/system/src/Grav/Common/Assets/Traits/AssetUtilsTrait.php +++ b/system/src/Grav/Common/Assets/Traits/AssetUtilsTrait.php @@ -38,11 +38,10 @@ trait AssetUtilsTrait * * @param array $assets * @param bool $css - * @param array $no_pipeline * * @return string */ - protected function gatherLinks(array $assets, $css = true, &$no_pipeline = []) + protected function gatherLinks(array $assets, $css = true) { $buffer = ''; @@ -74,9 +73,6 @@ trait AssetUtilsTrait // No file found, skip it... if ($file === false) { - if (!$local) { // Assume we couldn't download this file for some reason assume it's not pipeline compatible - $no_pipeline[$id] = $asset; - } continue; } From 14eb1281f91be1fb04daa99f50d60dc7408c23ca Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Sat, 13 Apr 2019 13:53:46 -0600 Subject: [PATCH 04/10] Fix to force all `Page::taxonomy` to be treated as strings #2446 --- CHANGELOG.md | 1 + system/src/Grav/Common/Page/Page.php | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fd5ffa57..8fbd83db1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ 1. [](#bugfix) * Rework logic to pull out excluded files from pipeline more reliably [#2445](https://github.com/getgrav/grav/issues/2445) * Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216) + * Fix to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446) # v1.6.3 ## 04/12/2019 diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index def0bb526..7a4dae480 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -414,9 +414,7 @@ class Page implements PageInterface $this->markdown_extra = (bool)$this->header->markdown_extra; } if (isset($this->header->taxonomy)) { - foreach ((array)$this->header->taxonomy as $taxonomy => $taxitems) { - $this->taxonomy[$taxonomy] = (array)$taxitems; - } + $this->taxonomy($this->header->taxonomy); } if (isset($this->header->max_count)) { $this->max_count = (int)$this->header->max_count; @@ -2296,6 +2294,9 @@ class Page implements PageInterface public function taxonomy($var = null) { if ($var !== null) { + array_walk_recursive($var, function(&$value) { + $value = (string) $value; + }); $this->taxonomy = $var; } From d502ff08c1ca1881dedb4b6f43480e4329c1afe8 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Sat, 13 Apr 2019 17:20:45 -0600 Subject: [PATCH 05/10] Attempt to resolve issue in form#332 --- CHANGELOG.md | 1 + .../Grav/Framework/Form/Traits/FormTrait.php | 31 +++++++++++-------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fbd83db1..a12d604bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Rework logic to pull out excluded files from pipeline more reliably [#2445](https://github.com/getgrav/grav/issues/2445) * Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216) * Fix to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446) + * Fix issue with `Grav['user']` not being available [form#332](https://github.com/getgrav/grav-plugin-form/issues/332) # v1.6.3 ## 04/12/2019 diff --git a/system/src/Grav/Framework/Form/Traits/FormTrait.php b/system/src/Grav/Framework/Form/Traits/FormTrait.php index 23f941093..d46517742 100644 --- a/system/src/Grav/Framework/Form/Traits/FormTrait.php +++ b/system/src/Grav/Framework/Form/Traits/FormTrait.php @@ -16,7 +16,6 @@ use Grav\Common\Form\FormFlash; use Grav\Common\Grav; use Grav\Common\Utils; use Grav\Framework\Form\Interfaces\FormInterface; -use Grav\Framework\Session\Session; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\UploadedFileInterface; @@ -309,24 +308,30 @@ trait FormTrait public function getFlash(): FormFlash { if (null === $this->flash) { + /** @var Grav $grav */ $grav = Grav::instance(); - $user = $grav['user']; $id = null; - $rememberState = $this->getBlueprint()->get('form/remember_state'); - if ($rememberState === 'user') { - $id = $user->username; + $user = $grav['user'] ?? null; + if (isset($user)) { + $rememberState = $this->getBlueprint()->get('form/remember_state'); + if ($rememberState === 'user') { + $id = $user->username; + } } - // By default store flash by the session id. - if (null === $id) { - /** @var Session $session */ - $session = $grav['session']; - $id = $session->getId(); - } + // Session Required for flash form + $session = $grav['session'] ?? null; + if (isset($session)) { + // By default store flash by the session id. + if (null === $id) { + $id = $session->getId(); + } - $this->flash = new FormFlash($id, $this->getUniqueId(), $this->getName()); - $this->flash->setUrl($grav['uri']->url)->setUser($user); + + $this->flash = new FormFlash($id, $this->getUniqueId(), $this->getName()); + $this->flash->setUrl($grav['uri']->url)->setUser($user); + } } return $this->flash; From 9a5fa7e6998fb07e2555dac4822fbd8eff63d75c Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Sun, 14 Apr 2019 13:08:57 -0600 Subject: [PATCH 06/10] Extra forcing of first level arrays in taxonomy --- system/src/Grav/Common/Page/Page.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index 7a4dae480..82ff71cb2 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -2294,6 +2294,11 @@ class Page implements PageInterface public function taxonomy($var = null) { if ($var !== null) { + // make sure first level are arrays + array_walk($var, function(&$value) { + $value = (array) $value; + }); + // make sure all values are strings array_walk_recursive($var, function(&$value) { $value = (string) $value; }); From 436be1788101c7e6984db8293952773b4c9a7c1a Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Mon, 15 Apr 2019 14:26:55 +0300 Subject: [PATCH 07/10] Fixed Flex simple storage not being properly initialized if used with caching --- CHANGELOG.md | 5 +-- .../Framework/Flex/Storage/FolderStorage.php | 2 +- .../Framework/Flex/Storage/SimpleStorage.php | 34 ++++++++++++++++++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a12d604bb..740fae499 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,9 @@ 1. [](#bugfix) * Rework logic to pull out excluded files from pipeline more reliably [#2445](https://github.com/getgrav/grav/issues/2445) * Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216) - * Fix to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446) - * Fix issue with `Grav['user']` not being available [form#332](https://github.com/getgrav/grav-plugin-form/issues/332) + * Fixed to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446) + * Fixed issue with `Grav['user']` not being available [form#332](https://github.com/getgrav/grav-plugin-form/issues/332) + * Fixed Flex simple storage not being properly initialized if used with caching # v1.6.3 ## 04/12/2019 diff --git a/system/src/Grav/Framework/Flex/Storage/FolderStorage.php b/system/src/Grav/Framework/Flex/Storage/FolderStorage.php index 7a23d8408..2304e8013 100644 --- a/system/src/Grav/Framework/Flex/Storage/FolderStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/FolderStorage.php @@ -71,7 +71,7 @@ class FolderStorage extends AbstractFilesystemStorage */ public function hasKey(string $key): bool { - return $key && !strpos($key, '@@') && file_exists($this->getPathFromKey($key)); + return $key && strpos($key, '@@') === false && file_exists($this->getPathFromKey($key)); } /** diff --git a/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php b/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php index d2ee183e8..7f37b1a98 100644 --- a/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php @@ -71,7 +71,11 @@ class SimpleStorage extends AbstractFilesystemStorage */ public function hasKey(string $key): bool { - return $key && !strpos($key, '@@') && isset($this->data[$key]); + if (null === $this->data) { + $this->buildIndex(); + } + + return $key && strpos($key, '@@') === false && isset($this->data[$key]); } /** @@ -80,6 +84,10 @@ class SimpleStorage extends AbstractFilesystemStorage */ public function createRows(array $rows): array { + if (null === $this->data) { + $this->buildIndex(); + } + $list = []; foreach ($rows as $key => $row) { $key = $this->getNewKey(); @@ -99,6 +107,10 @@ class SimpleStorage extends AbstractFilesystemStorage */ public function readRows(array $rows, array &$fetched = null): array { + if (null === $this->data) { + $this->buildIndex(); + } + $list = []; foreach ($rows as $key => $row) { if (null === $row || (!\is_object($row) && !\is_array($row))) { @@ -123,6 +135,10 @@ class SimpleStorage extends AbstractFilesystemStorage */ public function updateRows(array $rows): array { + if (null === $this->data) { + $this->buildIndex(); + } + $list = []; foreach ($rows as $key => $row) { $key = (string)$key; @@ -144,6 +160,10 @@ class SimpleStorage extends AbstractFilesystemStorage */ public function deleteRows(array $rows): array { + if (null === $this->data) { + $this->buildIndex(); + } + $list = []; foreach ($rows as $key => $row) { $key = (string)$key; @@ -166,6 +186,10 @@ class SimpleStorage extends AbstractFilesystemStorage */ public function replaceRows(array $rows): array { + if (null === $this->data) { + $this->buildIndex(); + } + $list = []; foreach ($rows as $key => $row) { $this->data[$key] = $list[$key] = $row; @@ -184,6 +208,10 @@ class SimpleStorage extends AbstractFilesystemStorage */ public function renameRow(string $src, string $dst): bool { + if (null === $this->data) { + $this->buildIndex(); + } + if ($this->hasKey($dst)) { throw new \RuntimeException("Cannot rename object: key '{$dst}' is already taken"); } @@ -221,6 +249,10 @@ class SimpleStorage extends AbstractFilesystemStorage protected function save() : void { + if (null === $this->data) { + $this->buildIndex(); + } + try { $file = $this->getFile($this->getStoragePath()); $file->save($this->data); From d69ef0e39cb81c2f55bef238ddaf565f523eb203 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Mon, 15 Apr 2019 11:00:11 -0600 Subject: [PATCH 08/10] Refactored rounded logic in Utils::parseSize() #2394 --- CHANGELOG.md | 1 + system/src/Grav/Common/Utils.php | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 740fae499..e0353ebce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216) * Fixed to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446) * Fixed issue with `Grav['user']` not being available [form#332](https://github.com/getgrav/grav-plugin-form/issues/332) + * Updated rounding logic for `Utils::parseSize()` [#2394](https://github.com/getgrav/grav/issues/2394) * Fixed Flex simple storage not being properly initialized if used with caching # v1.6.3 diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index e15894a2e..42f1fbe69 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -1405,10 +1405,10 @@ abstract class Utils $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); $size = preg_replace('/[^0-9\.]/', '', $size); if ($unit) { - return (int)((int)$size * (1024 ** stripos('bkmgtpezy', $unit[0]))); + return round($size * pow(1024, stripos('bkmgtpezy', $unit[0]))); + } else { + return round($size); } - - return (int)$size; } /** From ad173ca1295c62a9216c4181a605f894e7051819 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Mon, 15 Apr 2019 12:44:48 -0600 Subject: [PATCH 09/10] Improved `redirect_default_route` logic as well as `Uri::toArray()` to take into account `root_path` and `extension` --- CHANGELOG.md | 1 + .../Common/Service/PagesServiceProvider.php | 2 + system/src/Grav/Common/Uri.php | 43 ++++++++++++++++--- tests/unit/Grav/Common/UriTest.php | 26 +++++++++-- 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0353ebce..f91416f1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## mm/dd/2019 1. [](#bugfix) + * Improved `redirect_default_route` logic as well as `Uri::toArray()` to take into account `root_path` and `extension` * Rework logic to pull out excluded files from pipeline more reliably [#2445](https://github.com/getgrav/grav/issues/2445) * Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216) * Fixed to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446) diff --git a/system/src/Grav/Common/Service/PagesServiceProvider.php b/system/src/Grav/Common/Service/PagesServiceProvider.php index 0a37e831d..f148ce9af 100644 --- a/system/src/Grav/Common/Service/PagesServiceProvider.php +++ b/system/src/Grav/Common/Service/PagesServiceProvider.php @@ -80,6 +80,8 @@ class PagesServiceProvider implements ServiceProviderInterface } // Default route test and redirect if ($config->get('system.pages.redirect_default_route') && $page->route() !== $path) { + $uri->setUriProperties(['path' => $page->route()]); + $url = (string) $uri; $c->redirect($url); } } diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php index e92d68628..25724af38 100644 --- a/system/src/Grav/Common/Uri.php +++ b/system/src/Grav/Common/Uri.php @@ -187,11 +187,9 @@ class Uri $this->extension = $parts['extension']; } - $valid_page_types = implode('|', $config->get('system.pages.types')); - // Strip the file extension for valid page types - if (preg_match('/\.(' . $valid_page_types . ')$/', $parts['basename'])) { - $path = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS) . '/' . $parts['filename']; + if ($this->isValidExtension($this->extension)) { + $path = Utils::replaceLastOccurrence(".{$this->extension}", '', $path); } // set the new url @@ -586,13 +584,16 @@ class Uri public function toArray() { + $root_path = $this->root_path ?? ''; + $extension = isset($this->extension) && $this->isValidExtension($this->extension) ? '.' . $this->extension : ''; + $path = $root_path . $this->path . $extension; return [ 'scheme' => $this->scheme, 'host' => $this->host, 'port' => $this->port, 'user' => $this->user, 'pass' => $this->password, - 'path' => $this->path, + 'path' => $path, 'params' => $this->params, 'query' => $this->query, 'fragment' => $this->fragment @@ -1326,6 +1327,38 @@ class Uri return null; } + /** + * Check if this is a valid Grav extension + * + * @param $extension + * @return bool + */ + public function isValidExtension($extension) + { + $valid_page_types = implode('|', Grav::instance()['config']->get('system.pages.types')); + + // Strip the file extension for valid page types + if (preg_match('/(' . $valid_page_types . ')/', $extension)) { + return true; + } + return false; + } + + /** + * Allow overriding of any element (be careful!) + * + * @param $data + * @return Uri + */ + public function setUriProperties($data) + { + foreach (get_object_vars($this) as $property => $default) { + if (!array_key_exists($property, $data)) continue; + $this->{$property} = $data[$property]; // assign value to object + } + return $this; + } + /** * Get the base URI with port if needed * diff --git a/tests/unit/Grav/Common/UriTest.php b/tests/unit/Grav/Common/UriTest.php index 32db8a112..d42c58ac1 100644 --- a/tests/unit/Grav/Common/UriTest.php +++ b/tests/unit/Grav/Common/UriTest.php @@ -573,7 +573,7 @@ class UriTest extends \Codeception\TestCase\Test 'rootUrl' => 'http://localhost', 'extension' => 'html', 'addNonce' => 'http://localhost/a-page.html/nonce:{{nonce}}', - '__toString' => 'http://localhost/a-page', // FIXME <- + '__toString' => 'http://localhost/a-page.html', ], 'http://localhost/a-page.json' => [ 'scheme' => 'http://', @@ -596,7 +596,7 @@ class UriTest extends \Codeception\TestCase\Test 'rootUrl' => 'http://localhost', 'extension' => 'json', 'addNonce' => 'http://localhost/a-page.json/nonce:{{nonce}}', - '__toString' => 'http://localhost/a-page', // FIX ME <- + '__toString' => 'http://localhost/a-page.json', ], 'http://localhost/admin/ajax.json/task:getnewsfeed' => [ 'scheme' => 'http://', @@ -619,7 +619,7 @@ class UriTest extends \Codeception\TestCase\Test 'rootUrl' => 'http://localhost', 'extension' => 'json', 'addNonce' => 'http://localhost/admin/ajax.json/task:getnewsfeed/nonce:{{nonce}}', - '__toString' => 'http://localhost/admin/ajax/task:getnewsfeed', + '__toString' => 'http://localhost/admin/ajax.json/task:getnewsfeed', ], 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==' => [ 'scheme' => 'http://', @@ -642,7 +642,7 @@ class UriTest extends \Codeception\TestCase\Test 'rootUrl' => 'http://localhost', 'extension' => 'json', 'addNonce' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==/nonce:{{nonce}}', - '__toString' => 'http://localhost/grav/admin/media/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==', // FIXME <- + '__toString' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==', ], 'http://localhost/a-page.foo' => [ 'scheme' => 'http://', @@ -1121,6 +1121,24 @@ class UriTest extends \Codeception\TestCase\Test ]; $this->assertSame('http://foo:bar@localhost:8080/test?x=2#xxx', Uri::buildUrl($parsed_url)); + + /** @var Uri $uri */ + $uri = Grav::instance()['uri']; + + $uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html', '/subdir')->init(); + $this->assertSame('https://testing.dev/subdir/path1/path2/file.html', Uri::buildUrl($uri->toArray())); + + $uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.foo', '/subdir')->init(); + $this->assertSame('https://testing.dev/subdir/path1/path2/file.foo', Uri::buildUrl($uri->toArray())); + + $uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html', '/subdir/path1')->init(); + $this->assertSame('https://testing.dev/subdir/path1/path2/file.html', Uri::buildUrl($uri->toArray())); + + $uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom', '/subdir')->init(); + $this->assertSame('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom', Uri::buildUrl($uri->toArray())); + + $uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom?fig=something', '/subdir')->init(); + $this->assertSame('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom?fig=something', Uri::buildUrl($uri->toArray())); } public function testConvertUrl() From abefbfc776d86f12b7c6fe4b6bd75dea923236e7 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Mon, 15 Apr 2019 14:48:01 -0600 Subject: [PATCH 10/10] prepare for release --- CHANGELOG.md | 2 +- system/defines.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f91416f1a..d4e46867e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # v1.6.4 -## mm/dd/2019 +## 04/15/2019 1. [](#bugfix) * Improved `redirect_default_route` logic as well as `Uri::toArray()` to take into account `root_path` and `extension` diff --git a/system/defines.php b/system/defines.php index 0420293ec..ce7b82d18 100644 --- a/system/defines.php +++ b/system/defines.php @@ -8,7 +8,7 @@ // Some standard defines define('GRAV', true); -define('GRAV_VERSION', '1.6.3'); +define('GRAV_VERSION', '1.6.4'); define('GRAV_TESTING', false); define('DS', '/');