diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md
index cf90bc2e50f34..f5471bf653f4b 100644
--- a/CHANGELOG-2.7.md
+++ b/CHANGELOG-2.7.md
@@ -7,6 +7,10 @@ in 2.7 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.7.0...v2.7.1
+* 2.7.31 (2017-07-05)
+
+ * bug #23378 [FrameworkBundle] Do not remove files from assets dir (1ed)
+
* 2.7.30 (2017-07-03)
* bug #23341 [DoctrineBridge][Security][Validator] do not validate empty values (xabbuh)
diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md
index 661863ef7ce54..a73a824d4cf45 100644
--- a/CHANGELOG-2.8.md
+++ b/CHANGELOG-2.8.md
@@ -7,6 +7,19 @@ in 2.8 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.8.0...v2.8.1
+* 2.8.25 (2017-07-17)
+
+ * security #23507 [Security] validate empty passwords again (xabbuh)
+ * bug #23526 [HttpFoundation] Set meta refresh time to 0 in RedirectResponse content (jnvsor)
+ * bug #23540 Disable inlining deprecated services (alekitto)
+ * bug #23468 [DI] Handle root namespace in service definitions (ro0NL)
+ * bug #23256 [Security] Fix authentication.failure event not dispatched on AccountStatusException (chalasr)
+ * bug #23461 Use rawurlencode() to transform the Cookie into a string (javiereguiluz)
+ * bug #23459 [TwigBundle] allow to configure custom formats in XML configs (xabbuh)
+ * bug #23460 Don't display the Symfony debug toolbar when printing the page (javiereguiluz)
+ * bug #23261 Fixed absolute url generation for query strings and hash urls (alexander-schranz)
+ * bug #23398 [Filesystem] Dont copy perms when origin is remote (nicolas-grekas)
+
* 2.8.24 (2017-07-05)
* bug #23378 [FrameworkBundle] Do not remove files from assets dir (1ed)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 0b695308c528f..3e670f8d67e90 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -70,9 +70,9 @@ Symfony is the result of the work of many people who made the code better
- Deni
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
+ - Jáchym Toušek (enumag)
- Titouan Galopin (tgalopin)
- Douglas Greenshields (shieldo)
- - Jáchym Toušek (enumag)
- Konstantin Myakshin (koc)
- Lee McDermott
- Brandon Turner
@@ -99,11 +99,12 @@ Symfony is the result of the work of many people who made the code better
- Baptiste Clavié (talus)
- Vladimir Reznichenko (kalessil)
- marc.weistroff
+ - Yonel Ceruto González (yonelceruto)
- lenar
- Włodzimierz Gajda (gajdaw)
- - Yonel Ceruto González (yonelceruto)
- Alexander Schwenn (xelaris)
- Jacob Dreesen (jdreesen)
+ - Tobias Nyholm (tobias)
- Florian Voutzinos (florianv)
- Colin Frei
- Adrien Brault (adrienbrault)
@@ -111,7 +112,6 @@ Symfony is the result of the work of many people who made the code better
- Peter Kokot (maastermedia)
- David Buchmann (dbu)
- excelwebzone
- - Tobias Nyholm (tobias)
- Tomáš Votruba (tomas_votruba)
- Fabien Pennequin (fabienpennequin)
- Gordon Franke (gimler)
@@ -133,12 +133,15 @@ Symfony is the result of the work of many people who made the code better
- Guilherme Blanco (guilhermeblanco)
- Pablo Godel (pgodel)
- Jérémie Augustin (jaugustin)
+ - Dany Maillard (maidmaid)
- Andréia Bohner (andreia)
- Rafael Dohms (rdohms)
- Arnaud Kleinpeter (nanocom)
- jwdeitch
+ - David Maicher (dmaicher)
- Mikael Pajunen
- Joel Wurtz (brouznouf)
+ - Grégoire Paris (greg0ire)
- Philipp Wahala (hifi)
- Vyacheslav Pavlov
- Richard van Laak (rvanlaak)
@@ -147,11 +150,9 @@ Symfony is the result of the work of many people who made the code better
- Thomas Rabaix (rande)
- Rouven Weßling (realityking)
- Teoh Han Hui (teohhanhui)
- - David Maicher (dmaicher)
- Jérôme Vasseur (jvasseur)
- Clemens Tolboom
- Helmer Aaviksoo
- - Grégoire Paris (greg0ire)
- Hiromi Hishida (77web)
- Matthieu Ouellette-Vachon (maoueh)
- Michał Pipa (michal.pipa)
@@ -234,7 +235,6 @@ Symfony is the result of the work of many people who made the code better
- Arjen Brouwer (arjenjb)
- Katsuhiro OGAWA
- Patrick McDougle (patrick-mcdougle)
- - Dany Maillard (maidmaid)
- Alif Rachmawadi
- Kristen Gilden (kgilden)
- Pierre-Yves LEBECQ (pylebecq)
@@ -620,6 +620,7 @@ Symfony is the result of the work of many people who made the code better
- develop
- ReenExe
- Mark Sonnabaum
+ - Maxime Veber (nek-)
- Richard Quadling
- jochenvdv
- Arturas Smorgun (asarturas)
@@ -642,6 +643,7 @@ Symfony is the result of the work of many people who made the code better
- Trent Steel (trsteel88)
- Yuen-Chi Lian
- Besnik Br
+ - Jose Gonzalez
- Dariusz Ruminski
- Joshua Nye
- Claudio Zizza
@@ -1081,7 +1083,6 @@ Symfony is the result of the work of many people who made the code better
- Max Summe
- WedgeSama
- Felds Liscia
- - Maxime Veber (nek-)
- Sullivan SENECHAL
- Tadcka
- Beth Binkovitz
@@ -1092,12 +1093,12 @@ Symfony is the result of the work of many people who made the code better
- Tomaz Ahlin
- Marcus Stöhr (dafish)
- Emmanuel Vella (emmanuel.vella)
+ - Adam Szaraniec (mimol)
- Carsten Nielsen (phreaknerd)
- Mathieu Rochette
- Jay Severson
- René Kerner
- Nathaniel Catchpole
- - Jose Gonzalez
- Adrien Samson (adriensamson)
- Samuel Gordalina (gordalina)
- Max Romanovsky (maxromanovsky)
@@ -1258,6 +1259,7 @@ Symfony is the result of the work of many people who made the code better
- Aarón Nieves Fernández
- Mike Meier
- Kirill Saksin
+ - Julien Pauli
- Koalabaerchen
- michalmarcinkowski
- Warwick
@@ -1305,6 +1307,7 @@ Symfony is the result of the work of many people who made the code better
- klemens
- dened
- Dmitry Korotovsky
+ - mcorteel
- Michael van Tricht
- Sam Ward
- Walther Lalk
@@ -1335,6 +1338,7 @@ Symfony is the result of the work of many people who made the code better
- Jan Marek (janmarek)
- Mark de Haan (markdehaan)
- Dan Patrick (mdpatrick)
+ - Pedro Magalhães (pmmaga)
- Rares Vlaseanu (raresvla)
- tante kinast (tante)
- Vincent LEFORT (vlefort)
@@ -1542,6 +1546,7 @@ Symfony is the result of the work of many people who made the code better
- Abdulkadir N. A.
- Yevgen Kovalienia
- Lebnik
+ - Shude
- Ondřej Führer
- Sema
- Elan Ruusamäe
diff --git a/composer.json b/composer.json
index 8da4f2529cc93..8e2db75120a47 100644
--- a/composer.json
+++ b/composer.json
@@ -17,6 +17,7 @@
],
"require": {
"php": ">=5.3.9",
+ "ext-xml": "*",
"doctrine/common": "~2.4",
"twig/twig": "~1.34|~2.4",
"psr/log": "~1.0",
diff --git a/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php
index 90b515ee320ba..0dad40cfa0a3f 100644
--- a/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php
@@ -72,6 +72,13 @@ public function generateAbsoluteUrl($path)
$port = ':'.$this->requestContext->getHttpsPort();
}
+ if ('#' === $path[0]) {
+ $queryString = $this->requestContext->getQueryString();
+ $path = $this->requestContext->getPathInfo().($queryString ? '?'.$queryString : '').$path;
+ } elseif ('?' === $path[0]) {
+ $path = $this->requestContext->getPathInfo().$path;
+ }
+
if ('/' !== $path[0]) {
$path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path;
}
@@ -82,6 +89,12 @@ public function generateAbsoluteUrl($path)
return $path;
}
+ if ('#' === $path[0]) {
+ $path = $request->getRequestUri().$path;
+ } elseif ('?' === $path[0]) {
+ $path = $request->getPathInfo().$path;
+ }
+
if (!$path || '/' !== $path[0]) {
$prefix = $request->getPathInfo();
$last = strlen($prefix) - 1;
diff --git a/src/Symfony/Bridge/Twig/Form/TwigRenderer.php b/src/Symfony/Bridge/Twig/Form/TwigRenderer.php
index 2485c0a88c530..9f4d7c56ea886 100644
--- a/src/Symfony/Bridge/Twig/Form/TwigRenderer.php
+++ b/src/Symfony/Bridge/Twig/Form/TwigRenderer.php
@@ -19,16 +19,19 @@
*/
class TwigRenderer extends FormRenderer implements TwigRendererInterface
{
- /**
- * @var TwigRendererEngineInterface
- */
- private $engine;
-
public function __construct(TwigRendererEngineInterface $engine, $csrfTokenManager = null)
{
parent::__construct($engine, $csrfTokenManager);
+ }
- $this->engine = $engine;
+ /**
+ * Returns the engine used by this renderer.
+ *
+ * @return TwigRendererEngineInterface The renderer engine
+ */
+ public function getEngine()
+ {
+ return parent::getEngine();
}
/**
@@ -36,6 +39,6 @@ public function __construct(TwigRendererEngineInterface $engine, $csrfTokenManag
*/
public function setEnvironment(Environment $environment)
{
- $this->engine->setEnvironment($environment);
+ $this->getEngine()->setEnvironment($environment);
}
}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php
index 8f0c66ad78bb4..fcff0c0e1b93b 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php
@@ -42,6 +42,15 @@ public function getGenerateAbsoluteUrlData()
array('http://example.com/baz', 'http://example.com/baz', '/'),
array('https://example.com/baz', 'https://example.com/baz', '/'),
array('//example.com/baz', '//example.com/baz', '/'),
+
+ array('http://localhost/foo/bar?baz', '?baz', '/foo/bar'),
+ array('http://localhost/foo/bar?baz=1', '?baz=1', '/foo/bar?foo=1'),
+ array('http://localhost/foo/baz?baz=1', 'baz?baz=1', '/foo/bar?foo=1'),
+
+ array('http://localhost/foo/bar#baz', '#baz', '/foo/bar'),
+ array('http://localhost/foo/bar?0#baz', '#baz', '/foo/bar?0'),
+ array('http://localhost/foo/bar?baz=1#baz', '?baz=1#baz', '/foo/bar?foo=1'),
+ array('http://localhost/foo/baz?baz=1#baz', 'baz?baz=1#baz', '/foo/bar?foo=1'),
);
}
diff --git a/src/Symfony/Bundle/DebugBundle/composer.json b/src/Symfony/Bundle/DebugBundle/composer.json
index 0221a3f2bb81e..98305f79dcbcc 100644
--- a/src/Symfony/Bundle/DebugBundle/composer.json
+++ b/src/Symfony/Bundle/DebugBundle/composer.json
@@ -17,6 +17,7 @@
],
"require": {
"php": ">=5.3.9",
+ "ext-xml": "*",
"symfony/http-kernel": "~2.6|~3.0.0",
"symfony/twig-bridge": "~2.6|~3.0.0",
"symfony/var-dumper": "~2.6|~3.0.0"
diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json
index 34117bff7cb6e..04fd6473053e8 100644
--- a/src/Symfony/Bundle/SecurityBundle/composer.json
+++ b/src/Symfony/Bundle/SecurityBundle/composer.json
@@ -17,6 +17,7 @@
],
"require": {
"php": ">=5.3.9",
+ "ext-xml": "*",
"symfony/security": "~2.8|~3.0.0",
"symfony/security-acl": "~2.7|~3.0.0",
"symfony/http-kernel": "~2.7|~3.0.0",
diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/schema/twig-1.0.xsd b/src/Symfony/Bundle/TwigBundle/Resources/config/schema/twig-1.0.xsd
index 474b6c9721e0c..70b6de5c38d5c 100644
--- a/src/Symfony/Bundle/TwigBundle/Resources/config/schema/twig-1.0.xsd
+++ b/src/Symfony/Bundle/TwigBundle/Resources/config/schema/twig-1.0.xsd
@@ -9,6 +9,9 @@
+
+
+
@@ -28,6 +31,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/formats.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/formats.php
new file mode 100644
index 0000000000000..630a9a9edc01a
--- /dev/null
+++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/formats.php
@@ -0,0 +1,14 @@
+loadFromExtension('twig', array(
+ 'date' => array(
+ 'format' => 'Y-m-d',
+ 'interval_format' => '%d',
+ 'timezone' => 'Europe/Berlin',
+ ),
+ 'number_format' => array(
+ 'decimals' => 2,
+ 'decimal_point' => ',',
+ 'thousands_separator' => '.',
+ ),
+));
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/formats.xml b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/formats.xml
new file mode 100644
index 0000000000000..1ab39e49229cd
--- /dev/null
+++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/formats.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/formats.yml b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/formats.yml
new file mode 100644
index 0000000000000..290921630f9e6
--- /dev/null
+++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/formats.yml
@@ -0,0 +1,9 @@
+twig:
+ date:
+ format: Y-m-d
+ interval_format: '%d'
+ timezone: Europe/Berlin
+ number_format:
+ decimals: 2
+ decimal_point: ','
+ thousands_separator: .
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
index f5809cc045c42..f385ec04fd28c 100644
--- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
+++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
@@ -150,6 +150,26 @@ public function testLoadDefaultTemplateEscapingGuesserConfiguration($format)
$this->assertEquals('name', $options['autoescape']);
}
+ /**
+ * @dataProvider getFormats
+ */
+ public function testLoadCustomDateFormats($fileFormat)
+ {
+ $container = $this->createContainer();
+ $container->registerExtension(new TwigExtension());
+ $this->loadFromFile($container, 'formats', $fileFormat);
+ $this->compileContainer($container);
+
+ $environmentConfigurator = $container->getDefinition('twig.configurator.environment');
+
+ $this->assertSame('Y-m-d', $environmentConfigurator->getArgument(0));
+ $this->assertSame('%d', $environmentConfigurator->getArgument(1));
+ $this->assertSame('Europe/Berlin', $environmentConfigurator->getArgument(2));
+ $this->assertSame(2, $environmentConfigurator->getArgument(3));
+ $this->assertSame(',', $environmentConfigurator->getArgument(4));
+ $this->assertSame('.', $environmentConfigurator->getArgument(5));
+ }
+
public function testGlobalsWithDifferentTypesAndValues()
{
$globals = array(
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
index c148954f5a9c8..16a3310d77178 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
@@ -527,3 +527,10 @@
padding: 5px 0;
margin-right: 10px;
}
+
+/***** Media query print: Do not print the Toolbar. *****/
+@media print {
+ .sf-toolbar {
+ display: none;
+ }
+}
diff --git a/src/Symfony/Component/BrowserKit/Cookie.php b/src/Symfony/Component/BrowserKit/Cookie.php
index 42f184d532e02..c042c6a525295 100644
--- a/src/Symfony/Component/BrowserKit/Cookie.php
+++ b/src/Symfony/Component/BrowserKit/Cookie.php
@@ -62,7 +62,7 @@ public function __construct($name, $value, $expires = null, $path = null, $domai
$this->rawValue = $value;
} else {
$this->value = $value;
- $this->rawValue = urlencode($value);
+ $this->rawValue = rawurlencode($value);
}
$this->name = $name;
$this->path = empty($path) ? '/' : $path;
diff --git a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
index 38ea81220bb2c..2f5a08d104143 100644
--- a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
+++ b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
@@ -16,6 +16,21 @@
class CookieTest extends TestCase
{
+ public function testToString()
+ {
+ $cookie = new Cookie('foo', 'bar', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
+ $this->assertEquals('foo=bar; expires=Fri, 20 May 2011 15:25:52 GMT; domain=.myfoodomain.com; path=/; secure; httponly', (string) $cookie, '->__toString() returns string representation of the cookie');
+
+ $cookie = new Cookie('foo', 'bar with white spaces', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
+ $this->assertEquals('foo=bar%20with%20white%20spaces; expires=Fri, 20 May 2011 15:25:52 GMT; domain=.myfoodomain.com; path=/; secure; httponly', (string) $cookie, '->__toString() encodes the value of the cookie according to RFC 3986 (white space = %20)');
+
+ $cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com');
+ $this->assertEquals('foo=; expires=Thu, 01 Jan 1970 00:00:01 GMT; domain=.myfoodomain.com; path=/admin/; httponly', (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
+
+ $cookie = new Cookie('foo', 'bar', 0, '/', '');
+ $this->assertEquals('foo=bar; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; httponly', (string) $cookie);
+ }
+
/**
* @dataProvider getTestsForToFromString
*/
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
index 1beaaf0c53ce0..bf95ea5b0a269 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
@@ -113,7 +113,7 @@ private function isInlineableDefinition(ContainerBuilder $container, $id, Defini
return true;
}
- if ($definition->isPublic() || $definition->isLazy()) {
+ if ($definition->isDeprecated() || $definition->isPublic() || $definition->isLazy()) {
return false;
}
diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php
index ea804c701bb0f..869339ef63132 100644
--- a/src/Symfony/Component/DependencyInjection/Container.php
+++ b/src/Symfony/Component/DependencyInjection/Container.php
@@ -30,16 +30,6 @@
*
* Parameter and service keys are case insensitive.
*
- * A service id can contain lowercased letters, digits, underscores, and dots.
- * Underscores are used to separate words, and dots to group services
- * under namespaces:
- *
- *
- * - request
- * - mysql_session_storage
- * - symfony.mysql_session_storage
- *
- *
* A service can also be defined by creating a method named
* getXXXService(), where XXX is the camelized version of the id:
*
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index 6c131aae19770..713550bb4109e 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -377,15 +377,9 @@ private function addServiceReturn($id, $definition)
*/
private function addServiceInstance($id, Definition $definition)
{
- $class = $definition->getClass();
-
- if ('\\' === substr($class, 0, 1)) {
- $class = substr($class, 1);
- }
-
- $class = $this->dumpValue($class);
+ $class = $this->dumpValue($definition->getClass());
- if (0 === strpos($class, "'") && !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
+ if (0 === strpos($class, "'") && !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
}
@@ -1460,11 +1454,13 @@ private function dumpLiteralClass($class)
if (false !== strpos($class, '$')) {
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
}
- if (0 !== strpos($class, "'") || !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
+ if (0 !== strpos($class, "'") || !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s)', $class ?: 'n/a'));
}
- return '\\'.substr(str_replace('\\\\', '\\', $class), 1, -1);
+ $class = substr(str_replace('\\\\', '\\', $class), 1, -1);
+
+ return 0 === strpos($class, '\\') ? $class : '\\'.$class;
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
index 732ce97a17dcc..3c14bfc19895e 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
@@ -891,6 +891,27 @@ public function testAutowiring()
$this->assertEquals('a', (string) $container->getDefinition('b')->getArgument(0));
}
+
+ /**
+ * This test checks the trigger of a deprecation note and should not be removed in major releases.
+ *
+ * @group legacy
+ * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed.
+ */
+ public function testPrivateServiceTriggersDeprecation()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', 'stdClass')
+ ->setPublic(false)
+ ->setDeprecated(true);
+ $container->register('bar', 'stdClass')
+ ->setPublic(true)
+ ->setProperty('foo', new Reference('foo'));
+
+ $container->compile();
+
+ $container->get('bar');
+ }
}
class FooClass
diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php
index dbe18f607e968..721932591f177 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php
@@ -134,8 +134,8 @@ public function testGetServiceIds()
public function testSet()
{
$sc = new Container();
- $sc->set('foo', $foo = new \stdClass());
- $this->assertSame($foo, $sc->get('foo'), '->set() sets a service');
+ $sc->set('._. \\o/', $foo = new \stdClass());
+ $this->assertSame($foo, $sc->get('._. \\o/'), '->set() sets a service');
}
public function testSetWithNullResetTheService()
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index 06d4c70ad2e08..c49586463d7cc 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -347,4 +347,43 @@ public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServic
$this->addToAssertionCount(1);
}
+
+ public function testDumpHandlesLiteralClassWithRootNamespace()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', '\\stdClass');
+
+ $dumper = new PhpDumper($container);
+ eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Literal_Class_With_Root_Namespace')));
+
+ $container = new \Symfony_DI_PhpDumper_Test_Literal_Class_With_Root_Namespace();
+
+ $this->assertInstanceOf('stdClass', $container->get('foo'));
+ }
+
+ /**
+ * This test checks the trigger of a deprecation note and should not be removed in major releases.
+ *
+ * @group legacy
+ * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed.
+ */
+ public function testPrivateServiceTriggersDeprecation()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', 'stdClass')
+ ->setPublic(false)
+ ->setDeprecated(true);
+ $container->register('bar', 'stdClass')
+ ->setPublic(true)
+ ->setProperty('foo', new Reference('foo'));
+
+ $container->compile();
+
+ $dumper = new PhpDumper($container);
+ eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Private_Service_Triggers_Deprecation')));
+
+ $container = new \Symfony_DI_PhpDumper_Test_Private_Service_Triggers_Deprecation();
+
+ $container->get('bar');
+ }
}
diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php
index cfa6540399dbe..56f8c85a38109 100644
--- a/src/Symfony/Component/Filesystem/Filesystem.php
+++ b/src/Symfony/Component/Filesystem/Filesystem.php
@@ -37,7 +37,8 @@ class Filesystem
*/
public function copy($originFile, $targetFile, $overwriteNewerFiles = false)
{
- if (stream_is_local($originFile) && !is_file($originFile)) {
+ $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://');
+ if ($originIsLocal && !is_file($originFile)) {
throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
}
@@ -68,11 +69,13 @@ public function copy($originFile, $targetFile, $overwriteNewerFiles = false)
throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
}
- // Like `cp`, preserve executable permission bits
- @chmod($targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));
+ if ($originIsLocal) {
+ // Like `cp`, preserve executable permission bits
+ @chmod($targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));
- if (stream_is_local($originFile) && $bytesCopied !== ($bytesOrigin = filesize($originFile))) {
- throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile);
+ if ($bytesCopied !== $bytesOrigin = filesize($originFile)) {
+ throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile);
+ }
}
}
}
diff --git a/src/Symfony/Component/HttpFoundation/Cookie.php b/src/Symfony/Component/HttpFoundation/Cookie.php
index 91783a6ad2b50..fb1e7dfd74ea4 100644
--- a/src/Symfony/Component/HttpFoundation/Cookie.php
+++ b/src/Symfony/Component/HttpFoundation/Cookie.php
@@ -82,7 +82,7 @@ public function __toString()
if ('' === (string) $this->getValue()) {
$str .= 'deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001);
} else {
- $str .= urlencode($this->getValue());
+ $str .= rawurlencode($this->getValue());
if (0 !== $this->getExpiresTime()) {
$str .= '; expires='.gmdate('D, d-M-Y H:i:s T', $this->getExpiresTime());
diff --git a/src/Symfony/Component/HttpFoundation/RedirectResponse.php b/src/Symfony/Component/HttpFoundation/RedirectResponse.php
index 5a775ad159f3a..4118fff24c892 100644
--- a/src/Symfony/Component/HttpFoundation/RedirectResponse.php
+++ b/src/Symfony/Component/HttpFoundation/RedirectResponse.php
@@ -83,7 +83,7 @@ public function setTargetUrl($url)
-
+
Redirecting to %1$s
diff --git a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php
index f3f74f635eb40..2d9fb09d3d4b6 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php
@@ -160,6 +160,9 @@ public function testToString()
$cookie = new Cookie('foo', 'bar', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
$this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() returns string representation of the cookie');
+ $cookie = new Cookie('foo', 'bar with white spaces', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
+ $this->assertEquals('foo=bar%20with%20white%20spaces; expires=Fri, 20-May-2011 15:25:52 GMT; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() encodes the value of the cookie according to RFC 3986 (white space = %20)');
+
$cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com');
$this->assertEquals('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; path=/admin/; domain=.myfoodomain.com; httponly', (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 056d2e2aad253..a94e866c36fbb 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -59,11 +59,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface
protected $startTime;
protected $loadClassCache;
- const VERSION = '2.8.24';
- const VERSION_ID = 20824;
+ const VERSION = '2.8.25';
+ const VERSION_ID = 20825;
const MAJOR_VERSION = 2;
const MINOR_VERSION = 8;
- const RELEASE_VERSION = 24;
+ const RELEASE_VERSION = 25;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '11/2018';
diff --git a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php
index 16de8daaeda93..4c0a7459d070c 100644
--- a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php
+++ b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php
@@ -83,9 +83,9 @@ public function authenticate(TokenInterface $token)
break;
}
} catch (AccountStatusException $e) {
- $e->setToken($token);
+ $lastException = $e;
- throw $e;
+ break;
} catch (AuthenticationException $e) {
$lastException = $e;
}
diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationProviderManagerTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationProviderManagerTest.php
index 9b8105012c3d8..373369d455959 100644
--- a/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationProviderManagerTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationProviderManagerTest.php
@@ -13,6 +13,9 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager;
+use Symfony\Component\Security\Core\AuthenticationEvents;
+use Symfony\Component\Security\Core\Event\AuthenticationEvent;
+use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Core\Exception\ProviderNotFoundException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\AccountStatusException;
@@ -124,6 +127,50 @@ public function testEraseCredentialFlag()
$this->assertEquals('bar', $token->getCredentials());
}
+ public function testAuthenticateDispatchesAuthenticationFailureEvent()
+ {
+ $token = new UsernamePasswordToken('foo', 'bar', 'key');
+ $provider = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface')->getMock();
+ $provider->expects($this->once())->method('supports')->willReturn(true);
+ $provider->expects($this->once())->method('authenticate')->willThrowException($exception = new AuthenticationException());
+
+ $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
+ $dispatcher
+ ->expects($this->once())
+ ->method('dispatch')
+ ->with(AuthenticationEvents::AUTHENTICATION_FAILURE, $this->equalTo(new AuthenticationFailureEvent($token, $exception)));
+
+ $manager = new AuthenticationProviderManager(array($provider));
+ $manager->setEventDispatcher($dispatcher);
+
+ try {
+ $manager->authenticate($token);
+ $this->fail('->authenticate() should rethrow exceptions');
+ } catch (AuthenticationException $e) {
+ $this->assertSame($token, $exception->getToken());
+ }
+ }
+
+ public function testAuthenticateDispatchesAuthenticationSuccessEvent()
+ {
+ $token = new UsernamePasswordToken('foo', 'bar', 'key');
+
+ $provider = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface')->getMock();
+ $provider->expects($this->once())->method('supports')->willReturn(true);
+ $provider->expects($this->once())->method('authenticate')->willReturn($token);
+
+ $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
+ $dispatcher
+ ->expects($this->once())
+ ->method('dispatch')
+ ->with(AuthenticationEvents::AUTHENTICATION_SUCCESS, $this->equalTo(new AuthenticationEvent($token)));
+
+ $manager = new AuthenticationProviderManager(array($provider));
+ $manager->setEventDispatcher($dispatcher);
+
+ $this->assertSame($token, $manager->authenticate($token));
+ }
+
protected function getAuthenticationProvider($supports, $token = null, $exception = null)
{
$provider = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface')->getMock();
diff --git a/src/Symfony/Component/Security/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php b/src/Symfony/Component/Security/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php
index 7ebe65c647d99..942a4a6350f27 100644
--- a/src/Symfony/Component/Security/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php
@@ -90,6 +90,29 @@ public function testPasswordIsNotValid()
->assertRaised();
}
+ /**
+ * @dataProvider emptyPasswordData
+ */
+ public function testEmptyPasswordsAreNotValid($password)
+ {
+ $constraint = new UserPassword(array(
+ 'message' => 'myMessage',
+ ));
+
+ $this->validator->validate($password, $constraint);
+
+ $this->buildViolation('myMessage')
+ ->assertRaised();
+ }
+
+ public function emptyPasswordData()
+ {
+ return array(
+ array(null),
+ array(''),
+ );
+ }
+
/**
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
*/
diff --git a/src/Symfony/Component/Security/Core/User/UserProviderInterface.php b/src/Symfony/Component/Security/Core/User/UserProviderInterface.php
index 146ed65ad303d..9570edc2776ab 100644
--- a/src/Symfony/Component/Security/Core/User/UserProviderInterface.php
+++ b/src/Symfony/Component/Security/Core/User/UserProviderInterface.php
@@ -48,7 +48,7 @@ interface UserProviderInterface
public function loadUserByUsername($username);
/**
- * Refreshes the user for the account interface.
+ * Refreshes the user.
*
* It is up to the implementation to decide if the user data should be
* totally reloaded (e.g. from the database), or if the UserInterface
@@ -59,7 +59,7 @@ public function loadUserByUsername($username);
*
* @return UserInterface
*
- * @throws UnsupportedUserException if the account is not supported
+ * @throws UnsupportedUserException if the user is not supported
*/
public function refreshUser(UserInterface $user);
diff --git a/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php b/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php
index 5f4c146cab469..c2ab13b2f6d29 100644
--- a/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php
+++ b/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php
@@ -40,6 +40,8 @@ public function validate($password, Constraint $constraint)
}
if (null === $password || '' === $password) {
+ $this->context->addViolation($constraint->message);
+
return;
}