11
11
12
12
namespace Symfony \Component \Validator \Constraints ;
13
13
14
+ use Symfony \Component \HttpFoundation \File \File ;
15
+ use Symfony \Component \Mime \MimeTypes ;
14
16
use Symfony \Component \Validator \Constraint ;
15
17
use Symfony \Component \Validator \Exception \ConstraintDefinitionException ;
16
18
use Symfony \Component \Validator \Exception \LogicException ;
@@ -50,7 +52,13 @@ public function validate(mixed $value, Constraint $constraint): void
50
52
return ;
51
53
}
52
54
53
- $ size = @getimagesize ($ value );
55
+ $ isSvg = $ this ->isSvg ($ value );
56
+
57
+ if ($ isSvg ) {
58
+ $ size = $ this ->getSvgSize ($ value );
59
+ } else {
60
+ $ size = @getimagesize ($ value );
61
+ }
54
62
55
63
if (!$ size || (0 === $ size [0 ]) || (0 === $ size [1 ])) {
56
64
$ this ->context ->buildViolation ($ constraint ->sizeNotDetectedMessage )
@@ -63,7 +71,7 @@ public function validate(mixed $value, Constraint $constraint): void
63
71
$ width = $ size [0 ];
64
72
$ height = $ size [1 ];
65
73
66
- if ($ constraint ->minWidth ) {
74
+ if (! $ isSvg && $ constraint ->minWidth ) {
67
75
if (!ctype_digit ((string ) $ constraint ->minWidth )) {
68
76
throw new ConstraintDefinitionException (\sprintf ('"%s" is not a valid minimum width. ' , $ constraint ->minWidth ));
69
77
A93C
}
@@ -79,7 +87,7 @@ public function validate(mixed $value, Constraint $constraint): void
79
87
}
80
88
}
81
89
82
- if ($ constraint ->maxWidth ) {
90
+ if (! $ isSvg && $ constraint ->maxWidth ) {
83
91
if (!ctype_digit ((string ) $ constraint ->maxWidth )) {
84
92
throw new ConstraintDefinitionException (\sprintf ('"%s" is not a valid maximum width. ' , $ constraint ->maxWidth ));
85
93
}
@@ -95,7 +103,7 @@ public function validate(mixed $value, Constraint $constraint): void
95
103
}
96
104
}
97
105
98
- if ($ constraint ->minHeight ) {
106
+ if (! $ isSvg && $ constraint ->minHeight ) {
99
107
if (!ctype_digit ((string ) $ constraint ->minHeight )) {
100
108
throw new ConstraintDefinitionException (\sprintf ('"%s" is not a valid minimum height. ' , $ constraint ->minHeight ));
101
109
}
@@ -111,7 +119,7 @@ public function validate(mixed $value, Constraint $constraint): void
111
119
}
112
120
}
113
121
114
- if ($ constraint ->maxHeight ) {
122
+ if (! $ isSvg && $ constraint ->maxHeight ) {
115
123
if (!ctype_digit ((string ) $ constraint ->maxHeight )) {
116
124
throw new ConstraintDefinitionException (\sprintf ('"%s" is not a valid maximum height. ' , $ constraint ->maxHeight ));
117
125
}
@@ -127,7 +135,7 @@ public function validate(mixed $value, Constraint $constraint): void
127
135
128
136
$ pixels = $ width * $ height ;
129
137
130
- if (null !== $ constraint ->minPixels ) {
138
+ if (! $ isSvg && null !== $ constraint ->minPixels ) {
131
139
if (!ctype_digit ((string ) $ constraint ->minPixels )) {
132
140
throw new ConstraintDefinitionException (\sprintf ('"%s" is not a valid minimum amount of pixels. ' , $ constraint ->minPixels ));
133
141
}
@@ -143,7 +151,7 @@ public function validate(mixed $value, Constraint $constraint): void
143
151
}
144
152
}
145
153
146
- if (null !== $ constraint ->maxPixels ) {
154
+ if (! $ isSvg && null !== $ constraint ->maxPixels ) {
147
155
if (!ctype_digit ((string ) $ constraint ->maxPixels )) {
148
156
throw new ConstraintDefinitionException (\sprintf ('"%s" is not a valid maximum amount of pixels. ' , $ constraint ->maxPixels ));
149
157
}
@@ -231,4 +239,59 @@ public function validate(mixed $value, Constraint $constraint): void
231
239
imagedestroy ($ resource );
232
240
}
233
241
}
242
+
243
+ /**
244
+ * Check whether a value is an SVG image.
245
+ *
246
+ * Return true if value is an SVG, false if it's not, or if we can't detect its MimeType.
247
+ */
248
+ private function isSvg (mixed $ value ): bool
249
+ {
250
+ if ($ value instanceof File) {
251
+ $ mime = $ value ->getMimeType ();
252
+ } elseif (class_exists (MimeTypes::class)) {
253
+ $ mime = MimeTypes::getDefault ()->guessMimeType ($ value );
254
+ } elseif (!class_exists (File::class)) {
255
+ return false ;
256
+ } else {
257
+ $ mime = (new File ($ value ))->getMimeType ();
258
+ }
259
+
260
+ return 'image/svg+xml ' === $ mime ;
261
+ }
262
+
263
+ /**
264
+ * Extract width and height from an SVG image.
265
+ *
266
+ * @return array{int, int}|null index 0 and 1 contains respectively the width and the height of the image, null if size can't be found
267
+ */
268
+ private function getSvgSize (mixed $ value ): ?array
269
+ {
270
+ if ($ value instanceof File) {
271
+ $ content = $ value ->getContent ();
272
+ } elseif (!class_exists (File::class)) {
273
+ return null ;
274
+ } else {
275
+ $ content = (new File ($ value ))->getContent ();
276
+ }
277
+
278
+ if (1 === preg_match ('/<svg[^<>]+width="([0-9]+)"[^<>]*>/ ' , $ content , $ widthMatches )) {
279
+ $ width = (int ) $ widthMatches [1 ];
280
+ }
281
+
282
+ if (1 === preg_match ('/<svg[^<>]+height="([0-9]+)"[^<>]*>/ ' , $ content , $ heightMatches )) {
283
+ $ height = (int ) $ heightMatches [1 ];
284
+ }
285
+
286
+ if (1 === preg_match ('/<svg[^<>]+viewBox="(-?[0-9]+) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+)"[^<>]*>/ ' , $ content , $ viewBoxMatches )) {
287
+ $ width ??= (int ) $ viewBoxMatches [3 ];
288
+
111C
$ height ??= (int ) $ viewBoxMatches [4 ];
289
+ }
290
+
291
+ if (isset ($ width ) && isset ($ height )) {
292
+ return [$ width , $ height ];
293
+ }
294
+
295
+ return null ;
296
+ }
234
297
}
0 commit comments