Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 609ee2d

Browse filesBrowse files
committed
Merge branch '2.7' into 2.8
* 2.7: [Routing] Add missing options in docblock [VarDumper] Fix dumping continuations [HttpFoundation] fixed Request::getContent() reusage bug [Form] Skip CSRF validation on form when POST max size is exceeded Enhance the phpDoc return types so IDEs can handle the configuration tree. fixes Remove 3.0 from branch suggestions for fixes in PR template [Process] Strengthen Windows pipe files opening (again...) Fix #19531 [Form] DateType fails parsing when midnight is not a valid time
2 parents 4009b5e + adb7033 commit 609ee2d
Copy full SHA for 609ee2d

File tree

20 files changed

+191
-58
lines changed
Filter options

20 files changed

+191
-58
lines changed

‎.github/PULL_REQUEST_TEMPLATE.md

Copy file name to clipboardExpand all lines: .github/PULL_REQUEST_TEMPLATE.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
| Q | A
22
| ------------- | ---
3-
| Branch? | "master" for new features / 2.7, 2.8, 3.0 or 3.1 for fixes
3+
| Branch? | "master" for new features / 2.7, 2.8 or 3.1 for fixes
44
| Bug fix? | yes/no
55
| New feature? | yes/no
66
| BC breaks? | yes/no

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/form_csrf.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/form_csrf.xml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<argument>%form.type_extension.csrf.field_name%</argument>
1818
<argument type="service" id="translator.default" />
1919
<argument>%validator.translation_domain%</argument>
20+
<argument type="service" id="form.server_params" />
2021
</service>
2122
</services>
2223
</container>

‎src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public function variableNode($name)
138138
/**
139139
* Returns the parent node.
140140
*
141-
* @return ParentNodeDefinitionInterface The parent node
141+
* @return ParentNodeDefinitionInterface|NodeDefinition The parent node
142142
*/
143143
public function end()
144144
{

‎src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public function attribute($key, $value)
107107
/**
108108
* Returns the parent node.
109109
*
110-
* @return NodeParentInterface|null The builder of the parent node
110+
* @return NodeParentInterface|NodeBuilder|NodeDefinition|null The builder of the parent node
111111
*/
112112
public function end()
113113
{

‎src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
+37-6Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,20 +117,29 @@ public function reverseTransform($value)
117117
return;
118118
}
119119

120-
$timestamp = $this->getIntlDateFormatter()->parse($value);
120+
// date-only patterns require parsing to be done in UTC, as midnight might not exist in the local timezone due
121+
// to DST changes
122+
$dateOnly = $this->isPatternDateOnly();
123+
124+
$timestamp = $this->getIntlDateFormatter($dateOnly)->parse($value);
121125

122126
if (intl_get_error_code() != 0) {
123127
throw new TransformationFailedException(intl_get_error_message());
124128
}
125129

126130
try {
127-
// read timestamp into DateTime object - the formatter delivers in UTC
128-
$dateTime = new \DateTime(sprintf('@%s', $timestamp));
131+
if ($dateOnly) {
132+
// we only care about year-month-date, which has been delivered as a timestamp pointing to UTC midnight
133+
return new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->inputTimezone));
134+
}
135+
136+
// read timestamp into DateTime object - the formatter delivers a timestamp
137+
$dateTime = new \DateTime(sprintf('@%s', $timestamp), new \DateTimeZone($this->outputTimezone));
129138
} catch (\Exception $e) {
130139
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
131140
}
132141

