[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 3 /** 4 * 5 * Basic compiler for Savant2. 6 * 7 * This is a simple compiler provided as an example. It probably won't 8 * work with streams, but it does limit the template syntax in a 9 * relatively strict way. It's not perfect, but it's OK for many 10 * purposes. Basically, the compiler converts specialized instances of 11 * curly braces into PHP commands or Savant2 method calls. It will 12 * probably mess up embedded JavaScript unless you change the prefix 13 * and suffix to something else (e.g., '<!-- ' and ' -->', but then it 14 * will mess up your HTML comments ;-). 15 * 16 * When in "restrict" mode, ise of PHP commands not in the whitelists 17 * will cause the compiler to * fail. Use of various constructs and 18 * superglobals, likewise. 19 * 20 * Use {$var} or {$this->var} to print a variable. 21 * 22 * Use {: function-list} to print the results of function calls. 23 * 24 * Use {['pluginName', 'arg1', $arg2, $this->arg3]} to call plugins. 25 * 26 * Use these for looping: 27 * {foreach ():} ... {endforeach} 28 * {for ():} ... {endfor} 29 * {while ():} ... {endwhile} 30 * 31 * Use these for conditionals (normal PHP can go in the parens): 32 * {if (...):} 33 * {elseif (...):} 34 * {else:} 35 * {endif} 36 * {switch (...):} 37 * {case ...:} 38 * {default:} 39 * {endswitch} 40 * 41 * {break} and {continue} are supported as well. 42 * 43 * Use this to include a template: 44 * {tpl 'template.tpl.php'} 45 * {tpl $tplname} 46 * {tpl $this->tplname} 47 * 48 * $Id: Savant2_Compiler_basic.php 18360 2005-05-26 19:38:09Z mipmip $ 49 * 50 * @author Paul M. Jones <pmjones@ciaweb.net> 51 * 52 * @package Savant2 53 * 54 * @license http://www.gnu.org/copyleft/lesser.html LGPL 55 * 56 * This program is free software; you can redistribute it and/or modify 57 * it under the terms of the GNU Lesser General Public License as 58 * published by the Free Software Foundation; either version 2.1 of the 59 * License, or (at your option) any later version. 60 * 61 * This program is distributed in the hope that it will be useful, but 62 * WITHOUT ANY WARRANTY; without even the implied warranty of 63 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 64 * Lesser General Public License for more details. 65 * 66 */ 67 68 require_once 'Savant2/Compiler.php'; 69 require_once 'Savant2/Error.php'; 70 require_once 'Savant2/PHPCodeAnalyzer.php'; 71 72 class Savant2_Compiler_basic extends Savant2_Compiler { 73 74 75 /** 76 * 77 * The template directive prefix. 78 * 79 * @access public 80 * 81 * @var array 82 * 83 */ 84 85 var $prefix = '{'; 86 87 88 /** 89 * 90 * The template directive suffix. 91 * 92 * @access public 93 * 94 * @var array 95 * 96 */ 97 98 var $suffix = '}'; 99 100 101 /** 102 * 103 * The conversion regular expressions. 104 * 105 * @access public 106 * 107 * @var array 108 * 109 */ 110 111 var $convert = array( 112 113 // branching 114 '(if\s*(.+):)' => '$1', 115 '(elseif\s*(.+):)' => '$1', 116 '(else\s*(.+):)' => '$1', 117 '(endif)' => '$1', 118 '(switch\s*(.+):)' => '$1', 119 '(case\s*(.+):)' => '$1', 120 '(default:)' => '$1', 121 '(endswitch)' => '$1', 122 '(break)' => '$1', 123 124 // looping 125 '(foreach\s*(.+):)' => '$1', 126 '(endforeach)' => '$1', 127 '(for\s*(.+):)' => '$1', 128 '(endfor)' => '$1', 129 '(while\s*(.+):)' => '$1', 130 '(endwhile)' => '$1', 131 '(continue)' => '$1', 132 133 // simple variable printing 134 '(\$(.+))' => 'print $1', 135 136 // extended printing 137 '(\:(.+))' => 'print ($2)', 138 139 // comments 140 '\*(.*)?\*' => '/**$1*/', 141 142 // template includes 143 'tpl (.*)' => 'include $this->findTemplate($1)', 144 145 // plugins 146 '\[\s*(.+)?\s*\]' => '$this->plugin($1)', 147 ); 148 149 150 /** 151 * 152 * The list of allowed functions when in restricted mode. 153 * 154 * @access public 155 * 156 * @var array 157 * 158 */ 159 160 var $allowedFunctions = array(); 161 162 163 /** 164 * 165 * The list of allowed static methods when in restricted mode. 166 * 167 * @access public 168 * 169 * @var array 170 * 171 */ 172 173 var $allowedStatic = array(); 174 175 176 /** 177 * 178 * The directory where compiled templates are saved. 179 * 180 * @access public 181 * 182 * @var string 183 * 184 */ 185 186 var $compileDir = null; 187 188 189 /** 190 * 191 * Whether or not to force every template to be compiled every time. 192 * 193 * @access public 194 * 195 * @var bool 196 * 197 */ 198 199 var $forceCompile = false; 200 201 202 203 /** 204 * 205 * Whether or not to strict-check the compiled template. 206 * 207 * Strict-checks are off by default until all problems with 208 * PhpCodeAnalyzer have been resolved. 209 * 210 * @access public 211 * 212 * @var bool 213 * 214 */ 215 216 var $strict = false; 217 218 219 /** 220 * 221 * Constructor. 222 * 223 */ 224 225 function Savant2_Compiler_basic($conf = array()) 226 { 227 parent::Savant2_Compiler($conf); 228 $this->ca =& new PHPCodeAnalyzer(); 229 $this->allowedFunctions = $this->allowedFunctions(); 230 $this->allowedStatic = $this->allowedStatic(); 231 } 232 233 234 /** 235 * 236 * Has the source template changed since it was last compiled? 237 * 238 * @access public 239 * 240 * @var string $tpl The source template file. 241 * 242 */ 243 244 function changed($tpl) 245 { 246 // the path for the compiled file 247 $file = $this->getPath($tpl); 248 249 // if the copmiled file does not exist, or if the mod-time of 250 // the source is later than that of the existing compiled file, 251 // then the source template file has changed. 252 if (! file_exists($file) || 253 filemtime($tpl) > filemtime($file)) { 254 return true; 255 } else { 256 return false; 257 } 258 } 259 260 261 /** 262 * 263 * Saves the PHP compiled from template source. 264 * 265 * @access public 266 * 267 * @var string $tpl The source template file. 268 * 269 */ 270 271 function saveCompiled($tpl, $php) 272 { 273 $fp = fopen($this->getPath($tpl), 'w'); 274 if (! $fp) { 275 return false; 276 } else { 277 $result = fwrite($fp, $php); 278 fclose($fp); 279 return $result; 280 } 281 } 282 283 284 /** 285 * 286 * Gets the path to the compiled PHP for a template source. 287 * 288 * @access public 289 * 290 * @var string $tpl The source template file. 291 * 292 */ 293 294 function getPath($tpl) 295 { 296 $dir = $this->compileDir; 297 if (substr($dir, -1) != DIRECTORY_SEPARATOR) { 298 $dir .= DIRECTORY_SEPARATOR; 299 } 300 return $dir . 'Savant2_' . md5($tpl); 301 } 302 303 304 /** 305 * 306 * Compiles a template source into PHP code for Savant. 307 * 308 * @access public 309 * 310 * @var string $tpl The source template file. 311 * 312 */ 313 314 function compile($tpl) 315 { 316 // create a end-tag so that text editors don't 317 // stop colorizing text 318 $end = '?' . '>'; 319 320 // recompile only if we are forcing compiled, or 321 // if the template source has changed. 322 if ($this->forceCompile || $this->changed($tpl)) { 323 324 // get the template source text 325 $php = file_get_contents($tpl); 326 327 /** 328 * @todo Do we really care about PHP tags? The code analyzer 329 * will disallow any offending PHP regardless. 330 */ 331 332 // disallow PHP long tags 333 $php = str_replace('<?php', '<?php', $php); 334 335 // disallow PHP short tags (if turned on) 336 if (ini_get('short_open_tag')) { 337 $php = str_replace('<?', '<?', $php); 338 $php = str_replace('<?=', '<?=', $php); 339 } 340 341 // disallow closing tags 342 $php = str_replace($end, '?>', $php); 343 344 // convert each template command 345 foreach ($this->convert as $find => $replace) { 346 347 // allow whitespace around the command 348 $find = preg_quote($this->prefix) . '\s*' . $find . 349 '\s*' . preg_quote($this->suffix); 350 351 // actually do the find-and-replace 352 $php = preg_replace( 353 "/$find/U", 354 "<?php $replace $end", 355 $php 356 ); 357 358 } 359 360 // +++ DEBUG 361 // $this->saveCompiled($tpl, $php); 362 // --- DEBUG 363 364 // are we doing strict checking? 365 if ($this->strict) { 366 // analyze the code for restriction violations. 367 $report = $this->analyze($php); 368 if (count($report) > 0) { 369 // there were violations, report them as a generic 370 // Savant error and return. Savant will wrap this 371 // generic rror with another error that will report 372 // properly to the customized error handler (if any). 373 return new Savant2_Error( 374 array( 375 'code' => SAVANT2_ERROR_COMPILE_FAIL, 376 'text' => $GLOBALS['_SAVANT2']['error'][SAVANT2_ERROR_COMPILE_FAIL], 377 'info' => $report 378 ) 379 ); 380 } 381 } 382 383 // otherwise, save the compiled template 384 $this->saveCompiled($tpl, $php); 385 } 386 387 // return the path to the compiled PHP script 388 return $this->getPath($tpl); 389 } 390 391 392 /** 393 * 394 * Analyze a compiled template for restriction violations. 395 * 396 * @access public 397 * 398 * @var string $php The compiled PHP code from a template source. 399 * 400 * @return array An array of restriction violations; if empty, then 401 * there were no violations discovered by analysis. 402 * 403 */ 404 405 function analyze(&$php) 406 { 407 // analyze the compiled code 408 $ca =& $this->ca; 409 $ca->source =& $php; 410 $ca->analyze(); 411 412 // array of captured restriction violations 413 $report = array(); 414 415 // ------------------------------------------------------------- 416 // 417 // go through the list of called functions and make sure each 418 // one is allowed via the whitelist. if not, record each non- 419 // allowed function. this also restricts variable-functions 420 // such as $var(). 421 // 422 423 foreach ($ca->calledFunctions as $func => $lines) { 424 if (! in_array($func, $this->allowedFunctions)) { 425 $report[$func] = $lines; 426 } 427 } 428 429 // ------------------------------------------------------------- 430 // 431 // disallow use of various constructs (include is allowed, we 432 // need it for {tpl}). 433 // 434 435 $tmp = array( 436 'eval', 437 'global', 438 'include_once', 439 'require', 440 'require_once', 441 'parent', 442 'self' 443 ); 444 445 foreach ($tmp as $val) { 446 if (isset($ca->calledConstructs[$val])) { 447 $report[$val] = $ca->calledConstructs[$val]; 448 } 449 } 450 451 // ------------------------------------------------------------- 452 // 453 // disallow instantiation of new classes 454 // 455 456 foreach ($ca->classesInstantiated as $key => $val) { 457 $report['new ' . $key] = $val; 458 } 459 460 // ------------------------------------------------------------- 461 // 462 // disallow access to the various superglobals 463 // so that templates cannot manipulate them. 464 // 465 466 $tmp = array( 467 '$_COOKIE', 468 '$_ENV', 469 '$_FILES', 470 '$_GET', 471 '$_POST', 472 '$_REQUEST', 473 '$_SERVER', 474 '$_SESSION', 475 '$GLOBALS', 476 '$HTTP_COOKIE_VARS', 477 '$HTTP_ENV_VARS', 478 '$HTTP_GET_VARS', 479 '$HTTP_POST_FILES', 480 '$HTTP_POST_VARS', 481 '$HTTP_SERVER_VARS', 482 '$HTTP_SESSION_VARS' 483 ); 484 485 foreach ($ca->usedVariables as $var => $lines) { 486 if (in_array(strtoupper($var), $tmp)) { 487 $report[$var] = $lines; 488 } 489 } 490 491 // ------------------------------------------------------------- 492 // 493 // allow only certain $this methods 494 // 495 496 $tmp = array('plugin', 'splugin', 'findTemplate'); 497 if (isset($ca->calledMethods['$this'])) { 498 foreach ($ca->calledMethods['$this'] as $method => $lines) { 499 if (! in_array($method, $tmp)) { 500 $report['$this->' . $method] = $lines; 501 } 502 } 503 } 504 505 // ------------------------------------------------------------- 506 // 507 // disallow private and variable-variable $this properties 508 // 509 510 if (isset($ca->usedMemberVariables['$this'])) { 511 foreach ($ca->usedMemberVariables['$this'] as $prop => $lines) { 512 $char = substr($prop, 0, 1); 513 if ($char == '_' || $char == '$') { 514 $report['$this->' . $prop] = $lines; 515 } 516 } 517 } 518 519 // ------------------------------------------------------------- 520 // 521 // allow only certain static method calls 522 // 523 524 foreach ($ca->calledStaticMethods as $class => $methods) { 525 foreach ($methods as $method => $lines) { 526 if (! array_key_exists($class, $this->allowedStatic)) { 527 528 // the class itself is not allowed 529 $report["$class::$method"] = $lines; 530 531 } elseif (! in_array('*', $this->allowedStatic[$class]) && 532 ! in_array($method, $this->allowedStatic[$class])){ 533 534 // the specific method is not allowed, 535 // and there is no wildcard for the class methods. 536 $report["$class::$method"] = $lines; 537 538 } 539 } 540 } 541 542 // ------------------------------------------------------------- 543 // 544 // only allow includes via $this->findTemplate(*) 545 // 546 547 foreach ($ca->filesIncluded as $text => $lines) { 548 549 // in each include statment, look for $this->findTemplate. 550 preg_match( 551 '/(.*)?\$this->findTemplate\((.*)?\)(.*)/i', 552 $text, 553 $matches 554 ); 555 556 if (! empty($matches[1]) || ! empty($matches[3]) || 557 empty($matches[2])) { 558 559 // there is something before or after the findTemplate call, 560 // or it's a direct include (which is not allowed) 561 $report["include $text"] = $lines; 562 563 } 564 } 565 566 // ------------------------------------------------------------- 567 // 568 // do not allow the use of "$this" by itself; 569 // it must be always be followed by "->" or another 570 // valid variable-name character (a-z, 0-9, or _). 571 // 572 573 $regex = '/(.*)?\$this(?!(\-\>)|([a-z0-9_]))(.*)?/i'; 574 preg_match_all($regex, $php, $matches, PREG_SET_ORDER); 575 foreach ($matches as $val) { 576 $report['\'$this\' without \'->\''][] = $val[0]; 577 } 578 579 /** @todo disallow standalone variable-variables, $$var */ 580 581 /** @todo disallow vars from static classes? class::$var */ 582 583 584 // ------------------------------------------------------------- 585 // 586 // done! 587 // 588 589 // +++ DEBUG 590 //echo "<pre>"; 591 //print_r($ca); 592 //echo "</pre>"; 593 // --- DEBUG 594 595 return $report; 596 } 597 598 599 /** 600 * 601 * A list of allowed static method calls for templates. 602 * 603 * The format is ... 604 * 605 * array( 606 * 'Class1' => array('method1', 'method2'), 607 * 'Class2' => array('methodA', 'methodB'), 608 * 'Class3' => '*' 609 * ); 610 * 611 * If you want to allow all methods from the static class to be allowed, 612 * use a '*' in the method name list. 613 * 614 */ 615 616 function allowedStatic() 617 { 618 return array(); 619 } 620 621 622 /** 623 * 624 * A list of allowed functions for templates. 625 * 626 */ 627 628 function allowedFunctions() 629 { 630 return array( 631 632 // arrays 633 'array_count_values', 634 'array_key_exists', 635 'array_keys', 636 'array_sum', 637 'array_values', 638 'compact', 639 'count', 640 'current', 641 'each', 642 'end', 643 'extract', 644 'in_array', 645 'key', 646 'list', 647 'next', 648 'pos', 649 'prev', 650 'reset', 651 'sizeof', 652 653 // calendar 654 'cal_days_in_month', 655 'cal_from_jd', 656 'cal_to_jd', 657 'easter_date', 658 'easter_days', 659 'FrenchToJD', 660 'GregorianToJD', 661 'JDDayOfWeek', 662 'JDMonthName', 663 'JDToFrench', 664 'JDToGregorian', 665 'jdtojewish', 666 'JDToJulian', 667 'jdtounix', 668 'JewishToJD', 669 'JulianToJD', 670 'unixtojd', 671 672 // date 673 'checkdate', 674 'date_sunrise', 675 'date_sunset', 676 'date', 677 'getdate', 678 'gettimeofday', 679 'gmdate', 680 'gmmktime', 681 'gmstrftime', 682 'idate', 683 'localtime', 684 'microtime', 685 'mktime', 686 'strftime', 687 'strptime', 688 'strtotime', 689 'time', 690 691 // gettext 692 '_', 693 'gettext', 694 'ngettext', 695 696 // math 697 'abs', 698 'acos', 699 'acosh', 700 'asin', 701 'asinh', 702 'atan2', 703 'atan', 704 'atanh', 705 'base_convert', 706 'bindec', 707 'ceil', 708 'cos', 709 'cosh', 710 'decbin', 711 'dechex', 712 'decoct', 713 'deg2rad', 714 'exp', 715 'expm1', 716 'floor', 717 'fmod', 718 'getrandmax', 719 'hexdec', 720 'hypot', 721 'is_finite', 722 'is_infinite', 723 'is_nan', 724 'lcg_value', 725 'log10', 726 'log1p', 727 'log', 728 'max', 729 'min', 730 'mt_getrandmax', 731 'mt_rand', 732 'mt_srand', 733 'octdec', 734 'pi', 735 'pow', 736 'rad2deg', 737 'rand', 738 'round', 739 'sin', 740 'sinh', 741 'sqrt', 742 'srand', 743 'tan', 744 'tanh', 745 746 // strings 747 'chop', 748 'count_chars', 749 'echo', 750 'explode', 751 'hebrev', 752 'hebrevc', 753 'html_entity_decode', 754 'htmlentities', 755 'htmlspecialchars', 756 'implode', 757 'join', 758 'localeconv', 759 'ltrim', 760 'money_format', 761 'nl_langinfo', 762 'nl2br', 763 'number_format', 764 'ord', 765 'print', 766 'printf', 767 'quoted_printable_decode', 768 'rtrim', 769 'sprintf', 770 'sscanf', 771 'str_pad', 772 'str_repeat', 773 'str_replace', 774 'str_rot13', 775 'str_shuffle', 776 'str_word_count', 777 'strcasecmp', 778 'strchr', 779 'strcmp', 780 'strcoll', 781 'strcspn', 782 'strip_tags', 783 'stripcslashes', 784 'stripos', 785 'stripslashes', 786 'stristr', 787 'strlen', 788 'strnatcasecmp', 789 'strnatcmp', 790 'strncasecmp', 791 'strncmp', 792 'strpbrk', 793 'strpos', 794 'strrchr', 795 'strrev', 796 'strripos', 797 'strrpos', 798 'strspn', 799 'strstr', 800 'strtok', 801 'strtolower', 802 'strtoupper', 803 'strtr', 804 'substr_compare', 805 'substr_count', 806 'substr_replace', 807 'substr', 808 'trim', 809 'ucfirst', 810 'ucwords', 811 'wordwrap', 812 813 // url 814 'base64_decode', 815 'base64_encode', 816 'rawurldecode', 817 'rawurlencode', 818 'urldecode', 819 'urlencode', 820 821 // variables 822 'empty', 823 'is_array', 824 'is_bool', 825 'is_double', 826 'is_float', 827 'is_int', 828 'is_integer', 829 'is_long', 830 'is_null', 831 'is_numeric', 832 'is_object', 833 'is_real', 834 'is_resource', 835 'is_scalar', 836 'is_string', 837 'isset', 838 'print_r', 839 'unset', 840 'var_dump', 841 ); 842 } 843 } 844 845 846 847 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |