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 5e23cee

Browse filesBrowse files
committed
[Form] UrlType should not add protocol to emails
1 parent ff70bd1 commit 5e23cee
Copy full SHA for 5e23cee

File tree

8 files changed

+119
-28
lines changed
Filter options

8 files changed

+119
-28
lines changed

‎UPGRADE-5.4.md

Copy file name to clipboardExpand all lines: UPGRADE-5.4.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Form
2222
------
2323

2424
* Deprecate calling `FormErrorIterator::children()` if the current element is not iterable.
25+
* Add `'default_protocol_skip_email' => true` to `UrlType` options.
2526

2627
FrameworkBundle
2728
---------------

‎src/Symfony/Component/Form/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Deprecate calling `FormErrorIterator::children()` if the current element is not iterable.
88
* Allow to pass `TranslatableMessage` objects to the `help` option
99
* Add the `EnumType`
10+
* Deprecate usage of `UrlType` without option `'default_protocol_skip_email' => true`, added to prevent emails from being converted to valid URLs.
1011

1112
5.3
1213
---

‎src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
class FixUrlProtocolListener implements EventSubscriberInterface
2424
{
2525
private $defaultProtocol;
26+
private $skipEmail = false;
2627

2728
/**
2829
* @param string|null $defaultProtocol The URL scheme to add when there is none or null to not modify the data
@@ -32,11 +33,25 @@ public function __construct(?string $defaultProtocol = 'http')
3233
$this->defaultProtocol = $defaultProtocol;
3334
}
3435

36+
/**
37+
* @param bool $skipEmail the URL scheme is not added to values that match an email pattern
38+
*/
39+
public function skipEmail(): void
40+
{
41+
$this->skipEmail = true;
42+
}
43+
3544
public function onSubmit(FormEvent $event)
3645
{
3746
$data = $event->getData();
3847

3948
if ($this->defaultProtocol && $data && \is_string($data) && !preg_match('~^[\w+.-]+://~', $data)) {
49+
if (preg_match('~^[^:/]+@[A-Za-z0-9-.]+\.[A-Za-z0-9]+$~', $data)) {
50+
if ($this->skipEmail) {
51+
return;
52+
}
53+
trigger_deprecation('symfony/form', '5.4', 'Class "%s", will add a scheme to urls that looks like emails in 6.0. Call "setIgnoreEmail(true)"', __CLASS__);
54+
}
4055
$event->setData($this->defaultProtocol.'://'.$data);
4156
}
4257
}

‎src/Symfony/Component/Form/Extension/Core/Type/UrlType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/UrlType.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ class UrlType extends AbstractType
2727
public function buildForm(FormBuilderInterface $builder, array $options)
2828
{
2929
if (null !== $options['default_protocol']) {
30-
$builder->addEventSubscriber(new FixUrlProtocolListener($options['default_protocol']));
30+
$subscriber = new FixUrlProtocolListener($options['default_protocol']);
31+
if ($options['default_protocol_skip_email']) {
32+
$subscriber->skipEmail();
33+
} else {
34+
trigger_deprecation('symfony/form', '5.4', 'Type "%s" option "default_protocol_skip_email" will be "true" in 6.0.', static::class);
35+
}
36+
$builder->addEventSubscriber($subscriber);
3137
}
3238
}
3339

@@ -54,9 +60,11 @@ public function configureOptions(OptionsResolver $resolver)
5460
? $previousValue
5561
: 'Please enter a valid URL.';
5662
},
63+
'default_protocol_skip_email' => false,
5764
]);
5865

5966
$resolver->setAllowedTypes('default_protocol', ['null', 'string']);
67+
$resolver->setAllowedTypes('default_protocol_skip_email', 'bool');
6068
}
6169