133-
if ('UTC' !== $this->inputTimezone) {
142+
if ($this->outputTimezone !== $this->inputTimezone) {
134143
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
135144
}
136145

@@ -140,15 +149,17 @@ public function reverseTransform($value)
140149
/**
141150
* Returns a preconfigured IntlDateFormatter instance.
142151
*
152+
* @param bool $ignoreTimezone Use UTC regardless of the configured timezone.
153+
*
143154
* @return \IntlDateFormatter
144155
*
145156
* @throws TransformationFailedException in case the date formatter can not be constructed.
146157
*/
147-
protected function getIntlDateFormatter()
158+
protected function getIntlDateFormatter($ignoreTimezone = false)
148159
{
149160
$dateFormat = $this->dateFormat;
150161
$timeFormat = $this->timeFormat;
151-
$timezone = $this->outputTimezone;
162+
$timezone = $ignoreTimezone ? 'UTC' : $this->outputTimezone;
152163
$calendar = $this->calendar;
153164
$pattern = $this->pattern;
154165

@@ -163,4 +174,24 @@ protected function getIntlDateFormatter()
163174

164175
return $intlDateFormatter;
165176
}
177+
178+
/**
179+
* Checks if the pattern contains only a date.
180+
*
181+
* @param string $pattern The input pattern
182+
*
183+
* @return bool
184+
*/
185+
protected function isPatternDateOnly()
186+
{
187+
if (null === $this->pattern) {
188+
return false;
189+
}
190+
191+
// strip escaped text
192+
$pattern = preg_replace("#'(.*?)'#", '', $this->pattern);
193+
194+
// check for the absence of time-related placeholders
195+
return 0 === preg_match('#[ahHkKmsSAzZOvVxX]#', $pattern);
196+
}
166197
}

‎src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
+10-2Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Form\FormEvents;
1919
use Symfony\Component\Form\FormError;
2020
use Symfony\Component\Form\FormEvent;
21+
use Symfony\Component\Form\Util\ServerParams;
2122
use Symfony\Component\Security\Csrf\CsrfToken;
2223
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
2324
use Symfony\Component\Translation\TranslatorInterface;
@@ -68,14 +69,19 @@ class CsrfValidationListener implements EventSubscriberInterface
6869
*/
6970
private $translationDomain;
7071

72+
/**
73+
* @var ServerParams
74+
*/
75+
private $serverParams;
76+
7177
public static function getSubscribedEvents()
7278
{
7379
return array(
7480
FormEvents::PRE_SUBMIT => 'preSubmit',
7581
);
7682
}
7783

