GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — develop ( baac3d...439f66 )
by gyeong-won
17:54
created

Validator::_compile2js()   F

Complexity

Conditions 26
Paths > 20000

Size

Total Lines 137
Code Lines 71

Duplication

Lines 8
Ratio 5.84 %

Importance

Changes 0
Metric Value
cc 26
eloc 71
nc 230560
nop 0
dl 8
loc 137
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) NAVER <http://www.navercorp.com> */
3
4
/**
5
 * Validator class
6
 * @author NAVER ([email protected])
7
 * @package /classes/validator
8
 * @version 0.1
9
 */
10
class Validator
11
{
12
13
	/**
14
	 * cache directory
15
	 * @var string
16
	 */
17
	var $_cache_dir = '';
18
19
	/**
20
	 * last error
21
	 * @var array
22
	 */
23
	var $_last_error;
24
25
	/**
26
	 * xml ruleset object
27
	 * @var Xml_Node_ object
28
	 */
29
	var $_xml_ruleset = NULL;
30
31
	/**
32
	 * rule list
33
	 * @var array
34
	 */
35
	var $_rules;
36
37
	/**
38
	 * filter list
39
	 * @var array
40
	 */
41
	var $_filters;
42
43
	/**
44
	 * custom message list
45
	 * @var array
46
	 */
47
	var $_messages;
48
49
	/**
50
	 * custom field name list
51
	 * @var array
52
	 */
53
	var $_fieldNames;
54
55
	/**
56
	 * Can usable status for multibyte string function
57
	 * @var boolean
58
	 */
59
	var $_has_mb_func;
60
61
	/**
62
	 * validator version
63
	 * @var string
64
	 */
65
	var $_version = '1.0';
66
67
	/**
68
	 * ruleset xml file path
69
	 * @var string
70
	 */
71
	var $_xml_path = '';
72
73
	/**
74
	 * @constructor
75
	 * @param string $xml_path
76
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
77
	 */
78
	function __construct($xml_path = '')
79
	{
80
		$this->_rules = array();
81
		$this->_filters = array();
82
		$this->_xml_ruleset = NULL;
83
84
		if($xml_path)
85
			$this->load($xml_path);
86
87
		// predefined rules
88
		$this->addRule(array(
0 ignored issues
show
Documentation introduced by
array('email' => '/^[\\w... '/^(?:[1-9]\\d*|0)$/') is of type array<string,string,{"em...ng","number":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
89
			'email' => '/^[\w-]+((?:\.|\+|\~)[\w-]+)*@[\w-]+(\.[\w-]+)+$/',
90
			'userid' => '/^[a-z]+[\w-]*[a-z0-9_]+$/i',
91
			'url' => '/^(https?|ftp|mms):\/\/[0-9a-z-]+(\.[_0-9a-z-]+)+(:\d+)?/',
92
			'alpha' => '/^[a-z]*$/i',
93
			'alpha_number' => '/^[a-z][a-z0-9_]*$/i',
94
			'number' => '/^(?:[1-9]\\d*|0)$/'
95
		));
96
97
		$this->_has_mb_func = is_callable('mb_strlen');
98
		$this->setCacheDir(_XE_PATH_ . 'files/cache');
99
	}
100
101
	/**
102
	 * @destructor
103
	 * @return void
104
	 */
105
	function __destruct()
106
	{
107
		$this->_rules = NULL;
0 ignored issues
show
Documentation Bug introduced by
It seems like NULL of type null is incompatible with the declared type array of property $_rules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
108
		$this->_filters = NULL;
0 ignored issues
show
Documentation Bug introduced by
It seems like NULL of type null is incompatible with the declared type array of property $_filters.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
109
	}
110
111
	/**
112
	 * Load a xml file
113
	 * @param string $xml_path A file name to be loaded
114
	 * @return boolean
115
	 */
116
	function load($xml_path)
117
	{
118
		$this->_xml_ruleset = NULL;
119
120
		$xml_path = realpath($xml_path);
121
		if(!is_readable($xml_path))
122
		{
123
			return FALSE;
124
		}
125
126
		$parser = new XmlParser();
127
		$xml = $parser->loadXmlFile($xml_path);
128
		if(!isset($xml->ruleset) || !isset($xml->ruleset->fields) || !isset($xml->ruleset->fields->field))
129
		{
130
			return FALSE;
131
		}
132
133
		// custom rules
134
		if(isset($xml->ruleset->customrules) && isset($xml->ruleset->customrules->rule))
135
		{
136
			$customrules = $xml->ruleset->customrules->rule;
137
			if(!is_array($customrules))
138
			{
139
				$customrules = array($customrules);
140
			}
141
142
			$rules = array();
143
			$messages = array();
144
			foreach($customrules as $rule)
145
			{
146
				if(!isset($rule->attrs) || !isset($rule->attrs->name))
147
				{
148
					continue;
149
				}
150
151
				$message = $rule->message ? $rule->message->body : NULL;
152
				$rule = (array) $rule->attrs;
153
				$rule['message'] = $message;
154
				$name = $rule['name'];
155
				unset($rule['name']);
156
157
				$rules[$name] = $rule;
158
				if(isset($message))
159
				{
160
					$messages['invalid_' . $name] = $message;
161
				}
162
			}
163
			if(count($rules))
164
			{
165
				$this->addRule($rules);
0 ignored issues
show
Documentation introduced by
$rules is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
166
			}
167
		}
168
169
		// filters
170
		$fields = $xml->ruleset->fields->field;
171
		if(!is_array($fields))
172
		{
173
			$fields = array($fields);
174
		}
175
176
		$filters = array();
177
		$fieldsNames = array();
178
		foreach($fields as $field)
179
		{
180
			$name = '';
0 ignored issues
show
Unused Code introduced by
$name is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
181
			$filter = array();
0 ignored issues
show
Unused Code introduced by
$filter is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
182
183
			if(!isset($field->attrs) || !isset($field->attrs->name))
184
			{
185
				continue;
186
			}
187
188
			$title = $field->title ? $field->title->body : NULL;
189
			$filter = (array) $field->attrs;
190
			$filter['title'] = $title;
191
192
			$name = $filter['name'];
193
			if(isset($title))
194
			{
195
				$fieldsNames[$name] = $title;
196
			}
197
			
198
			unset($filter['name']);
199
200
			// conditional statement
201
			if(isset($field->if))
202
			{
203
				$if = $field->if;
204
				if(!is_array($if))
205
				{
206
					$if = array($if);
207
				}
208
				foreach($if as $idx => $cond)
209
				{
210
					$if[$idx] = (array) $cond->attrs;
211
				}
212
				$filter['if'] = $if;
213
			}
214
215
			$filters[$name] = $filter;
216
		}
217
218
		$this->_xml_ruleset = $xml->ruleset;
219
		$this->_filters = $filters;
220
		$this->_message = $messages;
0 ignored issues
show
Bug introduced by
The property _message does not seem to exist. Did you mean _messages?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The variable $messages does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
221
		$this->_fieldNames = $fieldsNames;
222
		$this->_xml_path = $xml_path;
223
224
		return TRUE;
225
	}
226
227
	/**
228
	 * Set root cache directory
229
	 * @param string $cache_dir Root cache directory
230
	 * @return void
231
	 */
232
	function setCacheDir($cache_dir)
233
	{
234
		if(is_dir($cache_dir))
235
		{
236
			$this->_cache_dir = preg_replace('@/$@', '', $cache_dir);
237
		}
238
	}
239
240
	/**
241
	 * Validate the fields. If the fields aren't passed, validation will be execute on the Context variables.
242
	 * @param array $fields Target fields. The keys of the array represents field's name, its values represents field's value.
0 ignored issues
show
Documentation introduced by
There is no parameter named $fields. Did you maybe mean $fields_?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
243
	 * @return boolean TRUE if it is valid, FALSE otherwise.
244
	 */
245
	function validate($fields_ = null)
246
	{
247
		if(is_array($fields_))
248
		{
249
			$fields = $fields_;
250
		}
251
		else
252
		{
253
			$args = array_keys($this->_filters);
0 ignored issues
show
Unused Code introduced by
$args is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
254
			$fields = (array) Context::getRequestVars();
255
		}
256
257
		if(!is_array($fields))
258
		{
259
			return TRUE;
260
		}
261
262
		$filter_default = array(
263
			'required' => 'false',
264
			'default' => '',
265
			'modifiers' => array(),
266
			'length' => 0,
267
			'equalto' => 0,
268
			'rule' => 0,
269
			'if' => array()
270
		);
271
272
		$fields = array_map(array($this, 'arrayTrim'), $fields);
273
		$field_names = array_keys($fields);
274
275
		$filters = array();
276
277
		// get field names matching patterns
278
		foreach($this->_filters as $key => $filter)
279
		{
280
			$names = array();
281
			if($key{0} == '^')
282
			{
283
				$names = preg_grep('/^' . preg_quote(substr($key, 1)) . '/', $field_names);
284
			}
285
			elseif(substr($key, -2) == '[]')
286
			{
287
				$filters[substr($key, 0, -2)] = $filter;
288
				unset($filters[$key]);
289
			}
290
			else
291
			{
292
				$filters[$key] = $filter;
293
			}
294
295
			if(!count($names))
296
			{
297
				continue;
298
			}
299
300
			foreach($names as $name)
301
			{
302
				$filters[$name] = $filter;
303
			}
304
			unset($filters[$key]);
305
		}
306
307
		foreach($filters as $key => $filter)
308
		{
309
			$fname = preg_replace('/\[\]$/', '', $key);
310
			$filter = array_merge($filter_default, $filter);
311
312
			if(preg_match("/(^[a-z_]*)[\[](?:\'|\")?([a-z_]*)(?:\'|\")?[\]]$/i", $key, $matches))
313
			{
314
				$exists = array_key_exists($matches[1], $fields);
315
				$value = $exists ? $fields[$matches[1]][$matches[2]] : NULL;
316
			}
317
			else
318
			{
319
				$exists = array_key_exists($key, $fields);
320
				$value = $exists ? $fields[$fname] : NULL;
321
			}
322
323
			if(is_array($value))
324
			{
325
				if(!isset($value[tmp_name]))
326
				{
327
					$value = implode('', $value);
328
				}
329
				else
330
				{
331
					$value = $value['name'];
332
				}
333
			}
334
335
			// conditional statement
336
			foreach($filter['if'] as $cond)
0 ignored issues
show
Bug introduced by
The expression $filter['if'] of type string|array|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
337
			{
338
				if(!isset($cond['test']) || !isset($cond['attr']))
339
				{
340
					continue;
341
				}
342
343
				$func_body = preg_replace('/\\$(\w+)/', '$c[\'$1\']', $cond['test']);
344
				$func = create_function('$c', "return !!({$func_body});");
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
345
346
				if($func($fields))
347
				{
348
					$filter[$cond['attr']] = $cond['value'];
349
				}
350
			}
351
352
			// attr : default
353
			if(!$value && strlen($default = trim($filter['default'])))
354
			{
355
				$value = $default;
356
				if(is_null($fields_))
357
				{
358
					Context::set($fname, $value);
359
				}
360
				else
361
				{
362
					$fields_[$fname] = $value;
363
				}
364
			}
365
			$value_len = strlen($value);
366
367
			// attr : modifier
368
			if(is_string($modifiers = $filter['modifiers']))
369
			{
370
				$modifiers = explode(',', trim($modifiers));
371
			}
372
373
			// attr : required
374
			if($filter['required'] === 'true' && !$value_len)
375
			{
376
				return $this->error($key, 'isnull');
377
			}
378
379
			// if the field wasn't passed, ignore this value
380
			if(!$exists && !$value_len)
381
			{
382
				continue;
383
			}
384
385
			// attr : length
386
			if($length = $filter['length'])
387
			{
388
				list($min, $max) = explode(':', trim($length));
389
				$is_min_b = (substr($min, -1) === 'b');
390
				$is_max_b = (substr($max, -1) === 'b');
391
				list($min, $max) = array((int) $min, (int) $max);
392
393
				$strbytes = strlen($value);
394
				if(!$is_min_b || !$is_max_b)
395
				{
396
					$strlength = $this->_has_mb_func ? mb_strlen($value, 'utf-8') : $this->mbStrLen($value);
397
				}
398
399
				if(($min && $min > ($is_min_b ? $strbytes : $strlength)) || ($max && $max < ($is_max_b ? $strbytes : $strlength)))
0 ignored issues
show
Bug introduced by
The variable $strlength does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
400
				{
401
					return $this->error($key, 'outofrange');
402
				}
403
			}
404
405
			// equalto
406
			if($equalto = $filter['equalto'])
407
			{
408
				if(!array_key_exists($equalto, $fields) || trim($fields[$equalto]) !== $value)
409
				{
410
					return $this->error($key, 'equalto');
411
				}
412
			}
413
414
			// rules
415
			if($rules = $filter['rule'])
416
			{
417
				$rules = explode(',', $rules);
418
				foreach($rules as $rule)
419
				{
420
					$result = $this->applyRule($rule, $value);
421
					// apply the 'not' modifier
422
					if(in_array('not', $modifiers))
423
					{
424
						$result = !$result;
425
					}
426
					if(!$result)
427
					{
428
						return $this->error($key, 'invalid_' . $rule);
429
					}
430
				}
431
			}
432
		}
433
434
		return TRUE;
435
	}
436
437
	/**
438
	 * apply trim recursive
439
	 * @param string|array $array
440
	 * @return string|array
441
	 */
442
	function arrayTrim($array)
443
	{
444
		if(!is_array($array))
445
		{
446
			return trim($array);
447
		}
448
449
		foreach($array as $key => $value)
450
		{
451
			$array[$key] = $this->arrayTrim($value);
452
		}
453
454
		return $array;
455
	}
456
457
	/**
458
	 * Log an error
459
	 * @param $msg error message
460
	 * @return boolean always false
461
	 */
462
	function error($field, $msg)
463
	{
464
		if(isset($this->_message[$msg]))
0 ignored issues
show
Bug introduced by
The property _message does not seem to exist. Did you mean _messages?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
465
		{
466
			$msg = $this->_message[$msg];
0 ignored issues
show
Bug introduced by
The property _message does not seem to exist. Did you mean _messages?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
467
		}
468
		else
469
		{
470
			$lang_filter = Context::getLang('filter');
471
			$msg = isset($lang_filter->{$msg}) ? $lang_filter->{$msg} : $lang_filter->invalid;
472
		}
473
474
		if(isset($this->_fieldNames[$field]))
475
		{
476
			$fieldName = $this->_fieldNames[$field];
477
		}
478
		else
479
		{
480
			$fieldName = Context::getLang($field);
481
		}
482
483
		$msg = sprintf($msg, $fieldName);
484
485
		$this->_last_error = array('field' => $field, 'msg' => $msg);
486
487
		return FALSE;
488
	}
489
490
	/**
491
	 * Returns the last error infomation including a field name and an error message.
492
	 * @return array The last error infomation
493
	 */
494
	function getLastError()
495
	{
496
		return $this->_last_error;
497
	}
498
499
	/**
500
	 * Add a new rule
501
	 * @param string $name rule name
502
	 * @param mixed $rule
503
	 * @return void
504
	 */
505
	function addRule($name, $rule = '')
506
	{
507
		if(is_array($name))
508
		{
509
			$args = $name;
510
		}
511
		else
512
		{
513
			$args = array($name => $rule);
514
		}
515
516
		foreach($args as $name => $rule)
517
		{
518
			if(!$rule)
519
			{
520
				continue;
521
			}
522
			if(is_string($rule))
523
			{
524
				$rule = array('type' => 'regex', 'test' => $rule);
525
			}
526
527
			if($rule['type'] == 'enum')
528
			{
529
				$delim = isset($rule['delim']) ? $rule['delim'] : ',';
530
				$rule['test'] = explode($delim, $rule['test']);
531
			}
532
533
			$this->_rules[$name] = $rule;
534
		}
535
	}
536
537
	/**
538
	 * Remove a rule
539
	 * @param string $name rule name
540
	 * @return void
541
	 */
542
	function removeRule($name)
543
	{
544
		unset($this->_rules[$name]);
545
	}
546
547
	/**
548
	 * add filter to filter list
549
	 * @param string $name rule name
550
	 * @param string $filter filter
551
	 * @return void
552
	 */
553
	function addFilter($name, $filter = '')
554
	{
555
		if(is_array($name))
556
		{
557
			$args = $name;
558
		}
559
		else
560
		{
561
			$args = array($name => $filter);
562
		}
563
564
		foreach($args as $name => $filter)
565
		{
566
			if(!$filter)
567
			{
568
				continue;
569
			}
570
571
			if(isset($filter['if']))
572
			{
573
				if(is_array($filter['if']) && count($filter['if']))
574
				{
575
					$key = key($filter['if']);
576
					if(!is_int($key))
577
					{
578
						$filter['if'] = array($filter['if']);
579
					}
580
				}
581
				else
582
				{
583
					unset($filter['if']);
584
				}
585
			}
586
587
			$this->_filters[$name] = $filter;
588
		}
589
	}
590
591
	/**
592
	 * remove filter from filter list
593
	 * @param string $name rule name
594
	 * @return void
595
	 */
596
	function removeFilter($name)
597
	{
598
		unset($this->_filters[$name]);
599
	}
600
601
	/**
602
	 * Find whether the field is valid with the rule
603
	 * @param string $name rule name
604
	 * @param string $value a value to be validated
605
	 * @return boolean TRUE if the field is valid, FALSE otherwise.
606
	 */
607
	function applyRule($name, $value)
608
	{
609
		$rule = $this->_rules[$name];
610
611
		if(is_array($value) && isset($value['tmp_name']))
612
		{
613
			$value = $value['name'];
614
		}
615
616
		switch($rule['type'])
617
		{
618
			case 'regex':
619
				return (preg_match($rule['test'], $value) > 0);
620
			case 'enum':
621
				return in_array($value, $rule['test']);
622
			case 'expr':
623
				if(!$rule['func_test'])
624
				{
625
					$rule['func_test'] = create_function('$a', 'return (' . preg_replace('/\$\$/', '$a', html_entity_decode($rule['test'])) . ');');
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
626
				}
627
				return $rule['func_test']($value);
628
		}
629
630
		return TRUE;
631
	}
632
633
	/**
634
	 * if not supported 'mb_strlen' function, this method can use.
635
	 * @param string $str
636
	 * @return int
637
	 */
638
	function mbStrLen($str)
639
	{
640
		$arr = count_chars($str);
641
		for($i = 0x80; $i < 0xc0; $i++)
642
		{
643
			unset($arr[$i]);
644
		}
645
		return array_sum($arr);
646
	}
647
648
	/**
649
	 * Returns compiled javascript file path. The path begins from XE root directory.
650
	 * @return string Compiled JavaScript file path
651
	 */
652
	function getJsPath()
653
	{
654
		if(!$this->_cache_dir)
655
		{
656
			return FALSE;
657
		}
658
659
		$dir = $this->_cache_dir . '/ruleset';
660
		if(!is_dir($dir) && !mkdir($dir))
661
		{
662
			return FALSE;
663
		}
664
		if(!$this->_xml_path)
665
		{
666
			return FALSE;
667
		}
668
669
		// current language
670
		$lang_type = class_exists('Context', false) ? Context::getLangType() : 'en';
671
672
		// check the file
673
		$filepath = $dir . '/' . md5($this->_version . ' ' . $this->_xml_path) . ".{$lang_type}.js";
674
		if(is_readable($filepath) && filemtime($filepath) > filemtime($this->_xml_path))
675
		{
676
			return $filepath;
677
		}
678
679
		$content = $this->_compile2js();
680
		if($content === FALSE)
681
		{
682
			return FALSE;
683
		}
684
685
		@file_put_contents($filepath, $content, LOCK_EX);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
686
687
		return $filepath;
688
	}
689
690
	/**
691
	 * Compile a ruleset to a javascript file
692
	 * @return string
693
	 */
694
	function _compile2js()
695
	{
696
		global $lang;
697
698
		$ruleset = basename($this->_xml_path, '.xml');
699
		$content = array();
0 ignored issues
show
Unused Code introduced by
$content is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
700
701
		if(preg_match('@(^|/)files/ruleset/\w+\.xml$@i', $this->_xml_path))
702
		{
703
			$ruleset = '@' . $ruleset;
704
		}
705
706
		list($ruleset) = explode('.', $ruleset);
707
708
		// current language
709
		$lang_type = class_exists('Context', false) ? Context::getLangType() : 'en';
0 ignored issues
show
Unused Code introduced by
$lang_type is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
710
711
		// custom rulesets
712
		$addrules = array();
713
		foreach($this->_rules as $name => $rule)
714
		{
715
			$name = strtolower($name);
716
717
			if(in_array($name, array('email', 'userid', 'url', 'alpha', 'alpha_number', 'number')))
718
			{
719
				continue;
720
			}
721
			switch($rule['type'])
722
			{
723
				case 'regex':
724
					$addrules[] = "v.cast('ADD_RULE', ['{$name}', {$rule['test']}]);";
725
					break;
726
				case 'enum':
727
					$enums = '"' . implode('","', $rule['test']) . '"';
728
					$addrules[] = "v.cast('ADD_RULE', ['{$name}', function($$){ return ($.inArray($$,[{$enums}]) > -1); }]);";
729
					break;
730
				case 'expr':
731
					$addrules[] = "v.cast('ADD_RULE', ['{$name}', function($$){ return ({$rule['test']}); }]);";
732
					break;
733
			}
734
735
			// if have a message, add message
736
			if(isset($rule['message']))
737
			{
738
				$text = preg_replace('@\r?\n@', '\\n', addslashes($rule['message']));
739
				$addrules[] = "v.cast('ADD_MESSAGE',['invalid_{$name}','{$text}']);";
740
			}
741
		}
742
		$addrules = implode('', $addrules);
743
744
		// filters
745
		$content = array();
746
		$messages = array();
747
		foreach($this->_filters as $name => $filter)
748
		{
749
			$field = array();
750
751
			// form filed name
752
			if(isset($filter['title']))
753
			{
754
				$field_lang = addslashes($filter['title']);
755
				$messages[] = "v.cast('ADD_MESSAGE',['{$name}','{$field_lang}']);";
756
			}
757
			elseif(isset($lang->{$name}))
758
			{
759
				$field_lang = addslashes($lang->{$name});
760
				$messages[] = "v.cast('ADD_MESSAGE',['{$name}','{$field_lang}']);";
761
			}
762
763
			if($filter['required'] == 'true')
764
			{
765
				$field[] = 'required:true';
766
			}
767
			if($filter['rule'])
768
			{
769
				$field[] = "rule:'" . strtolower($filter['rule']) . "'";
770
			}
771
			if($filter['default'])
772
			{
773
				$field[] = "default:'{$filter['default']}'";
774
			}
775
			if($filter['modifier'])
776
			{
777
				$field[] = "modifier:'{$filter['modifier']}'";
778
			}
779
			if($filter['length'])
780
			{
781
				list($min, $max) = explode(':', $filter['length']);
782
				if($min)
783
				{
784
					$field[] = "minlength:'{$min}'";
785
				}
786
				if($max)
787
				{
788
					$field[] = "maxlength:'{$max}'";
789
				}
790
			}
791
			if($filter['if'])
792
			{
793
				$ifs = array();
794
				if(!isset($filter['if'][0]))
795
				{
796
					$filter['if'] = array($filter['if']);
797
				}
798
				foreach($filter['if'] as $if)
799
				{
800
					$ifs[] = "{test:'" . addslashes($if['test']) . "', attr:'{$if['attr']}', value:'" . addslashes($if['value']) . "'}";
801
				}
802
				$field[] = "'if':[" . implode(',', $ifs) . "]";
803
			}
804
			if(count($field))
805
			{
806
				$field = '{' . implode(',', $field) . '}';
807
				$content[] = "'{$name}':{$field}";
808
			}
809
		}
810
811
		if(!$content)
0 ignored issues
show
Bug Best Practice introduced by
The expression $content of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
812
		{
813
			return '/* Error : empty ruleset  */';
814
		}
815
816
		// error messages
817 View Code Duplication
		foreach($lang->filter as $key => $text)
818
		{
819
			if($text)
820
			{
821
				$text = preg_replace('@\r?\n@', '\\n', addslashes($text));
822
				$messages[] = "v.cast('ADD_MESSAGE',['{$key}','{$text}']);";
823
			}
824
		}
825
826
		$content = implode(',', $content);
827
		$messages = implode("\n", $messages);
828
829
		return "(function($,v){\nv=xe.getApp('validator')[0];if(!v)return;\n{$addrules}\nv.cast('ADD_FILTER',['{$ruleset}', {{$content}}]);\n{$messages}\n})(jQuery);";
830
	}
831
832
}
833
/* End of file Validator.class.php */
834
/* Location: ./classes/validator/Validator.class.php */
835