FilterInput::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0416

Importance

Changes 0
Metric Value
cc 3
eloc 11
nc 4
nop 5
dl 0
loc 22
rs 9.9
c 0
b 0
f 0
ccs 10
cts 12
cp 0.8333
crap 3.0416
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 */
11
12
namespace Xmf;
13
14
/**
15
 * FilterInput is a class for filtering input from any data source
16
 *
17
 * Forked from the php input filter library by Daniel Morris
18
 *
19
 * Original Contributors: Gianpaolo Racca, Ghislain Picard,
20
 *                        Marco Wandschneider, Chris Tobin and Andrew Eddie.
21
 *
22
 * @category  Xmf\FilterInput
23
 * @package   Xmf
24
 * @author    Daniel Morris <[email protected]>
25
 * @author    Louis Landry <[email protected]>
26
 * @author    Grégory Mage (Aka Mage)
27
 * @author    trabis <[email protected]>
28
 * @author    Richard Griffith <[email protected]>
29
 * @copyright 2005 Daniel Morris
30
 * @copyright 2005 - 2013 Open Source Matters, Inc. All rights reserved.
31
 * @copyright 2011-2018 XOOPS Project (https://xoops.org)
32
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
33
 * @link      https://xoops.org
34
 */
35
class FilterInput
36
{
37
    protected $tagsArray;         // default is empty array
38
    protected $attrArray;         // default is empty array
39
40
    protected $tagsMethod;        // default is 0
41
    protected $attrMethod;        // default is 0
42
43
    protected $xssAuto;           // default is 1
44
    protected $tagBlacklist = array(
45
        'applet',
46
        'body',
47
        'bgsound',
48
        'base',
49
        'basefont',
50
        'embed',
51
        'frame',
52
        'frameset',
53
        'head',
54
        'html',
55
        'id',
56
        'iframe',
57
        'ilayer',
58
        'layer',
59
        'link',
60
        'meta',
61
        'name',
62
        'object',
63
        'script',
64
        'style',
65
        'title',
66
        'xml'
67
    );
68
    // also will strip ALL event handlers
69
    protected $attrBlacklist = array('action', 'background', 'codebase', 'dynsrc', 'lowsrc');
70
71
    /**
72
     * Constructor
73
     *
74
     * @param array $tagsArray  - list of user-defined tags
75
     * @param array $attrArray  - list of user-defined attributes
76
     * @param int   $tagsMethod - 0 = allow just user-defined, 1 = allow all but user-defined
77
     * @param int   $attrMethod - 0 = allow just user-defined, 1 = allow all but user-defined
78
     * @param int   $xssAuto    - 0 = only auto clean essentials, 1 = allow clean blacklisted tags/attr
79
     */
80 4
    protected function __construct(
81
        $tagsArray = array(),
82
        $attrArray = array(),
83
        $tagsMethod = 0,
84
        $attrMethod = 0,
85
        $xssAuto = 1
86
    ) {
87
        // make sure user defined arrays are in lowercase
88 4
        $tagsArrayCount = count($tagsArray);
89 4
        for ($i = 0; $i < $tagsArrayCount; ++$i) {
90
            $tagsArray[$i] = strtolower($tagsArray[$i]);
91
        }
92 4
        $attrArrayCount = count($attrArray);
93 4
        for ($i = 0; $i < $attrArrayCount; ++$i) {
94
            $attrArray[$i] = strtolower($attrArray[$i]);
95
        }
96
        // assign to member vars
97 4
        $this->tagsArray  = (array) $tagsArray;
98 4
        $this->attrArray  = (array) $attrArray;
99 4
        $this->tagsMethod = $tagsMethod;
100 4
        $this->attrMethod = $attrMethod;
101 4
        $this->xssAuto    = $xssAuto;
102 4
    }
103
104
    /**
105
     * Returns an input filter object, only creating it if it does not already exist.
106
     *
107
     * This method must be invoked as:
108
     *   $filter = FilterInput::getInstance();
109
     *
110
     * @param array $tagsArray  list of user-defined tags
111
     * @param array $attrArray  list of user-defined attributes
112
     * @param int   $tagsMethod WhiteList method = 0, BlackList method = 1
113
     * @param int   $attrMethod WhiteList method = 0, BlackList method = 1
114
     * @param int   $xssAuto    Only auto clean essentials = 0,
115
     *                          Allow clean blacklisted tags/attr = 1
116
     *
117
     * @return FilterInput object.
118
     */
119 22
    public static function getInstance(
120
        $tagsArray = array(),
121
        $attrArray = array(),
122
        $tagsMethod = 0,
123
        $attrMethod = 0,
124
        $xssAuto = 1
125
    ) {
126 22
        static $instances;
127
128 22
        $className = get_called_class(); // so an extender gets an instance of itself
129
130 22
        $sig = md5(serialize(array($className, $tagsArray, $attrArray, $tagsMethod, $attrMethod, $xssAuto)));
131
132 22
        if (!isset($instances)) {
133
            $instances = array();
134
        }
135
136 22
        if (empty($instances[$sig])) {
137 4
            $instances[$sig] = new static($tagsArray, $attrArray, $tagsMethod, $attrMethod, $xssAuto);
138
        }
139
140 22
        return $instances[$sig];
141
    }
142
143
    /**
144
     * Method to be called by another php script. Processes for XSS and
145
     * any specified bad code.
146
     *
147
     * @param mixed $source - input string/array-of-string to be 'cleaned'
148
     *
149
     * @return string $source - 'cleaned' version of input parameter
150
     */
151 23
    public function process($source)
152
    {
153 23
        if (is_array($source)) {
154
            // clean all elements in this array
155 3
            foreach ($source as $key => $value) {
156
                // filter element for XSS and other 'bad' code etc.
157 3
                if (is_string($value)) {
158 3
                    $source[$key] = $this->remove($this->decode($value));
159
                }
160
            }
161 3
            return $source;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $source returns the type array which is incompatible with the documented return type string.
Loading history...
162 20
        } elseif (is_string($source)) {
163
            // clean this string
164 20
            return $this->remove($this->decode($source));
165
        } else {
166
            // return parameter as given
167
            return $source;
168
        }
169
    }
170
171
    /**
172
     * Static method to be called by another php script.
173
     * Clean the supplied input using the default filter
174
     *
175
     * @param mixed  $source Input string/array-of-string to be 'cleaned'
176
     * @param string $type   Return/cleaning type for the variable, one of
177
     *                       (INTEGER, FLOAT, BOOLEAN, WORD, ALPHANUM, CMD, BASE64,
178
     *                        STRING, ARRAY, PATH, USERNAME, WEBURL, EMAIL, IP)
179
     *
180
     * @return mixed 'Cleaned' version of input parameter
181
     * @static
182
     */
183 29
    public static function clean($source, $type = 'string')
184
    {
185 29
        static $filter = null;
186
187
        // need an instance for methods, since this is supposed to be static
188
        // we must instantiate the class - this will take defaults
189 29
        if (!is_object($filter)) {
190
            $filter = static::getInstance();
191
        }
192
193 29
        return $filter->cleanVar($source, $type);
194
    }
195
196
    /**
197
     * Method to be called by another php script. Processes for XSS and
198
     * specified bad code according to rules supplied when this instance
199
     * was instantiated.
200
     *
201
     * @param mixed  $source Input string/array-of-string to be 'cleaned'
202
     * @param string $type   Return/cleaning type for the variable, one of
203
     *                       (INTEGER, FLOAT, BOOLEAN, WORD, ALPHANUM, CMD, BASE64,
204
     *                        STRING, ARRAY, PATH, USERNAME, WEBURL, EMAIL, IP)
205
     *
206
     * @return mixed 'Cleaned' version of input parameter
207
     * @static
208
     */
209 44
    public function cleanVar($source, $type = 'string')
210
    {
211
        // Handle the type constraint
212 44
        switch (strtoupper($type)) {
213 44
            case 'INT':
214 41
            case 'INTEGER':
215
                // Only use the first integer value
216 4
                preg_match('/-?\d+/', (string) $source, $matches);
217 4
                $result = @ (int) $matches[0];
218 4
                break;
219
220 40
            case 'FLOAT':
221 37
            case 'DOUBLE':
222
                // Only use the first floating point value
223 4
                preg_match('/-?\d+(\.\d+)?/', (string) $source, $matches);
224 4
                $result = @ (float) $matches[0];
225 4
                break;
226
227 36
            case 'BOOL':
228 33
            case 'BOOLEAN':
229 5
                $result = (bool) $source;
230 5
                break;
231
232 32
            case 'WORD':
233 4
                $result = (string) preg_replace('/[^A-Z_]/i', '', $source);
234 4
                break;
235
236 29
            case 'ALPHANUM':
237 28
            case 'ALNUM':
238 2
                $result = (string) preg_replace('/[^A-Z0-9]/i', '', $source);
239 2
                break;
240
241 27
            case 'CMD':
242 2
                $result = (string) preg_replace('/[^A-Z0-9_\.-]/i', '', $source);
243 2
                $result = strtolower($result);
244 2
                break;
245
246 25
            case 'BASE64':
247
                $result = (string) preg_replace('/[^A-Z0-9\/+=]/i', '', $source);
248
                break;
249
250 25
            case 'STRING':
251 12
                $result = (string) $this->process($source);
252 12
                break;
253
254 13
            case 'ARRAY':
255 4
                $result = (array) $this->process($source);
256 4
                break;
257
258 9
            case 'PATH':
259 1
                $source = trim((string) $source);
260 1
                $pattern = '/^([-_\.\/A-Z0-9=&%?~]+)(.*)$/i';
261 1
                preg_match($pattern, $source, $matches);
262 1
                $result = @ (string) $matches[1];
263 1
                break;
264
265 8
            case 'USERNAME':
266
                $result = (string) preg_replace('/[\x00-\x1F\x7F<>"\'%&]/', '', $source);
267
                break;
268
269 8
            case 'WEBURL':
270 1
                $result = (string) $this->process($source);
271
                // allow only relative, http or https
272 1
                $urlparts = parse_url($result);
273 1
                if (!empty($urlparts['scheme'])
274 1
                    && !($urlparts['scheme'] === 'http' || $urlparts['scheme'] === 'https')
275
                ) {
276 1
                    $result = '';
277
                }
278
                // do not allow quotes, tag brackets or controls
279 1
                if (!preg_match('#^[^"<>\x00-\x1F]+$#', $result)) {
280 1
                    $result = '';
281
                }
282 1
                break;
283
284 7
            case 'EMAIL':
285 1
                $result = (string) $source;
286 1
                if (!filter_var((string) $source, FILTER_VALIDATE_EMAIL)) {
287 1
                    $result = '';
288
                }
289 1
                break;
290
291 6
            case 'IP':
292 2
                $result = (string) $source;
293
                // this may be too restrictive.
294
                // Should the FILTER_FLAG_NO_PRIV_RANGE flag be excluded?
295 2
                if (!filter_var((string) $source, FILTER_VALIDATE_IP)) {
296 2
                    $result = '';
297
                }
298 2
                break;
299
300
            default:
301 4
                $result = $this->process($source);
302 4
                break;
303
        }
304
305 44
        return $result;
306
    }
307
308
    /**
309
     * Internal method to iteratively remove all unwanted tags and attributes
310
     *
311
     * @param String $source - input string to be 'cleaned'
312
     *
313
     * @return String $source - 'cleaned' version of input parameter
314
     */
315 23
    protected function remove($source)
316
    {
317 23
        $loopCounter = 0;
318
        // provides nested-tag protection
319 23
        while ($source != $this->filterTags($source)) {
320 14
            $source = $this->filterTags($source);
321 14
            ++$loopCounter;
322
        }
323
324 23
        return $source;
325
    }
326
327
    /**
328
     * Internal method to strip a string of certain tags
329
     *
330
     * @param String $source - input string to be 'cleaned'
331
     *
332
     * @return String $source - 'cleaned' version of input parameter
333
     */
334 23
    protected function filterTags($source)
335
    {
336
        // filter pass setup
337 23
        $preTag = null;
338 23
        $postTag = $source;
339
        // find initial tag's position
340 23
        $tagOpen_start = strpos($source, '<');
341
        // iterate through string until no tags left
342 23
        while ($tagOpen_start !== false) {
343
            // process tag iteratively
344 16
            $preTag .= substr($postTag, 0, $tagOpen_start);
345 16
            $postTag = substr($postTag, $tagOpen_start);
346 16
            $fromTagOpen = substr($postTag, 1);
347
            // end of tag
348 16
            $tagOpen_end = strpos($fromTagOpen, '>');
349 16
            if ($tagOpen_end === false) {
350
                break;
351
            }
352
            // next start of tag (for nested tag assessment)
353 16
            $tagOpen_nested = strpos($fromTagOpen, '<');
354 16
            if (($tagOpen_nested !== false) && ($tagOpen_nested < $tagOpen_end)) {
355
                $preTag .= substr($postTag, 0, ($tagOpen_nested + 1));
356
                $postTag = substr($postTag, ($tagOpen_nested + 1));
357
                $tagOpen_start = strpos($postTag, '<');
358
                continue;
359
            }
360 16
            $currentTag = substr($fromTagOpen, 0, $tagOpen_end);
361 16
            $tagLength = strlen($currentTag);
362 16
            if (!$tagOpen_end) {
363
                $preTag .= $postTag;
364
            }
365
            // iterate through tag finding attribute pairs - setup
366 16
            $tagLeft = $currentTag;
367 16
            $attrSet = array();
368 16
            $currentSpace = strpos($tagLeft, ' ');
369 16
            if (substr($currentTag, 0, 1) === "/") {
370
                // is end tag
371 16
                $isCloseTag = true;
372 16
                list($tagName) = explode(' ', $currentTag);
373 16
                $tagName = substr($tagName, 1);
374
            } else {
375
                // is start tag
376 16
                $isCloseTag = false;
377 16
                list($tagName) = explode(' ', $currentTag);
378
            }
379
            // excludes all "non-regular" tagnames OR no tagname OR remove if xssauto is on and tag is blacklisted
380 16
            if ((!preg_match("/^[a-z][a-z0-9]*$/i", $tagName))
381 16
                || (!$tagName)
382 16
                || ((in_array(strtolower($tagName), $this->tagBlacklist))
383 16
                    && ($this->xssAuto))
384
            ) {
385 12
                $postTag = substr($postTag, ($tagLength + 2));
386 12
                $tagOpen_start = strpos($postTag, '<');
387
                // don't append this tag
388 12
                continue;
389
            }
390
            // this while is needed to support attribute values with spaces in!
391 14
            while ($currentSpace !== false) {
392
                $fromSpace = substr($tagLeft, ($currentSpace + 1));
393
                $nextSpace = strpos($fromSpace, ' ');
394
                $openQuotes = strpos($fromSpace, '"');
395
                $closeQuotes = strpos(substr($fromSpace, ($openQuotes + 1)), '"') + $openQuotes + 1;
396
                // another equals exists
397
                if (strpos($fromSpace, '=') !== false) {
398
                    // opening and closing quotes exists
399
                    if (($openQuotes !== false)
400
                        && (strpos(substr($fromSpace, ($openQuotes + 1)), '"') !== false)
401
                    ) {
402
                        $attr = substr($fromSpace, 0, ($closeQuotes + 1));
403
                    } else {
404
                        $attr = substr($fromSpace, 0, $nextSpace);
405
                    }
406
                    // one or neither exist
407
                } else {
408
                    // no more equals exist
409
                    $attr = substr($fromSpace, 0, $nextSpace);
410
                }
411
                // last attr pair
412
                if (!$attr) {
413
                    $attr = $fromSpace;
414
                }
415
                // add to attribute pairs array
416
                $attrSet[] = $attr;
417
                // next inc
418
                $tagLeft = substr($fromSpace, strlen($attr));
419
                $currentSpace = strpos($tagLeft, ' ');
420
            }
421
            // appears in array specified by user
422 14
            $tagFound = in_array(strtolower($tagName), $this->tagsArray);
423
            // remove this tag on condition
424 14
            if ((!$tagFound && $this->tagsMethod) || ($tagFound && !$this->tagsMethod)) {
425
                // reconstruct tag with allowed attributes
426 4
                if (!$isCloseTag) {
427 4
                    $attrSet = $this->filterAttr($attrSet);
428 4
                    $preTag .= '<' . $tagName;
429 4
                    $attrSetCount = count($attrSet);
430 4
                    for ($i = 0; $i < $attrSetCount; ++$i) {
431
                        $preTag .= ' ' . $attrSet[$i];
432
                    }
433
                    // reformat single tags to XHTML
434 4
                    if (strpos($fromTagOpen, "</" . $tagName)) {
435 4
                        $preTag .= '>';
436
                    } else {
437 4
                        $preTag .= ' />';
438
                    }
439
                } else {
440
                    // just the tagname
441 4
                    $preTag .= '</' . $tagName . '>';
442
                }
443
            }
444
            // find next tag's start
445 14
            $postTag = substr($postTag, ($tagLength + 2));
446 14
            $tagOpen_start = strpos($postTag, '<');
447
        }
448
        // append any code after end of tags
449 23
        $preTag .= $postTag;
450
451 23
        return $preTag;
452
    }
453
454
    /**
455
     * Internal method to strip a tag of certain attributes
456
     *
457
     * @param array $attrSet attributes
458
     *
459
     * @return array $newSet stripped attributes
460
     */
461 4
    protected function filterAttr($attrSet)
462
    {
463 4
        $newSet = array();
464
        // process attributes
465 4
        $attrSetCount = count($attrSet);
466 4
        for ($i = 0; $i < $attrSetCount; ++$i) {
467
            // skip blank spaces in tag
468
            if (!$attrSet[$i]) {
469
                continue;
470
            }
471
            // split into attr name and value
472
            $attrSubSet = explode('=', trim($attrSet[$i]));
473
            list($attrSubSet[0]) = explode(' ', $attrSubSet[0]);
474
            // removes all "non-regular" attr names AND also attr blacklisted
475
            if ((!preg_match('/[a-z]*$/i', $attrSubSet[0]))
476
                || (($this->xssAuto)
477
                    && ((in_array(strtolower($attrSubSet[0]), $this->attrBlacklist))
478
                        || (substr($attrSubSet[0], 0, 2) === 'on')))
479
            ) {
480
                continue;
481
            }
482
            // xss attr value filtering
483
            if ($attrSubSet[1]) {
484
                // strips unicode, hex, etc
485
                $attrSubSet[1] = str_replace('&#', '', $attrSubSet[1]);
486
                // strip normal newline within attr value
487
                $attrSubSet[1] = preg_replace('/\s+/', '', $attrSubSet[1]);
488
                // strip double quotes
489
                $attrSubSet[1] = str_replace('"', '', $attrSubSet[1]);
490
                // [requested feature] convert single quotes from either side to doubles
491
                // (Single quotes shouldn't be used to pad attr value)
492
                if ((substr($attrSubSet[1], 0, 1) === "'")
493
                    && (substr($attrSubSet[1], (strlen($attrSubSet[1]) - 1), 1) === "'")
494
                ) {
495
                    $attrSubSet[1] = substr($attrSubSet[1], 1, (strlen($attrSubSet[1]) - 2));
496
                }
497
                // strip slashes
498
                $attrSubSet[1] = stripslashes($attrSubSet[1]);
499
            }
500
            // auto strip attr's with "javascript:
501
            if (((strpos(strtolower($attrSubSet[1]), 'expression') !== false)
502
                    && (strtolower($attrSubSet[0]) === 'style')) ||
503
                (strpos(strtolower($attrSubSet[1]), 'javascript:') !== false) ||
504
                (strpos(strtolower($attrSubSet[1]), 'behaviour:') !== false) ||
505
                (strpos(strtolower($attrSubSet[1]), 'vbscript:') !== false) ||
506
                (strpos(strtolower($attrSubSet[1]), 'mocha:') !== false) ||
507
                (strpos(strtolower($attrSubSet[1]), 'livescript:') !== false)
508
            ) {
509
                continue;
510
            }
511
512
            // if matches user defined array
513
            $attrFound = in_array(strtolower($attrSubSet[0]), $this->attrArray);
514
            // keep this attr on condition
515
            if ((!$attrFound && $this->attrMethod) || ($attrFound && !$this->attrMethod)) {
516
                if ($attrSubSet[1]) {
517
                    // attr has value
518
                    $newSet[] = $attrSubSet[0] . '="' . $attrSubSet[1] . '"';
519
                } elseif ($attrSubSet[1] == "0") {
520
                    // attr has decimal zero as value
521
                    $newSet[] = $attrSubSet[0] . '="0"';
522
                } else {
523
                    // reformat single attributes to XHTML
524
                    $newSet[] = $attrSubSet[0] . '="' . $attrSubSet[0] . '"';
525
                }
526
            }
527
        }
528
529 4
        return $newSet;
530
    }
531
532
    /**
533
     * Try to convert to plaintext
534
     *
535
     * @param String $source string to decode
536
     *
537
     * @return String $source decoded
538
     */
539 23
    protected function decode($source)
540
    {
541
        // url decode
542 23
        $charset = defined('_CHARSET') ? constant('_CHARSET') : 'utf-8';
543 23
        $source = html_entity_decode($source, ENT_QUOTES, $charset);
544
        // convert decimal
545 23
        $source = preg_replace_callback(
546 23
            '/&#(\d+);/m',
547
            function ($matches) {
548
                return chr($matches[1]);
549 23
            },
550
            $source
551
        );
552
        // convert hex notation
553 23
        $source = preg_replace_callback(
554 23
            '/&#x([a-f0-9]+);/mi',
555
            function ($matches) {
556
                return chr('0x' . $matches[1]);
0 ignored issues
show
Bug introduced by
'0x' . $matches[1] of type string is incompatible with the type integer expected by parameter $codepoint of chr(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

556
                return chr(/** @scrutinizer ignore-type */ '0x' . $matches[1]);
Loading history...
557 23
            },
558
            $source
559
        );
560
561 23
        return $source;
562
    }
563
564
    /**
565
     * gather - gather input from a source
566
     *
567
     * @param string $source    name of source superglobal, get, post or cookie
568
     * @param array  $input_map each element of the array is an array consisting of
569
     *                          elements to gather and clean from source
570
     *                            - name - key in source superglobal, no default
571
     *                            - type - FilterInput::clean type, default string
572
     *                            - default - default value, default ''
573
     *                            - trim - true to trim spaces from input, default true
574
     *                            - max length - maximum length to accept, 0=no limit, default 0
575
     *                          Example: array('op','string','view',true)
576
     * @param mixed  $require   name of required element, or false for nothing
577
     *                          required name. If the require name is set, values
578
     *                          will only be returned if the key $require is set
579
     *                          in the source array.
580
     *
581
     * @return array|false array of cleaned elements as specified by input_map, or
582
     *                     false if require key specified but not set
583
     *
584
     * @deprecated
585
     */
586 1
    public static function gather($source, $input_map, $require = false)
587
    {
588 1
        $output = array();
589
590 1
        if (!empty($source)) {
591 1
            $source = strtolower($source);
592 1
            foreach ($input_map as $input) {
593
                // set defaults
594 1
                if (isset($input[0])) {
595 1
                    $name = $input[0];
596 1
                    $type = isset($input[1]) ? $input[1] : 'string';
597 1
                    $default = isset($input[2]) ?
598 1
                        (($require && $require==$name) ? '': $input[2]) : '';
599 1
                    $trim = isset($input[3]) ? $input[3] : true;
600 1
                    $maxlen = isset($input[4]) ? $input[4] : 0;
601 1
                    $value = $default;
602 1
                    switch ($source) {
603 1
                        case 'get':
604
                            if (isset($_GET[$name])) {
605
                                $value=$_GET[$name];
606
                            }
607
                            break;
608 1
                        case 'post':
609 1
                            if (isset($_POST[$name])) {
610 1
                                $value=$_POST[$name];
611
                            }
612 1
                            break;
613
                        case 'cookie':
614
                            if (isset($_COOKIE[$name])) {
615
                                $value=$_COOKIE[$name];
616
                            }
617
                            break;
618
                    }
619 1
                    if ($trim) {
620 1
                        $value = trim($value);
621
                    }
622 1
                    if ($maxlen>0) {
623 1
                        if (function_exists('mb_strlen')) {
624 1
                            if (mb_strlen($value)>$maxlen) {
625 1
                                $value=mb_substr($value, 0, $maxlen);
626
                            }
627
                        } else {
628
                            $value=substr($value, 0, $maxlen);
629
                        }
630 1
                        if ($trim) {
631 1
                            $value = trim($value);
632
                        }
633
                    }
634 1
                    $output[$name] = self::clean($value, $type);
635
                }
636
            }
637
        }
638 1
        if ($require) {
639 1
            if (empty($output[$require])) {
640 1
                $output = false;
641
            }
642
        }
643 1
        return $output;
644
    }
645
}
646