78-
public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null)
84+
public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null, ServerParams $serverParams = null)
7985
{
8086
if ($tokenManager instanceof CsrfProviderInterface) {
8187
$tokenManager = new CsrfProviderAdapter($tokenManager);
@@ -89,13 +95,15 @@ public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage,
8995
$this->errorMessage = $errorMessage;
9096
$this->translator = $translator;
9197
$this->translationDomain = $translationDomain;
98+
$this->serverParams = $serverParams ?: new ServerParams();
9299
}
93100

94101
public function preSubmit(FormEvent $event)
95102
{
96103
$form = $event->getForm();
104+
$postRequestSizeExceeded = $form->getConfig()->getMethod() === 'POST' && $this->serverParams->hasPostMaxSizeBeenExceeded();
97105

98-
if ($form->isRoot() && $form->getConfig()->getOption('compound')) {
106+
if ($form->isRoot() && $form->getConfig()->getOption('compound') && !$postRequestSizeExceeded) {
99107
$data = $event->getData();
100108

101109
if (!isset($data[$this->fieldName]) || !$this->tokenManager->isTokenValid(new CsrfToken($this->tokenId, $data[$this->fieldName]))) {

‎src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
+10-2Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\Form\FormBuilderInterface;
2121
use Symfony\Component\Form\FormView;
2222
use Symfony\Component\Form\FormInterface;
23+
use Symfony\Component\Form\Util\ServerParams;
2324
use Symfony\Component\OptionsResolver\Options;
2425
use Symfony\Component\OptionsResolver\OptionsResolver;
2526
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
@@ -55,7 +56,12 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
5556
*/
5657
private $translationDomain;
5758

58-
public function __construct($defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null)
59+
/**
60+
* @var ServerParams
61+
*/
62+
private $serverParams;
63+
64+
public function __construct($defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null, ServerParams $serverParams = null)
5965
{
6066
if ($defaultTokenManager instanceof CsrfProviderInterface) {
6167
$defaultTokenManager = new CsrfProviderAdapter($defaultTokenManager);
@@ -68,6 +74,7 @@ public function __construct($defaultTokenManager, $defaultEnabled = true, $defau
6874
$this->defaultFieldName = $defaultFieldName;
6975
$this->translator = $translator;
7076
$this->translationDomain = $translationDomain;
77+
$this->serverParams = $serverParams;
7178
}
7279

7380
/**
@@ -89,7 +96,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
8996
$options['csrf_token_id'] ?: ($builder->getName() ?: get_class($builder->getType()->getInnerType())),
9097
$options['csrf_message'],
9198
$this->translator,
92-
$this->translationDomain
99+
$this->translationDomain,
100+
$this->serverParams
93101
))
94102
;
95103
}

‎src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
+1-4Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,7 @@ public function handleRequest(FormInterface $form, $request = null)
7373
// Mark the form with an error if the uploaded size was too large
7474
// This is done here and not in FormValidator because $_POST is
7575
// empty when that error occurs. Hence the form is never submitted.
76-
$contentLength = $this->serverParams->getContentLength();
77-
$maxContentLength = $this->serverParams->getPostMaxSize();
78-
79-
if (!empty($maxContentLength) && $contentLength > $maxContentLength) {
76+
if ($this->serverParams->hasPostMaxSizeBeenExceeded()) {
8077
// Submit the form, but don't clear the default values
8178
$form->submit(null, false);
8279

‎src/Symfony/Component/Form/NativeRequestHandler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/NativeRequestHandler.php
+1-4Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,7 @@ public function handleRequest(FormInterface $form, $request = null)
8181
// Mark the form with an error if the uploaded size was too large
8282
// This is done here and not in FormValidator because $_POST is
8383
// empty when that error occurs. Hence the form is never submitted.
84-
$contentLength = $this->serverParams->getContentLength();
85-
$maxContentLength = $this->serverParams->getPostMaxSize();
86-
87-
if (!empty($maxContentLength) && $contentLength > $maxContentLength) {
84+
if ($this->serverParams->hasPostMaxSizeBeenExceeded()) {
8885
// Submit the form, but don't clear the default values
8986
$form->submit(null, false);
9087

‎src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,26 @@ public function testReverseTransformWithDifferentPatterns()
230230
$this->assertDateTimeEquals($this->dateTime, $transformer->reverseTransform('02*2010*03 04|05|06'));
231231
}
232232

233+
public function testReverseTransformDateOnlyWithDstIssue()
234+
{
235+
$transformer = new DateTimeToLocalizedStringTransformer('Europe/Rome', 'Europe/Rome', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'dd/MM/yyyy');
236+
237+
$this->assertDateTimeEquals(
238+
new \DateTime('1978-05-28', new \DateTimeZone('Europe/Rome')),
239+
$transformer->reverseTransform('28/05/1978')
240+
);
241+
}
242+
243+
public function testReverseTransformDateOnlyWithDstIssueAndEscapedText()
244+
{
245+
$transformer = new DateTimeToLocalizedStringTransformer('Europe/Rome', 'Europe/Rome', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, "'day': dd 'month': MM 'year': yyyy");
246+
247+
$this->assertDateTimeEquals(
248+
new \DateTime('1978-05-28', new \DateTimeZone('Europe/Rome')),
249+
$transformer->reverseTransform('day: 28 month: 05 year: 1978')
250+
);
251+
}
252+
233253
public function testReverseTransformEmpty()
234254
{
235255
$transformer = new DateTimeToLocalizedStringTransformer();

‎src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener;
1313

14+
use Symfony\Component\Form\Form;
1415
use Symfony\Component\Form\FormBuilder;
1516
use Symfony\Component\Form\FormEvent;
1617
use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
@@ -72,4 +73,25 @@ public function testStringFormData()
7273
// Validate accordingly
7374
$this->assertSame($data, $event->getData());
7475
}
76+
77+
public function testMaxPostSizeExceeded()
78+
{
79+
$serverParams = $this
80+
->getMockBuilder('\Symfony\Component\Form\Util\ServerParams')
81+
->disableOriginalConstructor()
82+
->getMock()
83+
;
84+
85+
$serverParams
86+
->expects($this->once())
87+
->method('hasPostMaxSizeBeenExceeded')
88+
->willReturn(true)
89+
;
90+
91+
$event = new FormEvent($this->form, array('csrf' => 'token'));
92+
$validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Error message', null, null, $serverParams);
93+
94+
$validation->preSubmit($event);
95+
$this->assertEmpty($this->form->getErrors());
96+
}
7597
}

‎src/Symfony/Component/Form/Util/ServerParams.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Util/ServerParams.php
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ public function __construct(RequestStack $requestStack = null)
2525
$this->requestStack = $requestStack;
2626
}
2727

28+
/**
29+
* Returns true if the POST max size has been exceeded in the request.
30+
*
31+
* @return bool
32+
*/
33+
public function hasPostMaxSizeBeenExceeded()
34+
{
35+
$contentLength = $this->getContentLength();
36+
$maxContentLength = $this->getPostMaxSize();
37+
38+
return $maxContentLength && $contentLength > $maxContentLength;
39+
}
40+
2841
/**
2942
* Returns maximum post size in bytes.
3043
*

‎src/Symfony/Component/HttpFoundation/Request.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Request.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1522,7 +1522,7 @@ public function getContent($asResource = false)
15221522
return stream_get_contents($this->content);
15231523
}
15241524

1525-
if (null === $this->content) {
1525+
if (null === $this->content || false === $this->content) {
15261526
$this->content = file_get_contents('php://input');
15271527
}
15281528

‎src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+13-3Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,8 +1042,16 @@ public function testGetContentCantBeCalledTwiceWithResources($first, $second)
10421042
$req->getContent($second);
10431043
}
10441044

1045+
public function getContentCantBeCalledTwiceWithResourcesProvider()
1046+
{
1047+
return array(
1048+
'Resource then fetch' => array(true, false),
1049+
'Resource then resource' => array(true, true),
1050+
);
1051+
}
1052+
10451053
/**
1046-
* @dataProvider getContentCantBeCalledTwiceWithResourcesProvider
1054+
* @dataProvider getContentCanBeCalledTwiceWithResourcesProvider
10471055
* @requires PHP 5.6
10481056
*/
10491057
public function testGetContentCanBeCalledTwiceWithResources($first, $second)
@@ -1060,12 +1068,14 @@ public function testGetContentCanBeCalledTwiceWithResources($first, $second)
10601068
$b = stream_get_contents($b);
10611069
}
10621070

1063-
$this->assertEquals($a, $b);
1071+
$this->assertSame($a, $b);
10641072
}
10651073

1066-
public function getContentCantBeCalledTwiceWithResourcesProvider()
1074+
public function getContentCanBeCalledTwiceWithResourcesProvider()
10671075
{
10681076
return array(
1077+
'Fetch then fetch' => array(false, false),
1078+
'Fetch then resource' => array(false, true),
10691079
'Resource then fetch' => array(true, false),
10701080
'Resource then resource' => array(true, true),
10711081
);

‎src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php
+1-2Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,7 @@ public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1)
211211
// getLimitedClone is @deprecated, to be removed in 3.0
212212
$dumper->dump($dump['data']->getLimitedClone($maxDepthLimit, $maxItemsPerDepth));
213213
}
214-
rewind($data);
215-
$dump['data'] = stream_get_contents($data);
214+
$dump['data'] = stream_get_contents($data, -1, 0);
216215
ftruncate($data, 0);
217216
rewind($data);
218217
$dumps[] = $dump;

‎src/Symfony/Component/Process/Pipes/WindowsPipes.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Process/Pipes/WindowsPipes.php
+8-3Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,22 @@ public function __construct($disableOutput, $input)
5151
Process::STDOUT => Process::OUT,
5252
Process::STDERR => Process::ERR,
5353
);
54+
$tmpCheck = false;
5455
$tmpDir = sys_get_temp_dir();
55-
$error = 'unknown reason';
56-
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
56+
$lastError = 'unknown reason';
57+
set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
5758
for ($i = 0;; ++$i) {
5859
foreach ($pipes as $pipe => $name) {
5960
$file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
6061
if (file_exists($file) && !unlink($file)) {
6162
continue 2;
6263
}
6364
$h = fopen($file, 'xb');
64-
if (!$h && false === strpos($error, 'File exists')) {
65+
if (!$h) {
66+
$error = $lastError;
67+
if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) {
68+
continue;
69+
}
6570
restore_error_handler();
6671
throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error));
6772
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.