Passed
Push — release_2_1 ( c5a9af...7447ed )
by Tomasz
29:40
created

InputValidation::hugeInteger()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 6
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
/*
4
 * *****************************************************************************
5
 * Contributions to this work were made on behalf of the GÉANT project, a 
6
 * project that has received funding from the European Union’s Framework 
7
 * Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus),
8
 * Horizon 2020 research and innovation programme under Grant Agreements No. 
9
 * 691567 (GN4-1) and No. 731122 (GN4-2).
10
 * On behalf of the aforementioned projects, GEANT Association is the sole owner
11
 * of the copyright in all material which was developed by a member of the GÉANT
12
 * project. GÉANT Vereniging (Association) is registered with the Chamber of 
13
 * Commerce in Amsterdam with registration number 40535155 and operates in the 
14
 * UK as a branch of GÉANT Vereniging.
15
 * 
16
 * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands. 
17
 * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
18
 *
19
 * License: see the web/copyright.inc.php file in the file structure or
20
 *          <base_url>/copyright.php after deploying the software
21
 */
22
23
namespace web\lib\common;
24
25
use \Exception;
0 ignored issues
show
Bug introduced by
The type \Exception was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
27
/**
28
 * performs validation of user inputs
29
 */
30
class InputValidation extends \core\common\Entity
31
{
32
33
    /**
34
     * returns a simple HTML <p> element with basic explanations about what was
35
     * wrong with the input
36
     * 
37
     * @param string $customtext explanation provided by the validator function
38
     * @return string
39
     */
40
    private function inputValidationError($customtext)
41
    {
42
        \core\common\Entity::intoThePotatoes();
43
        $retval = "<p>" . _("Input validation error: ") . $customtext . "</p>";
44
        \core\common\Entity::outOfThePotatoes();
45
        return $retval;
46
    }
47
48
    /**
49
     * Is this a known Federation? Optionally, also check if the authenticated
50
     * user is a federation admin of that federation
51
     * @param mixed       $input the ISO code of the federation
52
     * @param string|NULL $owner the authenticated username, optional
53
     * @return \core\Federation
54
     * @throws Exception
55
     */
56
    public function existingFederation($input, $owner = NULL)
57
    {
58
59
        $cat = new \core\CAT(); // initialises Entity static members
60
        $fedIdentifiers = array_keys($cat->knownFederations);
61
        if (!in_array(strtoupper($input), $fedIdentifiers)) {
62
            throw new Exception($this->inputValidationError(sprintf("This %s does not exist!", \core\common\Entity::$nomenclature_fed)));
63
        }
64
        // totally circular, but this hopefully *finally* make Scrutinizer happier
65
        $correctIndex = array_search(strtoupper($input), $fedIdentifiers);
66
        $postFed = $fedIdentifiers[$correctIndex];
67
68
        $temp = new \core\Federation($postFed);
69
        if ($owner === NULL) {
70
            return $temp;
71
        }
72
73
        foreach ($temp->listFederationAdmins() as $oneowner) {
74
            if ($oneowner == $owner) {
75
                return $temp;
76
            }
77
        }
78
        throw new Exception($this->inputValidationError(sprintf("User is not %s administrator!", \core\common\Entity::$nomenclature_fed)));
79
    }
80
81
    
82
    /**
83
     * Is this a known IdP? Optionally, also check if the authenticated
84
     * user is an admin of that IdP
85
     * It is a wrapper around existingIdPInt.
86
     * 
87
     * @param mixed            $input             the numeric ID of the IdP in the system
88
     * @param string           $owner             the authenticated username, optional
89
     * @param \core\Federation $claimedFedBinding if set, cross-check that IdP belongs to specified federation (useful in admin API mode)
90
     * @return \core\IdP
91
     * @throws Exception
92
     */
93
    public function existingIdP($input, $owner = NULL, $claimedFedBinding = NULL)
94
    {
95
        $clean = $this->integer($input);
96
        if ($clean === FALSE) {
97
            throw new Exception($this->inputValidationError("Value for IdP is not an integer!"));
98
        }
99
        
100
        $checkResult = $this->existingIdPInt($input, $owner, $claimedFedBinding);
101
        $this->loggerInstance->debug(4, $checkResult, "existingIdP:", "\n");
102
        if ($checkResult[1] == 'fullaccess') {
103
            return $checkResult[0];
104
        }
105
        if ($owner == NULL && $checkResult[1] == 'nouser') {
106
            return $checkResult[0];
107
        }
108
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type core\IdP.
Loading history...
109
    }
110
    
111
    
112
    /**
113
     * Is this a known IdP? Optionally, also check if the authenticated
114
     * user is an admin of that IdP or a federation admin for the parent federation
115
     * federaton admins get read-only access
116
     * @param mixed            $input             the numeric ID of the IdP in the system
117
     * @param string           $owner             the authenticated username, optional
118
     * @param \core\Federation $claimedFedBinding if set, cross-check that IdP belongs to specified federation (useful in admin API mode)
119
     * @return \core\IdP
120
     * @throws Exception
121
     */
122
    public function existingIdPInt($input, $owner = NULL, $claimedFedBinding = NULL)
123
    {
124
        $clean = $this->integer($input);
125
        if ($clean === FALSE) {
126
            throw new Exception($this->inputValidationError("Value for IdP is not an integer!"));
127
        }
128
        $temp = new \core\IdP($input); // constructor throws an exception if NX, game over
129
        if ($owner !== NULL) { // check if the authenticated user is allowed to see this institution
130
            $user = new \core\User($owner);        
131
            foreach ($temp->listOwners() as $oneowner) {
132
                if ($oneowner['ID'] == $owner) {
133
                    return [$temp, 'fullaccess'];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array($temp, 'fullaccess') returns the type array<integer,core\IdP|string> which is incompatible with the documented return type core\IdP.
Loading history...
134
                }
135
            }
136
            if ($user->isFederationAdmin($temp->federation)) {
137
                $this->loggerInstance->debug(4, "You are fed admin for this IdP\n");
138
                return [$temp,'readonly'];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array($temp, 'readonly') returns the type array<integer,core\IdP|string> which is incompatible with the documented return type core\IdP.
Loading history...
139
            }
140
            throw new Exception($this->inputValidationError("This IdP identifier is not accessible!"));
141
        }
142
        if ($claimedFedBinding !== NULL && strtoupper($temp->federation) != strtoupper($claimedFedBinding->tld)) {
143
            throw new Exception($this->inputValidationError("This IdP does not belong to the claimed federation!"));
144
        }
145
        return [$temp,'nouser'];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array($temp, 'nouser') returns the type array<integer,core\IdP|string> which is incompatible with the documented return type core\IdP.
Loading history...
146
    }
147
148
    /**
149
     * Checks if the input refers to a known Profile. Optionally also takes an
150
     * IdP identifier and then checks if the Profile belongs to the referenced 
151
     * IdP
152
     * 
153
     * @param mixed    $input         the numeric ID of the Profile in the system
154
     * @param int|NULL $idpIdentifier the numeric ID of the IdP in the system, optional
155
     * @return \core\AbstractProfile
156
     * @throws Exception
157
     */
158
    public function existingProfile($input, $idpIdentifier = NULL)
159
    {
160
        $clean = $this->integer($input);
161
        if ($clean === FALSE) {
162
            throw new Exception("Non-integer was passed to Profile validator!");
163
        }
164
        $temp = \core\ProfileFactory::instantiate($clean); // constructor throws an exception if NX, game over
165
166
        if ($idpIdentifier !== NULL && $temp->institution != $idpIdentifier) {
167
            throw new Exception($this->inputValidationError("The profile does not belong to the IdP!"));
168
        }
169
        return $temp;
170
    }
171
172
    /**
173
     * Checks if the input refers to a known DeploymentManaged. Optionally also takes an
174
     * IdP identifier and then checks if the Profile belongs to the referenced 
175
     * IdP
176
     * 
177
     * @param mixed     $input the numeric ID of the Deployment in the system
178
     * @param \core\IdP $idp   the IdP
179
     * @return \core\DeploymentManaged
180
     * @throws Exception
181
     */
182
    public function existingDeploymentManaged($input, $idp)
183
    {
184
        $clean = $this->integer($input);
185
        if ($clean === FALSE) {
186
            throw new Exception("Non-integer was passed to Profile validator!");
187
        }
188
        $temp = new \core\DeploymentManaged($idp, $clean); // constructor throws an exception if NX, game over
189
190
        if ($temp->institution != $idp->identifier) {
191
            throw new Exception($this->inputValidationError("The profile does not belong to the IdP!"));
192
        }
193
        return $temp;
194
    }
195
196
    /**
197
     * Checks if this is a device known to the system
198
     * @param mixed $input the name of the device (index in the Devices.php array)
199
     * @return string returns the same string on success, throws an Exception on failure
200
     * @throws Exception
201
     */
202
    public function existingDevice($input)
203
    {
204
        $devicelist = \devices\Devices::listDevices();
205
        $keyArray = array_keys($devicelist);
206
        if (!isset($devicelist[$input])) {
207
            throw new Exception($this->inputValidationError("This device does not exist!"));
208
        }
209
        $correctIndex = array_search($input, $keyArray);
210
        return $keyArray[$correctIndex];
211
    }
212
213
    /**
214
     * Checks if the input was a valid string.
215
     * 
216
     * @param mixed   $input           a string to be made SQL-safe
217
     * @param boolean $allowWhitespace whether some whitespace (e.g. newlines should be preserved (true) or redacted (false)
218
     * @return string the massaged string
219
     * @throws Exception
220
     */
221
    public function string($input, $allowWhitespace = FALSE)
222
    {
223
        // always chop out invalid characters, and surrounding whitespace
224
        $retvalStep0 = iconv("UTF-8", "UTF-8//TRANSLIT", $input);
225
        if ($retvalStep0 === FALSE) {
226
            throw new Exception("iconv failure for string sanitisation. With TRANSLIT, this should never happen!");
227
        }
228
        $retvalStep1 = trim($retvalStep0);
229
        // if some funny person wants to inject markup tags, remove them
230
        $retval = filter_var($retvalStep1, FILTER_SANITIZE_STRING, ["flags" => FILTER_FLAG_NO_ENCODE_QUOTES]);
231
        if ($retval === FALSE) {
232
            throw new Exception("filter_var failure for string sanitisation.");
233
        }
234
        // unless explicitly wanted, take away intermediate disturbing whitespace
235
        // a simple "space" is NOT disturbing :-)
236
        if ($allowWhitespace === FALSE) {
237
            $afterWhitespace = preg_replace('/(\0|\r|\x0b|\t|\n)/', '', $retval);
238
        } else {
239
            // even if we allow whitespace, not pathological ones!
240
            $afterWhitespace = preg_replace('/(\0|\r|\x0b)/', '', $retval);
241
        }
242
        if (is_array($afterWhitespace)) {
243
            throw new Exception("This function has to be given a string and returns a string. preg_replace has generated an array instead!");
244
        }
245
        return (string) $afterWhitespace;
246
    }
247
248
    /**
249
     * Is this an integer, or a string that represents an integer?
250
     * 
251
     * @param mixed $input the raw input
252
     * @return boolean|int returns the input, or FALSE if it is not an integer-like value
253
     */
254
    public function integer($input)
255
    {
256
        if (is_numeric($input)) {
257
            return (int) $input;
258
        }
259
        return FALSE;
260
    }
261
262
    /**
263
     * Is this a string representing a potentially more than 64-Bit length integer?
264
     * 
265
     * @param string $input the input data which is possibly a really large integer
266
     * @return boolean|string returns the input, or FALSE if it is not an integer-like string
267
     */
268
    public function hugeInteger($input)
269
    {
270
        if (is_numeric($input)) {
271
            return $input;
272
        }
273
        return FALSE;
274
    }
275
276
    /**
277
     * Checks if the input is the hex representation of a Consortium OI (i.e. three
278
     * or five bytes)
279
     * 
280
     * @param mixed $input the raw input
281
     * @return boolean|string returns the input, or FALSE on validation failure
282
     */
283
    public function consortiumOI($input)
284
    {
285
        $shallow = $this->string($input);
286
        if (strlen($shallow) != 6 && strlen($shallow) != 10) {
287
            return FALSE;
288
        }
289
        if (!preg_match("/^[a-fA-F0-9]+$/", $shallow)) {
290
            return FALSE;
291
        }
292
        return $shallow;
293
    }
294
295
    /**
296
     * Is the input an NAI realm? Throws HTML error and returns FALSE if not.
297
     * 
298
     * @param mixed $input the input to check
299
     * @return boolean|string returns the realm, or FALSE if it was malformed
300
     */
301
    public function realm($input)
302
    {
303
        \core\common\Entity::intoThePotatoes();
304
        if (strlen($input) == 0) {
305
            echo $this->inputValidationError(_("Realm is empty!"));
306
            \core\common\Entity::outOfThePotatoes();
307
            return FALSE;
308
        }
309
310
        // basic string checks
311
        $check = $this->string($input);
312
        // list of things to check, and the error they produce
313
        $pregCheck = [
314
            "/@/" => _("Realm contains an @ sign!"),
315
            "/^\./" => _("Realm begins with a . (dot)!"),
316
            "/\.$/" => _("Realm ends with a . (dot)!"),
317
            "/ /" => _("Realm contains spaces!"),
318
        ];
319
320
        // bark on invalid constructs
321
        foreach ($pregCheck as $search => $error) {
322
            if (preg_match($search, $check) == 1) {
323
                echo $this->inputValidationError($error);
324
                \core\common\Entity::outOfThePotatoes();
325
                return FALSE;
326
            }
327
        }
328
329
        if (preg_match("/\./", $check) == 0) {
330
            echo $this->inputValidationError(_("Realm does not contain at least one . (dot)!"));
331
            \core\common\Entity::outOfThePotatoes();
332
            return FALSE;
333
        }
334
335
        // none of the special HTML entities should be here. In case someone wants
336
        // to mount a CSS attack by providing something that matches the realm constructs
337
        // below but has interesting stuff between, mangle the input so that these
338
        // characters do not do any harm.
339
        \core\common\Entity::outOfThePotatoes();
340
        return htmlentities($check, ENT_QUOTES);
341
    }
342
343
    /**
344
     * could this be a valid username? 
345
     * 
346
     * Only checks correct form, not if the user actually exists in the system.
347
     * 
348
     * @param mixed $input the username
349
     * @return string echoes back the input string, or throws an Exception if bogus
350
     * @throws Exception
351
     */
352
    public function syntaxConformUser($input)
353
    {
354
        $retvalStep0 = iconv("UTF-8", "UTF-8//TRANSLIT", $input);
355
        if ($retvalStep0 === FALSE) {
356
            throw new Exception("iconv failure for string sanitisation. With TRANSLIT, this should never happen!");
357
        }
358
        $retvalStep1 = trim($retvalStep0);
359
360
        $retval = preg_replace('/(\0|\r|\x0b|\t|\n)/', '', $retvalStep1);
361
        if ($retval != "" && !ctype_print($retval)) {
362
            throw new Exception($this->inputValidationError("The user identifier is not an ASCII string!"));
363
        }
364
365
        return $retval;
366
    }
367
368
    /**
369
     * could this be a valid token? 
370
     * 
371
     * Only checks correct form, not if the token actually exists in the system.
372
     * @param mixed $input the raw input
373
     * @return string echoes back the input string, or throws an Exception if bogus
374
     * @throws Exception
375
     */
376
    public function token($input)
377
    {
378
        $retval = $input;
379
        if ($input != "" && preg_match('/[^0-9a-fA-F]/', $input) != 0) {
380
            throw new Exception($this->inputValidationError("Token is not a hexadecimal string!"));
381
        }
382
        return $retval;
383
    }
384
385
    /**
386
     * Is this be a valid coordinate vector on one axis?
387
     * 
388
     * @param mixed $input a numeric value in range of a geo coordinate [-180;180]
389
     * @return string returns back the input if all is good; throws an Exception if out of bounds or not numeric
390
     * @throws Exception
391
     */
392
    public function coordinate($input)
393
    {
394
        $oldlocale = setlocale(LC_NUMERIC, 0);
395
        setlocale(LC_NUMERIC, "en_GB");
396
        if (!is_numeric($input)) {
397
            throw new Exception($this->inputValidationError("Coordinate is not a numeric value!"));
398
        }
399
        setlocale(LC_NUMERIC, $oldlocale);
400
        // lat and lon are always in the range of [-180;+180]
401
        if ($input < -180 || $input > 180) {
402
            throw new Exception($this->inputValidationError("Coordinate is out of bounds. Which planet are you from?"));
403
        }
404
        return $input;
405
    }
406
407
    /**
408
     * Is this a valid coordinate pair in JSON encoded representation?
409
     * 
410
     * @param mixed $input the string to be checked: is this a serialised array with lat/lon keys in a valid number range?
411
     * @return string returns $input if checks have passed; throws an Exception if something's wrong
412
     * @throws Exception
413
     */
414
    public function coordJsonEncoded($input)
415
    {
416
        $tentative = json_decode($input, true);
417
        if (is_array($tentative)) {
418
            if (isset($tentative['lon']) && isset($tentative['lat']) && $this->coordinate($tentative['lon']) && $this->coordinate($tentative['lat'])) {
419
                return $input;
420
            }
421
        }
422
        throw new Exception($this->inputValidationError("Wrong coordinate encoding (2.0 uses JSON, not serialize)!"));
423
    }
424
425
    /**
426
     * This checks the state of a HTML GET/POST "boolean".
427
     * 
428
     * If not checked, no value is submitted at all; if checked, has the word "on". 
429
     * Anything else is a big error.
430
     * 
431
     * @param mixed $input the string to test
432
     * @return boolean TRUE if the input was "on". It is not possible in HTML to signal "off"
433
     * @throws Exception
434
     */
435
    public function boolean($input)
436
    {
437
        if ($input != "on") {
438
            throw new Exception($this->inputValidationError("Unknown state of boolean option!"));
439
        }
440
        return TRUE;
441
    }
442
443
    /**
444
     * checks if we have the strings "IdP" "SP" or "IdPSP"
445
     * 
446
     * @param string $partTypeRaw the string to be validated as participant type
447
     * @return string validated result
448
     * @throws Exception
449
     */
450
    public function partType($partTypeRaw)
451
    {
452
        switch ($partTypeRaw) {
453
            case \core\IdP::TYPE_IDP:
454
                return \core\IdP::TYPE_IDP;
455
            case \core\IdP::TYPE_SP:
456
                return \core\IdP::TYPE_SP;
457
            case \core\IdP::TYPE_IDPSP:
458
                return \core\IdP::TYPE_IDPSP;
459
            default:
460
                throw new Exception("Unknown Participant Type!");
461
        }
462
    }
463
464
    const TABLEMAPPING = [
465
        "IdP" => "institution_option",
466
        "Profile" => "profile_option",
467
        "FED" => "federation_option",
468
    ];
469
470
    /**
471
     * Is this a valid database reference? Has the form <tablename>-<rowID> and there
472
     * needs to be actual data at that place
473
     * 
474
     * @param string $input the reference to check
475
     * @return boolean|array the reference split up into "table" and "rowindex", or FALSE
476
     */
477
    public function databaseReference($input)
478
    {
479
        $pregMatches = [];
480
        if (preg_match("/^ROWID-(IdP|Profile|FED)-([0-9]+)$/", $input, $pregMatches) != 1) {
481
            return FALSE;
482
        }
483
        $rownumber = $this->integer($pregMatches[2]);
484
        if ($rownumber === FALSE) {
485
            return FALSE;
486
        }
487
        return ["table" => self::TABLEMAPPING[$pregMatches[1]], "rowindex" => $rownumber];
488
    }
489
490
    /**
491
     * is this a valid hostname?
492
     * 
493
     * @param mixed $input the raw input
494
     * @return boolean|string echoes the hostname, or FALSE if bogus
495
     */
496
    public function hostname($input)
497
    {
498
        // is it a valid IP address (IPv4 or IPv6), or a hostname?
499
        if (filter_var($input, FILTER_VALIDATE_IP) || filter_var($input, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
500
            // if it's a verified IP address or hostname then it does not contain
501
            // rubbish of course. But just to be sure, run htmlspecialchars around it
502
            return htmlspecialchars($input, ENT_QUOTES);
503
        }
504
        return FALSE;
505
    }
506
507
    /**
508
     * is this a valid email address?
509
     * 
510
     * @param mixed $input the raw input
511
     * @return boolean|string echoes the mail address, or FALSE if bogus
512
     */
513
    public function email($input)
514
    {
515
516
        if (filter_var($this->string($input), FILTER_VALIDATE_EMAIL)) {
517
            return $input;
518
        }
519
        // if we get here, it's bogus
520
        return FALSE;
521
    }
522
523
    /**
524
     * is this a well-formed SMS number? Light massaging - leading + will be removed
525
     * @param string $input the raw input
526
     * @return boolean|string
527
     */
528
    public function sms($input)
529
    {
530
        $number = str_replace(' ', '', str_replace(".", "", str_replace("+", "", $input)));
531
        if (!is_numeric($number)) {
532
            return FALSE;
533
        }
534
        return $number;
535
    }
536
537
    /**
538
     * Is this is a language we support? If not, sanitise to our configured default language.
539
     * 
540
     * @param mixed $input the candidate language identifier
541
     * @return string
542
     * @throws Exception
543
     */
544
    public function supportedLanguage($input)
545
    {
546
        if (!array_key_exists($input, \config\Master::LANGUAGES)) {
547
            return \config\Master::APPEARANCE['defaultlocale'];
548
        }
549
        // otherwise, use the inversion trick to convince Scrutinizer that this is
550
        // a vetted value
551
        $retval = array_search(\config\Master::LANGUAGES[$input], \config\Master::LANGUAGES);
552
        if ($retval === FALSE) {
553
            throw new Exception("Impossible: the value we are searching for does exist, because we reference it directly.");
554
        }
555
        return $retval;
556
    }
557
558
    /**
559
     * Makes sure we are not receiving a bogus option name. The called function throws
560
     * an assertion if the name is not known.
561
     * 
562
     * @param mixed $input the unvetted option name
563
     * @return string
564
     */
565
    public function optionName($input)
566
    {
567
        $object = \core\Options::instance();
568
        return $object->assertValidOptionName($input);
569
    }
570
571
    /**
572
     * Checks to see if the input is a valid image of sorts
573
     * 
574
     * @param mixed $binary blob that may or may not be a parseable image
575
     * @return boolean
576
     */
577
    public function image($binary)
578
    {
579
        if (class_exists('\\Gmagick')) { 
580
            $image = new \Gmagick(); 
581
        } else {
582
            $image = new \Imagick();
583
        }
584
        try {
585
            $image->readImageBlob($binary);
586
        } catch (\ImagickException $exception) {
587
            echo "Error" . $exception->getMessage();
588
            return FALSE;
589
        }
590
        // image survived the sanity check
591
        return TRUE;
592
    }
593
594
    /**
595
     * searches for values in GET and POST, and filters the value according to
596
     * which kind of data is expected
597
     * 
598
     * @param string $varName name of the variable in GET/POST
599
     * @param string $filter  which type of filter to apply (safe_text / int)
600
     * @return NULL|string|integer the returned value
601
     */
602
    public function simpleInputFilter($varName, $filter)
603
    {
604
        $safeText = ["options" => ["regexp" => "/^[\w\d-]+$/"]];
605
        switch ($filter) {
606
            case 'safe_text':
607
                $out = filter_input(INPUT_GET, $varName, FILTER_VALIDATE_REGEXP, $safeText) ?? filter_input(INPUT_POST, $varName, FILTER_VALIDATE_REGEXP, $safeText);
608
                break;
609
            case 'int':
610
                $out = filter_input(INPUT_GET, $varName, FILTER_VALIDATE_INT) ?? filter_input(INPUT_POST, $varName, FILTER_VALIDATE_INT);
611
                break;
612
            default:
613
                $out = NULL;
614
                break;
615
        }
616
        if ($out === false) { // an error occurred during the filter_input runs; make this NULL instead then
617
            $out = NULL;
618
        }
619
        return $out;
620
    }
621
622
}
623