@@ -58,7 +58,7 @@ public function __construct(private ReflectionProvider $reflectionProvider, priv
58
58
59
59
public function getOffsetValueType (Type $ inputType , Type $ offsetType , ?Type $ filterType , ?Type $ flagsType ): Type
60
60
{
61
- $ inexistentOffsetType = $ this ->hasFlag ($ this -> getConstant ( 'FILTER_NULL_ON_FAILURE ' ) , $ flagsType )
61
+ $ inexistentOffsetType = $ this ->hasFlag ('FILTER_NULL_ON_FAILURE ' , $ flagsType )
62
62
? new ConstantBooleanType (false )
63
63
: new NullType ();
64
64
@@ -107,6 +107,9 @@ public function getType(Type $inputType, ?Type $filterType, ?Type $flagsType): T
107
107
108
108
if ($ filterType === null ) {
109
109
$ filterValue = $ this ->getConstant ('FILTER_DEFAULT ' );
110
+ if (null === $ filterValue ) {
111
+ return $ mixedType ;
112
+ }
110
113
} else {
111
114
if (!$ filterType instanceof ConstantIntegerType) {
112
115
return $ mixedType ;
@@ -121,17 +124,17 @@ public function getType(Type $inputType, ?Type $filterType, ?Type $flagsType): T
121
124
$ hasOptions = $ this ->hasOptions ($ flagsType );
122
125
$ options = $ hasOptions ->yes () ? $ this ->getOptions ($ flagsType , $ filterValue ) : [];
123
126
124
- $ defaultType = $ options ['default ' ] ?? ($ this ->hasFlag ($ this -> getConstant ( 'FILTER_NULL_ON_FAILURE ' ) , $ flagsType )
127
+ $ defaultType = $ options ['default ' ] ?? ($ this ->hasFlag ('FILTER_NULL_ON_FAILURE ' , $ flagsType )
125
128
? new NullType ()
126
129
: new ConstantBooleanType (false ));
127
130
128
131
$ inputIsArray = $ inputType ->isArray ();
129
- $ hasRequireArrayFlag = $ this ->hasFlag ($ this -> getConstant ( 'FILTER_REQUIRE_ARRAY ' ) , $ flagsType );
132
+ $ hasRequireArrayFlag = $ this ->hasFlag ('FILTER_REQUIRE_ARRAY ' , $ flagsType );
130
133
if ($ inputIsArray ->no () && $ hasRequireArrayFlag ) {
131
134
return $ defaultType ;
132
135
}
133
136
134
- $ hasForceArrayFlag = $ this ->hasFlag ($ this -> getConstant ( 'FILTER_FORCE_ARRAY ' ) , $ flagsType );
137
+ $ hasForceArrayFlag = $ this ->hasFlag ('FILTER_FORCE_ARRAY ' , $ flagsType );
135
138
if ($ inputIsArray ->yes () && ($ hasRequireArrayFlag || $ hasForceArrayFlag )) {
136
139
$ inputArrayKeyType = $ inputType ->getIterableKeyType ();
137
140
$ inputType = $ inputType ->getIterableValueType ();
@@ -187,32 +190,46 @@ private function getFilterTypeMap(): array
187
190
$ stringType = new StringType ();
188
191
$ nonFalsyStringType = TypeCombinator::intersect ($ stringType , new AccessoryNonFalsyStringType ());
189
192
190
- $ this -> filterTypeMap = [
191
- $ this -> getConstant ( 'FILTER_UNSAFE_RAW ' ) => $ stringType ,
192
- $ this -> getConstant ( 'FILTER_SANITIZE_EMAIL ' ) => $ stringType ,
193
- $ this -> getConstant ( 'FILTER_SANITIZE_ENCODED ' ) => $ stringType ,
194
- $ this -> getConstant ( 'FILTER_SANITIZE_NUMBER_FLOAT ' ) => $ stringType ,
195
- $ this -> getConstant ( 'FILTER_SANITIZE_NUMBER_INT ' ) => $ stringType ,
196
- $ this -> getConstant ( 'FILTER_SANITIZE_SPECIAL_CHARS ' ) => $ stringType ,
197
- $ this -> getConstant ( 'FILTER_SANITIZE_STRING ' ) => $ stringType ,
198
- $ this -> getConstant ( 'FILTER_SANITIZE_URL ' ) => $ stringType ,
199
- $ this -> getConstant ( 'FILTER_VALIDATE_BOOLEAN ' ) => $ booleanType ,
200
- $ this -> getConstant ( 'FILTER_VALIDATE_DOMAIN ' ) => $ stringType ,
201
- $ this -> getConstant ( 'FILTER_VALIDATE_EMAIL ' ) => $ nonFalsyStringType ,
202
- $ this -> getConstant ( 'FILTER_VALIDATE_FLOAT ' ) => $ floatType ,
203
- $ this -> getConstant ( 'FILTER_VALIDATE_INT ' ) => $ intType ,
204
- $ this -> getConstant ( 'FILTER_VALIDATE_IP ' ) => $ nonFalsyStringType ,
205
- $ this -> getConstant ( 'FILTER_VALIDATE_MAC ' ) => $ nonFalsyStringType ,
206
- $ this -> getConstant ( 'FILTER_VALIDATE_REGEXP ' ) => $ stringType ,
207
- $ this -> getConstant ( 'FILTER_VALIDATE_URL ' ) => $ nonFalsyStringType ,
193
+ $ map = [
194
+ 'FILTER_UNSAFE_RAW ' => $ stringType ,
195
+ 'FILTER_SANITIZE_EMAIL ' => $ stringType ,
196
+ 'FILTER_SANITIZE_ENCODED ' => $ stringType ,
197
+ 'FILTER_SANITIZE_NUMBER_FLOAT ' => $ stringType ,
198
+ 'FILTER_SANITIZE_NUMBER_INT ' => $ stringType ,
199
+ 'FILTER_SANITIZE_SPECIAL_CHARS ' => $ stringType ,
200
+ 'FILTER_SANITIZE_STRING ' => $ stringType ,
201
+ 'FILTER_SANITIZE_URL ' => $ stringType ,
202
+ 'FILTER_VALIDATE_BOOLEAN ' => $ booleanType ,
203
+ 'FILTER_VALIDATE_DOMAIN ' => $ stringType ,
204
+ 'FILTER_VALIDATE_EMAIL ' => $ nonFalsyStringType ,
205
+ 'FILTER_VALIDATE_FLOAT ' => $ floatType ,
206
+ 'FILTER_VALIDATE_INT ' => $ intType ,
207
+ 'FILTER_VALIDATE_IP ' => $ nonFalsyStringType ,
208
+ 'FILTER_VALIDATE_MAC ' => $ nonFalsyStringType ,
209
+ 'FILTER_VALIDATE_REGEXP ' => $ stringType ,
210
+ 'FILTER_VALIDATE_URL ' => $ nonFalsyStringType ,
208
211
];
209
212
213
+ $ this ->filterTypeMap = [];
214
+ foreach ($ map as $ filter => $ type ) {
215
+ $ constant = $ this ->getConstant ($ filter );
216
+ if (null !== $ constant ) {
217
+ $ this ->filterTypeMap [$ constant ] = $ type ;
218
+ }
219
+ }
220
+
210
221
if ($ this ->reflectionProvider ->hasConstant (new Node \Name ('FILTER_SANITIZE_MAGIC_QUOTES ' ), null )) {
211
- $ this ->filterTypeMap [$ this ->getConstant ('FILTER_SANITIZE_MAGIC_QUOTES ' )] = $ stringType ;
222
+ $ sanitizeMagicQuote = $ this ->getConstant ('FILTER_SANITIZE_MAGIC_QUOTES ' );
223
+ if (null !== $ sanitizeMagicQuote ) {
224
+ $ this ->filterTypeMap [$ sanitizeMagicQuote ] = $ stringType ;
225
+ }
212
226
}
213
227
214
228
if ($ this ->reflectionProvider ->hasConstant (new Node \Name ('FILTER_SANITIZE_ADD_SLASHES ' ), null )) {
215
- $ this ->filterTypeMap [$ this ->getConstant ('FILTER_SANITIZE_ADD_SLASHES ' )] = $ stringType ;
229
+ $ sanitizeAddSlashes = $ this ->getConstant ('FILTER_SANITIZE_ADD_SLASHES ' );
230
+ if (null !== $ sanitizeAddSlashes ) {
231
+ $ this ->filterTypeMap [$ sanitizeAddSlashes ] = $ stringType ;
232
+ }
216
233
}
217
234
218
235
return $ this ->filterTypeMap ;
@@ -227,24 +244,32 @@ private function getFilterTypeOptions(): array
227
244
return $ this ->filterTypeOptions ;
228
245
}
229
246
230
- $ this -> filterTypeOptions = [
231
- $ this -> getConstant ( 'FILTER_VALIDATE_INT ' ) => ['min_range ' , 'max_range ' ],
247
+ $ map = [
248
+ 'FILTER_VALIDATE_INT ' => ['min_range ' , 'max_range ' ],
232
249
// PHPStan does not yet support FloatRangeType
233
- // $this->getConstant( 'FILTER_VALIDATE_FLOAT') => ['min_range', 'max_range'],
250
+ // 'FILTER_VALIDATE_FLOAT' => ['min_range', 'max_range'],
234
251
];
235
252
253
+ $ this ->filterTypeOptions = [];
254
+ foreach ($ map as $ filter => $ type ) {
255
+ $ constant = $ this ->getConstant ($ filter );
256
+ if (null !== $ constant ) {
257
+ $ this ->filterTypeOptions [$ constant ] = $ type ;
258
+ }
259
+ }
260
+
236
261
return $ this ->filterTypeOptions ;
237
262
}
238
263
239
264
/**
240
265
* @param non-empty-string $constantName
241
266
*/
242
- private function getConstant (string $ constantName ): int
267
+ private function getConstant (string $ constantName ): ? int
243
268
{
244
269
$ constant = $ this ->reflectionProvider ->getConstant (new Node \Name ($ constantName ), null );
245
270
$ valueType = $ constant ->getValueType ();
246
271
if (!$ valueType instanceof ConstantIntegerType) {
247
- throw new ShouldNotHappenException ( sprintf ( ' Constant %s does not have integer type. ' , $ constantName )) ;
272
+ return null ;
248
273
}
249
274
250
275
return $ valueType ->getValue ();
@@ -301,8 +326,8 @@ private function determineExactType(Type $in, int $filterValue, Type $defaultTyp
301
326
302
327
if ($ in instanceof ConstantStringType) {
303
328
$ value = $ in ->getValue ();
304
- $ allowOctal = $ this ->hasFlag ($ this -> getConstant ( 'FILTER_FLAG_ALLOW_OCTAL ' ) , $ flagsType );
305
- $ allowHex = $ this ->hasFlag ($ this -> getConstant ( 'FILTER_FLAG_ALLOW_HEX ' ) , $ flagsType );
329
+ $ allowOctal = $ this ->hasFlag ('FILTER_FLAG_ALLOW_OCTAL ' , $ flagsType );
330
+ $ allowHex = $ this ->hasFlag ('FILTER_FLAG_ALLOW_HEX ' , $ flagsType );
306
331
307
332
if ($ allowOctal && preg_match ('/\A0[oO][0-7]+\z/ ' , $ value ) === 1 ) {
308
333
$ octalValue = octdec ($ value );
@@ -411,8 +436,13 @@ private function getOptions(Type $flagsType, int $filterValue): array
411
436
return $ options ;
412
437
}
413
438
414
- private function hasFlag (int $ flag , ?Type $ flagsType ): bool
439
+ private function hasFlag (string $ flagName , ?Type $ flagsType ): bool
415
440
{
441
+ $ flag = $ this ->getConstant ($ flagName );
442
+ if (null === $ flag ) {
443
+ return false ;
444
+ }
445
+
416
446
if ($ flagsType === null ) {
417
447
return false ;
418
448
}
@@ -441,9 +471,9 @@ private function canStringBeSanitized(int $filterValue, ?Type $flagsType): bool
441
471
// FILTER_DEFAULT will not sanitize, unless it has FILTER_FLAG_STRIP_LOW,
442
472
// FILTER_FLAG_STRIP_HIGH, or FILTER_FLAG_STRIP_BACKTICK
443
473
if ($ filterValue === $ this ->getConstant ('FILTER_DEFAULT ' )) {
444
- return $ this ->hasFlag ($ this -> getConstant ( 'FILTER_FLAG_STRIP_LOW ' ) , $ flagsType )
445
- || $ this ->hasFlag ($ this -> getConstant ( 'FILTER_FLAG_STRIP_HIGH ' ) , $ flagsType )
446
- || $ this ->hasFlag ($ this -> getConstant ( 'FILTER_FLAG_STRIP_BACKTICK ' ) , $ flagsType );
474
+ return $ this ->hasFlag ('FILTER_FLAG_STRIP_LOW ' , $ flagsType )
475
+ || $ this ->hasFlag ('FILTER_FLAG_STRIP_HIGH ' , $ flagsType )
476
+ || $ this ->hasFlag ('FILTER_FLAG_STRIP_BACKTICK ' , $ flagsType );
447
477
}
448
478
449
479
return true ;
0 commit comments