diff --git a/app/controllers/studip_controller.php b/app/controllers/studip_controller.php index 556ff8b6284b866679fc2636c9fd186484d347d1..7c0991e480686bd85c165da0501e4d6b41c20a0e 100644 --- a/app/controllers/studip_controller.php +++ b/app/controllers/studip_controller.php @@ -349,7 +349,7 @@ abstract class StudipController extends Trails_Controller $to = $this->adjustToArguments(...func_get_args()); if (Request::isDialog()) { - $this->response->add_header('X-Location', rawurlencode($to)); + $this->response->add_header('X-Location', encodeURI($to)); $this->render_nothing(); } else { parent::redirect($to); diff --git a/lib/functions.php b/lib/functions.php index 96dd9551731d1b750b9212aa9460f8b397a44d46..bbed6298f50e796dc37224fee062e54673c60d8d 100644 --- a/lib/functions.php +++ b/lib/functions.php @@ -1827,3 +1827,37 @@ function get_default_http_stream_context($url = '') } return stream_context_get_default($opts); } + +/** + * Encodes an uri just like encodeURI() in Javascript would do. + * + * encodeURI() escapes all characters except: + * + * A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) # + * + * @param string $uri + * @return string + * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI + */ +function encodeURI(string $uri): string +{ + $replacements = [ + '%21' => '!', + '%23' => '#', + '%24' => '$', + '%26' => '&', + '%27' => "'", + '%28' => '(', + '%29' => ')', + '%2A' => '*', + '%2B' => '+', + '%2C' => ',', + '%3B' => ';', + '%2F' => '/', + '%3A' => ':', + '%3D' => '=', + '%3F' => '?', + '%40' => '@', + ]; + return strtr(rawurlencode($uri), $replacements); +} diff --git a/resources/assets/javascripts/lib/dialog.js b/resources/assets/javascripts/lib/dialog.js index de016ed72f07797f09a535aaa1381b57a8522e31..0ce30c6eef60f72a09c686c4bd2ea770f9af50c1 100644 --- a/resources/assets/javascripts/lib/dialog.js +++ b/resources/assets/javascripts/lib/dialog.js @@ -103,7 +103,7 @@ const Dialog = { // Handler for HTTP header X-Location: Relocate to another location Dialog.handlers.header['X-Location'] = function(location, options) { - location = decodeURIComponent(location); + location = decodeURI(location); if (document.location.href === location) { document.location.reload(true); diff --git a/tests/unit/lib/FunctionsTest.php b/tests/unit/lib/FunctionsTest.php index 2d3c868f3eae64161c74101b8471666dd21c8e43..61ad409ed50bc44123d6164c372e39130212a6bf 100644 --- a/tests/unit/lib/FunctionsTest.php +++ b/tests/unit/lib/FunctionsTest.php @@ -42,7 +42,7 @@ class FunctionsTest extends \Codeception\Test\Unit $this->assertEquals(range(1, 7), array_flatten($array)); } - + function testRelsize() { // Test basic sizes and suffixed 's' if value is <> 1 @@ -62,7 +62,7 @@ class FunctionsTest extends \Codeception\Test\Unit $this->assertEquals('1 Exabyte', relsize(pow(1024, 6))); $this->assertEquals('1 Zettabyte', relsize(pow(1024, 7))); $this->assertEquals('1 Yottabyte', relsize(pow(1024, 8))); - + // Test displayed levels $this->assertEquals('1 Megabyte', relsize(1024 * 1024 + 2 * 1024 + 3, true, 1)); $this->assertEquals('1.5 Megabytes', relsize(1024 * 1024 + 512 * 1024 + 3, true, 1)); @@ -70,4 +70,18 @@ class FunctionsTest extends \Codeception\Test\Unit $this->assertEquals('1 Megabyte, 2 Kilobytes, 3 Bytes', relsize(1024 * 1024 + 2 * 1024 + 3, true, 3)); $this->assertEquals('1 Megabyte, 2 Kilobytes, 3 Bytes', relsize(1024 * 1024 + 2 * 1024 + 3, true, 0)); } + + public function testEncodeURI() + { + $input = 'A-Za-z0-9;,/?:@&=+$-_.!~*\'()#'; + $this->assertEquals($input, encodeURI($input)); + + $input = 'https://example.org/?x=шеллы'; + $output = 'https://example.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B'; + $this->assertEquals($output, encodeURI($input)); + + $input = 'https://mäuschen-hüpft.de/öffnungszeiten?menu=Spaß&page=23'; + $output = 'https://m%C3%A4uschen-h%C3%BCpft.de/%C3%B6ffnungszeiten?menu=Spa%C3%9F&page=23'; + $this->assertEquals($output, encodeURI($input)); + } }