source: trunk/instant_messenger/controller.php @ 261

Revision 261, 27.5 KB checked in by niltonneto, 16 years ago (diff)
Line 
1<?php
2
3class Controller
4{
5        const __CONTROLLER_SECURITY__                           = 'controller-security';
6        const __CONTROLLER_CONTENTES__                          = 'controller-contentes';
7        const __CONTROLLER_SECTIONS__                           = 'controller-sections';
8
9        const __STRING_ACCESS__                                         = 'string-access';
10        const __STRING_DELIMITER__                                      = 'string-delimiter';
11
12        const __CONTROLLER_CONTENTES_ITEM__                     = 'item';
13        const __CONTROLLER_CONTENTES_ITEM_PARAM__       = 'param';
14        const __CONTROLLER_CONTENTES_ITEM_SECTION__     = 'section';
15
16        const __CONTROLLER_SECTIONS_ITEM__                      = 'item';
17
18        public function __construct()
19        {
20                $this->dom = new DOMDocument;
21                $this->dom->preserveWhiteSpace = FALSE;
22                $this->dom->load('controller.xml');
23
24                $this->controller_security = $this->dom->getElementsByTagName(self::__CONTROLLER_SECURITY__);
25                ( $this->controller_security->length === (int)0 )
26                        and die(__CLASS__ . ' [ ERROR #0 ] :: the tag "' . self::__CONTROLLER_SECURITY__ . '" does not exist');
27                ( $this->controller_security->length === (int)1 )
28                        or die(__CLASS__ . ' [ ERROR #1 ] :: exists more of a tag "' . self::__CONTROLLER_SECURITY__ . '"');
29
30                $this->controller_contentes = $this->dom->getElementsByTagName(self::__CONTROLLER_CONTENTES__);
31                ( $this->controller_contentes->length === (int)0 )
32                        and die(__CLASS__ . ' [ ERROR #2 ] :: the tag "' . self::__CONTROLLER_CONTENTES__ . '" does not exist');
33                ( $this->controller_contentes->length === (int)1 )
34                        or die(__CLASS__ . ' [ ERROR #3 ] :: exists more of a tag "' . self::__CONTROLLER_CONTENTES__ . '"');
35                $this->controller_contentes = $this->controller_contentes->item(0);
36
37                $this->controller_sections = $this->dom->getElementsByTagName("controller-sections");
38                ( $this->controller_sections->length === (int)0 )
39                        and die(__CLASS__ . ' [ ERROR #4 ] :: the tag "' . self::__CONTROLLER_SECTIONS__ . '" does not exist');
40                ( $this->controller_sections->length === (int)1 )
41                        or die(__CLASS__ . ' [ ERROR #5 ] :: exists more of a tag "' . self::__CONTROLLER_SECTIONS__ . '"');
42                $this->controller_sections = $this->controller_sections->item(0);
43
44                $this->string_access = $this->controller_security->item(0)->getElementsByTagName(self::__STRING_ACCESS__);
45                ( $this->string_access->length === (int)0 )
46                        and die(__CLASS__ . ' [ ERROR #6 ] :: the tag "' . self::__STRING_ACCESS__ . '" does not exist');
47                ( $this->string_access->length === (int)1 )
48                        or die(__CLASS__ . ' [ ERROR #7 ] :: exists more of a tag "' . self::__STRING_ACCESS__ . '"');
49                $this->string_access = $this->string_access->item(0)->nodeValue;
50
51                $this->string_delimiter = $this->controller_security->item(0)->getElementsByTagName(self::__STRING_DELIMITER__);
52                ( $this->string_delimiter->length === (int)0 )
53                        and die(__CLASS__ . ' [ ERROR #8 ] :: the tag "' . self::__STRING_DELIMITER__ . '" does not exist');
54                ( $this->string_delimiter->length === (int)1 )
55                        or die(__CLASS__ . ' [ ERROR #9 ] :: exists more of a tag "' . self::__STRING_DELIMITER__ . '"');
56                $this->string_delimiter = $this->string_delimiter->item(0)->nodeValue;
57        }
58
59        public function exec(array &$pRequest)
60        {
61                ( $pRequest[$this->string_access] )
62                        or die(__CLASS__ . ' [ ERROR #10 ] :: bad string action argument');
63
64                list($section_name, $ref, $alias) = explode($this->string_delimiter, $pRequest[$this->string_access]);
65                unset($pRequest[$this->string_access]);
66
67                $contents_itens = $this->controller_contentes->getElementsByTagName(self::__CONTROLLER_CONTENTES_ITEM__);
68
69                for ( $i = 0; $i < $contents_itens->length && $contents_itens->item($i)->getAttribute(self::__CONTROLLER_CONTENTES_ITEM_PARAM__) != $section_name; $i++ );
70                ( !($i < $contents_itens->length) )
71                        and die(__CLASS__ . ' [ ERROR #11 ] :: invalid section "' . $section_name . '"');
72
73                $section_name = $contents_itens->item($i)->getAttribute(self::__CONTROLLER_CONTENTES_ITEM_SECTION__);
74
75                $section = $this->controller_sections->getElementsByTagName($section_name);
76                ( $section->length === (int)0 )
77                        and die(__CLASS__ . ' [ ERROR #12 ] :: the tag "' . $section_name . '" does not exist');
78                ( $section->length === (int)1 )
79                        or die(__CLASS__ . ' [ ERROR #13 ] :: exists more of a tag "' . $section_name . '"');
80                $section = $section->item(0);
81
82                $section_itens = $section->getElementsByTagName(self::__CONTROLLER_SECTIONS_ITEM__);
83
84                if ( empty($alias) && $alias !== '0' )
85                        for ( $i = 0; $i < $section_itens->length && $section_itens->item($i)->getAttribute('ref') != $ref; $i++ );
86                else
87                        for ( $i = 0; $i < $section_itens->length && ( $section_itens->item($i)->getAttribute('ref') != $ref || $section_itens->item($i)->getAttribute('alias') !== $alias); $i++ );
88
89                ( !($i < $section_itens->length) )
90                        and die(__CLASS__ . ' [ ERROR #14 ] :: invalid reference "' . $ref . '"');
91
92                $path = $section_itens->item($i)->getAttribute('path')
93                        or $path = $section->getAttribute('path')
94                        or die(__CLASS__ . ' [ ERROR #15 ] :: bad path argument');
95
96                $prefix = $section_itens->item($i)->getAttribute('prefix')
97                        or $prefix = $section->getAttribute('prefix');
98
99                $suffix = $section_itens->item($i)->getAttribute('suffix')
100                        or $suffix = $section->getAttribute('suffix')
101                        or die(__CLASS__ . ' [ ERROR #16 ] :: bad suffix argument');
102
103                $this->$section_name(array("pSectionItem" => $section_itens->item($i), "pPath" => $path, "pPrefix" => $prefix, "pSuffix" => $suffix, "pRequest" => $pRequest));
104        }
105
106        private final function php()
107        {
108                $params = func_get_args();
109                extract($params[0]);
110
111                $class = $pSectionItem->getAttribute('class')
112                        and $method = $pSectionItem->getAttribute('method')
113                        or die(__CLASS__ . ' [ ERROR #17 ] :: bad class or method argument');
114
115                $file = "{$pPath}/{$pPrefix}{$class}{$pSuffix}";
116
117                file_exists($file)
118                        or die(__CLASS__ . ' [ ERROR #18 ] :: the file that has the class was not opened');
119
120                require_once $file;
121
122                $obj = new $class;
123
124                if ( $pRequest )
125                        $result = $obj -> $method($pRequest);
126                else
127                        $result = $obj -> $method();
128
129                printf("%s", $result);
130        }
131
132        private final function js()
133        {
134                $params = func_get_args();
135                extract($params[0]);
136
137                $js = $pSectionItem->getAttribute('js')
138                        or die(__CLASS__ . ' [ ERROR #18 ] :: bad js argument');
139
140                $file = "{$pPath}/{$pPrefix}{$js}{$pSuffix}";
141
142                file_exists($file)
143                        or die(__CLASS__ . ' [ ERROR #19 ] :: the file that has the class was not opened');
144
145                $packed_file = "{$pPath}/{$pPrefix}{$js}.packer{$pSuffix}";
146
147                (
148                        file_exists($packed_file)
149                        and filemtime($packed_file) > filemtime($file)
150                        and $packed = file_get_contents($packed_file)
151                )
152                or
153                (
154                        $packer = new JavaScriptPacker(file_get_contents($file), 'High ASCII', true, true)
155                        and $packed = $packer->pack()
156                        and file_put_contents($packed_file, $packed)
157                );
158
159                printf("%s", $packed);
160        }
161}
162
163class JavaScriptPacker
164{
165        const IGNORE = '$1';
166
167        private $_script = '';
168        private $_encoding = 62;
169        private $_fastDecode = true;
170        private $_specialChars = false;
171
172        private $_parsers = array();
173
174        private $LITERAL_ENCODING = array(
175                'None' => 0,
176                'Numeric' => 10,
177                'Normal' => 62,
178                'High ASCII' => 95
179        );
180
181        public function __construct ($pScript, $pEncoding = 62, $pFastDecode = true, $pSpecialChars = false)
182        {
183                $this->_script = $pScript . "\n";
184                if ( array_key_exists($pEncoding, $this->LITERAL_ENCODING) )
185                        $pEncoding = $this->LITERAL_ENCODING[$pEncoding];
186
187                $this->_encoding = min((int)$pEncoding, 95);
188                $this->_fastDecode = $pFastDecode;
189                $this->_specialChars = $pSpecialChars;
190        }
191
192        public function pack()
193        {
194                $this->_addParser('_basicCompression');
195
196                if ( $this->_specialChars )
197                        $this->_addParser('_encodeSpecialChars');
198
199                if ( $this->_encoding )
200                        $this->_addParser('_encodeKeywords');
201
202                return $this->_pack($this->_script);
203        }
204
205        private function _pack($script)
206        {
207                for ( $i = 0; isset($this->_parsers[$i]); $i++ )
208                        $script = call_user_func(array(&$this,$this->_parsers[$i]), $script);
209
210                return $script;
211        }
212
213        // keep a list of parsing functions, they'll be executed all at once
214        private function _addParser($parser)
215        {
216                $this->_parsers[] = $parser;
217        }
218
219        // zero encoding - just removal of white space and comments
220        private function _basicCompression($script)
221        {
222                $parser = new ParseMaster();
223                // make safe
224                $parser->escapeChar = '\\';
225                // protect strings
226                $parser->add('/\'[^\'\\n\\r]*\'/', self::IGNORE);
227                $parser->add('/"[^"\\n\\r]*"/', self::IGNORE);
228                // remove comments
229                $parser->add('/\\/\\/[^\\n\\r]*[\\n\\r]/', ' ');
230                $parser->add('/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\//', ' ');
231                // protect regular expressions
232                $parser->add('/\\s+(\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?)/', '$2'); // IGNORE
233                $parser->add('/[^\\w\\x24\\/\'"*)\\?:]\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?/', self::IGNORE);
234                // remove: ;;; doSomething();
235                if ($this->_specialChars) $parser->add('/;;;[^\\n\\r]+[\\n\\r]/');
236                // remove redundant semi-colons
237                $parser->add('/\\(;;\\)/', self::IGNORE); // protect for (;;) loops
238                $parser->add('/;+\\s*([};])/', '$2');
239                // apply the above
240                $script = $parser->exec($script);
241
242                // remove white-space
243                $parser->add('/(\\b|\\x24)\\s+(\\b|\\x24)/', '$2 $3');
244                $parser->add('/([+\\-])\\s+([+\\-])/', '$2 $3');
245                $parser->add('/\\s+/', '');
246                // done
247                return $parser->exec($script);
248        }
249
250        private function _encodeSpecialChars($script)
251        {
252                $parser = new ParseMaster();
253                // replace: $name -> n, $$name -> na
254                $parser->add('/((\\x24+)([a-zA-Z$_]+))(\\d*)/',
255                                         array('fn' => '_replace_name')
256                );
257                // replace: _name -> _0, double-underscore (__name) is ignored
258                $regexp = '/\\b_[A-Za-z\\d]\\w*/';
259                // build the word list
260                $keywords = $this->_analyze($script, $regexp, '_encodePrivate');
261                // quick ref
262                $encoded = $keywords['encoded'];
263
264                $parser->add($regexp,
265                        array(
266                                'fn' => '_replace_encoded',
267                                'data' => $encoded
268                        )
269                );
270                return $parser->exec($script);
271        }
272
273        private function _encodeKeywords($script) {
274                // escape high-ascii values already in the script (i.e. in strings)
275                if ($this->_encoding > 62)
276                        $script = $this->_escape95($script);
277                // create the parser
278                $parser = new ParseMaster();
279                $encode = $this->_getEncoder($this->_encoding);
280                // for high-ascii, don't encode single character low-ascii
281                $regexp = ($this->_encoding > 62) ? '/\\w\\w+/' : '/\\w+/';
282                // build the word list
283                $keywords = $this->_analyze($script, $regexp, $encode);
284                $encoded = $keywords['encoded'];
285
286                // encode
287                $parser->add($regexp,
288                        array(
289                                'fn' => '_replace_encoded',
290                                'data' => $encoded
291                        )
292                );
293                if (empty($script)) return $script;
294                else {
295                        //$res = $parser->exec($script);
296                        //$res = $this->_bootStrap($res, $keywords);
297                        //return $res;
298                        return $this->_bootStrap($parser->exec($script), $keywords);
299                }
300        }
301
302        private function _analyze($script, $regexp, $encode) {
303                // analyse
304                // retreive all words in the script
305                $all = array();
306                preg_match_all($regexp, $script, $all);
307                $_sorted = array(); // list of words sorted by frequency
308                $_encoded = array(); // dictionary of word->encoding
309                $_protected = array(); // instances of "protected" words
310                $all = $all[0]; // simulate the javascript comportement of global match
311                if (!empty($all)) {
312                        $unsorted = array(); // same list, not sorted
313                        $protected = array(); // "protected" words (dictionary of word->"word")
314                        $value = array(); // dictionary of charCode->encoding (eg. 256->ff)
315                        $this->_count = array(); // word->count
316                        $i = count($all); $j = 0; //$word = null;
317                        // count the occurrences - used for sorting later
318                        do {
319                                --$i;
320                                $word = '$' . $all[$i];
321                                if (!isset($this->_count[$word])) {
322                                        $this->_count[$word] = 0;
323                                        $unsorted[$j] = $word;
324                                        // make a dictionary of all of the protected words in this script
325                                        //  these are words that might be mistaken for encoding
326                                        //if (is_string($encode) && method_exists($this, $encode))
327                                        $values[$j] = call_user_func(array(&$this, $encode), $j);
328                                        $protected['$' . $values[$j]] = $j++;
329                                }
330                                // increment the word counter
331                                $this->_count[$word]++;
332                        } while ($i > 0);
333                        // prepare to sort the word list, first we must protect
334                        //  words that are also used as codes. we assign them a code
335                        //  equivalent to the word itself.
336                        // e.g. if "do" falls within our encoding range
337                        //      then we store keywords["do"] = "do";
338                        // this avoids problems when decoding
339                        $i = count($unsorted);
340                        do {
341                                $word = $unsorted[--$i];
342                                if (isset($protected[$word]) /*!= null*/) {
343                                        $_sorted[$protected[$word]] = substr($word, 1);
344                                        $_protected[$protected[$word]] = true;
345                                        $this->_count[$word] = 0;
346                                }
347                        } while ($i);
348
349                        // sort the words by frequency
350                        // Note: the javascript and php version of sort can be different :
351                        // in php manual, usort :
352                        // " If two members compare as equal,
353                        // their order in the sorted array is undefined."
354                        // so the final packed script is different of the Dean's javascript version
355                        // but equivalent.
356                        // the ECMAscript standard does not guarantee this behaviour,
357                        // and thus not all browsers (e.g. Mozilla versions dating back to at
358                        // least 2003) respect this.
359                        usort($unsorted, array(&$this, '_sortWords'));
360                        $j = 0;
361                        // because there are "protected" words in the list
362                        //  we must add the sorted words around them
363                        do {
364                                if (!isset($_sorted[$i]))
365                                        $_sorted[$i] = substr($unsorted[$j++], 1);
366                                $_encoded[$_sorted[$i]] = $values[$i];
367                        } while (++$i < count($unsorted));
368                }
369                return array(
370                        'sorted'  => $_sorted,
371                        'encoded' => $_encoded,
372                        'protected' => $_protected);
373        }
374
375        private $_count = array();
376        private function _sortWords($match1, $match2) {
377                return $this->_count[$match2] - $this->_count[$match1];
378        }
379
380        // build the boot function used for loading and decoding
381        private function _bootStrap($packed, $keywords) {
382                $ENCODE = $this->_safeRegExp('$encode\\($count\\)');
383
384                // $packed: the packed script
385                $packed = "'" . $this->_escape($packed) . "'";
386
387                // $ascii: base for encoding
388                $ascii = min(count($keywords['sorted']), $this->_encoding);
389                if ($ascii == 0) $ascii = 1;
390
391                // $count: number of words contained in the script
392                $count = count($keywords['sorted']);
393
394                // $keywords: list of words contained in the script
395                foreach ($keywords['protected'] as $i=>$value) {
396                        $keywords['sorted'][$i] = '';
397                }
398                // convert from a string to an array
399                ksort($keywords['sorted']);
400                $keywords = "'" . implode('|',$keywords['sorted']) . "'.split('|')";
401
402                $encode = ($this->_encoding > 62) ? '_encode95' : $this->_getEncoder($ascii);
403                $encode = $this->_getJSFunction($encode);
404                $encode = preg_replace('/_encoding/','$ascii', $encode);
405                $encode = preg_replace('/arguments\\.callee/','$encode', $encode);
406                $inline = '\\$count' . ($ascii > 10 ? '.toString(\\$ascii)' : '');
407
408                // $decode: code snippet to speed up decoding
409                if ($this->_fastDecode) {
410                        // create the decoder
411                        $decode = $this->_getJSFunction('_decodeBody');
412                        if ($this->_encoding > 62)
413                                $decode = preg_replace('/\\\\w/', '[\\xa1-\\xff]', $decode);
414                        // perform the encoding inline for lower ascii values
415                        elseif ($ascii < 36)
416                                $decode = preg_replace($ENCODE, $inline, $decode);
417                        // special case: when $count==0 there are no keywords. I want to keep
418                        //  the basic shape of the unpacking funcion so i'll frig the code...
419                        if ($count == 0)
420                                $decode = preg_replace($this->_safeRegExp('($count)\\s*=\\s*1'), '$1=0', $decode, 1);
421                }
422
423                // boot function
424                $unpack = $this->_getJSFunction('_unpack');
425                if ($this->_fastDecode) {
426                        // insert the decoder
427                        $this->buffer = $decode;
428                        $unpack = preg_replace_callback('/\\{/', array(&$this, '_insertFastDecode'), $unpack, 1);
429                }
430                $unpack = preg_replace('/"/', "'", $unpack);
431                if ($this->_encoding > 62) { // high-ascii
432                        // get rid of the word-boundaries for regexp matches
433                        $unpack = preg_replace('/\'\\\\\\\\b\'\s*\\+|\\+\s*\'\\\\\\\\b\'/', '', $unpack);
434                }
435                if ($ascii > 36 || $this->_encoding > 62 || $this->_fastDecode) {
436                        // insert the encode function
437                        $this->buffer = $encode;
438                        $unpack = preg_replace_callback('/\\{/', array(&$this, '_insertFastEncode'), $unpack, 1);
439                } else {
440                        // perform the encoding inline
441                        $unpack = preg_replace($ENCODE, $inline, $unpack);
442                }
443                // pack the boot function too
444                $unpackPacker = new JavaScriptPacker($unpack, 0, false, true);
445                $unpack = $unpackPacker->pack();
446
447                // arguments
448                $params = array($packed, $ascii, $count, $keywords);
449                if ($this->_fastDecode) {
450                        $params[] = 0;
451                        $params[] = '{}';
452                }
453                $params = implode(',', $params);
454
455                // the whole thing
456                return 'eval(' . $unpack . '(' . $params . "))\n";
457        }
458
459        private $buffer;
460        private function _insertFastDecode($match) {
461                return '{' . $this->buffer . ';';
462        }
463        private function _insertFastEncode($match) {
464                return '{$encode=' . $this->buffer . ';';
465        }
466
467        // mmm.. ..which one do i need ??
468        private function _getEncoder($ascii) {
469                return $ascii > 10 ? $ascii > 36 ? $ascii > 62 ?
470                       '_encode95' : '_encode62' : '_encode36' : '_encode10';
471        }
472
473        // zero encoding
474        // characters: 0123456789
475        private function _encode10($charCode) {
476                return $charCode;
477        }
478
479        // inherent base36 support
480        // characters: 0123456789abcdefghijklmnopqrstuvwxyz
481        private function _encode36($charCode) {
482                return base_convert($charCode, 10, 36);
483        }
484
485        // hitch a ride on base36 and add the upper case alpha characters
486        // characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
487        private function _encode62($charCode) {
488                $res = '';
489                if ($charCode >= $this->_encoding) {
490                        $res = $this->_encode62((int)($charCode / $this->_encoding));
491                }
492                $charCode = $charCode % $this->_encoding;
493
494                if ($charCode > 35)
495                        return $res . chr($charCode + 29);
496                else
497                        return $res . base_convert($charCode, 10, 36);
498        }
499
500        // use high-ascii values
501        // characters: ¡¢£€¥Š§š©ª«¬­®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãÀåÊçÚéêëìíîïðñòóÎõö÷ÞùúûÌÜß
502        private function _encode95($charCode) {
503                $res = '';
504                if ($charCode >= $this->_encoding)
505                        $res = $this->_encode95($charCode / $this->_encoding);
506
507                return $res . chr(($charCode % $this->_encoding) + 161);
508        }
509
510        private function _safeRegExp($string) {
511                return '/'.preg_replace('/\$/', '\\\$', $string).'/';
512        }
513
514        private function _encodePrivate($charCode) {
515                return "_" . $charCode;
516        }
517
518        // protect characters used by the parser
519        private function _escape($script) {
520                return preg_replace('/([\\\\\'])/', '\\\$1', $script);
521        }
522
523        // protect high-ascii characters already in the script
524        private function _escape95($script) {
525                return preg_replace_callback(
526                        '/[\\xa1-\\xff]/',
527                        array(&$this, '_escape95Bis'),
528                        $script
529                );
530        }
531        private function _escape95Bis($match) {
532                return '\x'.((string)dechex(ord($match)));
533        }
534
535
536        private function _getJSFunction($aName) {
537                if (defined('self::JSFUNCTION'.$aName))
538                        return constant('self::JSFUNCTION'.$aName);
539                else
540                        return '';
541        }
542
543        // JavaScript Functions used.
544        // Note : In Dean's version, these functions are converted
545        // with 'String(aFunctionName);'.
546        // This internal conversion complete the original code, ex :
547        // 'while (aBool) anAction();' is converted to
548        // 'while (aBool) { anAction(); }'.
549        // The JavaScript functions below are corrected.
550
551        // unpacking function - this is the boot strap function
552        //  data extracted from this packing routine is passed to
553        //  this function when decoded in the target
554        // NOTE ! : without the ';' final.
555        const JSFUNCTION_unpack =
556
557'function($packed, $ascii, $count, $keywords, $encode, $decode) {
558    while ($count--) {
559        if ($keywords[$count]) {
560            $packed = $packed.replace(new RegExp(\'\\\\b\' + $encode($count) + \'\\\\b\', \'g\'), $keywords[$count]);
561        }
562    }
563    return $packed;
564}';
565/*
566'function($packed, $ascii, $count, $keywords, $encode, $decode) {
567    while ($count--)
568        if ($keywords[$count])
569            $packed = $packed.replace(new RegExp(\'\\\\b\' + $encode($count) + \'\\\\b\', \'g\'), $keywords[$count]);
570    return $packed;
571}';
572*/
573
574        // code-snippet inserted into the unpacker to speed up decoding
575        const JSFUNCTION_decodeBody =
576//_decode = function() {
577// does the browser support String.replace where the
578//  replacement value is a function?
579
580'    if (!\'\'.replace(/^/, String)) {
581        // decode all the values we need
582        while ($count--) {
583            $decode[$encode($count)] = $keywords[$count] || $encode($count);
584        }
585        // global replacement function
586        $keywords = [function ($encoded) {return $decode[$encoded]}];
587        // generic match
588        $encode = function () {return \'\\\\w+\'};
589        // reset the loop counter -  we are now doing a global replace
590        $count = 1;
591    }
592';
593//};
594/*
595'       if (!\'\'.replace(/^/, String)) {
596        // decode all the values we need
597        while ($count--) $decode[$encode($count)] = $keywords[$count] || $encode($count);
598        // global replacement function
599        $keywords = [function ($encoded) {return $decode[$encoded]}];
600        // generic match
601        $encode = function () {return\'\\\\w+\'};
602        // reset the loop counter -  we are now doing a global replace
603        $count = 1;
604    }';
605*/
606
607         // zero encoding
608         // characters: 0123456789
609         const JSFUNCTION_encode10 =
610'function($charCode) {
611    return $charCode;
612}';//;';
613
614         // inherent base36 support
615         // characters: 0123456789abcdefghijklmnopqrstuvwxyz
616         const JSFUNCTION_encode36 =
617'function($charCode) {
618    return $charCode.toString(36);
619}';//;';
620
621        // hitch a ride on base36 and add the upper case alpha characters
622        // characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
623        const JSFUNCTION_encode62 =
624'function($charCode) {
625    return ($charCode < _encoding ? \'\' : arguments.callee(parseInt($charCode / _encoding))) +
626    (($charCode = $charCode % _encoding) > 35 ? String.fromCharCode($charCode + 29) : $charCode.toString(36));
627}';
628
629        // use high-ascii values
630        // characters: ¡¢£€¥Š§š©ª«¬­®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãÀåÊçÚéêëìíîïðñòóÎõö÷ÞùúûÌÜß
631        const JSFUNCTION_encode95 =
632'function($charCode) {
633    return ($charCode < _encoding ? \'\' : arguments.callee($charCode / _encoding)) +
634        String.fromCharCode($charCode % _encoding + 161);
635}';
636
637}
638
639
640class ParseMaster {
641        public $ignoreCase = false;
642        public $escapeChar = '';
643
644        // constants
645        const EXPRESSION = 0;
646        const REPLACEMENT = 1;
647        const LENGTH = 2;
648
649        // used to determine nesting levels
650        private $GROUPS = '/\\(/';//g
651        private $SUB_REPLACE = '/\\$\\d/';
652        private $INDEXED = '/^\\$\\d+$/';
653        private $TRIM = '/([\'"])\\1\\.(.*)\\.\\1\\1$/';
654        private $ESCAPE = '/\\\./';//g
655        private $QUOTE = '/\'/';
656        private $DELETED = '/\\x01[^\\x01]*\\x01/';//g
657
658        public function add($expression, $replacement = '') {
659                // count the number of sub-expressions
660                //  - add one because each pattern is itself a sub-expression
661                $length = 1 + preg_match_all($this->GROUPS, $this->_internalEscape((string)$expression), $out);
662
663                // treat only strings $replacement
664                if (is_string($replacement)) {
665                        // does the pattern deal with sub-expressions?
666                        if (preg_match($this->SUB_REPLACE, $replacement)) {
667                                // a simple lookup? (e.g. "$2")
668                                if (preg_match($this->INDEXED, $replacement)) {
669                                        // store the index (used for fast retrieval of matched strings)
670                                        $replacement = (int)(substr($replacement, 1)) - 1;
671                                } else { // a complicated lookup (e.g. "Hello $2 $1")
672                                        // build a function to do the lookup
673                                        $quote = preg_match($this->QUOTE, $this->_internalEscape($replacement))
674                                                 ? '"' : "'";
675                                        $replacement = array(
676                                                'fn' => '_backReferences',
677                                                'data' => array(
678                                                        'replacement' => $replacement,
679                                                        'length' => $length,
680                                                        'quote' => $quote
681                                                )
682                                        );
683                                }
684                        }
685                }
686                // pass the modified arguments
687                if (!empty($expression)) $this->_add($expression, $replacement, $length);
688                else $this->_add('/^$/', $replacement, $length);
689        }
690
691        public function exec($string) {
692                // execute the global replacement
693                $this->_escaped = array();
694
695                // simulate the _patterns.toSTring of Dean
696                $regexp = '/';
697                foreach ($this->_patterns as $reg) {
698                        $regexp .= '(' . substr($reg[self::EXPRESSION], 1, -1) . ')|';
699                }
700                $regexp = substr($regexp, 0, -1) . '/';
701                $regexp .= ($this->ignoreCase) ? 'i' : '';
702
703                $string = $this->_escape($string, $this->escapeChar);
704                $string = preg_replace_callback(
705                        $regexp,
706                        array(
707                                &$this,
708                                '_replacement'
709                        ),
710                        $string
711                );
712                $string = $this->_unescape($string, $this->escapeChar);
713
714                return preg_replace($this->DELETED, '', $string);
715        }
716
717        public function reset() {
718                // clear the patterns collection so that this object may be re-used
719                $this->_patterns = array();
720        }
721
722        // private
723        private $_escaped = array();  // escaped characters
724        private $_patterns = array(); // patterns stored by index
725
726        // create and add a new pattern to the patterns collection
727        private function _add() {
728                $arguments = func_get_args();
729                $this->_patterns[] = $arguments;
730        }
731
732        // this is the global replace function (it's quite complicated)
733        private function _replacement($arguments) {
734                if (empty($arguments)) return '';
735
736                $i = 1; $j = 0;
737                // loop through the patterns
738                while (isset($this->_patterns[$j])) {
739                        $pattern = $this->_patterns[$j++];
740                        // do we have a result?
741                        if (isset($arguments[$i]) && ($arguments[$i] != '')) {
742                                $replacement = $pattern[self::REPLACEMENT];
743
744                                if (is_array($replacement) && isset($replacement['fn'])) {
745
746                                        if (isset($replacement['data'])) $this->buffer = $replacement['data'];
747                                        return call_user_func(array(&$this, $replacement['fn']), $arguments, $i);
748
749                                } elseif (is_int($replacement)) {
750                                        return $arguments[$replacement + $i];
751
752                                }
753                                $delete = ($this->escapeChar == '' ||
754                                           strpos($arguments[$i], $this->escapeChar) === false)
755                                        ? '' : "\x01" . $arguments[$i] . "\x01";
756                                return $delete . $replacement;
757
758                        // skip over references to sub-expressions
759                        } else {
760                                $i += $pattern[self::LENGTH];
761                        }
762                }
763        }
764
765        private function _backReferences($match, $offset) {
766                $replacement = $this->buffer['replacement'];
767                $quote = $this->buffer['quote'];
768                $i = $this->buffer['length'];
769                while ($i) {
770                        $replacement = str_replace('$'.$i--, $match[$offset + $i], $replacement);
771                }
772                return $replacement;
773        }
774
775        private function _replace_name($match, $offset){
776                $length = strlen($match[$offset + 2]);
777                $start = $length - max($length - strlen($match[$offset + 3]), 0);
778                return substr($match[$offset + 1], $start, $length) . $match[$offset + 4];
779        }
780
781        private function _replace_encoded($match, $offset) {
782                return $this->buffer[$match[$offset]];
783        }
784
785
786        // php : we cannot pass additional data to preg_replace_callback,
787        // and we cannot use &$this in create_function, so let's go to lower level
788        private $buffer;
789
790        // encode escaped characters
791        private function _escape($string, $escapeChar) {
792                if ($escapeChar) {
793                        $this->buffer = $escapeChar;
794                        return preg_replace_callback(
795                                '/\\' . $escapeChar . '(.)' .'/',
796                                array(&$this, '_escapeBis'),
797                                $string
798                        );
799
800                } else {
801                        return $string;
802                }
803        }
804        private function _escapeBis($match) {
805                $this->_escaped[] = $match[1];
806                return $this->buffer;
807        }
808
809        // decode escaped characters
810        private function _unescape($string, $escapeChar) {
811                if ($escapeChar) {
812                        $regexp = '/'.'\\'.$escapeChar.'/';
813                        $this->buffer = array('escapeChar'=> $escapeChar, 'i' => 0);
814                        return preg_replace_callback
815                        (
816                                $regexp,
817                                array(&$this, '_unescapeBis'),
818                                $string
819                        );
820
821                } else {
822                        return $string;
823                }
824        }
825        private function _unescapeBis() {
826                if (!empty($this->_escaped[$this->buffer['i']])) {
827                         $temp = $this->_escaped[$this->buffer['i']];
828                } else {
829                        $temp = '';
830                }
831                $this->buffer['i']++;
832                return $this->buffer['escapeChar'] . $temp;
833        }
834
835        private function _internalEscape($string) {
836                return preg_replace($this->ESCAPE, '', $string);
837        }
838}
839
840$request_method = '_' . $_SERVER['REQUEST_METHOD'];
841switch ( $request_method )
842{
843        case '_GET' :
844                $params = $_GET;
845        break;
846        case '_POST' :
847                $params = $_POST;
848        break;
849        case '_HEAD' :
850        case '_PUT' :
851        default :
852                echo "controller - request method not avaible";
853                return false;
854}
855$controller = new Controller;
856$controller->exec($$request_method);
857
858exit(0);
859?>
Note: See TracBrowser for help on using the repository browser.