6270
/**

‎src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php
+25-12Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1516
use Symfony\Component\EventDispatcher\EventDispatcher;
1617
use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener;
1718
use Symfony\Component\Form\Form;
@@ -20,25 +21,16 @@
2021

2122
class FixUrlProtocolListenerTest extends TestCase
2223
{
24+
use ExpectDeprecationTrait;
25+
2326
public function testFixHttpUrl()
2427
{
2528
$data = 'www.symfony.com';
2629
$form = new Form(new FormConfigBuilder('name', null, new EventDispatcher()));
2730
$event = new FormEvent($form, $data);
2831

2932
$filter = new FixUrlProtocolListener('http');
30-
$filter->onSubmit($event);
31-
32-
$this->assertEquals('http://www.symfony.com', $event->getData());
33-
}
34-
35-
public function testSkipKnownUrl()
36-
{
37-
$data = 'http://www.symfony.com';
38-
$form = new Form(new FormConfigBuilder('name', null, new EventDispatcher()));
39-
$event = new FormEvent($form, $data);
40-
41-
$filter = new FixUrlProtocolListener('http');
33+
$filter->skipEmail();
4234
$filter->onSubmit($event);
4335

4436
$this->assertEquals('http://www.symfony.com', $event->getData());
@@ -47,11 +39,14 @@ public function testSkipKnownUrl()
4739
public function provideUrlsWithSupportedProtocols()
4840
{
4941
return [
42+
['http://www.symfony.com'],
5043
['ftp://www.symfony.com'],
5144
['chrome-extension://foo'],
5245
['h323://foo'],
5346
['iris.beep://foo'],
5447
['foo+bar://foo'],
48+
['fabien@symfony.com'],
49+
['Contact+42@subdomain.example.com'],
5550
];
5651
}
5752

@@ -64,8 +59,26 @@ public function testSkipOtherProtocol($url)
6459
$event = new FormEvent($form, $url);
6560

6661
$filter = new FixUrlProtocolListener('http');
62+
$filter->skipEmail();
6763
$filter->onSubmit($event);
6864

6965
$this->assertEquals($url, $event->getData());
7066
}
67+
68+
/**
69+
* @group legacy
70+
*/
71+
public function testDeprecatedFixEmail()
72+
{
73+
$this->expectDeprecation('Since symfony/form 5.4: Class "Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener", will add a scheme to urls that looks like emails in 6.0. Call "setIgnoreEmail(true)"');
74+
75+
$data = 'fabien@symfony.com';
76+
$form = new Form(new FormConfigBuilder('name', null, new EventDispatcher()));
77+
$event = new FormEvent($form, $data);
78+
79+
$filter = new FixUrlProtocolListener('http');
80+
$filter->onSubmit($event);
81+
82+
$this->assertEquals('http://fabien@symfony.com', $event->getData());
83+
}
7184
}

‎src/Symfony/Component/Form/Tests/Extension/Core/Type/TextTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Extension/Core/Type/TextTypeTest.php
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ public function testSubmitNull($expected = null, $norm = null, $view = null)
2222

