Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commit488ff61

Browse files
popsorinCalinBolea
andcommitted
[Validator] Add CidrValidator to allow validation of CIDR notations
Co-authored-by: Calin Bolea <calin.bolea@gmail.com>
1 parent2d0a08b commit488ff61

File tree

8 files changed

+580
-0
lines changed

8 files changed

+580
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
5.4
55
---
66

7+
* Add a`Cidr` constraint to validate CIDR notations
78
* Add a`CssColor` constraint to validate CSS colors
89
* Add support for`ConstraintViolationList::createFromMessage()`
910
* Add error's uid to`Count` and`Length` constraints with "exactly" option enabled
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
namespaceSymfony\Component\Validator\Constraints;
13+
14+
useSymfony\Component\Validator\Constraint;
15+
useSymfony\Component\Validator\Exception\ConstraintDefinitionException;
16+
17+
/**
18+
* Validates that a value is a valid CIDR notation.
19+
*
20+
* @Annotation
21+
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
22+
*
23+
* @author Sorin Pop <popsorin15@gmail.com>
24+
* @author Calin Bolea <calin.bolea@gmail.com>
25+
*/
26+
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
27+
class Cidrextends Constraint
28+
{
29+
publicconstINVALID_CIDR_ERROR ='5649e53a-5afb-47c5-a360-ffbab3be8567';
30+
publicconstOUT_OF_RANGE_ERROR ='b9f14a51-acbd-401a-a078-8c6b204ab32f';
31+
32+
protectedstatic$errorNames = [
33+
self::INVALID_CIDR_ERROR =>'INVALID_CIDR_ERROR',
34+
self::OUT_OF_RANGE_ERROR =>'OUT_OF_RANGE_VIOLATION',
35+
];
36+
37+
privateconstNET_MAXES = [
38+
Ip::ALL =>128,
39+
Ip::V4 =>32,
40+
Ip::V6 =>128,
41+
];
42+
43+
public$version = Ip::ALL;
44+
45+
public$message ='This value is not a valid CIDR notation.';
46+
47+
public$netmaskRangeViolationMessage ='The value of the netmask should be between {{ min }} and {{ max }}.';
48+
49+
public$netmaskMin =0;
50+
51+
public$netmaskMax;
52+
53+
publicfunction__construct(
54+
array$options =null,
55+
string$version =null,
56+
int$netmaskMin =null,
57+
int$netmaskMax =null,
58+
string$message =null,
59+
array$groups =null,
60+
$payload =null
61+
) {
62+
$this->version =$version ??$options['version'] ??$this->version;
63+
64+
if (!\in_array($this->version,array_keys(self::NET_MAXES))) {
65+
thrownewConstraintDefinitionException(sprintf('The option "version" must be one of "%s".',implode('", "',array_keys(self::NET_MAXES))));
66+
}
67+
68+
$this->netmaskMin =$netmaskMin ??$options['netmaskMin'] ??$this->netmaskMin;
69+
$this->netmaskMax =$netmaskMax ??$options['netmaskMax'] ??self::NET_MAXES[$this->version];
70+
$this->message =$message ??$this->message;
71+
72+
unset($options['netmaskMin'],$options['netmaskMax'],$options['version']);
73+
74+
if ($this->netmaskMin <0 ||$this->netmaskMax >self::NET_MAXES[$this->version] ||$this->netmaskMin >$this->netmaskMax) {
75+
thrownewConstraintDefinitionException(sprintf('The netmask range must be between 0 and %d.',self::NET_MAXES[$this->version]));
76+
}
77+
78+
parent::__construct($options,$groups,$payload);
79+
}
80+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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+
namespaceSymfony\Component\Validator\Constraints;
13+
14+
useSymfony\Component\Validator\Constraint;
15+
useSymfony\Component\Validator\ConstraintValidator;
16+
useSymfony\Component\Validator\Exception\UnexpectedTypeException;
17+
useSymfony\Component\Validator\Exception\UnexpectedValueException;
18+
19+
class CidrValidatorextends ConstraintValidator
20+
{
21+
publicfunctionvalidate($value,Constraint$constraint):void
22+
{
23+
if (!$constraintinstanceof Cidr) {
24+
thrownewUnexpectedTypeException($constraint, Cidr::class);
25+
}
26+
27+
if (null ===$value ||'' ===$value) {
28+
return;
29+
}
30+
31+
if (!\is_string($value)) {
32+
thrownewUnexpectedValueException($value,'string');
33+
}
34+
35+
$cidrParts =explode('/',$value,2);
36+
37+
if (!isset($cidrParts[1])
38+
|| !ctype_digit($cidrParts[1])
39+
||'' ===$cidrParts[0]
40+
) {
41+
$this->context
42+
->buildViolation($constraint->message)
43+
->setCode(Cidr::INVALID_CIDR_ERROR)
44+
->addViolation();
45+
46+
return;
47+
}
48+
49+
$ipAddress =$cidrParts[0];
50+
$netmask = (int)$cidrParts[1];
51+
52+
$validV4 = Ip::V6 !==$constraint->version
53+
&&filter_var($ipAddress, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)
54+
&&$netmask <=32;
55+
56+
$validV6 = Ip::V4 !==$constraint->version
57+
&&filter_var($ipAddress, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6);
58+
59+
if (!$validV4 && !$validV6) {
60+
$this->context
61+
->buildViolation($constraint->message)
62+
->setCode(Cidr::INVALID_CIDR_ERROR)
63+
->addViolation();
64+
65+
return;
66+
}
67+
68+
if ($netmask <$constraint->netmaskMin ||$netmask >$constraint->netmaskMax) {
69+
$this->context
70+
->buildViolation($constraint->netmaskRangeViolationMessage)
71+
->setParameter('{{ min }}',$constraint->netmaskMin)
72+
->setParameter('{{ max }}',$constraint->netmaskMax)
73+
->setCode(Cidr::OUT_OF_RANGE_ERROR)
74+
->addViolation();
75+
}
76+
}
77+
}

‎src/Symfony/Component/Validator/Resources/translations/validators.en.xlf‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,14 @@
394394
<source>This value is not a valid CSS color.</source>
395395
<target>This value is not a valid CSS color.</target>
396396
</trans-unit>
397+
<trans-unitid="102">
398+
<source>This value is not a valid CIDR notation.</source>
399+
<target>This value is not a valid CIDR notation.</target>
400+
</trans-unit>
401+
<trans-unitid="103">
402+
<source>The value of the netmask should be between {{ min }} and {{ max }}.</source>
403+
<target>The value of the netmask should be between {{ min }} and {{ max }}.</target>
404+
</trans-unit>
397405
</body>
398406
</file>
399407
</xliff>

‎src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,14 @@
394394
<source>This value is not a valid CSS color.</source>
395395
<target>Cette valeur n'est pas une couleur CSS valide.</target>
396396
</trans-unit>
397+
<trans-unitid="102">
398+
<source>This value is not a valid CIDR notation.</source>
399+
<target>Cette valeur n'est pas une notation CIDR valide.</target>
400+
</trans-unit>
401+
<trans-unitid="103">
402+
<source>The value of the netmask should be between {{ min }} and {{ max }}.</source>
403+
<target>La valeur du masque de réseau doit être comprise entre {{ min }} et {{ max }}.</target>
404+
</trans-unit>
397405
</body>
398406
</file>
399407
</xliff>

‎src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,14 @@
390390
<source>This value should be a valid expression.</source>
391391
<target>Această valoare ar trebui să fie o expresie validă.</target>
392392
</trans-unit>
393+
<trans-unitid="102">
394+
<source>This value is not a valid CIDR notation.</source>
395+
<target>Această valoare nu este o notație CIDR validă.</target>
396+
</trans-unit>
397+
<trans-unitid="103">
398+
<source>The value of the netmask should be between {{ min }} and {{ max }}.</source>
399+
<target>Valoarea netmask-ului trebuie sa fie intre {{ min }} si {{ max }}.</target>
400+
</trans-unit>
393401
</body>
394402
</file>
395403
</xliff>
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
3+
namespaceSymfony\Component\Validator\Tests\Constraints;
4+
5+
usePHPUnit\Framework\TestCase;
6+
useSymfony\Component\Validator\Constraints\Cidr;
7+
useSymfony\Component\Validator\Constraints\Ip;
8+
useSymfony\Component\Validator\Exception\ConstraintDefinitionException;
9+
useSymfony\Component\Validator\Mapping\ClassMetadata;
10+
useSymfony\Component\Validator\Mapping\Loader\AnnotationLoader;
11+
12+
class CidrTestextends TestCase
13+
{
14+
publicfunctiontestForAll()
15+
{
16+
$cidrConstraint =newCidr();
17+
18+
self::assertEquals(Ip::ALL,$cidrConstraint->version);
19+
self::assertEquals(0,$cidrConstraint->netmaskMin);
20+
self::assertEquals(128,$cidrConstraint->netmaskMax);
21+
}
22+
23+
publicfunctiontestForV4()
24+
{
25+
$cidrConstraint =newCidr(['version' => Ip::V4]);
26+
27+
self::assertEquals(Ip::V4,$cidrConstraint->version);
28+
self::assertEquals(0,$cidrConstraint->netmaskMin);
29+
self::assertEquals(32,$cidrConstraint->netmaskMax);
30+
}
31+
32+
publicfunctiontestForV6()
33+
{
34+
$cidrConstraint =newCidr(['version' => Ip::V6]);
35+
36+
self::assertEquals(Ip::V6,$cidrConstraint->version);
37+
self::assertEquals(0,$cidrConstraint->netmaskMin);
38+
self::assertEquals(128,$cidrConstraint->netmaskMax);
39+
}
40+
41+
publicfunctiontestWithInvalidVersion()
42+
{
43+
$availableVersions = [Ip::ALL, Ip::V4, Ip::V6];
44+
45+
self::expectException(ConstraintDefinitionException::class);
46+
self::expectExceptionMessage(sprintf('The option "version" must be one of "%s".',implode('", "',$availableVersions)));
47+
48+
newCidr(['version' =>'8']);
49+
}
50+
51+
/**
52+
* @dataProvider getValidMinMaxValues
53+
*/
54+
publicfunctiontestWithValidMinMaxValues(string$ipVersion,int$netmaskMin,int$netmaskMax)
55+
{
56+
$cidrConstraint =newCidr([
57+
'version' =>$ipVersion,
58+
'netmaskMin' =>$netmaskMin,
59+
'netmaskMax' =>$netmaskMax,
60+
]);
61+
62+
self::assertEquals($ipVersion,$cidrConstraint->version);
63+
self::assertEquals($netmaskMin,$cidrConstraint->netmaskMin);
64+
self::assertEquals($netmaskMax,$cidrConstraint->netmaskMax);
65+
}
66+
67+
/**
68+
* @dataProvider getInvalidMinMaxValues
69+
*/
70+
publicfunctiontestWithInvalidMinMaxValues(string$ipVersion,int$netmaskMin,int$netmaskMax)
71+
{
72+
$expectedMax = Ip::V4 ==$ipVersion ?32 :128;
73+
74+
self::expectException(ConstraintDefinitionException::class);
75+
self::expectExceptionMessage(sprintf('The netmask range must be between 0 and %d.',$expectedMax));
76+
77+
newCidr([
78+
'version' =>$ipVersion,
79+
'netmaskMin' =>$netmaskMin,
80+
'netmaskMax' =>$netmaskMax,
81+
]);
82+
}
83+
84+
publicfunctiongetInvalidMinMaxValues():array
85+
{
86+
return [
87+
[Ip::ALL, -1,23],
88+
[Ip::ALL,23,130],
89+
[Ip::ALL,2, -4],
90+
[Ip::ALL, -12, -40],
91+
[Ip::V4,0,33],
92+
[Ip::V4,2, -10],
93+
[Ip::V4, -4,128],
94+
[Ip::V4, -5, -1],
95+
[Ip::V6,5,200],
96+
[Ip::V6, -1,120],
97+
[Ip::V6,0, -10],
98+
[Ip::V6, -15, -20],
99+
];
100+
}
101+
102+
publicfunctiongetValidMinMaxValues():array
103+
{
104+
return [
105+
[Ip::ALL,0,23],
106+
[Ip::ALL,23,120],
107+
[Ip::V4,0,5],
108+
[Ip::V4,2,10],
109+
[Ip::V6,0,43],
110+
[Ip::V6,33,100],
111+
];
112+
}
113+
114+
/**
115+
* @requires PHP 8
116+
*/
117+
publicfunctiontestAttributes()
118+
{
119+
$metadata =newClassMetadata(CidrDummy::class);
120+
$loader =newAnnotationLoader();
121+
self::assertTrue($loader->loadClassMetadata($metadata));
122+
123+
[$aConstraint] =$metadata->properties['a']->getConstraints();
124+
self::assertSame(Ip::ALL,$aConstraint->version);
125+
self::assertSame(0,$aConstraint->netmaskMin);
126+
self::assertSame(128,$aConstraint->netmaskMax);
127+
128+
[$bConstraint] =$metadata->properties['b']->getConstraints();
129+
self::assertSame(Ip::V6,$bConstraint->version);
130+
self::assertSame('myMessage',$bConstraint->message);
131+
self::assertSame(10,$bConstraint->netmaskMin);
132+
self::assertSame(126,$bConstraint->netmaskMax);
133+
self::assertSame(['Default','CidrDummy'],$bConstraint->groups);
134+
135+
[$cConstraint] =$metadata->properties['c']->getConstraints();
136+
self::assertSame(['my_group'],$cConstraint->groups);
137+
self::assertSame('some attached data',$cConstraint->payload);
138+
}
139+
}
140+
141+
class CidrDummy
142+
{
143+
#[Cidr]
144+
private$a;
145+
146+
#[Cidr(version: Ip::V6, message:'myMessage', netmaskMin:10, netmaskMax:126)]
147+
private$b;
148+
149+
#[Cidr(groups: ['my_group'], payload:'some attached data')]
150+
private$c;
151+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp