diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index c9bd72085e803..42d2f02fbd24f 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -44,11 +44,6 @@ jobs:
with:
fetch-depth: 2
- - name: Configure for PHP >= 8.2
- if: "matrix.php >= '8.2'"
- run: |
- composer config platform.php 8.1.99
-
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
@@ -70,7 +65,7 @@ jobs:
echo COLUMNS=120 >> $GITHUB_ENV
echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data,integration" >> $GITHUB_ENV
- echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV
+ echo COMPOSER_UP='composer update --no-progress --ansi'$([[ "${{ matrix.php }}" = "8.2" ]] && echo ' --ignore-platform-req=php+') >> $GITHUB_ENV
SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V)
SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | cut -d "'" -f2 | cut -d '.' -f 1-2)
diff --git a/CHANGELOG-4.4.md b/CHANGELOG-4.4.md
index b3498d37227df..9c685daa837a5 100644
--- a/CHANGELOG-4.4.md
+++ b/CHANGELOG-4.4.md
@@ -7,6 +7,22 @@ in 4.4 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/v4.4.0...v4.4.1
+* 4.4.46 (2022-09-30)
+
+ * bug #47547 [Ldap] Do not run ldap_set_option on failed connection (tatankat)
+ * bug #47578 [Security] Fix AbstractFormLoginAuthenticator return types (AndrolGenhald)
+ * bug #47614 [FrameworkBundle] Fix a phpdoc in mailer assertions (HeahDude)
+ * bug #47516 [HttpFoundation] Prevent BinaryFileResponse::prepare from adding content type if no content is sent (naitsirch)
+ * bug #47533 [Messenger] decode URL-encoded characters in DSN's usernames/passwords (xabbuh)
+ * bug #47530 [HttpFoundation] Always return strings from accept headers (ausi)
+ * bug #47497 [Bridge] Fix mkdir() race condition in ProxyCacheWarmer (andrey-tech)
+ * bug #47415 [HttpClient] Psr18Client ignore invalid HTTP headers (nuryagdym)
+ * bug #47435 [HttpKernel] lock when writting profiles (nicolas-grekas)
+ * bug #47437 [Mime] Fix email rendering when having inlined parts that are not related to the content (fabpot)
+ * bug #47434 [HttpFoundation] move flushing outside of Response::closeOutputBuffers (nicolas-grekas)
+ * bug #47351 [FrameworkBundle] Do not throw when describing a factory definition (MatTheCat)
+ * bug #47403 [Mailer] Fix edge cases in STMP transports (fabpot)
+
* 4.4.45 (2022-08-26)
* bug #47358 Fix broken request stack state if throwable is thrown. (Warxcell)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 167d559dc9e9f..d652d3de50a5c 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -16,15 +16,15 @@ The Symfony Connect username in parenthesis allows to get more information
- Grégoire Pineau (lyrixx)
- Wouter de Jong (wouterj)
- Maxime Steinhausser (ogizanagi)
- - Christophe Coevoet (stof)
- Kévin Dunglas (dunglas)
+ - Christophe Coevoet (stof)
- Jordi Boggiano (seldaek)
- Roland Franssen (ro0)
- Victor Berchet (victor)
- Yonel Ceruto (yonelceruto)
- Tobias Nyholm (tobias)
- - Oskar Stark (oskarstark)
- Javier Eguiluz (javier.eguiluz)
+ - Oskar Stark (oskarstark)
- Ryan Weaver (weaverryan)
- Johannes S (johannes)
- Jakub Zalas (jakubzalas)
@@ -52,8 +52,8 @@ The Symfony Connect username in parenthesis allows to get more information
- HypeMC (hypemc)
- Matthias Pigulla (mpdude)
- Laurent VOULLEMIER (lvo)
- - Pierre du Plessis (pierredup)
- Antoine Makdessi (amakdessi)
+ - Pierre du Plessis (pierredup)
- Grégoire Paris (greg0ire)
- Gabriel Ostrolucký (gadelat)
- Jonathan Wage (jwage)
@@ -76,14 +76,14 @@ The Symfony Connect username in parenthesis allows to get more information
- Bulat Shakirzyanov (avalanche123)
- Iltar van der Berg
- Miha Vrhovnik (mvrhov)
- - Saša Stamenković (umpirsky)
- Mathieu Piot (mpiot)
+ - Saša Stamenković (umpirsky)
- Alex Pott
- Guilhem N (guilhemn)
+ - Vincent Langlet (deviling)
- Vladimir Reznichenko (kalessil)
- Sarah Khalil (saro0h)
- Konstantin Kudryashov (everzet)
- - Vincent Langlet (deviling)
- Tomas Norkūnas (norkunas)
- Bilal Amarni (bamarni)
- Eriksen Costa
@@ -115,6 +115,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Maxime Helias (maxhelias)
- Ener-Getick
- Ruud Kamphuis (ruudk)
+ - Mathieu Lechat (mat_the_cat)
- Sebastiaan Stok (sstok)
- Jérôme Vasseur (jvasseur)
- Ion Bazan (ionbazan)
@@ -126,6 +127,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Bart van den Burg (burgov)
- Jordan Alliot (jalliot)
- Smaine Milianni (ismail1432)
+ - Antoine Lamirault
- John Wards (johnwards)
- Dariusz Ruminski
- Lars Strojny (lstrojny)
@@ -134,7 +136,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Konstantin.Myakshin
- Rokas Mikalkėnas (rokasm)
- Arman Hosseini (arman)
- - Antoine Lamirault
- Arnaud Le Blanc (arnaud-lb)
- Maxime STEINHAUSSER
- Peter Kokot (maastermedia)
@@ -147,7 +148,6 @@ The Symfony Connect username in parenthesis allows to get more information
- YaFou
- Gary PEGEOT (gary-p)
- Chris Wilkinson (thewilkybarkid)
- - Mathieu Lechat (mat_the_cat)
- Brice BERNARD (brikou)
- Roman Martinuk (a2a4)
- Gregor Harlan (gharlan)
@@ -159,13 +159,14 @@ The Symfony Connect username in parenthesis allows to get more information
- Jesse Rushlow (geeshoe)
- Théo FIDRY
- jeremyFreeAgent (jeremyfreeagent)
+ - Michael Babker (mbabker)
- Włodzimierz Gajda (gajdaw)
- Christian Scheb
- Guillaume (guill)
- Tugdual Saunier (tucksaun)
- Jacob Dreesen (jdreesen)
+ - Jeroen Spee (jeroens)
- Joel Wurtz (brouznouf)
- - Michael Babker (mbabker)
- Olivier Dolbeau (odolbeau)
- Florian Voutzinos (florianv)
- zairig imad (zairigimad)
@@ -173,7 +174,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Javier Spagnoletti (phansys)
- excelwebzone
- Jérôme Parmentier (lctrs)
- - Jeroen Spee (jeroens)
- HeahDude
- Richard van Laak (rvanlaak)
- Paráda József (paradajozsef)
@@ -181,6 +181,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Alexander Schwenn (xelaris)
- Fabien Pennequin (fabienpennequin)
- Gordon Franke (gimler)
+ - François-Xavier de Guillebon (de-gui_f)
- Christopher Hertel (chertel)
- Gabriel Caruso
- Anthony GRASSIOT (antograssiot)
@@ -195,6 +196,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Tigran Azatyan (tigranazatyan)
- Eric GELOEN (gelo)
- Matthieu Napoli (mnapoli)
+ - Andreas Schempp (aschempp)
- Tomáš Votruba (tomas_votruba)
- Joshua Thijssen
- Stefano Sala (stefano.sala)
@@ -211,13 +213,12 @@ The Symfony Connect username in parenthesis allows to get more information
- Timo Bakx (timobakx)
- Juti Noppornpitak (shiroyuki)
- Joe Bennett (kralos)
+ - Nate Wiebe (natewiebe13)
- Hugo Alliaume (kocal)
- Anthony MARTIN
- Colin O'Dell (colinodell)
- Sebastian Hörl (blogsh)
- Ben Davies (bendavies)
- - Andreas Schempp (aschempp)
- - François-Xavier de Guillebon (de-gui_f)
- Daniel Gomes (danielcsgomes)
- Michael Käfer (michael_kaefer)
- Hidenori Goto (hidenorigoto)
@@ -226,12 +227,12 @@ The Symfony Connect username in parenthesis allows to get more information
- Guilherme Blanco (guilhermeblanco)
- Chi-teck
- Antonio Pauletich (x-coder264)
- - Nate Wiebe (natewiebe13)
- Michael Voříšek
- SpacePossum
- Pablo Godel (pgodel)
- Romaric Drigon (romaricdrigon)
- Andréia Bohner (andreia)
+ - Dāvis Zālītis (k0d3r1s)
- Jannik Zschiesche
- Rafael Dohms (rdohms)
- George Mponos (gmponos)
@@ -257,7 +258,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Justin Hileman (bobthecow)
- Niels Keurentjes (curry684)
- Vyacheslav Pavlov
- - Dāvis Zālītis (k0d3r1s)
- Richard Shank (iampersistent)
- Andre Rømcke (andrerom)
- Dmitrii Poddubnyi (karser)
@@ -314,6 +314,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Wojciech Kania
- Alexey Kopytko (sanmai)
- Sergey Linnik (linniksa)
+ - Warxcell (warxcell)
- Richard Miller
- Leo Feyer (leofeyer)
- Mario A. Alvarez Garcia (nomack84)
@@ -346,6 +347,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Loick Piera (pyrech)
- Vitalii Ekert (comrade42)
- Clara van Miert
+ - Martin Auswöger
- Alexander Menshchikov
- Stepan Anchugov (kix)
- bronze1man
@@ -358,8 +360,8 @@ The Symfony Connect username in parenthesis allows to get more information
- Edi Modrić (emodric)
- Philipp Wahala (hifi)
- Nikolay Labinskiy (e-moe)
- - Warxcell (warxcell)
- Martin Schuhfuß (usefulthink)
+ - Phil Taylor (prazgod)
- apetitpa
- Vladyslav Loboda
- Pierre Minnieur (pminnieur)
@@ -385,7 +387,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Markus Fasselt (digilist)
- Maxime Veber (nek-)
- Marcin Sikoń (marphi)
- - Martin Auswöger
- Sullivan SENECHAL (soullivaneuh)
- Rui Marinho (ruimarinho)
- Marc Weistroff (futurecat)
@@ -404,7 +405,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Alex Bowers
- Simon Podlipsky (simpod)
- Marcel Beerta (mazen)
- - Phil Taylor (prazgod)
- flack (flack)
- Craig Duncan (duncan3dc)
- Mantis Development
@@ -500,6 +500,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Chris Tanaskoski
- julien57
- Loïc Frémont (loic425)
+ - Ippei Sumida (ippey_s)
- Ben Ramsey (ramsey)
- Matthieu Auger (matthieuauger)
- Kévin THERAGE (kevin_therage)
@@ -536,6 +537,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Soufian EZ ZANTAR (soezz)
- Jan van Thoor (janvt)
- Martin Kirilov (wucdbm)
+ - Axel Guckelsberger (guite)
- Chris Smith (cs278)
- Florian Klein (docteurklein)
- Bilge
@@ -561,6 +563,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Yannick Ihmels (ihmels)
- Saif Eddin G
- Emmanuel BORGES (eborges78)
+ - siganushka (siganushka)
- Aurelijus Valeiša (aurelijus)
- Evert Harmeling (evertharmeling)
- Jan Decavele (jandc)
@@ -633,7 +636,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Andy Palmer (andyexeter)
- Marko H. Tamminen (gzumba)
- Francesco Levorato
- - Ippei Sumida (ippey_s)
- DerManoMann
- David Molineus
- Desjardins Jérôme (jewome62)
@@ -708,7 +710,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Steve Grunwell
-
- Alex (aik099)
- - Axel Guckelsberger (guite)
- Greg Thornton (xdissent)
- BENOIT POLASZEK (bpolaszek)
- Shaharia Azam
@@ -771,7 +772,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Shakhobiddin
- Kai
- Lee Rowlands
- - siganushka (siganushka)
- Alain Hippolyte (aloneh)
- Karoly Negyesi (chx)
- Xavier HAUSHERR
@@ -903,6 +903,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Damien Fa
- Kevin McBride
- Sergio Santoro
+ - AndrolGenhald
- Philipp Rieber (bicpi)
- Dennis Væversted (srnzitcom)
- Manuel de Ruiter (manuel)
@@ -917,6 +918,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jon Dufresne
- Chad Sikorra (chadsikorra)
- Mathias Brodala (mbrodala)
+ - naitsirch (naitsirch)
- Evan S Kaufman (evanskaufman)
- Jonathan Sui Lioung Lee Slew (jlslew)
- mcben
@@ -989,6 +991,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ziumin
- Matthias Schmidt
- Lenar Lõhmus
+ - Ilija Tovilo (ilijatovilo)
- Samaël Villette (samadu61)
- Zach Badgett (zachbadgett)
- Loïc Faugeron
@@ -1001,6 +1004,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Philipp Keck
- Disquedur
- Markus S. (staabm)
+ - Guilherme Ferreira
- Geoffrey Tran (geoff)
- Elan Ruusamäe (glen)
- Brad Jones
@@ -1050,6 +1054,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Safonov Nikita (ns3777k)
- Simon DELICATA
- Thibault Buathier (gwemox)
+ - Julien Boudry
- vitaliytv
- Andreas Hennings
- Arnaud Frézet
@@ -1074,6 +1079,7 @@ The Symfony Connect username in parenthesis allows to get more information
- pizzaminded
- Matthieu Calie (matth--)
- Stéphane Escandell (sescandell)
+ - Philippe SEGATORI (tigitz)
- ivan
- linh
- Oleg Krasavin (okwinza)
@@ -1354,7 +1360,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Toni Peric (tperic)
- yclian
- Aleksey Prilipko
- - AndrolGenhald
- Andrew Berry
- Wybren Koelmans (wybren_koelmans)
- Dmytro Dzubenko
@@ -1432,6 +1437,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Dennis Hotson
- Andrew Tchircoff (andrewtch)
- Lars Vierbergen (vierbergenlars)
+ - Barney Hanlon
- Bart Wach
- Jos Elstgeest
- Kirill Lazarev
@@ -1568,6 +1574,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Gennadi Janzen
- SenTisso
- Joe Springe
+ - Ivan Kurnosov
- Flinsch
- botbotbot
- Timon van der Vorm
@@ -1675,7 +1682,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Cyrille Bourgois (cyrilleb)
- Gerard van Helden (drm)
- Johnny Peck (johnnypeck)
- - naitsirch (naitsirch)
- Geoffrey Monte (numerogeek)
- Martijn Boers (plebian)
- Plamen Mishev (pmishev)
@@ -1969,6 +1975,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Kirill Nesmeyanov (serafim)
- Reece Fowell (reecefowell)
- Guillaume Gammelin
+ - wuchen90
- Valérian Galliat
- d-ph
- Renan Taranto (renan-taranto)
@@ -1982,7 +1989,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Mikkel Paulson
- ergiegonzaga
- Liverbool (liverbool)
- - Julien Boudry
- Dalibor Karlović
- Sam Malone
- Ha Phan (haphan)
@@ -2083,8 +2089,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Troy McCabe
- Ville Mattila
- gr1ev0us
+ - Léo VINCENT
- mlazovla
- Max Beutel
+ - Nathan Sepulveda
- Antanas Arvasevicius
- Pierre Dudoret
- Michal Trojanowski
@@ -2187,6 +2195,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Vladimir Luchaninov (luchaninov)
- spdionis
- rchoquet
+ - v.shevelev
- gitlost
- Taras Girnyk
- Sergio
@@ -2201,6 +2210,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Gilles Doge (gido)
- abulford
- Philipp Kretzschmar
+ - Jairo Pastor
- Ilya Vertakov
- Brooks Boyd
- Axel Venet
@@ -2252,6 +2262,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Sergey Yuferev
- Tobias Stöckler
- Mario Young
+ - martkop26
- Sander Hagen
- Ilia (aliance)
- cilefen (cilefen)
@@ -2356,6 +2367,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Daniel Richter (richtermeister)
- Sandro Hopf (senaria)
- ChrisC
+ - jack.shpartko
- Kim Laï Trinh
- Jason Desrosiers
- m.chwedziak
@@ -2401,6 +2413,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Daniel González Zaballos (dem3trio)
- Emmanuel Vella (emmanuel.vella)
- Guillaume BRETOU (guiguiboy)
+ - nuryagdy mustapayev (nueron)
- Carsten Nielsen (phreaknerd)
- Jay Severson
- René Kerner
@@ -2614,6 +2627,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jesper Noordsij
- DerStoffel
- Maciej Schmidt
+ - tatankat
- nuncanada
- Thierry Marianne
- František Bereň
@@ -2626,6 +2640,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Kamil Madejski (kmadejski)
- Nicolas Tallefourtané (nicolab)
- Botond Dani (picur)
+ - Radek Wionczek (rwionczek)
- Nick Stemerdink
- David Stone
- Grayson Koonce
@@ -2694,6 +2709,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Artem Lopata (bumz)
- alex
- Roman Orlov
+ - Andreas Allacher
- VolCh
- Alexey Popkov
- Gijs Kunze
@@ -2779,18 +2795,21 @@ The Symfony Connect username in parenthesis allows to get more information
- Alexander Zogheb
- Rémi Blaise
- Nicolas Séverin
+ - Houssem
- Joel Marcey
- zolikonta
- David Christmann
- root
- pf
- Vincent Chalnot
+ - Patrizio Bekerle
- Tom Maguire
- Mateusz Lerczak
- Richard Quadling
- David Zuelke
- Adrian
- neFAST
+ - Peter Gribanov
- Pierre Rineau
- Florian Morello
- Maxim Lovchikov
@@ -2840,7 +2859,6 @@ The Symfony Connect username in parenthesis allows to get more information
- David Windell
- Gabriel Birke
- Derek Bonner
- - Ivan Kurnosov
- martijn
- annesosensio
- NothingWeAre
@@ -3049,6 +3067,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Neophy7e
- bokonet
- Arrilot
+ - andrey-tech
- Shaun Simmons
- Markus Staab
- Pierre-Louis LAUNAY
@@ -3120,6 +3139,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Lin Lu
- arduanov
- sualko
+ - Martin Komischke
- ADmad
- Nicolas Roudaire
- Abdouni Karim (abdounikarim)
@@ -3154,7 +3174,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Gerry Vandermaesen (gerryvdm)
- Arash Tabrizian (ghost098)
- Vladislav Krupenkin (ideea)
- - Ilija Tovilo (ilijatovilo)
- Peter Orosz (ill_logical)
- Imangazaliev Muhammad (imangazaliev)
- j0k (j0k)
diff --git a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php
index 24cf25be59f3d..08f9fef880e51 100644
--- a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php
+++ b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php
@@ -49,7 +49,7 @@ public function warmUp($cacheDir)
foreach ($this->registry->getManagers() as $em) {
// we need the directory no matter the proxy cache generation strategy
if (!is_dir($proxyCacheDir = $em->getConfiguration()->getProxyDir())) {
- if (false === @mkdir($proxyCacheDir, 0777, true)) {
+ if (false === @mkdir($proxyCacheDir, 0777, true) && !is_dir($proxyCacheDir)) {
throw new \RuntimeException(sprintf('Unable to create the Doctrine Proxy directory "%s".', $proxyCacheDir));
}
} elseif (!is_writable($proxyCacheDir)) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
index 64841b1a25d4e..3af3ec03f437a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
@@ -219,7 +219,7 @@ private function getContainerDefinitionData(Definition $definition, bool $omitTa
if ($factory[0] instanceof Reference) {
$data['factory_service'] = (string) $factory[0];
} elseif ($factory[0] instanceof Definition) {
- throw new \InvalidArgumentException('Factory is not describable.');
+ $data['factory_service'] = sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'class not configured');
} else {
$data['factory_class'] = $factory[0];
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
index a2360a094ee9a..4d48620236f79 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
@@ -196,7 +196,7 @@ protected function describeContainerDefinition(Definition $definition, array $op
if ($factory[0] instanceof Reference) {
$output .= "\n".'- Factory Service: `'.$factory[0].'`';
} elseif ($factory[0] instanceof Definition) {
- throw new \InvalidArgumentException('Factory is not describable.');
+ $output .= "\n".sprintf('- Factory Service: inline factory service (%s)', $factory[0]->getClass() ? sprintf('`%s`', $factory[0]->getClass()) : 'not configured');
} else {
$output .= "\n".'- Factory Class: `'.$factory[0].'`';
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
index 67669e5a3c3cc..5163a8730795b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
@@ -309,7 +309,7 @@ protected function describeContainerDefinition(Definition $definition, array $op
if ($factory[0] instanceof Reference) {
$tableRows[] = ['Factory Service', $factory[0]];
} elseif ($factory[0] instanceof Definition) {
- throw new \InvalidArgumentException('Factory is not describable.');
+ $tableRows[] = ['Factory Service', sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'class not configured')];
} else {
$tableRows[] = ['Factory Class', $factory[0]];
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
index 65e3dbc17b077..28044126f9a7f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
@@ -294,7 +294,7 @@ private function getContainerDefinitionDocument(Definition $definition, string $
if ($factory[0] instanceof Reference) {
$factoryXML->setAttribute('service', (string) $factory[0]);
} elseif ($factory[0] instanceof Definition) {
- throw new \InvalidArgumentException('Factory is not describable.');
+ $factoryXML->setAttribute('service', sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'not configured'));
} else {
$factoryXML->setAttribute('class', $factory[0]);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php
index d0ca84e25ae7a..fe20731a78a7b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php
@@ -91,7 +91,7 @@ public static function assertEmailAddressContains(RawMessage $email, string $hea
}
/**
- * @return MessageEvents[]
+ * @return MessageEvent[]
*/
public static function getMailerEvents(string $transport = null): array
{
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php
index a097e058be7dd..4d96e90f0ef27 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php
@@ -123,6 +123,7 @@ public static function getContainerDefinitions()
{
$definition1 = new Definition('Full\\Qualified\\Class1');
$definition2 = new Definition('Full\\Qualified\\Class2');
+ $definition3 = new Definition('Full\\Qualified\\Class3');
return [
'definition_1' => $definition1
@@ -154,6 +155,9 @@ public static function getContainerDefinitions()
->addTag('tag2')
->addMethodCall('setMailer', [new Reference('mailer')])
->setFactory([new Reference('factory.service'), 'get']),
+ '.definition_3' => $definition3
+ ->setFile('/path/to/file')
+ ->setFactory([new Definition('Full\\Qualified\\FactoryClass'), 'get']),
'definition_without_class' => new Definition(),
];
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json
index 0eda1932f7a15..401c588c03d42 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json
@@ -34,6 +34,20 @@
"parameters": []
}
]
+ },
+ ".definition_3": {
+ "class": "Full\\Qualified\\Class3",
+ "public": false,
+ "synthetic": false,
+ "lazy": false,
+ "shared": true,
+ "abstract": false,
+ "autowire": false,
+ "autoconfigure": false,
+ "file": "\/path\/to\/file",
+ "factory_service": "inline factory service (Full\\Qualified\\FactoryClass)",
+ "factory_method": "get",
+ "tags": []
}
},
"aliases": {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md
index 2d0edfd01952e..f8667daa86793 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md
@@ -25,6 +25,20 @@ Definitions
- Attr3: val3
- Tag: `tag2`
+### .definition_3
+
+- Class: `Full\Qualified\Class3`
+- Public: no
+- Synthetic: no
+- Lazy: no
+- Shared: yes
+- Abstract: no
+- Autowired: no
+- Autoconfigured: no
+- File: `/path/to/file`
+- Factory Service: inline factory service (`Full\Qualified\FactoryClass`)
+- Factory Method: `get`
+
Aliases
-------
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.txt
index 82b4909242d84..daf47ddc39187 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.txt
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.txt
@@ -7,5 +7,6 @@
--------------- ------------------------
.alias_2 alias for ".service_2"
.definition_2 Full\Qualified\Class2
+ .definition_3 Full\Qualified\Class3
--------------- ------------------------
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml
index a311a2e2bb991..b9416fd069d05 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml
@@ -17,4 +17,7 @@
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json
new file mode 100644
index 0000000000000..4bf56746493f8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json
@@ -0,0 +1,14 @@
+{
+ "class": "Full\\Qualified\\Class3",
+ "public": false,
+ "synthetic": false,
+ "lazy": false,
+ "shared": true,
+ "abstract": false,
+ "autowire": false,
+ "autoconfigure": false,
+ "file": "\/path\/to\/file",
+ "factory_service": "inline factory service (Full\\Qualified\\FactoryClass)",
+ "factory_method": "get",
+ "tags": []
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md
new file mode 100644
index 0000000000000..68f51634db99f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md
@@ -0,0 +1,11 @@
+- Class: `Full\Qualified\Class3`
+- Public: no
+- Synthetic: no
+- Lazy: no
+- Shared: yes
+- Abstract: no
+- Autowired: no
+- Autoconfigured: no
+- File: `/path/to/file`
+- Factory Service: inline factory service (`Full\Qualified\FactoryClass`)
+- Factory Method: `get`
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt
new file mode 100644
index 0000000000000..35ddaf3e452a8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt
@@ -0,0 +1,18 @@
+ ----------------- ------------------------------------------------------
+ [32m Option [39m [32m Value [39m
+ ----------------- ------------------------------------------------------
+ Service ID -
+ Class Full\Qualified\Class3
+ Tags -
+ Public no
+ Synthetic no
+ Lazy no
+ Shared yes
+ Abstract no
+ Autowired no
+ Autoconfigured no
+ Required File /path/to/file
+ Factory Service inline factory service (Full\Qualified\FactoryClass)
+ Factory Method get
+ ----------------- ------------------------------------------------------
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml
new file mode 100644
index 0000000000000..e81c77014253f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json
new file mode 100644
index 0000000000000..94c2fda5402fc
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json
@@ -0,0 +1,15 @@
+{
+ "class": "Full\\Qualified\\Class3",
+ "public": false,
+ "synthetic": false,
+ "lazy": false,
+ "shared": true,
+ "abstract": false,
+ "autowire": false,
+ "autoconfigure": false,
+ "arguments": [],
+ "file": "\/path\/to\/file",
+ "factory_service": "inline factory service (Full\\Qualified\\FactoryClass)",
+ "factory_method": "get",
+ "tags": []
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md
new file mode 100644
index 0000000000000..2ce1f264dfc6c
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md
@@ -0,0 +1,12 @@
+- Class: `Full\Qualified\Class3`
+- Public: no
+- Synthetic: no
+- Lazy: no
+- Shared: yes
+- Abstract: no
+- Autowired: no
+- Autoconfigured: no
+- Arguments: no
+- File: `/path/to/file`
+- Factory Service: inline factory service (`Full\Qualified\FactoryClass`)
+- Factory Method: `get`
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt
new file mode 100644
index 0000000000000..6e400de44e8ff
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt
@@ -0,0 +1,18 @@
+ ----------------- ------------------------------------------------------
+ [32m Option [39m [32m Value [39m
+ ----------------- ------------------------------------------------------
+ Service ID -
+ Class Full\Qualified\Class3
+ Tags -
+ Public no
+ Synthetic no
+ Lazy no
+ Shared yes
+ Abstract no
+ Autowired no
+ Autoconfigured no
+ Required File /path/to/file
+ Factory Service inline factory service (Full\Qualified\FactoryClass)
+ Factory Method get
+ ----------------- ------------------------------------------------------
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml
new file mode 100644
index 0000000000000..e81c77014253f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
index e7ce0ec218976..d752cd4c2f13d 100644
--- a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
+++ b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
@@ -46,7 +46,7 @@ public function applyVersion($path)
{
$versionized = sprintf($this->format, ltrim($path, '/'), $this->getVersion($path));
- if ($path && '/' == $path[0]) {
+ if ($path && '/' === $path[0]) {
return '/'.$versionized;
}
diff --git a/src/Symfony/Component/Cache/README.md b/src/Symfony/Component/Cache/README.md
index 74052052c8c33..c466d57883c2f 100644
--- a/src/Symfony/Component/Cache/README.md
+++ b/src/Symfony/Component/Cache/README.md
@@ -1,13 +1,13 @@
Symfony PSR-6 implementation for caching
========================================
-The Cache component provides an extended
-[PSR-6](http://www.php-fig.org/psr/psr-6/) implementation for adding cache to
+The Cache component provides extended
+[PSR-6](https://www.php-fig.org/psr/psr-6/) implementations for adding cache to
your applications. It is designed to have a low overhead so that caching is
-fastest. It ships with a few caching adapters for the most widespread and
-suited to caching backends. It also provides a `doctrine/cache` proxy adapter
-to cover more advanced caching needs and a proxy adapter for greater
-interoperability between PSR-6 implementations.
+fastest. It ships with adapters for the most widespread caching backends.
+It also provides a [PSR-16](https://www.php-fig.org/psr/psr-16/) adapter,
+and implementations for [symfony/cache-contracts](https://github.com/symfony/cache-contracts)'
+`CacheInterface` and `TagAwareCacheInterface`.
Resources
---------
diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json
index 6ef5eac991d20..7a9e8df5a40e4 100644
--- a/src/Symfony/Component/Cache/composer.json
+++ b/src/Symfony/Component/Cache/composer.json
@@ -1,7 +1,7 @@
{
"name": "symfony/cache",
"type": "library",
- "description": "Provides an extended PSR-6, PSR-16 (and tags) implementation",
+ "description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
"keywords": ["caching", "psr6"],
"homepage": "https://symfony.com",
"license": "MIT",
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
index 51d42494d1def..bae85a86fbec5 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
@@ -121,7 +121,7 @@ public function reverseTransform($value)
$outputTz = new \DateTimeZone($this->outputTimezone);
$dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
- $lastErrors = \DateTime::getLastErrors();
+ $lastErrors = \DateTime::getLastErrors() ?: ['error_count' => 0, 'warning_count' => 0];
if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {
throw new TransformationFailedException(implode(', ', array_merge(array_values($lastErrors['warnings']), array_values($lastErrors['errors']))));
diff --git a/src/Symfony/Component/HttpClient/Psr18Client.php b/src/Symfony/Component/HttpClient/Psr18Client.php
index 67c2fdb8f07bc..7f79af16426a1 100644
--- a/src/Symfony/Component/HttpClient/Psr18Client.php
+++ b/src/Symfony/Component/HttpClient/Psr18Client.php
@@ -100,7 +100,11 @@ public function sendRequest(RequestInterface $request): ResponseInterface
foreach ($response->getHeaders(false) as $name => $values) {
foreach ($values as $value) {
- $psrResponse = $psrResponse->withAddedHeader($name, $value);
+ try {
+ $psrResponse = $psrResponse->withAddedHeader($name, $value);
+ } catch (\InvalidArgumentException $e) {
+ // ignore invalid header
+ }
}
}
diff --git a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php
index 1ef36fc5bd09e..366d555ae03f9 100644
--- a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php
@@ -13,10 +13,12 @@
use Nyholm\Psr7\Factory\Psr17Factory;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\NativeHttpClient;
use Symfony\Component\HttpClient\Psr18Client;
use Symfony\Component\HttpClient\Psr18NetworkException;
use Symfony\Component\HttpClient\Psr18RequestException;
+use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Contracts\HttpClient\Test\TestHttpServer;
class Psr18ClientTest extends TestCase
@@ -81,4 +83,22 @@ public function test404()
$response = $client->sendRequest($factory->createRequest('GET', 'http://localhost:8057/404'));
$this->assertSame(404, $response->getStatusCode());
}
+
+ public function testInvalidHeaderResponse()
+ {
+ $responseHeaders = [
+ // space in header name not allowed in RFC 7230
+ ' X-XSS-Protection' => '0',
+ 'Cache-Control' => 'no-cache',
+ ];
+ $response = new MockResponse('body', ['response_headers' => $responseHeaders]);
+ $this->assertArrayHasKey(' x-xss-protection', $response->getHeaders());
+
+ $client = new Psr18Client(new MockHttpClient($response));
+ $request = $client->createRequest('POST', 'http://localhost:8057/post')
+ ->withBody($client->createStream('foo=0123456789'));
+
+ $resultResponse = $client->sendRequest($request);
+ $this->assertCount(1, $resultResponse->getHeaders());
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
index f44eb6daf44e9..2cd105c3bb0f3 100644
--- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
+++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
@@ -201,15 +201,17 @@ public function setContentDisposition($disposition, $filename = '', $filenameFal
*/
public function prepare(Request $request)
{
- if (!$this->headers->has('Content-Type')) {
- $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
- }
+ parent::prepare($request);
- if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) {
- $this->setProtocolVersion('1.1');
+ if ($this->isInformational() || $this->isEmpty()) {
+ $this->maxlen = 0;
+
+ return $this;
}
- $this->ensureIEOverSSLCompatibility($request);
+ if (!$this->headers->has('Content-Type')) {
+ $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
+ }
$this->offset = 0;
$this->maxlen = -1;
@@ -217,6 +219,7 @@ public function prepare(Request $request)
if (false === $fileSize = $this->file->getSize()) {
return $this;
}
+ $this->headers->remove('Transfer-Encoding');
$this->headers->set('Content-Length', $fileSize);
if (!$this->headers->has('Accept-Ranges')) {
@@ -286,6 +289,10 @@ public function prepare(Request $request)
}
}
+ if ($request->isMethod('HEAD')) {
+ $this->maxlen = 0;
+ }
+
return $this;
}
@@ -309,40 +316,42 @@ private function hasValidIfRangeHeader(?string $header): bool
*/
public function sendContent()
{
- if (!$this->isSuccessful()) {
- return parent::sendContent();
- }
+ try {
+ if (!$this->isSuccessful()) {
+ return parent::sendContent();
+ }
- if (0 === $this->maxlen) {
- return $this;
- }
+ if (0 === $this->maxlen) {
+ return $this;
+ }
- $out = fopen('php://output', 'w');
- $file = fopen($this->file->getPathname(), 'r');
+ $out = fopen('php://output', 'w');
+ $file = fopen($this->file->getPathname(), 'r');
- ignore_user_abort(true);
+ ignore_user_abort(true);
- if (0 !== $this->offset) {
- fseek($file, $this->offset);
- }
+ if (0 !== $this->offset) {
+ fseek($file, $this->offset);
+ }
- $length = $this->maxlen;
- while ($length && !feof($file)) {
- $read = ($length > $this->chunkSize) ? $this->chunkSize : $length;
- $length -= $read;
+ $length = $this->maxlen;
+ while ($length && !feof($file)) {
+ $read = ($length > $this->chunkSize) ? $this->chunkSize : $length;
+ $length -= $read;
- stream_copy_to_stream($file, $out, $read);
+ stream_copy_to_stream($file, $out, $read);
- if (connection_aborted()) {
- break;
+ if (connection_aborted()) {
+ break;
+ }
}
- }
- fclose($out);
- fclose($file);
-
- if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) {
- unlink($this->file->getPathname());
+ fclose($out);
+ fclose($file);
+ } finally {
+ if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) {
+ unlink($this->file->getPathname());
+ }
}
return $this;
diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php
index 4b2c4d96752c4..32e07b532e379 100644
--- a/src/Symfony/Component/HttpFoundation/Request.php
+++ b/src/Symfony/Component/HttpFoundation/Request.php
@@ -1646,7 +1646,8 @@ public function getLanguages()
$languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
$this->languages = [];
- foreach ($languages as $lang => $acceptHeaderItem) {
+ foreach ($languages as $acceptHeaderItem) {
+ $lang = $acceptHeaderItem->getValue();
if (str_contains($lang, '-')) {
$codes = explode('-', $lang);
if ('i' === $codes[0]) {
@@ -1684,7 +1685,7 @@ public function getCharsets()
return $this->charsets;
}
- return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all());
+ return $this->charsets = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all()));
}
/**
@@ -1698,7 +1699,7 @@ public function getEncodings()
return $this->encodings;
}
- return $this->encodings = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all());
+ return $this->encodings = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all()));
}
/**
@@ -1712,7 +1713,7 @@ public function getAcceptableContentTypes()
return $this->acceptableContentTypes;
}
- return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all());
+ return $this->acceptableContentTypes = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all()));
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php
index c14a7bbfdfcb5..75f64fa9eb907 100644
--- a/src/Symfony/Component/HttpFoundation/Response.php
+++ b/src/Symfony/Component/HttpFoundation/Response.php
@@ -384,6 +384,7 @@ public function send()
fastcgi_finish_request();
} elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
static::closeOutputBuffers(0, true);
+ flush();
}
return $this;
@@ -1236,7 +1237,6 @@ public static function closeOutputBuffers(int $targetLevel, bool $flush): void
while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || ($s['flags'] & $flags) === $flags : $s['del'])) {
if ($flush) {
ob_end_flush();
- flush();
} else {
ob_end_clean();
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php
index f88c8a48df1aa..4e4ddbf4446ef 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php
@@ -373,6 +373,21 @@ public function testStream()
$this->assertNull($response->headers->get('Content-Length'));
}
+ public function testPrepareNotAddingContentTypeHeaderIfNoContentResponse()
+ {
+ $request = Request::create('/');
+ $request->headers->set('If-Modified-Since', date('D, d M Y H:i:s').' GMT');
+
+ $response = new BinaryFileResponse(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']);
+ $response->setLastModified(new \DateTimeImmutable('-1 day'));
+ $response->isNotModified($request);
+
+ $response->prepare($request);
+
+ $this->assertSame(BinaryFileResponse::HTTP_NOT_MODIFIED, $response->getStatusCode());
+ $this->assertFalse($response->headers->has('Content-Type'));
+ }
+
protected function provideResponse()
{
return new BinaryFileResponse(__DIR__.'/../README.md', 200, ['Content-Type' => 'application/octet-stream']);
diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
index 6035dd5d32da9..060de405e58ae 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
@@ -1582,6 +1582,20 @@ public function testGetLanguages()
$this->assertEquals(['zh', 'cherokee'], $request->getLanguages());
}
+ public function testGetAcceptHeadersReturnString()
+ {
+ $request = new Request();
+ $request->headers->set('Accept', '123');
+ $request->headers->set('Accept-Charset', '123');
+ $request->headers->set('Accept-Encoding', '123');
+ $request->headers->set('Accept-Language', '123');
+
+ $this->assertSame(['123'], $request->getAcceptableContentTypes());
+ $this->assertSame(['123'], $request->getCharsets());
+ $this->assertSame(['123'], $request->getEncodings());
+ $this->assertSame(['123'], $request->getLanguages());
+ }
+
public function testGetRequestFormat()
{
$request = new Request();
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index adb9a94727c5e..c6476b615d29a 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -76,11 +76,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private static $freshCache = [];
- public const VERSION = '4.4.45';
- public const VERSION_ID = 40445;
+ public const VERSION = '4.4.46';
+ public const VERSION_ID = 40446;
public const MAJOR_VERSION = 4;
public const MINOR_VERSION = 4;
- public const RELEASE_VERSION = 45;
+ public const RELEASE_VERSION = 46;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '11/2022';
diff --git a/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php
index d729994c1f0cc..aa494691d1fc1 100644
--- a/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php
+++ b/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php
@@ -115,19 +115,7 @@ public function purge()
*/
public function read($token): ?Profile
{
- if (!$token || !file_exists($file = $this->getFilename($token))) {
- return null;
- }
-
- if (\function_exists('gzcompress')) {
- $file = 'compress.zlib://'.$file;
- }
-
- if (!$data = unserialize(file_get_contents($file))) {
- return null;
- }
-
- return $this->createProfileFromData($token, $data);
+ return $this->doRead($token);
}
/**
@@ -169,14 +157,13 @@ public function write(Profile $profile): bool
'status_code' => $profile->getStatusCode(),
];
- $context = stream_context_create();
+ $data = serialize($data);
- if (\function_exists('gzcompress')) {
- $file = 'compress.zlib://'.$file;
- stream_context_set_option($context, 'zlib', 'level', 3);
+ if (\function_exists('gzencode')) {
+ $data = gzencode($data, 3);
}
- if (false === file_put_contents($file, serialize($data), 0, $context)) {
+ if (false === file_put_contents($file, $data, \LOCK_EX)) {
return false;
}
@@ -293,21 +280,34 @@ protected function createProfileFromData($token, $data, $parent = null)
}
foreach ($data['children'] as $token) {
- if (!$token || !file_exists($file = $this->getFilename($token))) {
- continue;
+ if (null !== $childProfile = $this->doRead($token, $profile)) {
+ $profile->addChild($childProfile);
}
+ }
- if (\function_exists('gzcompress')) {
- $file = 'compress.zlib://'.$file;
- }
+ return $profile;
+ }
- if (!$childData = unserialize(file_get_contents($file))) {
- continue;
- }
+ private function doRead($token, Profile $profile = null): ?Profile
+ {
+ if (!$token || !file_exists($file = $this->getFilename($token))) {
+ return null;
+ }
+
+ $h = fopen($file, 'r');
+ flock($h, \LOCK_SH);
+ $data = stream_get_contents($h);
+ flock($h, \LOCK_UN);
+ fclose($h);
- $profile->addChild($this->createProfileFromData($token, $childData, $profile));
+ if (\function_exists('gzdecode')) {
+ $data = @gzdecode($data) ?: $data;
}
- return $profile;
+ if (!$data = unserialize($data)) {
+ return null;
+ }
+
+ return $this->createProfileFromData($token, $data, $profile);
}
}
diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php
index defed4e35a787..9bd9cef35ce35 100644
--- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php
+++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php
@@ -159,7 +159,11 @@ private function connect()
}
}
- $this->connection = ldap_connect($this->config['connection_string']);
+ if (false === $connection = ldap_connect($this->config['connection_string'])) {
+ throw new LdapException('Invalid connection string: '.$this->config['connection_string']);
+ } else {
+ $this->connection = $connection;
+ }
foreach ($this->config['options'] as $name => $value) {
if (!\in_array(ConnectionOptions::getOption($name), self::PRECONNECT_OPTIONS, true)) {
@@ -167,10 +171,6 @@ private function connect()
}
}
- if (false === $this->connection) {
- throw new LdapException('Could not connect to Ldap server: '.ldap_error($this->connection));
- }
-
if ('tls' === $this->config['encryption'] && false === @ldap_start_tls($this->connection)) {
throw new LdapException('Could not initiate TLS connection: '.ldap_error($this->connection));
}
diff --git a/src/Symfony/Component/Lock/composer.json b/src/Symfony/Component/Lock/composer.json
index f7f8f84cc16db..1cd15c22a9e10 100644
--- a/src/Symfony/Component/Lock/composer.json
+++ b/src/Symfony/Component/Lock/composer.json
@@ -21,11 +21,11 @@
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
- "doctrine/dbal": "^2.6|^3.0",
+ "doctrine/dbal": "^2.7|^3.0",
"predis/predis": "~1.0"
},
"conflict": {
- "doctrine/dbal": "<2.6"
+ "doctrine/dbal": "<2.7"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Lock\\": "" },
diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php
index 5f8d3ba0d8180..c54b050b92963 100644
--- a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php
+++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php
@@ -13,6 +13,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mailer\Envelope;
+use Symfony\Component\Mailer\Exception\LogicException;
use Symfony\Component\Mailer\Exception\TransportException;
use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport;
use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream;
@@ -133,6 +134,35 @@ public function testWriteEncodedRecipientAndSenderAddresses()
$this->assertContains("RCPT TO:\r\n", $stream->getCommands());
$this->assertContains("RCPT TO:\r\n", $stream->getCommands());
}
+
+ public function testAssertResponseCodeNoCodes()
+ {
+ $this->expectException(LogicException::class);
+ $this->invokeAssertResponseCode('response', []);
+ }
+
+ public function testAssertResponseCodeWithEmptyResponse()
+ {
+ $this->expectException(TransportException::class);
+ $this->expectExceptionMessage('Expected response code "220" but got empty code.');
+ $this->invokeAssertResponseCode('', [220]);
+ }
+
+ public function testAssertResponseCodeWithNotValidCode()
+ {
+ $this->expectException(TransportException::class);
+ $this->expectExceptionMessage('Expected response code "220" but got code "550", with message "550 Access Denied".');
+ $this->expectExceptionCode(550);
+ $this->invokeAssertResponseCode('550 Access Denied', [220]);
+ }
+
+ private function invokeAssertResponseCode(string $response, array $codes): void
+ {
+ $transport = new SmtpTransport($this->getMockForAbstractClass(AbstractStream::class));
+ $m = new \ReflectionMethod($transport, 'assertResponseCode');
+ $m->setAccessible(true);
+ $m->invoke($transport, $response, $codes);
+ }
}
class DummyStream extends AbstractStream
diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php
index 25006fbb7d326..da2498aa0dc02 100644
--- a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php
+++ b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php
@@ -94,7 +94,9 @@ public function addAuthenticator(AuthenticatorInterface $authenticator): void
protected function doHeloCommand(): void
{
- $capabilities = $this->callHeloCommand();
+ if (!$capabilities = $this->callHeloCommand()) {
+ return;
+ }
/** @var SocketStream $stream */
$stream = $this->getStream();
@@ -123,6 +125,8 @@ private function callHeloCommand(): array
} catch (TransportExceptionInterface $e) {
try {
parent::doHeloCommand();
+
+ return [];
} catch (TransportExceptionInterface $ex) {
if (!$ex->getCode()) {
throw $e;
diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php
index 3c05e94e376d1..517aa0c31906a 100644
--- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php
+++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php
@@ -301,7 +301,8 @@ private function assertResponseCode(string $response, array $codes): void
if (!$valid || !$response) {
$codeStr = $code ? sprintf('code "%s"', $code) : 'empty code';
$responseStr = $response ? sprintf(', with message "%s"', trim($response)) : '';
- throw new TransportException(sprintf('Expected response code "%s" but got ', implode('/', $codes), $codeStr).$codeStr.$responseStr.'.', $code);
+
+ throw new TransportException(sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0);
}
}
diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php
index ab7771b9aedfc..5c27ed9415818 100644
--- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php
+++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php
@@ -230,15 +230,20 @@ private function guessHandledClasses(\ReflectionClass $handlerClass, string $ser
if ($type instanceof \ReflectionUnionType) {
$types = [];
+ $invalidTypes = [];
foreach ($type->getTypes() as $type) {
if (!$type->isBuiltin()) {
$types[] = (string) $type;
+ } else {
+ $invalidTypes[] = (string) $type;
}
}
if ($types) {
return $types;
}
+
+ throw new RuntimeException(sprintf('Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.', $serviceId, $parameters[0]->getName(), $handlerClass->getName(), implode('|', $invalidTypes)));
}
if ($type->isBuiltin()) {
diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php
index 940c32b374742..82fe774f2469d 100644
--- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php
+++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php
@@ -31,6 +31,7 @@
use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
+use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage;
use Symfony\Component\Messenger\Tests\Fixtures\DummyCommand;
use Symfony\Component\Messenger\Tests\Fixtures\DummyCommandHandler;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
@@ -39,6 +40,8 @@
use Symfony\Component\Messenger\Tests\Fixtures\MultipleBusesMessage;
use Symfony\Component\Messenger\Tests\Fixtures\MultipleBusesMessageHandler;
use Symfony\Component\Messenger\Tests\Fixtures\SecondMessage;
+use Symfony\Component\Messenger\Tests\Fixtures\UnionBuiltinTypeArgumentHandler;
+use Symfony\Component\Messenger\Tests\Fixtures\UnionTypeArgumentHandler;
use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver;
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
@@ -474,6 +477,43 @@ public function testBuiltinArgumentTypeHandler()
(new MessengerPass())->process($container);
}
+ /**
+ * @requires PHP 8
+ */
+ public function testUnionTypeArgumentsTypeHandler()
+ {
+ $container = $this->getContainerBuilder($busId = 'message_bus');
+ $container
+ ->register(UnionTypeArgumentHandler::class, UnionTypeArgumentHandler::class)
+ ->addTag('messenger.message_handler')
+ ;
+
+ (new MessengerPass())->process($container);
+
+ $handlersMapping = $container->getDefinition($busId.'.messenger.handlers_locator')->getArgument(0);
+
+ $this->assertArrayHasKey(ChildDummyMessage::class, $handlersMapping);
+ $this->assertArrayHasKey(DummyMessage::class, $handlersMapping);
+ $this->assertHandlerDescriptor($container, $handlersMapping, ChildDummyMessage::class, [UnionTypeArgumentHandler::class]);
+ $this->assertHandlerDescriptor($container, $handlersMapping, DummyMessage::class, [UnionTypeArgumentHandler::class]);
+ }
+
+ /**
+ * @requires PHP 8
+ */
+ public function testUnionBuiltinArgumentTypeHandler()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage(sprintf('Invalid handler service "%s": type-hint of argument "$message" in method "%s::__invoke()" must be a class , "string|int" given.', UnionBuiltinTypeArgumentHandler::class, UnionBuiltinTypeArgumentHandler::class));
+ $container = $this->getContainerBuilder();
+ $container
+ ->register(UnionBuiltinTypeArgumentHandler::class, UnionBuiltinTypeArgumentHandler::class)
+ ->addTag('messenger.message_handler')
+ ;
+
+ (new MessengerPass())->process($container);
+ }
+
public function testNeedsToHandleAtLeastOneMessage()
{
$this->expectException(RuntimeException::class);
diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/UnionBuiltinTypeArgumentHandler.php b/src/Symfony/Component/Messenger/Tests/Fixtures/UnionBuiltinTypeArgumentHandler.php
new file mode 100644
index 0000000000000..6061651de187b
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Tests/Fixtures/UnionBuiltinTypeArgumentHandler.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Messenger\Tests\Fixtures;
+
+class UnionBuiltinTypeArgumentHandler
+{
+ public function __invoke(string|int $message): void
+ {
+ }
+}
diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/UnionTypeArgumentHandler.php b/src/Symfony/Component/Messenger/Tests/Fixtures/UnionTypeArgumentHandler.php
new file mode 100644
index 0000000000000..85be3662ac974
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Tests/Fixtures/UnionTypeArgumentHandler.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Messenger\Tests\Fixtures;
+
+class UnionTypeArgumentHandler
+{
+ public function __invoke(ChildDummyMessage|DummyMessage $message): void
+ {
+ }
+}
diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php
index 2dba7d9f1045b..6f36a39250b36 100644
--- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php
+++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php
@@ -126,11 +126,11 @@ public static function fromDsn(string $dsn, array $options = [], AmqpFactory $am
], $options, $parsedQuery);
if (isset($parsedUrl['user'])) {
- $amqpOptions['login'] = $parsedUrl['user'];
+ $amqpOptions['login'] = urldecode($parsedUrl['user']);
}
if (isset($parsedUrl['pass'])) {
- $amqpOptions['password'] = $parsedUrl['pass'];
+ $amqpOptions['password'] = urldecode($parsedUrl['pass']);
}
if (!isset($amqpOptions['queues'])) {
diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
index 29eb6cb12e0d9..7f9f876dc54f4 100644
--- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
+++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
@@ -93,8 +93,8 @@ public static function fromDsn(string $dsn, array $redisOptions = [], \Redis $re
$stream = $pathParts[1] ?? $redisOptions['stream'] ?? null;
$group = $pathParts[2] ?? $redisOptions['group'] ?? null;
$consumer = $pathParts[3] ?? $redisOptions['consumer'] ?? null;
- $pass = '' !== ($parsedUrl['pass'] ?? '') ? $parsedUrl['pass'] : null;
- $user = '' !== ($parsedUrl['user'] ?? '') ? $parsedUrl['user'] : null;
+ $pass = '' !== ($parsedUrl['pass'] ?? '') ? urldecode($parsedUrl['pass']) : null;
+ $user = '' !== ($parsedUrl['user'] ?? '') ? urldecode($parsedUrl['user']) : null;
$connectionCredentials = [
'host' => $parsedUrl['host'] ?? '127.0.0.1',
diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json
index fd8aabb747cb9..1859442a96dab 100644
--- a/src/Symfony/Component/Messenger/composer.json
+++ b/src/Symfony/Component/Messenger/composer.json
@@ -21,7 +21,7 @@
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
- "doctrine/dbal": "^2.6|^3.0",
+ "doctrine/dbal": "^2.7|^3.0",
"doctrine/persistence": "^1.3|^2|^3",
"psr/cache": "^1.0|^2.0|^3.0",
"symfony/console": "^3.4|^4.0|^5.0",
@@ -36,6 +36,7 @@
"symfony/validator": "^3.4|^4.0|^5.0"
},
"conflict": {
+ "doctrine/dbal": "<2.7",
"doctrine/persistence": "<1.3",
"symfony/event-dispatcher": "<4.3",
"symfony/framework-bundle": "<4.4",
diff --git a/src/Symfony/Component/Mime/Email.php b/src/Symfony/Component/Mime/Email.php
index 9cdde13e533c6..70ea745788e8a 100644
--- a/src/Symfony/Component/Mime/Email.php
+++ b/src/Symfony/Component/Mime/Email.php
@@ -463,7 +463,7 @@ private function generateBody(): AbstractPart
$this->ensureValidity();
- [$htmlPart, $attachmentParts, $inlineParts] = $this->prepareParts();
+ [$htmlPart, $otherParts, $relatedParts] = $this->prepareParts();
$part = null === $this->text ? null : new TextPart($this->text, $this->textCharset);
if (null !== $htmlPart) {
@@ -474,15 +474,15 @@ private function generateBody(): AbstractPart
}
}
- if ($inlineParts) {
- $part = new RelatedPart($part, ...$inlineParts);
+ if ($relatedParts) {
+ $part = new RelatedPart($part, ...$relatedParts);
}
- if ($attachmentParts) {
+ if ($otherParts) {
if ($part) {
- $part = new MixedPart($part, ...$attachmentParts);
+ $part = new MixedPart($part, ...$otherParts);
} else {
- $part = new MixedPart(...$attachmentParts);
+ $part = new MixedPart(...$otherParts);
}
}
@@ -508,42 +508,44 @@ private function prepareParts(): ?array
}
// usage of reflection is a temporary workaround for missing getters that will be added in 6.2
- $dispositionRef = new \ReflectionProperty(TextPart::class, 'disposition');
- $dispositionRef->setAccessible(true);
$nameRef = new \ReflectionProperty(TextPart::class, 'name');
$nameRef->setAccessible(true);
- $attachmentParts = $inlineParts = [];
+ $otherParts = $relatedParts = [];
foreach ($this->attachments as $attachment) {
$part = $this->createDataPart($attachment);
if (isset($attachment['part'])) {
$attachment['name'] = $nameRef->getValue($part);
}
+ $related = false;
foreach ($names as $name) {
if ($name !== $attachment['name']) {
continue;
}
- if (isset($inlineParts[$name])) {
+ if (isset($relatedParts[$name])) {
continue 2;
}
$part->setDisposition('inline');
- $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html);
+ $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html, $count);
+ if ($count) {
+ $related = true;
+ }
$part->setName($part->getContentId());
break;
}
- if ('inline' === $dispositionRef->getValue($part)) {
- $inlineParts[$attachment['name']] = $part;
+ if ($related) {
+ $relatedParts[$attachment['name']] = $part;
} else {
- $attachmentParts[] = $part;
+ $otherParts[] = $part;
}
}
if (null !== $htmlPart) {
$htmlPart = new TextPart($html, $this->htmlCharset, 'html');
}
- return [$htmlPart, $attachmentParts, array_values($inlineParts)];
+ return [$htmlPart, $otherParts, array_values($relatedParts)];
}
private function createDataPart(array $attachment): DataPart
diff --git a/src/Symfony/Component/Mime/Tests/EmailTest.php b/src/Symfony/Component/Mime/Tests/EmailTest.php
index a79a785576361..2d03a8a9aeedd 100644
--- a/src/Symfony/Component/Mime/Tests/EmailTest.php
+++ b/src/Symfony/Component/Mime/Tests/EmailTest.php
@@ -302,6 +302,17 @@ public function testGenerateBodyWithHtmlContentAndAttachedFile()
$this->assertEquals(new MixedPart($html, $filePart), $e->getBody());
}
+ public function testGenerateBodyWithHtmlContentAndInlineImageNotreferenced()
+ {
+ [$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts();
+ $imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r'));
+ $imagePart->asInline();
+ $e = (new Email())->from('me@example.com')->to('you@example.com');
+ $e->embed($image);
+ $e->html('html content');
+ $this->assertEquals(new MixedPart($html, $imagePart), $e->getBody());
+ }
+
public function testGenerateBodyWithAttachedFileOnly()
{
[$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts();
@@ -310,6 +321,24 @@ public function testGenerateBodyWithAttachedFileOnly()
$this->assertEquals(new MixedPart($filePart), $e->getBody());
}
+ public function testGenerateBodyWithInlineImageOnly()
+ {
+ $imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r'));
+ $imagePart->asInline();
+ $e = (new Email())->from('me@example.com')->to('you@example.com');
+ $e->embed($image);
+ $this->assertEquals(new MixedPart($imagePart), $e->getBody());
+ }
+
+ public function testGenerateBodyWithEmbeddedImageOnly()
+ {
+ $imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r'));
+ $e = (new Email())->from('me@example.com')->to('you@example.com');
+ $e->embed($image);
+ $imagePart->asInline();
+ $this->assertEquals(new MixedPart($imagePart), $e->getBody());
+ }
+
public function testGenerateBodyWithTextAndHtmlContentAndAttachedFile()
{
[$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts();
diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.nb.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.nb.xlf
index 2d3a87c793ddf..7e75773798bf3 100644
--- a/src/Symfony/Component/Security/Core/Resources/translations/security.nb.xlf
+++ b/src/Symfony/Component/Security/Core/Resources/translations/security.nb.xlf
@@ -70,6 +70,14 @@
Invalid or expired login link.
Ugyldig eller utløpt påloggingskobling.
+
+ Too many failed login attempts, please try again in %minutes% minute.
+ For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutt.
+
+
+ Too many failed login attempts, please try again in %minutes% minutes.
+ For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutter.
+