This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /* 25 October 2011. version 1.1-FF4 |
||
3 | * |
||
4 | * This is the php version of the Dean Edwards JavaScript's Packer, |
||
5 | * Based on : |
||
6 | * |
||
7 | * ParseMaster, version 1.0.2 (2005-08-19) Copyright 2005, Dean Edwards |
||
8 | * a multi-pattern parser. |
||
9 | * KNOWN BUG: erroneous behavior when using escapeChar with a replacement |
||
10 | * value that is a function |
||
11 | * |
||
12 | * packer, version 2.0.2 (2005-08-19) Copyright 2004-2005, Dean Edwards |
||
13 | * |
||
14 | * License: http://creativecommons.org/licenses/LGPL/2.1/ |
||
15 | * |
||
16 | * Ported to PHP by Nicolas Martin. |
||
17 | * |
||
18 | * ---------------------------------------------------------------------- |
||
19 | * changelog: |
||
20 | * 1.1 : correct a bug, '\0' packed then unpacked becomes '\'. |
||
21 | * 1.1-FF4 : Firefox 4 fix, Copyright 2011, Mieczyslaw Nalewaj |
||
22 | * ---------------------------------------------------------------------- |
||
23 | * |
||
24 | * examples of usage : |
||
25 | * $myPacker = new JavaScriptPacker($script, 62, true, false); |
||
26 | * $packed = $myPacker->pack(); |
||
27 | * |
||
28 | * or |
||
29 | * |
||
30 | * $myPacker = new JavaScriptPacker($script, 'Normal', true, false); |
||
31 | * $packed = $myPacker->pack(); |
||
32 | * |
||
33 | * or (default values) |
||
34 | * |
||
35 | * $myPacker = new JavaScriptPacker($script); |
||
36 | * $packed = $myPacker->pack(); |
||
37 | * |
||
38 | * |
||
39 | * params of the constructor : |
||
40 | * $script: the JavaScript to pack, string. |
||
41 | * $encoding: level of encoding, int or string : |
||
42 | * 0,10,62,95 or 'None', 'Numeric', 'Normal', 'High ASCII'. |
||
43 | * default: 62. |
||
44 | * $fastDecode: include the fast decoder in the packed result, boolean. |
||
45 | * default : true. |
||
46 | * $specialChars: if you are flagged your private and local variables |
||
47 | * in the script, boolean. |
||
48 | * default: false. |
||
49 | * |
||
50 | * The pack() method return the compressed JavasScript, as a string. |
||
51 | * |
||
52 | * see http://dean.edwards.name/packer/usage/ for more information. |
||
53 | * |
||
54 | * Notes : |
||
55 | * # need PHP 5 . Tested with PHP 5.1.2, 5.1.3, 5.1.4, 5.2.3 |
||
56 | * |
||
57 | * # The packed result may be different than with the Dean Edwards |
||
58 | * version, but with the same length. The reason is that the PHP |
||
59 | * function usort to sort array don't necessarily preserve the |
||
60 | * original order of two equal member. The Javascript sort function |
||
61 | * in fact preserve this order (but that's not require by the |
||
62 | * ECMAScript standard). So the encoded keywords order can be |
||
63 | * different in the two results. |
||
64 | * |
||
65 | * # Be careful with the 'High ASCII' Level encoding if you use |
||
66 | * UTF-8 in your files... |
||
67 | */ |
||
68 | |||
69 | |||
70 | class JavaScriptPacker |
||
0 ignored issues
–
show
|
|||
71 | { |
||
72 | // constants |
||
73 | const IGNORE = '$1'; |
||
74 | |||
75 | // validate parameters |
||
76 | private $_script = ''; |
||
77 | private $_encoding = 62; |
||
78 | private $_fastDecode = true; |
||
79 | private $_specialChars = false; |
||
80 | |||
81 | private $LITERAL_ENCODING = array( |
||
82 | 'None' => 0, |
||
83 | 'Numeric' => 10, |
||
84 | 'Normal' => 62, |
||
85 | 'High ASCII' => 95 |
||
86 | ); |
||
87 | |||
88 | public function __construct($_script, $_encoding = 62, $_fastDecode = true, $_specialChars = false) |
||
89 | { |
||
90 | $this->_script = $_script . "\n"; |
||
91 | if (array_key_exists($_encoding, $this->LITERAL_ENCODING)) |
||
92 | $_encoding = $this->LITERAL_ENCODING[$_encoding]; |
||
93 | $this->_encoding = min((int) $_encoding, 95); |
||
94 | $this->_fastDecode = $_fastDecode; |
||
95 | $this->_specialChars = $_specialChars; |
||
96 | } |
||
97 | |||
98 | public function pack() |
||
99 | { |
||
100 | $this->_addParser('_basicCompression'); |
||
101 | if ($this->_specialChars) |
||
102 | $this->_addParser('_encodeSpecialChars'); |
||
103 | if ($this->_encoding) |
||
104 | $this->_addParser('_encodeKeywords'); |
||
105 | |||
106 | // go! |
||
107 | return $this->_pack($this->_script); |
||
108 | } |
||
109 | |||
110 | // apply all parsing routines |
||
111 | private function _pack($script) |
||
112 | { |
||
113 | for ($i = 0; isset($this->_parsers[$i]); $i++) { |
||
114 | $script = call_user_func(array(&$this, $this->_parsers[$i]), $script); |
||
115 | } |
||
116 | |||
117 | return $script; |
||
118 | } |
||
119 | |||
120 | // keep a list of parsing functions, they'll be executed all at once |
||
121 | private $_parsers = array(); |
||
122 | private function _addParser($parser) |
||
123 | { |
||
124 | $this->_parsers[] = $parser; |
||
125 | } |
||
126 | |||
127 | // zero encoding - just removal of white space and comments |
||
128 | private function _basicCompression($script) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
129 | { |
||
130 | $parser = new ParseMaster(); |
||
131 | // make safe |
||
132 | $parser->escapeChar = '\\'; |
||
133 | // protect strings |
||
134 | $parser->add('/\'[^\'\\n\\r]*\'/', self::IGNORE); |
||
135 | $parser->add('/"[^"\\n\\r]*"/', self::IGNORE); |
||
136 | // remove comments |
||
137 | $parser->add('/\\/\\/[^\\n\\r]*[\\n\\r]/', ' '); |
||
138 | $parser->add('/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\//', ' '); |
||
139 | // protect regular expressions |
||
140 | $parser->add('/\\s+(\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?)/', '$2'); // IGNORE |
||
141 | $parser->add('/[^\\w\\x24\\/\'"*)\\?:]\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?/', self::IGNORE); |
||
142 | // remove: ;;; doSomething(); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
55% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
143 | if ($this->_specialChars) $parser->add('/;;;[^\\n\\r]+[\\n\\r]/'); |
||
144 | // remove redundant semi-colons |
||
145 | $parser->add('/\\(;;\\)/', self::IGNORE); // protect for (;;) loops |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
46% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
146 | $parser->add('/;+\\s*([};])/', '$2'); |
||
147 | // apply the above |
||
148 | $script = $parser->exec($script); |
||
149 | |||
150 | // remove white-space |
||
151 | $parser->add('/(\\b|\\x24)\\s+(\\b|\\x24)/', '$2 $3'); |
||
152 | $parser->add('/([+\\-])\\s+([+\\-])/', '$2 $3'); |
||
153 | $parser->add('/\\s+/', ''); |
||
154 | // done |
||
155 | return $parser->exec($script); |
||
156 | } |
||
157 | |||
158 | private function _encodeSpecialChars($script) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
159 | { |
||
160 | $parser = new ParseMaster(); |
||
161 | // replace: $name -> n, $$name -> na |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
38% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
162 | $parser->add('/((\\x24+)([a-zA-Z$_]+))(\\d*)/', |
||
163 | array('fn' => '_replace_name') |
||
0 ignored issues
–
show
array('fn' => '_replace_name') is of type array<string,string,{"fn":"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);
![]() |
|||
164 | ); |
||
165 | // replace: _name -> _0, double-underscore (__name) is ignored |
||
166 | $regexp = '/\\b_[A-Za-z\\d]\\w*/'; |
||
167 | // build the word list |
||
168 | $keywords = $this->_analyze($script, $regexp, '_encodePrivate'); |
||
169 | // quick ref |
||
170 | $encoded = $keywords['encoded']; |
||
171 | |||
172 | $parser->add($regexp, |
||
173 | array( |
||
0 ignored issues
–
show
array('fn' => '_replace_...d', 'data' => $encoded) is of type array<string,string|arra...tring","data":"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);
![]() |
|||
174 | 'fn' => '_replace_encoded', |
||
175 | 'data' => $encoded |
||
176 | ) |
||
177 | ); |
||
178 | |||
179 | return $parser->exec($script); |
||
180 | } |
||
181 | |||
182 | private function _encodeKeywords($script) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
183 | { |
||
184 | // escape high-ascii values already in the script (i.e. in strings) |
||
185 | if ($this->_encoding > 62) |
||
186 | $script = $this->_escape95($script); |
||
187 | // create the parser |
||
188 | $parser = new ParseMaster(); |
||
189 | $encode = $this->_getEncoder($this->_encoding); |
||
190 | // for high-ascii, don't encode single character low-ascii |
||
191 | $regexp = ($this->_encoding > 62) ? '/\\w\\w+/' : '/\\w+/'; |
||
192 | // build the word list |
||
193 | $keywords = $this->_analyze($script, $regexp, $encode); |
||
194 | $encoded = $keywords['encoded']; |
||
195 | |||
196 | // encode |
||
197 | $parser->add($regexp, |
||
198 | array( |
||
0 ignored issues
–
show
array('fn' => '_replace_...d', 'data' => $encoded) is of type array<string,string|arra...tring","data":"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);
![]() |
|||
199 | 'fn' => '_replace_encoded', |
||
200 | 'data' => $encoded |
||
201 | ) |
||
202 | ); |
||
203 | if (empty($script)) return $script; |
||
204 | else { |
||
205 | //$res = $parser->exec($script); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
64% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
206 | //$res = $this->_bootStrap($res, $keywords); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
65% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
207 | //return $res; |
||
208 | return $this->_bootStrap($parser->exec($script), $keywords); |
||
209 | } |
||
210 | } |
||
211 | |||
212 | private function _analyze($script, $regexp, $encode) |
||
213 | { |
||
214 | // analyse |
||
215 | // retreive all words in the script |
||
216 | $all = array(); |
||
217 | preg_match_all($regexp, $script, $all); |
||
218 | $_sorted = array(); // list of words sorted by frequency |
||
219 | $_encoded = array(); // dictionary of word->encoding |
||
220 | $_protected = array(); // instances of "protected" words |
||
221 | $all = $all[0]; // simulate the javascript comportement of global match |
||
222 | if (!empty($all)) { |
||
223 | $unsorted = array(); // same list, not sorted |
||
224 | $protected = array(); // "protected" words (dictionary of word->"word") |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
36% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
225 | $value = array(); // dictionary of charCode->encoding (eg. 256->ff) |
||
0 ignored issues
–
show
$value 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 ![]() |
|||
226 | $this->_count = array(); // word->count |
||
227 | $i = count($all); $j = 0; //$word = null; |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
50% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
228 | // count the occurrences - used for sorting later |
||
229 | do { |
||
230 | --$i; |
||
231 | $word = '$' . $all[$i]; |
||
232 | if (!isset($this->_count[$word])) { |
||
233 | $this->_count[$word] = 0; |
||
234 | $unsorted[$j] = $word; |
||
235 | // make a dictionary of all of the protected words in this script |
||
236 | // these are words that might be mistaken for encoding |
||
237 | //if (is_string($encode) && method_exists($this, $encode)) |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
67% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
238 | $values[$j] = call_user_func(array(&$this, $encode), $j); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$values was never initialized. Although not strictly required by PHP, it is generally a good practice to add $values = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
239 | $protected['$' . $values[$j]] = $j++; |
||
0 ignored issues
–
show
The variable
$values 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
![]() |
|||
240 | } |
||
241 | // increment the word counter |
||
242 | $this->_count[$word]++; |
||
243 | } while ($i > 0); |
||
244 | // prepare to sort the word list, first we must protect |
||
245 | // words that are also used as codes. we assign them a code |
||
246 | // equivalent to the word itself. |
||
247 | // e.g. if "do" falls within our encoding range |
||
248 | // then we store keywords["do"] = "do"; |
||
249 | // this avoids problems when decoding |
||
250 | $i = count($unsorted); |
||
251 | do { |
||
252 | $word = $unsorted[--$i]; |
||
253 | if (isset($protected[$word]) /*!= null*/) { |
||
254 | $_sorted[$protected[$word]] = substr($word, 1); |
||
255 | $_protected[$protected[$word]] = true; |
||
256 | $this->_count[$word] = 0; |
||
257 | } |
||
258 | } while ($i); |
||
259 | |||
260 | // sort the words by frequency |
||
261 | // Note: the javascript and php version of sort can be different : |
||
262 | // in php manual, usort : |
||
263 | // " If two members compare as equal, |
||
264 | // their order in the sorted array is undefined." |
||
265 | // so the final packed script is different of the Dean's javascript version |
||
266 | // but equivalent. |
||
267 | // the ECMAscript standard does not guarantee this behaviour, |
||
268 | // and thus not all browsers (e.g. Mozilla versions dating back to at |
||
269 | // least 2003) respect this. |
||
270 | usort($unsorted, array(&$this, '_sortWords')); |
||
271 | $j = 0; |
||
272 | // because there are "protected" words in the list |
||
273 | // we must add the sorted words around them |
||
274 | do { |
||
275 | if (!isset($_sorted[$i])) |
||
276 | $_sorted[$i] = substr($unsorted[$j++], 1); |
||
277 | $_encoded[$_sorted[$i]] = $values[$i]; |
||
278 | } while (++$i < count($unsorted)); |
||
279 | } |
||
280 | |||
281 | return array( |
||
282 | 'sorted' => $_sorted, |
||
283 | 'encoded' => $_encoded, |
||
284 | 'protected' => $_protected); |
||
285 | } |
||
286 | |||
287 | private $_count = array(); |
||
288 | private function _sortWords($match1, $match2) |
||
289 | { |
||
290 | return $this->_count[$match2] - $this->_count[$match1]; |
||
291 | } |
||
292 | |||
293 | // build the boot function used for loading and decoding |
||
294 | private function _bootStrap($packed, $keywords) |
||
295 | { |
||
296 | $ENCODE = $this->_safeRegExp('$encode\\($count\\)'); |
||
297 | |||
298 | // $packed: the packed script |
||
299 | $packed = "'" . $this->_escape($packed) . "'"; |
||
300 | |||
301 | // $ascii: base for encoding |
||
302 | $ascii = min(count($keywords['sorted']), $this->_encoding); |
||
303 | if ($ascii == 0) $ascii = 1; |
||
304 | |||
305 | // $count: number of words contained in the script |
||
306 | $count = count($keywords['sorted']); |
||
307 | |||
308 | // $keywords: list of words contained in the script |
||
309 | foreach ($keywords['protected'] as $i=>$value) { |
||
310 | $keywords['sorted'][$i] = ''; |
||
311 | } |
||
312 | // convert from a string to an array |
||
313 | ksort($keywords['sorted']); |
||
314 | $keywords = "'" . implode('|', $keywords['sorted']) . "'.split('|')"; |
||
315 | |||
316 | $encode = ($this->_encoding > 62) ? '_encode95' : $this->_getEncoder($ascii); |
||
317 | $encode = $this->_getJSFunction($encode); |
||
318 | $encode = preg_replace('/_encoding/', '$ascii', $encode); |
||
319 | $encode = preg_replace('/arguments\\.callee/', '$encode', $encode); |
||
320 | $inline = '\\$count' . ($ascii > 10 ? '.toString(\\$ascii)' : ''); |
||
321 | |||
322 | // $decode: code snippet to speed up decoding |
||
323 | if ($this->_fastDecode) { |
||
324 | // create the decoder |
||
325 | $decode = $this->_getJSFunction('_decodeBody'); |
||
326 | if ($this->_encoding > 62) |
||
327 | $decode = preg_replace('/\\\\w/', '[\\xa1-\\xff]', $decode); |
||
328 | // perform the encoding inline for lower ascii values |
||
329 | elseif ($ascii < 36) |
||
330 | $decode = preg_replace($ENCODE, $inline, $decode); |
||
331 | // special case: when $count==0 there are no keywords. I want to keep |
||
332 | // the basic shape of the unpacking funcion so i'll frig the code... |
||
333 | if ($count == 0) |
||
334 | $decode = preg_replace($this->_safeRegExp('($count)\\s*=\\s*1'), '$1=0', $decode, 1); |
||
335 | } |
||
336 | |||
337 | // boot function |
||
338 | $unpack = $this->_getJSFunction('_unpack'); |
||
339 | if ($this->_fastDecode) { |
||
340 | // insert the decoder |
||
341 | $this->buffer = $decode; |
||
0 ignored issues
–
show
The variable
$decode 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
![]() |
|||
342 | $unpack = preg_replace_callback('/\\{/', array(&$this, '_insertFastDecode'), $unpack, 1); |
||
343 | } |
||
344 | $unpack = preg_replace('/"/', "'", $unpack); |
||
345 | if ($this->_encoding > 62) { // high-ascii |
||
346 | // get rid of the word-boundaries for regexp matches |
||
347 | $unpack = preg_replace('/\'\\\\\\\\b\'\s*\\+|\\+\s*\'\\\\\\\\b\'/', '', $unpack); |
||
348 | } |
||
349 | if ($ascii > 36 || $this->_encoding > 62 || $this->_fastDecode) { |
||
350 | // insert the encode function |
||
351 | $this->buffer = $encode; |
||
352 | $unpack = preg_replace_callback('/\\{/', array(&$this, '_insertFastEncode'), $unpack, 1); |
||
353 | } else { |
||
354 | // perform the encoding inline |
||
355 | $unpack = preg_replace($ENCODE, $inline, $unpack); |
||
356 | } |
||
357 | // pack the boot function too |
||
358 | $unpackPacker = new JavaScriptPacker($unpack, 0, false, true); |
||
359 | $unpack = $unpackPacker->pack(); |
||
360 | |||
361 | // arguments |
||
362 | $params = array($packed, $ascii, $count, $keywords); |
||
363 | if ($this->_fastDecode) { |
||
364 | $params[] = 0; |
||
365 | $params[] = '{}'; |
||
366 | } |
||
367 | $params = implode(',', $params); |
||
368 | |||
369 | // the whole thing |
||
370 | //Firefox 4 fix, old: return 'eval(' . $unpack . '(' . $params . "))\n"; |
||
371 | return "(typeof setTimeout=='function'?setTimeout:eval)(" . $unpack . "(" . $params . "));\n"; |
||
372 | } |
||
373 | |||
374 | private $buffer; |
||
375 | private function _insertFastDecode($match) |
||
0 ignored issues
–
show
|
|||
376 | { |
||
377 | return '{' . $this->buffer . ';'; |
||
378 | } |
||
379 | private function _insertFastEncode($match) |
||
0 ignored issues
–
show
|
|||
380 | { |
||
381 | return '{$encode=' . $this->buffer . ';'; |
||
382 | } |
||
383 | |||
384 | // mmm.. ..which one do i need ?? |
||
385 | private function _getEncoder($ascii) |
||
386 | { |
||
387 | return $ascii > 10 ? $ascii > 36 ? $ascii > 62 ? |
||
388 | '_encode95' : '_encode62' : '_encode36' : '_encode10'; |
||
389 | } |
||
390 | |||
391 | // zero encoding |
||
392 | // characters: 0123456789 |
||
393 | private function _encode10($charCode) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
394 | { |
||
395 | return $charCode; |
||
396 | } |
||
397 | |||
398 | // inherent base36 support |
||
399 | // characters: 0123456789abcdefghijklmnopqrstuvwxyz |
||
400 | private function _encode36($charCode) |
||
401 | { |
||
402 | return base_convert($charCode, 10, 36); |
||
403 | } |
||
404 | |||
405 | // hitch a ride on base36 and add the upper case alpha characters |
||
406 | // characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ |
||
407 | private function _encode62($charCode) |
||
408 | { |
||
409 | $res = ''; |
||
410 | if ($charCode >= $this->_encoding) { |
||
411 | $res = $this->_encode62((int) ($charCode / $this->_encoding)); |
||
412 | } |
||
413 | $charCode = $charCode % $this->_encoding; |
||
414 | |||
415 | if ($charCode > 35) |
||
416 | return $res . chr($charCode + 29); |
||
417 | else |
||
418 | return $res . base_convert($charCode, 10, 36); |
||
419 | } |
||
420 | |||
421 | // use high-ascii values |
||
422 | // characters: ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ |
||
423 | private function _encode95($charCode) |
||
424 | { |
||
425 | $res = ''; |
||
426 | if ($charCode >= $this->_encoding) |
||
427 | $res = $this->_encode95($charCode / $this->_encoding); |
||
428 | |||
429 | return $res . chr(($charCode % $this->_encoding) + 161); |
||
430 | } |
||
431 | |||
432 | private function _safeRegExp($string) |
||
433 | { |
||
434 | return '/'.preg_replace('/\$/', '\\\$', $string).'/'; |
||
435 | } |
||
436 | |||
437 | private function _encodePrivate($charCode) |
||
438 | { |
||
439 | return "_" . $charCode; |
||
440 | } |
||
441 | |||
442 | // protect characters used by the parser |
||
443 | private function _escape($script) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
444 | { |
||
445 | return preg_replace('/([\\\\\'])/', '\\\$1', $script); |
||
446 | } |
||
447 | |||
448 | // protect high-ascii characters already in the script |
||
449 | private function _escape95($script) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
450 | { |
||
451 | return preg_replace_callback( |
||
452 | '/[\\xa1-\\xff]/', |
||
453 | array(&$this, '_escape95Bis'), |
||
454 | $script |
||
455 | ); |
||
456 | } |
||
457 | private function _escape95Bis($match) |
||
458 | { |
||
459 | return '\x'.((string) dechex(ord($match))); |
||
460 | } |
||
461 | |||
462 | private function _getJSFunction($aName) |
||
463 | { |
||
464 | if (defined('self::JSFUNCTION'.$aName)) |
||
465 | return constant('self::JSFUNCTION'.$aName); |
||
466 | else |
||
467 | return ''; |
||
468 | } |
||
469 | |||
470 | // JavaScript Functions used. |
||
471 | // Note : In Dean's version, these functions are converted |
||
472 | // with 'String(aFunctionName);'. |
||
473 | // This internal conversion complete the original code, ex : |
||
474 | // 'while (aBool) anAction();' is converted to |
||
475 | // 'while (aBool) { anAction(); }'. |
||
476 | // The JavaScript functions below are corrected. |
||
477 | |||
478 | // unpacking function - this is the boot strap function |
||
479 | // data extracted from this packing routine is passed to |
||
480 | // this function when decoded in the target |
||
481 | // NOTE ! : without the ';' final. |
||
482 | const JSFUNCTION_unpack = |
||
483 | |||
484 | 'function ($packed, $ascii, $count, $keywords, $encode, $decode) { |
||
485 | while ($count--) { |
||
486 | if ($keywords[$count]) { |
||
487 | $packed = $packed.replace(new RegExp(\'\\\\b\' + $encode($count) + \'\\\\b\', \'g\'), $keywords[$count]); |
||
488 | } |
||
489 | } |
||
490 | |||
491 | return $packed; |
||
492 | }'; |
||
493 | /* |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
74% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
494 | 'function ($packed, $ascii, $count, $keywords, $encode, $decode) { |
||
495 | while ($count--) |
||
496 | if ($keywords[$count]) |
||
497 | $packed = $packed.replace(new RegExp(\'\\\\b\' + $encode($count) + \'\\\\b\', \'g\'), $keywords[$count]); |
||
498 | |||
499 | return $packed; |
||
500 | }'; |
||
501 | */ |
||
502 | |||
503 | // code-snippet inserted into the unpacker to speed up decoding |
||
504 | const JSFUNCTION_decodeBody = |
||
505 | //_decode = function () { |
||
506 | // does the browser support String.replace where the |
||
507 | // replacement value is a function? |
||
508 | |||
509 | ' if (!\'\'.replace(/^/, String)) { |
||
510 | // decode all the values we need |
||
511 | while ($count--) { |
||
512 | $decode[$encode($count)] = $keywords[$count] || $encode($count); |
||
513 | } |
||
514 | // global replacement function |
||
515 | $keywords = [function ($encoded) {return $decode[$encoded]}]; |
||
516 | // generic match |
||
517 | $encode = function () {return \'\\\\w+\'}; |
||
518 | // reset the loop counter - we are now doing a global replace |
||
519 | $count = 1; |
||
520 | } |
||
521 | '; |
||
522 | //}; |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
72% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
523 | /* |
||
524 | ' if (!\'\'.replace(/^/, String)) { |
||
525 | // decode all the values we need |
||
526 | while ($count--) $decode[$encode($count)] = $keywords[$count] || $encode($count); |
||
527 | // global replacement function |
||
528 | $keywords = [function ($encoded) {return $decode[$encoded]}]; |
||
529 | // generic match |
||
530 | $encode = function () {return\'\\\\w+\'}; |
||
531 | // reset the loop counter - we are now doing a global replace |
||
532 | $count = 1; |
||
533 | }'; |
||
534 | */ |
||
535 | |||
536 | // zero encoding |
||
537 | // characters: 0123456789 |
||
538 | const JSFUNCTION_encode10 = |
||
539 | 'function ($charCode) { |
||
540 | return $charCode; |
||
541 | }';//;'; |
||
542 | |||
543 | // inherent base36 support |
||
544 | // characters: 0123456789abcdefghijklmnopqrstuvwxyz |
||
545 | const JSFUNCTION_encode36 = |
||
546 | 'function ($charCode) { |
||
547 | return $charCode.toString(36); |
||
548 | }';//;'; |
||
549 | |||
550 | // hitch a ride on base36 and add the upper case alpha characters |
||
551 | // characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ |
||
552 | const JSFUNCTION_encode62 = |
||
553 | 'function ($charCode) { |
||
554 | return ($charCode < _encoding ? \'\' : arguments.callee(parseInt($charCode / _encoding))) + |
||
555 | (($charCode = $charCode % _encoding) > 35 ? String.fromCharCode($charCode + 29) : $charCode.toString(36)); |
||
556 | }'; |
||
557 | |||
558 | // use high-ascii values |
||
559 | // characters: ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ |
||
560 | const JSFUNCTION_encode95 = |
||
561 | 'function ($charCode) { |
||
562 | return ($charCode < _encoding ? \'\' : arguments.callee($charCode / _encoding)) + |
||
563 | String.fromCharCode($charCode % _encoding + 161); |
||
564 | }'; |
||
565 | |||
566 | } |
||
567 | |||
568 | class ParseMaster |
||
0 ignored issues
–
show
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.
You can fix this by adding a namespace to your class: namespace YourVendor;
class YourClass { }
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries. ![]() |
|||
569 | { |
||
570 | public $ignoreCase = false; |
||
571 | public $escapeChar = ''; |
||
572 | |||
573 | // constants |
||
574 | const EXPRESSION = 0; |
||
575 | const REPLACEMENT = 1; |
||
576 | const LENGTH = 2; |
||
577 | |||
578 | // used to determine nesting levels |
||
579 | private $GROUPS = '/\\(/';//g |
||
580 | private $SUB_REPLACE = '/\\$\\d/'; |
||
581 | private $INDEXED = '/^\\$\\d+$/'; |
||
582 | private $TRIM = '/([\'"])\\1\\.(.*)\\.\\1\\1$/'; |
||
0 ignored issues
–
show
|
|||
583 | private $ESCAPE = '/\\\./';//g |
||
584 | private $QUOTE = '/\'/'; |
||
585 | private $DELETED = '/\\x01[^\\x01]*\\x01/';//g |
||
586 | |||
587 | public function add($expression, $replacement = '') |
||
588 | { |
||
589 | // count the number of sub-expressions |
||
590 | // - add one because each pattern is itself a sub-expression |
||
591 | $length = 1 + preg_match_all($this->GROUPS, $this->_internalEscape((string) $expression), $out); |
||
592 | |||
593 | // treat only strings $replacement |
||
594 | if (is_string($replacement)) { |
||
595 | // does the pattern deal with sub-expressions? |
||
596 | if (preg_match($this->SUB_REPLACE, $replacement)) { |
||
597 | // a simple lookup? (e.g. "$2") |
||
598 | if (preg_match($this->INDEXED, $replacement)) { |
||
599 | // store the index (used for fast retrieval of matched strings) |
||
600 | $replacement = (int) (substr($replacement, 1)) - 1; |
||
601 | } else { // a complicated lookup (e.g. "Hello $2 $1") |
||
602 | // build a function to do the lookup |
||
603 | $quote = preg_match($this->QUOTE, $this->_internalEscape($replacement)) |
||
604 | ? '"' : "'"; |
||
605 | $replacement = array( |
||
606 | 'fn' => '_backReferences', |
||
607 | 'data' => array( |
||
608 | 'replacement' => $replacement, |
||
609 | 'length' => $length, |
||
610 | 'quote' => $quote |
||
611 | ) |
||
612 | ); |
||
613 | } |
||
614 | } |
||
615 | } |
||
616 | // pass the modified arguments |
||
617 | if (!empty($expression)) $this->_add($expression, $replacement, $length); |
||
618 | else $this->_add('/^$/', $replacement, $length); |
||
619 | } |
||
620 | |||
621 | public function exec($string) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
622 | { |
||
623 | // execute the global replacement |
||
624 | $this->_escaped = array(); |
||
625 | |||
626 | // simulate the _patterns.toSTring of Dean |
||
627 | $regexp = '/'; |
||
628 | foreach ($this->_patterns as $reg) { |
||
629 | $regexp .= '(' . substr($reg[self::EXPRESSION], 1, -1) . ')|'; |
||
630 | } |
||
631 | $regexp = substr($regexp, 0, -1) . '/'; |
||
632 | $regexp .= ($this->ignoreCase) ? 'i' : ''; |
||
633 | |||
634 | $string = $this->_escape($string, $this->escapeChar); |
||
635 | $string = preg_replace_callback( |
||
636 | $regexp, |
||
637 | array( |
||
638 | &$this, |
||
639 | '_replacement' |
||
640 | ), |
||
641 | $string |
||
642 | ); |
||
643 | $string = $this->_unescape($string, $this->escapeChar); |
||
644 | |||
645 | return preg_replace($this->DELETED, '', $string); |
||
646 | } |
||
647 | |||
648 | public function reset() |
||
649 | { |
||
650 | // clear the patterns collection so that this object may be re-used |
||
651 | $this->_patterns = array(); |
||
652 | } |
||
653 | |||
654 | // private |
||
655 | private $_escaped = array(); // escaped characters |
||
656 | private $_patterns = array(); // patterns stored by index |
||
657 | |||
658 | // create and add a new pattern to the patterns collection |
||
659 | private function _add() |
||
660 | { |
||
661 | $arguments = func_get_args(); |
||
662 | $this->_patterns[] = $arguments; |
||
663 | } |
||
664 | |||
665 | // this is the global replace function (it's quite complicated) |
||
666 | private function _replacement($arguments) |
||
667 | { |
||
668 | if (empty($arguments)) return ''; |
||
669 | |||
670 | $i = 1; $j = 0; |
||
671 | // loop through the patterns |
||
672 | while (isset($this->_patterns[$j])) { |
||
673 | $pattern = $this->_patterns[$j++]; |
||
674 | // do we have a result? |
||
675 | if (isset($arguments[$i]) && ($arguments[$i] != '')) { |
||
676 | $replacement = $pattern[self::REPLACEMENT]; |
||
677 | |||
678 | if (is_array($replacement) && isset($replacement['fn'])) { |
||
679 | |||
680 | if (isset($replacement['data'])) $this->buffer = $replacement['data']; |
||
681 | return call_user_func(array(&$this, $replacement['fn']), $arguments, $i); |
||
682 | |||
683 | } elseif (is_int($replacement)) { |
||
684 | return $arguments[$replacement + $i]; |
||
685 | |||
686 | } |
||
687 | $delete = ($this->escapeChar == '' || |
||
688 | strpos($arguments[$i], $this->escapeChar) === false) |
||
689 | ? '' : "\x01" . $arguments[$i] . "\x01"; |
||
690 | |||
691 | return $delete . $replacement; |
||
692 | |||
693 | // skip over references to sub-expressions |
||
694 | } else { |
||
695 | $i += $pattern[self::LENGTH]; |
||
696 | } |
||
697 | } |
||
698 | } |
||
699 | |||
700 | private function _backReferences($match, $offset) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
701 | { |
||
702 | $replacement = $this->buffer['replacement']; |
||
703 | $quote = $this->buffer['quote']; |
||
0 ignored issues
–
show
$quote 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 ![]() |
|||
704 | $i = $this->buffer['length']; |
||
705 | while ($i) { |
||
706 | $replacement = str_replace('$'.$i--, $match[$offset + $i], $replacement); |
||
707 | } |
||
708 | |||
709 | return $replacement; |
||
710 | } |
||
711 | |||
712 | private function _replace_name($match, $offset) |
||
713 | { |
||
714 | $length = strlen($match[$offset + 2]); |
||
715 | $start = $length - max($length - strlen($match[$offset + 3]), 0); |
||
716 | |||
717 | return substr($match[$offset + 1], $start, $length) . $match[$offset + 4]; |
||
718 | } |
||
719 | |||
720 | private function _replace_encoded($match, $offset) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
721 | { |
||
722 | return $this->buffer[$match[$offset]]; |
||
723 | } |
||
724 | |||
725 | |||
726 | // php : we cannot pass additional data to preg_replace_callback, |
||
727 | // and we cannot use &$this in create_function, so let's go to lower level |
||
728 | private $buffer; |
||
729 | |||
730 | // encode escaped characters |
||
731 | private function _escape($string, $escapeChar) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
732 | { |
||
733 | if ($escapeChar) { |
||
734 | $this->buffer = $escapeChar; |
||
735 | |||
736 | return preg_replace_callback( |
||
737 | '/\\' . $escapeChar . '(.)' .'/', |
||
738 | array(&$this, '_escapeBis'), |
||
739 | $string |
||
740 | ); |
||
741 | |||
742 | } else { |
||
743 | return $string; |
||
744 | } |
||
745 | } |
||
746 | private function _escapeBis($match) |
||
747 | { |
||
748 | $this->_escaped[] = $match[1]; |
||
749 | |||
750 | return $this->buffer; |
||
751 | } |
||
752 | |||
753 | // decode escaped characters |
||
754 | private function _unescape($string, $escapeChar) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
755 | { |
||
756 | if ($escapeChar) { |
||
757 | $regexp = '/'.'\\'.$escapeChar.'/'; |
||
758 | $this->buffer = array('escapeChar'=> $escapeChar, 'i' => 0); |
||
759 | |||
760 | return preg_replace_callback( |
||
761 | $regexp, |
||
762 | array(&$this, '_unescapeBis'), |
||
763 | $string |
||
764 | ); |
||
765 | |||
766 | } else { |
||
767 | return $string; |
||
768 | } |
||
769 | } |
||
770 | private function _unescapeBis() |
||
771 | { |
||
772 | if (isset($this->_escaped[$this->buffer['i']]) |
||
773 | && $this->_escaped[$this->buffer['i']] != '') |
||
774 | { |
||
775 | $temp = $this->_escaped[$this->buffer['i']]; |
||
776 | } else { |
||
777 | $temp = ''; |
||
778 | } |
||
779 | $this->buffer['i']++; |
||
780 | |||
781 | return $this->buffer['escapeChar'] . $temp; |
||
782 | } |
||
783 | |||
784 | private function _internalEscape($string) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
785 | { |
||
786 | return preg_replace($this->ESCAPE, '', $string); |
||
787 | } |
||
788 | } |
||
789 |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.