diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 0898741..e00ebb7 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.0-rc under development -------------------------- +- Bug #2563: Theming is not working if the path map of the theme contains ".." or "." in the paths (qiangxue) - Bug #3042: `yii\widgets\Pjax` should end application right after it finishes responding to a pjax request (qiangxue) - Bug #3066: `yii\db\mssql\Schema::getTableSchema()` should return null when the table does not exist (qiangxue) - Bug #3091: Fixed inconsistent treatment of `Widget::run()` when a widget is used as a container and as a self-contained object (qiangxue) diff --git a/framework/helpers/BaseFileHelper.php b/framework/helpers/BaseFileHelper.php index b7fa166..1f4c02c 100644 --- a/framework/helpers/BaseFileHelper.php +++ b/framework/helpers/BaseFileHelper.php @@ -28,16 +28,35 @@ class BaseFileHelper /** * Normalizes a file/directory path. - * After normalization, the directory separators in the path will be `DIRECTORY_SEPARATOR`, - * and any trailing directory separators will be removed. For example, '/home\demo/' on Linux - * will be normalized as '/home/demo'. + * The normalization does the following work: + * + * - Convert all directory separators into `DIRECTORY_SEPARATOR` (e.g. "\a/b\c" becomes "/a/b/c") + * - Remove trailing directory separators (e.g. "/a/b/c/" becomes "/a/b/c") + * - Turn multiple consecutive slashes into a single one (e.g. "/a///b/c" becomes "/a/b/c") + * - Remove ".." and "." based on their meanings (e.g. "/a/./b/../c" becomes "/a/c") + * * @param string $path the file/directory path to be normalized * @param string $ds the directory separator to be used in the normalized result. Defaults to `DIRECTORY_SEPARATOR`. * @return string the normalized file/directory path */ public static function normalizePath($path, $ds = DIRECTORY_SEPARATOR) { - return rtrim(strtr($path, ['/' => $ds, '\\' => $ds]), $ds); + $path = rtrim(strtr($path, ['/' => $ds, '\\' => $ds]), $ds); + if (strpos($ds . $path, "{$ds}.") === false && strpos($path, "{$ds}{$ds}") === false) { + return $path; + } + // the path may contain ".", ".." or double slashes, need to clean them up + $parts = []; + foreach (explode($ds, $path) as $part) { + if ($part === '..' && !empty($parts)) { + array_pop($parts); + } elseif ($part === '.' || $part === '' && !empty($parts)) { + continue; + } else { + $parts[] = $part; + } + } + return implode($ds, $parts); } /** diff --git a/tests/unit/framework/helpers/FileHelperTest.php b/tests/unit/framework/helpers/FileHelperTest.php index e0ea416..1ddde26 100644 --- a/tests/unit/framework/helpers/FileHelperTest.php +++ b/tests/unit/framework/helpers/FileHelperTest.php @@ -360,7 +360,13 @@ class FileHelperTest extends TestCase public function testNormalizePath() { - $this->assertEquals(DIRECTORY_SEPARATOR.'home'.DIRECTORY_SEPARATOR.'demo', FileHelper::normalizePath('/home\demo/')); + $ds = DIRECTORY_SEPARATOR; + $this->assertEquals("{$ds}a{$ds}b", FileHelper::normalizePath('//a\b/')); + $this->assertEquals("{$ds}b{$ds}c", FileHelper::normalizePath('/a/../b/c')); + $this->assertEquals("{$ds}c", FileHelper::normalizePath('/a\\b/../..///c')); + $this->assertEquals("{$ds}c", FileHelper::normalizePath('/a/.\\b//../../c')); + $this->assertEquals("c", FileHelper::normalizePath('/a/.\\b/../..//../c')); + $this->assertEquals("..{$ds}c", FileHelper::normalizePath('//a/.\\b//..//..//../../c')); } public function testLocalizedDirectory()