diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php
index d9079b1c7ef17..be617723886fb 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php
@@ -80,7 +80,7 @@ public function testGenerateFragmentUri()
]);
$twig->addRuntimeLoader($loader);
- $this->assertSame('/_fragment?_hash=XCg0hX8QzSwik8Xuu9aMXhoCeI4oJOob7lUVacyOtyY%3D&_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CController%255CTemplateController%253A%253AtemplateAction', $twig->render('index'));
+ $this->assertSame('/_fragment?_hash=XCg0hX8QzSwik8Xuu9aMXhoCeI4oJOob7lUVacyOtyY&_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CController%255CTemplateController%253A%253AtemplateAction', $twig->render('index'));
}
protected function getFragmentHandler($returnOrException): FragmentHandler
diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json
index 3af8ccbb7ecce..ca751c3f54ae7 100644
--- a/src/Symfony/Bridge/Twig/composer.json
+++ b/src/Symfony/Bridge/Twig/composer.json
@@ -32,7 +32,7 @@
"symfony/finder": "^6.4|^7.0",
"symfony/form": "^6.4|^7.0",
"symfony/html-sanitizer": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/http-foundation": "^7.3",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/intl": "^6.4|^7.0",
"symfony/mime": "^6.4|^7.0",
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php
index 6d8966a171ba2..b530d2cbc3bae 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php
@@ -50,6 +50,6 @@ public function testGenerateFragmentUri()
$client = self::createClient(['test_case' => 'Fragment', 'root_config' => 'config.yml', 'debug' => true]);
$client->request('GET', '/fragment_uri');
- $this->assertSame('/_fragment?_hash=CCRGN2D%2FoAJbeGz%2F%2FdoH3bNSPwLCrmwC1zAYCGIKJ0E%3D&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CTests%255CFunctional%255CBundle%255CTestBundle%255CController%255CFragmentController%253A%253AindexAction', $client->getResponse()->getContent());
+ $this->assertSame('/_fragment?_hash=CCRGN2D_oAJbeGz__doH3bNSPwLCrmwC1zAYCGIKJ0E&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CTests%255CFunctional%255CBundle%255CTestBundle%255CController%255CFragmentController%253A%253AindexAction', $client->getResponse()->getContent());
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index afaa9b03b6832..ef669713fecc0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -25,7 +25,7 @@
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/error-handler": "^6.4|^7.0",
"symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/http-foundation": "^7.3",
"symfony/http-kernel": "^7.2",
"symfony/polyfill-mbstring": "~1.0",
"symfony/filesystem": "^7.1",
diff --git a/src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php b/src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php
index 949e34760705a..927e2bda84db8 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php
@@ -70,13 +70,13 @@ public function testCheckWithDifferentArgSeparator()
$signer = new UriSigner('foobar');
$this->assertSame(
- 'http://example.com/foo?_hash=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D&baz=bay&foo=bar',
+ 'http://example.com/foo?_hash=rIOcC_F3DoEGo_vnESjSp7uU9zA9S_-OLhxgMexoPUM&baz=bay&foo=bar',
$signer->sign('http://example.com/foo?foo=bar&baz=bay')
);
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay')));
$this->assertSame(
- 'http://example.com/foo?_expiration=2145916800&_hash=xLhnPMzV3KqqHaaUffBUJvtRDAZ4%2FZ9Y8Sw%2BgmS%2B82Q%3D&baz=bay&foo=bar',
+ 'http://example.com/foo?_expiration=2145916800&_hash=xLhnPMzV3KqqHaaUffBUJvtRDAZ4_Z9Y8Sw-gmS-82Q&baz=bay&foo=bar',
$signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC')))
);
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2099-01-01 00:00:00'))));
@@ -103,13 +103,13 @@ public function testCheckWithDifferentParameter()
$signer = new UriSigner('foobar', 'qux', 'abc');
$this->assertSame(
- 'http://example.com/foo?baz=bay&foo=bar&qux=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D',
+ 'http://example.com/foo?baz=bay&foo=bar&qux=rIOcC_F3DoEGo_vnESjSp7uU9zA9S_-OLhxgMexoPUM',
$signer->sign('http://example.com/foo?foo=bar&baz=bay')
);
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay')));
$this->assertSame(
- 'http://example.com/foo?abc=2145916800&baz=bay&foo=bar&qux=kE4rK2MzeiwrYAKy%2B%2FGKvKA6bnzqCbACBdpC3yGnPVU%3D',
+ 'http://example.com/foo?abc=2145916800&baz=bay&foo=bar&qux=kE4rK2MzeiwrYAKy-_GKvKA6bnzqCbACBdpC3yGnPVU',
$signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC')))
);
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2099-01-01 00:00:00'))));
@@ -120,14 +120,14 @@ public function testSignerWorksWithFragments()
$signer = new UriSigner('foobar');
$this->assertSame(
- 'http://example.com/foo?_hash=EhpAUyEobiM3QTrKxoLOtQq5IsWyWedoXDPqIjzNj5o%3D&bar=foo&foo=bar#foobar',
+ 'http://example.com/foo?_hash=EhpAUyEobiM3QTrKxoLOtQq5IsWyWedoXDPqIjzNj5o&bar=foo&foo=bar#foobar',
$signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar')
);
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar')));
$this->assertSame(
- 'http://example.com/foo?_expiration=2145916800&_hash=jTdrIE9MJSorNpQmkX6tmOtocxXtHDzIJawcAW4IFYo%3D&bar=foo&foo=bar#foobar',
+ 'http://example.com/foo?_expiration=2145916800&_hash=jTdrIE9MJSorNpQmkX6tmOtocxXtHDzIJawcAW4IFYo&bar=foo&foo=bar#foobar',
$signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC')))
);
@@ -198,4 +198,10 @@ public function testCheckWithUriExpiration()
$this->assertFalse($signer->check($relativeUriFromNow2));
$this->assertFalse($signer->check($relativeUriFromNow3));
}
+
+ public function testNonUrlSafeBase64()
+ {
+ $signer = new UriSigner('foobar');
+ $this->assertTrue($signer->check('http://example.com/foo?_hash=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D&baz=bay&foo=bar'));
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/UriSigner.php b/src/Symfony/Component/HttpFoundation/UriSigner.php
index dd74434894676..1c9e25a5c0151 100644
--- a/src/Symfony/Component/HttpFoundation/UriSigner.php
+++ b/src/Symfony/Component/HttpFoundation/UriSigner.php
@@ -46,7 +46,7 @@ public function __construct(
*
* The expiration is added as a query string parameter.
*/
- public function sign(string $uri/*, \DateTimeInterface|\DateInterval|int|null $expiration = null*/): string
+ public function sign(string $uri/* , \DateTimeInterface|\DateInterval|int|null $expiration = null */): string
{
$expiration = null;
@@ -55,7 +55,7 @@ public function sign(string $uri/*, \DateTimeInterface|\DateInterval|int|null $e
}
if (null !== $expiration && !$expiration instanceof \DateTimeInterface && !$expiration instanceof \DateInterval && !\is_int($expiration)) {
- throw new \TypeError(\sprintf('The second argument of %s() must be an instance of %s or %s, an integer or null (%s given).', __METHOD__, \DateTimeInterface::class, \DateInterval::class, get_debug_type($expiration)));
+ throw new \TypeError(\sprintf('The second argument of "%s()" must be an instance of "%s" or "%s", an integer or null (%s given).', __METHOD__, \DateTimeInterface::class, \DateInterval::class, get_debug_type($expiration)));
}
$url = parse_url($uri);
@@ -103,7 +103,8 @@ public function check(string $uri): bool
$hash = $params[$this->hashParameter];
unset($params[$this->hashParameter]);
- if (!hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash)) {
+ // In 8.0, remove support for non-url-safe tokens
+ if (!hash_equals($this->computeHash($this->buildUrl($url, $params)), strtr(rtrim($hash, '='), ['/' => '_', '+' => '-']))) {
return false;
}
@@ -124,7 +125,7 @@ public function checkRequest(Request $request): bool
private function computeHash(string $uri): string
{
- return base64_encode(hash_hmac('sha256', $uri, $this->secret, true));
+ return strtr(rtrim(base64_encode(hash_hmac('sha256', $uri, $this->secret, true)), '='), ['/' => '_', '+' => '-']);
}
private function buildUrl(array $url, array $params = []): string
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php
index fa9885d2753cd..6a08d7eae688b 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php
@@ -61,7 +61,7 @@ public function testRenderControllerReference()
$altReference = new ControllerReference('alt_controller', [], []);
$this->assertEquals(
- '',
+ '',
$strategy->render($reference, $request, ['alt' => $altReference])->getContent()
);
}
@@ -79,7 +79,7 @@ public function testRenderControllerReferenceWithAbsoluteUri()
$altReference = new ControllerReference('alt_controller', [], []);
$this->assertSame(
- '',
+ '',
$strategy->render($reference, $request, ['alt' => $altReference, 'absolute_uri' => true])->getContent()
);
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php
index f74887ade36f4..82b80a86ff6b3 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php
@@ -32,7 +32,7 @@ public function testRenderWithControllerAndSigner()
{
$strategy = new HIncludeFragmentRenderer(null, new UriSigner('foo'));
- $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent());
+ $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent());
}
public function testRenderWithUri()
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php
index 4af00f9f75137..0d3f1dc2d4b62 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php
@@ -52,7 +52,7 @@ public function testRenderControllerReference()
$altReference = new ControllerReference('alt_controller', [], []);
$this->assertEquals(
- '',
+ '',
$strategy->render($reference, $request, ['alt' => $altReference])->getContent()
);
}
@@ -70,7 +70,7 @@ public function testRenderControllerReferenceWithAbsoluteUri()
$altReference = new ControllerReference('alt_controller', [], []);
$this->assertSame(
- '',
+ '',
$strategy->render($reference, $request, ['alt' => $altReference, 'absolute_uri' => true])->getContent()
);
}
diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json
index 89421417f58f1..e9cb077587abb 100644
--- a/src/Symfony/Component/HttpKernel/composer.json
+++ b/src/Symfony/Component/HttpKernel/composer.json
@@ -20,7 +20,7 @@
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/error-handler": "^6.4|^7.0",
"symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/http-foundation": "^7.3",
"symfony/polyfill-ctype": "^1.8",
"psr/log": "^1|^2|^3"
},