Merge branch 'MDL-81316-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE

This commit is contained in:
Huong Nguyen
2024-04-12 08:37:01 +07:00
2 changed files with 105 additions and 14 deletions
+68 -1
View File
@@ -24,7 +24,7 @@ namespace core;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \moodle_url
*/
class moodle_url_test extends \advanced_testcase {
final class moodle_url_test extends \advanced_testcase {
/**
* Test basic moodle_url construction.
*/
@@ -399,4 +399,71 @@ class moodle_url_test extends \advanced_testcase {
],
];
}
/**
* @dataProvider url_fragment_parsing_provider
*/
public function test_url_fragment_parsing(string $fragment, string $expected): void {
$url = new \moodle_url('/index.php', null, $fragment);
// Test the encoded fragment.
$this->assertEquals(
"#{$expected}",
$url->get_encoded_anchor(),
);
// Test the value of ->raw_out() with escaping enabled.
$parts = parse_url($url->raw_out(true), PHP_URL_FRAGMENT);
$this->assertEquals($expected, parse_url($url->raw_out(true), PHP_URL_FRAGMENT));
// Test the value of ->raw_out() with escaping disabled.
$parts = parse_url($url->raw_out(false));
$this->assertEquals($expected, $parts['fragment']);
// Test the value of ->out() with escaping enabled.
$parts = parse_url($url->out(true));
$this->assertEquals($expected, $parts['fragment']);
// Test the value of ->out() with escaping disabled.
$parts = parse_url($url->out(false));
$this->assertEquals($expected, $parts['fragment']);
$url->set_anchor($fragment);
$this->assertEquals(
"#{$expected}",
$url->get_encoded_anchor(),
);
}
/**
* Data provider for url_fragment_parsing tests.
*
* @return array
*/
public static function url_fragment_parsing_provider(): array {
return [
'Simple fragment' => ['test', 'test'],
// RFC 3986 allows the following characters in a fragment without them being encoded:
// pct-encoded: "%" HEXDIG HEXDIG
// unreserved: ALPHA / DIGIT / "-" / "." / "_" / "~" /
// sub-delims: "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" / ":" / "@"
// fragment: "/" / "?"
//
// These should not be encoded in the fragment unless they were already encoded.
'Fragment with RFC3986 characters' => [
'test-._~!$&\'()*+,;=:@/?',
'test-._~!$&\'()*+,;=:@/?',
],
'Fragment with already-encoded RFC3986 characters' => [
rawurlencode('test-._~!$&\'()*+,;=:@/?'),
rawurlencode('test-._~!$&\'()*+,;=:@/?'),
],
'Fragment with encoded slashes' => ['test%2fwith%2fencoded%2fslashes', 'test%2fwith%2fencoded%2fslashes'],
'Fragment with encoded characters' => ['test%20with%20encoded%20characters', 'test%20with%20encoded%20characters'],
// The following are examples which _should_ become encoded.
'Spaces become encoded' => ['test with spaces', 'test%20with%20spaces'],
'Quotes become encoded' => ['test with "quotes"', 'test%20with%20%22quotes%22'],
];
}
}
+37 -13
View File
@@ -618,13 +618,44 @@ class moodle_url {
if ($querystring !== '') {
$uri .= '?' . $querystring;
}
if (!is_null($this->anchor)) {
$uri .= '#'.$this->anchor;
}
$uri .= $this->get_encoded_anchor();
return $uri;
}
/**
* Encode the anchor according to RFC 3986.
*
* @return string The encoded anchor
*/
public function get_encoded_anchor(): string {
if (is_null($this->anchor)) {
return '';
}
// RFC 3986 allows the following characters in a fragment without them being encoded:
// pct-encoded: "%" HEXDIG HEXDIG
// unreserved: ALPHA / DIGIT / "-" / "." / "_" / "~" /
// sub-delims: "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" / ":" / "@"
// fragment: "/" / "?"
//
// All other characters should be encoded.
// These should not be encoded in the fragment unless they were already encoded.
$allowed = 'a-zA-Z0-9\\-._~!$&\'()*+,;=:@\/?%';
$anchor = '#';
$anchor .= preg_replace_callback(
'/[^' . $allowed . ']/',
function ($matches) {
return rawurlencode($matches[0]);
},
$this->anchor
);
return $anchor;
}
/**
* Returns url without parameters, everything before '?'.
*
@@ -638,8 +669,8 @@ class moodle_url {
$uri .= $this->host ? $this->host : '';
$uri .= $this->port ? ':'.$this->port : '';
$uri .= $this->path ? $this->path : '';
if ($includeanchor and !is_null($this->anchor)) {
$uri .= '#' . $this->anchor;
if ($includeanchor) {
$uri .= $this->get_encoded_anchor();
}
return $uri;
@@ -715,15 +746,8 @@ class moodle_url {
if (is_null($anchor)) {
// Remove.
$this->anchor = null;
} else if ($anchor === '') {
// Special case, used as empty link.
$this->anchor = '';
} else if (preg_match('|[a-zA-Z\_\:][a-zA-Z0-9\_\-\.\:]*|', $anchor)) {
// Match the anchor against the NMTOKEN spec.
$this->anchor = $anchor;
} else {
// Bad luck, no valid anchor found.
$this->anchor = null;
$this->anchor = $anchor;
}
}