|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* Parser Input |
|
5
|
|
|
*/ |
|
6
|
|
View Code Duplication |
class xKerman_Restricted_Source |
|
|
|
|
|
|
7
|
|
|
{ |
|
8
|
|
|
/** @var string $str given string to deserialize */ |
|
9
|
|
|
private $str; |
|
10
|
|
|
/** @var int $length given string length */ |
|
11
|
|
|
private $length; |
|
12
|
|
|
/** @var int $current current position of parser */ |
|
13
|
|
|
private $current; |
|
14
|
|
|
/** |
|
15
|
|
|
* constructor |
|
16
|
|
|
* |
|
17
|
|
|
* @param string $str parser input |
|
18
|
|
|
* @throws InvalidArgumentException |
|
19
|
|
|
*/ |
|
20
|
|
|
public function __construct($str) |
|
21
|
|
|
{ |
|
22
|
|
|
if (!is_string($str)) { |
|
23
|
|
|
throw new InvalidArgumentException('expected string, but got: ' . gettype($str)); |
|
24
|
|
|
} |
|
25
|
|
|
$this->str = $str; |
|
26
|
|
|
$this->length = strlen($str); |
|
27
|
|
|
$this->current = 0; |
|
28
|
|
|
} |
|
29
|
|
|
/** |
|
30
|
|
|
* throw error with currnt position |
|
31
|
|
|
* |
|
32
|
|
|
* @return void |
|
33
|
|
|
* @throws UnserializeFailedException |
|
34
|
|
|
*/ |
|
35
|
|
|
public function triggerError() |
|
36
|
|
|
{ |
|
37
|
|
|
$bytes = strlen($this->str); |
|
38
|
|
|
throw new xKerman_Restricted_UnserializeFailedException("unserialize(): Error at offset {$this->current} of {$bytes} bytes"); |
|
39
|
|
|
} |
|
40
|
|
|
/** |
|
41
|
|
|
* consume given string if it is as expected |
|
42
|
|
|
* |
|
43
|
|
|
* @param string $expected expected string |
|
44
|
|
|
* @param integer $length length of $expected |
|
45
|
|
|
* @return void |
|
46
|
|
|
* @throws UnserializeFailedException |
|
47
|
|
|
*/ |
|
48
|
|
|
public function consume($expected, $length) |
|
49
|
|
|
{ |
|
50
|
|
|
if (strpos($this->str, $expected, $this->current) !== $this->current) { |
|
51
|
|
|
return $this->triggerError(); |
|
52
|
|
|
} |
|
53
|
|
|
$this->current += $length; |
|
54
|
|
|
} |
|
55
|
|
|
/** |
|
56
|
|
|
* read givin length substring |
|
57
|
|
|
* |
|
58
|
|
|
* @param integer $length length to read |
|
59
|
|
|
* @return string |
|
60
|
|
|
* @throws UnserializeFailedException |
|
61
|
|
|
*/ |
|
62
|
|
|
public function read($length) |
|
63
|
|
|
{ |
|
64
|
|
|
if ($length < 0) { |
|
65
|
|
|
return $this->triggerError(); |
|
66
|
|
|
} |
|
67
|
|
|
if ($this->current + $length > $this->length) { |
|
68
|
|
|
return $this->triggerError(); |
|
69
|
|
|
} |
|
70
|
|
|
$this->current += $length; |
|
71
|
|
|
return substr($this->str, $this->current - $length, $length); |
|
72
|
|
|
} |
|
73
|
|
|
/** |
|
74
|
|
|
* return matching string for given regexp |
|
75
|
|
|
* |
|
76
|
|
|
* @param string $regexp Regular Expression for expected substring |
|
77
|
|
|
* @return array |
|
78
|
|
|
*/ |
|
79
|
|
|
public function match($regexp) |
|
80
|
|
|
{ |
|
81
|
|
|
if (!preg_match($regexp, $this->str, $matches, 0, $this->current)) { |
|
82
|
|
|
return $this->triggerError(); |
|
83
|
|
|
} |
|
84
|
|
|
$this->current += strlen($matches[0]); |
|
85
|
|
|
array_shift($matches); |
|
86
|
|
|
return $matches; |
|
87
|
|
|
} |
|
88
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.