2323
public function testSubmitNullReturnsNullWithEmptyDataAsString()
2424
{
25-
$form = $this->factory->create(static::TESTED_TYPE, 'name', [
25+
$form = $this->factory->create(static::TESTED_TYPE, 'name', array_merge($this->getTestOptions(), [
2626
'empty_data' => '',
27-
]);
27+
]));
2828

2929
$form->submit(null);
3030
$this->assertSame('', $form->getData());
@@ -48,9 +48,9 @@ public function provideZeros()
4848
*/
4949
public function testSetDataThroughParamsWithZero($data, $dataAsString)
5050
{
51-
$form = $this->factory->create(static::TESTED_TYPE, null, [
51+
$form = $this->factory->create(static::TESTED_TYPE, null, array_merge($this->getTestOptions(), [
5252
'data' => $data,
53-
]);
53+
]));
5454
$view = $form->createView();
5555

5656
$this->assertFalse($form->isEmpty());
+36Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13+
14+
/**
15+
* @group legacy
16+
*/
17+
class UrlTypeLegacyTest extends UrlTypeTest
18+
{
19+
/**
20+
* Legacy behavior. Replace test in parent class.
21+
*/
22+
public function testSubmitAddsNoDefaultProtocolToEmail()
23+
{
24+
$form = $this->factory->create(static::TESTED_TYPE, 'name', $this->getTestOptions());
25+
26+
$form->submit('contact@domain.com');
27+
28+
$this->assertSame('http://contact@domain.com', $form->getData());
29+
$this->assertSame('http://contact@domain.com', $form->getViewData());
30+
}
31+
32+
protected function getTestOptions(): array
33+
{
34+
return [];
35+
}
36+
}

‎src/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php
+28-11Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,29 @@ class UrlTypeTest extends TextTypeTest
1919

2020
public function testSubmitAddsDefaultProtocolIfNoneIsIncluded()
2121
{
22-
$form = $this->factory->create(static::TESTED_TYPE, 'name');
22+
$form = $this->factory->create(static::TESTED_TYPE, 'name', $this->getTestOptions());
2323

2424
$form->submit('www.domain.com');
2525

2626
$this->assertSame('http://www.domain.com', $form->getData());
2727
$this->assertSame('http://www.domain.com', $form->getViewData());
2828
}
2929

30+
public function testSubmitAddsNoDefaultProtocolToEmail()
31+
{
32+
$form = $this->factory->create(static::TESTED_TYPE, 'name', $this->getTestOptions());
33+
34+
$form->submit('contact@domain.com');
35+
36+
$this->assertSame('contact@domain.com', $form->getData());
37+
$this->assertSame('contact@domain.com', $form->getViewData());
38+
}
39+
3040
public function testSubmitAddsNoDefaultProtocolIfAlreadyIncluded()
3141
{
32-
$form = $this->factory->create(static::TESTED_TYPE, null, [
42+
$form = $this->factory->create(static::TESTED_TYPE, null, array_merge($this->getTestOptions(), [
3343
'default_protocol' => 'http',
34-
]);
44+
]));
3545

3646
$form->submit('ftp://www.domain.com');
3747

@@ -41,9 +51,9 @@ public function testSubmitAddsNoDefaultProtocolIfAlreadyIncluded()
4151

4252
public function testSubmitAddsNoDefaultProtocolIfEmpty()
4353
{
44-
$form = $this->factory->create(static::TESTED_TYPE, null, [
54+
$form = $this->factory->create(static::TESTED_TYPE, null, array_merge($this->getTestOptions(), [
4555
'default_protocol' => 'http',
46-
]);
56+
]));
4757

4858
$form->submit('');
4959

@@ -53,9 +63,9 @@ public function testSubmitAddsNoDefaultProtocolIfEmpty()
5363

5464
public function testSubmitAddsNoDefaultProtocolIfNull()
5565
{
56-
$form = $this->factory->create(static::TESTED_TYPE, null, [
66+
$form = $this->factory->create(static::TESTED_TYPE, null, array_merge($this->getTestOptions(), [
5767
'default_protocol' => 'http',
58-
]);
68+
]));
5969

6070
$form->submit(null);
6171

@@ -65,9 +75,9 @@ public function testSubmitAddsNoDefaultProtocolIfNull()
6575

6676
public function testSubmitAddsNoDefaultProtocolIfSetToNull()
6777
{
68-
$form = $this->factory->create(static::TESTED_TYPE, null, [
78+
$form = $this->factory->create(static::TESTED_TYPE, null, array_merge($this->getTestOptions(), [
6979
'default_protocol' => null,
70-
]);
80+
]));
7181

7282
$form->submit('www.domain.com');
7383

@@ -85,14 +95,21 @@ public function testThrowExceptionIfDefaultProtocolIsInvalid()
8595

8696
public function testSubmitNullUsesDefaultEmptyData($emptyData = 'empty', $expectedData = 'http://empty')
8797
{
88-
$form = $this->factory->create(static::TESTED_TYPE, null, [
98+
$form = $this->factory->create(static::TESTED_TYPE, null, array_merge($this->getTestOptions(), [
8999
'empty_data' => $emptyData,
90-
]);
100+
]));
91101
$form->submit(null);
92102

93103
// listener normalizes data on submit
94104
$this->assertSame($expectedData, $form->getViewData());
95105
$this->assertSame($expectedData, $form->getNormData());
96106
$this->assertSame($expectedData, $form->getData());
97107
}
108+
109+
protected function getTestOptions(): array
110+
{
111+
return [
112+
'default_protocol_skip_email' => true,
113+
];
114+
}
98115
}

0 commit comments

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