[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * @package phpBB3 5 * @version $Id$ 6 * @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 * 9 */ 10 11 /** 12 * @ignore 13 */ 14 if (!defined('IN_PHPBB')) 15 { 16 exit; 17 } 18 19 /** 20 * Extension of template class - Functions needed for compiling templates only. 21 * 22 * psoTFX, phpBB Development Team - Completion of file caching, decompilation 23 * routines and implementation of conditionals/keywords and associated changes 24 * 25 * The interface was inspired by PHPLib templates, and the template file (formats are 26 * quite similar) 27 * 28 * The keyword/conditional implementation is currently based on sections of code from 29 * the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released 30 * (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code 31 * derived from an LGPL application may be relicenced under the GPL, this applies 32 * to this source 33 * 34 * DEFINE directive inspired by a request by Cyberalien 35 * 36 * @package phpBB3 37 */ 38 class template_compile 39 { 40 var $template; 41 42 // Various storage arrays 43 var $block_names = array(); 44 var $block_else_level = array(); 45 46 /** 47 * constuctor 48 */ 49 function template_compile(&$template) 50 { 51 $this->template = &$template; 52 } 53 54 /** 55 * Load template source from file 56 * @access private 57 */ 58 function _tpl_load_file($handle, $store_in_db = false) 59 { 60 // Try and open template for read 61 if (!file_exists($this->template->files[$handle])) 62 { 63 trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR); 64 } 65 66 $this->template->compiled_code[$handle] = $this->compile(trim(@file_get_contents($this->template->files[$handle]))); 67 68 // Actually compile the code now. 69 $this->compile_write($handle, $this->template->compiled_code[$handle]); 70 71 // Store in database if required... 72 if ($store_in_db) 73 { 74 global $db, $user; 75 76 $sql_ary = array( 77 'template_id' => $this->template->files_template[$handle], 78 'template_filename' => $this->template->filename[$handle], 79 'template_included' => '', 80 'template_mtime' => time(), 81 'template_data' => trim(@file_get_contents($this->template->files[$handle])), 82 ); 83 84 $sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); 85 $db->sql_query($sql); 86 } 87 } 88 89 /** 90 * Remove any PHP tags that do not belong, these regular expressions are derived from 91 * the ones that exist in zend_language_scanner.l 92 * @access private 93 */ 94 function remove_php_tags(&$code) 95 { 96 // This matches the information gathered from the internal PHP lexer 97 $match = array( 98 '#<([\?%])=?.*?\1>#s', 99 '#<script\s+language\s*=\s*(["\']?)php\1\s*>.*?</script\s*>#s', 100 '#<\?php(?:\r\n?|[ \n\t]).*?\?>#s' 101 ); 102 103 $code = preg_replace($match, '', $code); 104 } 105 106 /** 107 * The all seeing all doing compile method. Parts are inspired by or directly from Smarty 108 * @access private 109 */ 110 function compile($code, $no_echo = false, $echo_var = '') 111 { 112 global $config; 113 114 if ($echo_var) 115 { 116 global $$echo_var; 117 } 118 119 // Remove any "loose" php ... we want to give admins the ability 120 // to switch on/off PHP for a given template. Allowing unchecked 121 // php is a no-no. There is a potential issue here in that non-php 122 // content may be removed ... however designers should use entities 123 // if they wish to display < and > 124 $this->remove_php_tags($code); 125 126 // Pull out all block/statement level elements and separate plain text 127 preg_match_all('#<!-- PHP -->(.*?)<!-- ENDPHP -->#s', $code, $matches); 128 $php_blocks = $matches[1]; 129 $code = preg_replace('#<!-- PHP -->.*?<!-- ENDPHP -->#s', '<!-- PHP -->', $code); 130 131 preg_match_all('#<!-- INCLUDE (\{\$?[A-Z0-9\-_]+\}|[a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches); 132 $include_blocks = $matches[1]; 133 $code = preg_replace('#<!-- INCLUDE (?:\{\$?[A-Z0-9\-_]+\}|[a-zA-Z0-9\_\-\+\./]+) -->#', '<!-- INCLUDE -->', $code); 134 135 preg_match_all('#<!-- INCLUDEPHP ([a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches); 136 $includephp_blocks = $matches[1]; 137 $code = preg_replace('#<!-- INCLUDEPHP [a-zA-Z0-9\_\-\+\./]+ -->#', '<!-- INCLUDEPHP -->', $code); 138 139 preg_match_all('#<!-- ([^<].*?) (.*?)? ?-->#', $code, $blocks, PREG_SET_ORDER); 140 141 $text_blocks = preg_split('#<!-- [^<].*? (?:.*?)? ?-->#', $code); 142 143 for ($i = 0, $j = sizeof($text_blocks); $i < $j; $i++) 144 { 145 $this->compile_var_tags($text_blocks[$i]); 146 } 147 $compile_blocks = array(); 148 149 for ($curr_tb = 0, $tb_size = sizeof($blocks); $curr_tb < $tb_size; $curr_tb++) 150 { 151 $block_val = &$blocks[$curr_tb]; 152 153 switch ($block_val[1]) 154 { 155 case 'BEGIN': 156 $this->block_else_level[] = false; 157 $compile_blocks[] = '<?php ' . $this->compile_tag_block($block_val[2]) . ' ?>'; 158 break; 159 160 case 'BEGINELSE': 161 $this->block_else_level[sizeof($this->block_else_level) - 1] = true; 162 $compile_blocks[] = '<?php }} else { ?>'; 163 break; 164 165 case 'END': 166 array_pop($this->block_names); 167 $compile_blocks[] = '<?php ' . ((array_pop($this->block_else_level)) ? '}' : '}}') . ' ?>'; 168 break; 169 170 case 'IF': 171 $compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], false) . ' ?>'; 172 break; 173 174 case 'ELSE': 175 $compile_blocks[] = '<?php } else { ?>'; 176 break; 177 178 case 'ELSEIF': 179 $compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], true) . ' ?>'; 180 break; 181 182 case 'ENDIF': 183 $compile_blocks[] = '<?php } ?>'; 184 break; 185 186 case 'DEFINE': 187 $compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], true) . ' ?>'; 188 break; 189 190 case 'UNDEFINE': 191 $compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], false) . ' ?>'; 192 break; 193 194 case 'INCLUDE': 195 $temp = array_shift($include_blocks); 196 197 // Dynamic includes 198 // Cheap match rather than a full blown regexp, we already know 199 // the format of the input so just use string manipulation. 200 if ($temp[0] == '{') 201 { 202 $file = false; 203 204 if ($temp[1] == '$') 205 { 206 $var = substr($temp, 2, -1); 207 //$file = $this->template->_tpldata['DEFINE']['.'][$var]; 208 $temp = "\$this->_tpldata['DEFINE']['.']['$var']"; 209 } 210 else 211 { 212 $var = substr($temp, 1, -1); 213 //$file = $this->template->_rootref[$var]; 214 $temp = "\$this->_rootref['$var']"; 215 } 216 } 217 else 218 { 219 $file = $temp; 220 } 221 222 $compile_blocks[] = '<?php ' . $this->compile_tag_include($temp) . ' ?>'; 223 224 // No point in checking variable includes 225 if ($file) 226 { 227 $this->template->_tpl_include($file, false); 228 } 229 break; 230 231 case 'INCLUDEPHP': 232 $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . $this->compile_tag_include_php(array_shift($includephp_blocks)) . ' ?>' : ''; 233 break; 234 235 case 'PHP': 236 $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . array_shift($php_blocks) . ' ?>' : ''; 237 break; 238 239 default: 240 $this->compile_var_tags($block_val[0]); 241 $trim_check = trim($block_val[0]); 242 $compile_blocks[] = (!$no_echo) ? ((!empty($trim_check)) ? $block_val[0] : '') : ((!empty($trim_check)) ? $block_val[0] : ''); 243 break; 244 } 245 } 246 247 $template_php = ''; 248 for ($i = 0, $size = sizeof($text_blocks); $i < $size; $i++) 249 { 250 $trim_check_text = trim($text_blocks[$i]); 251 $template_php .= (!$no_echo) ? (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '') : (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : ''); 252 } 253 254 // Remove unused opening/closing tags 255 $template_php = str_replace(' ?><?php ', ' ', $template_php); 256 257 // Now add a newline after each php closing tag which already has a newline 258 // PHP itself strips a newline if a closing tag is used (this is documented behaviour) and it is mostly not intended by style authors to remove newlines 259 $template_php = preg_replace('#\?\>([\r\n])#', '?>\1\1', $template_php); 260 261 // There will be a number of occasions where we switch into and out of 262 // PHP mode instantaneously. Rather than "burden" the parser with this 263 // we'll strip out such occurences, minimising such switching 264 if ($no_echo) 265 { 266 return "\$$echo_var .= '" . $template_php . "'"; 267 } 268 269 return $template_php; 270 } 271 272 /** 273 * Compile variables 274 * @access private 275 */ 276 function compile_var_tags(&$text_blocks) 277 { 278 // change template varrefs into PHP varrefs 279 $varrefs = array(); 280 281 // This one will handle varrefs WITH namespaces 282 preg_match_all('#\{((?:[a-z0-9\-_]+\.)+)(\$)?([A-Z0-9\-_]+)\}#', $text_blocks, $varrefs, PREG_SET_ORDER); 283 284 foreach ($varrefs as $var_val) 285 { 286 $namespace = $var_val[1]; 287 $varname = $var_val[3]; 288 $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); 289 290 $text_blocks = str_replace($var_val[0], $new, $text_blocks); 291 } 292 293 // This will handle the remaining root-level varrefs 294 // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array 295 if (strpos($text_blocks, '{L_') !== false) 296 { 297 $text_blocks = preg_replace('#\{L_([A-Z0-9\-_]+)\}#', "<?php echo ((isset(\$this->_rootref['L_\\1'])) ? \$this->_rootref['L_\\1'] : ((isset(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '{ \\1 }')); ?>", $text_blocks); 298 } 299 300 // Handle addslashed language variables prefixed with LA_ 301 // If a template variable already exist, it will be used in favor of it... 302 if (strpos($text_blocks, '{LA_') !== false) 303 { 304 $text_blocks = preg_replace('#\{LA_([A-Z0-9\-_]+)\}#', "<?php echo ((isset(\$this->_rootref['LA_\\1'])) ? \$this->_rootref['LA_\\1'] : ((isset(\$this->_rootref['L_\\1'])) ? addslashes(\$this->_rootref['L_\\1']) : ((isset(\$user->lang['\\1'])) ? addslashes(\$user->lang['\\1']) : '{ \\1 }'))); ?>", $text_blocks); 305 } 306 307 // Handle remaining varrefs 308 $text_blocks = preg_replace('#\{([A-Z0-9\-_]+)\}#', "<?php echo (isset(\$this->_rootref['\\1'])) ? \$this->_rootref['\\1'] : ''; ?>", $text_blocks); 309 $text_blocks = preg_replace('#\{\$([A-Z0-9\-_]+)\}#', "<?php echo (isset(\$this->_tpldata['DEFINE']['.']['\\1'])) ? \$this->_tpldata['DEFINE']['.']['\\1'] : ''; ?>", $text_blocks); 310 311 return; 312 } 313 314 /** 315 * Compile blocks 316 * @access private 317 */ 318 function compile_tag_block($tag_args) 319 { 320 $no_nesting = false; 321 322 // Is the designer wanting to call another loop in a loop? 323 if (strpos($tag_args, '!') === 0) 324 { 325 // Count the number of ! occurrences (not allowed in vars) 326 $no_nesting = substr_count($tag_args, '!'); 327 $tag_args = substr($tag_args, $no_nesting); 328 } 329 330 // Allow for control of looping (indexes start from zero): 331 // foo(2) : Will start the loop on the 3rd entry 332 // foo(-2) : Will start the loop two entries from the end 333 // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth 334 // foo(3,-4) : Will start the loop on the fourth entry and end it four from last 335 if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) 336 { 337 $tag_args = $match[1]; 338 339 if ($match[2] < 0) 340 { 341 $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; 342 } 343 else 344 { 345 $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; 346 } 347 348 if (strlen($match[3]) < 1 || $match[3] == -1) 349 { 350 $loop_end = '$_' . $tag_args . '_count'; 351 } 352 else if ($match[3] >= 0) 353 { 354 $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; 355 } 356 else //if ($match[3] < -1) 357 { 358 $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); 359 } 360 } 361 else 362 { 363 $loop_start = 0; 364 $loop_end = '$_' . $tag_args . '_count'; 365 } 366 367 $tag_template_php = ''; 368 array_push($this->block_names, $tag_args); 369 370 if ($no_nesting !== false) 371 { 372 // We need to implode $no_nesting times from the end... 373 $block = array_slice($this->block_names, -$no_nesting); 374 } 375 else 376 { 377 $block = $this->block_names; 378 } 379 380 if (sizeof($block) < 2) 381 { 382 // Block is not nested. 383 $tag_template_php = '$_' . $tag_args . "_count = (isset(\$this->_tpldata['$tag_args'])) ? sizeof(\$this->_tpldata['$tag_args']) : 0;"; 384 $varref = "\$this->_tpldata['$tag_args']"; 385 } 386 else 387 { 388 // This block is nested. 389 // Generate a namespace string for this block. 390 $namespace = implode('.', $block); 391 392 // Get a reference to the data array for this block that depends on the 393 // current indices of all parent blocks. 394 $varref = $this->generate_block_data_ref($namespace, false); 395 396 // Create the for loop code to iterate over this block. 397 $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; 398 } 399 400 $tag_template_php .= 'if ($_' . $tag_args . '_count) {'; 401 402 /** 403 * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory 404 * <code> 405 * if (!$offset) 406 * { 407 * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){'; 408 * } 409 * </code> 410 */ 411 412 $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; 413 $tag_template_php .= '$_'. $tag_args . '_val = &' . $varref . '[$_'. $tag_args. '_i];'; 414 415 return $tag_template_php; 416 } 417 418 /** 419 * Compile IF tags - much of this is from Smarty with 420 * some adaptions for our block level methods 421 * @access private 422 */ 423 function compile_tag_if($tag_args, $elseif) 424 { 425 // Tokenize args for 'if' tag. 426 preg_match_all('/(?: 427 "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | 428 \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | 429 [(),] | 430 [^\s(),]+)/x', $tag_args, $match); 431 432 $tokens = $match[0]; 433 $is_arg_stack = array(); 434 435 for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) 436 { 437 $token = &$tokens[$i]; 438 439 switch ($token) 440 { 441 case '!==': 442 case '===': 443 case '<<': 444 case '>>': 445 case '|': 446 case '^': 447 case '&': 448 case '~': 449 case ')': 450 case ',': 451 case '+': 452 case '-': 453 case '*': 454 case '/': 455 case '@': 456 break; 457 458 case '==': 459 case 'eq': 460 $token = '=='; 461 break; 462 463 case '!=': 464 case '<>': 465 case 'ne': 466 case 'neq': 467 $token = '!='; 468 break; 469 470 case '<': 471 case 'lt': 472 $token = '<'; 473 break; 474 475 case '<=': 476 case 'le': 477 case 'lte': 478 $token = '<='; 479 break; 480 481 case '>': 482 case 'gt': 483 $token = '>'; 484 break; 485 486 case '>=': 487 case 'ge': 488 case 'gte': 489 $token = '>='; 490 break; 491 492 case '&&': 493 case 'and': 494 $token = '&&'; 495 break; 496 497 case '||': 498 case 'or': 499 $token = '||'; 500 break; 501 502 case '!': 503 case 'not': 504 $token = '!'; 505 break; 506 507 case '%': 508 case 'mod': 509 $token = '%'; 510 break; 511 512 case '(': 513 array_push($is_arg_stack, $i); 514 break; 515 516 case 'is': 517 $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; 518 $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); 519 520 $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); 521 522 array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); 523 524 $i = $is_arg_start; 525 526 // no break 527 528 default: 529 if (preg_match('#^((?:[a-z0-9\-_]+\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) 530 { 531 $token = (!empty($varrefs[1])) ? $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']' : (($varrefs[2]) ? '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$this->_rootref[\'' . $varrefs[3] . '\']'); 532 } 533 else if (preg_match('#^\.((?:[a-z0-9\-_]+\.?)+)$#s', $token, $varrefs)) 534 { 535 // Allow checking if loops are set with .loopname 536 // It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example 537 $blocks = explode('.', $varrefs[1]); 538 539 // If the block is nested, we have a reference that we can grab. 540 // If the block is not nested, we just go and grab the block from _tpldata 541 if (sizeof($blocks) > 1) 542 { 543 $block = array_pop($blocks); 544 $namespace = implode('.', $blocks); 545 $varref = $this->generate_block_data_ref($namespace, true); 546 547 // Add the block reference for the last child. 548 $varref .= "['" . $block . "']"; 549 } 550 else 551 { 552 $varref = '$this->_tpldata'; 553 554 // Add the block reference for the last child. 555 $varref .= "['" . $blocks[0] . "']"; 556 } 557 $token = "sizeof($varref)"; 558 } 559 else if (!empty($token)) 560 { 561 $token = '(' . $token . ')'; 562 } 563 564 break; 565 } 566 } 567 568 // If there are no valid tokens left or only control/compare characters left, we do skip this statement 569 if (!sizeof($tokens) || str_replace(array(' ', '=', '!', '<', '>', '&', '|', '%', '(', ')'), '', implode('', $tokens)) == '') 570 { 571 $tokens = array('false'); 572 } 573 return (($elseif) ? '} else if (' : 'if (') . (implode(' ', $tokens) . ') { '); 574 } 575 576 /** 577 * Compile DEFINE tags 578 * @access private 579 */ 580 function compile_tag_define($tag_args, $op) 581 { 582 preg_match('#^((?:[a-z0-9\-_]+\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (\'?)([^\']*)(\'?))?$#', $tag_args, $match); 583 584 if (empty($match[2]) || (!isset($match[4]) && $op)) 585 { 586 return ''; 587 } 588 589 if (!$op) 590 { 591 return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; 592 } 593 594 // Are we a string? 595 if ($match[3] && $match[5]) 596 { 597 $match[4] = str_replace(array('\\\'', '\\\\', '\''), array('\'', '\\', '\\\''), $match[4]); 598 599 // Compile reference, we allow template variables in defines... 600 $match[4] = $this->compile($match[4]); 601 602 // Now replace the php code 603 $match[4] = "'" . str_replace(array('<?php echo ', '; ?>'), array("' . ", " . '"), $match[4]) . "'"; 604 } 605 else 606 { 607 preg_match('#true|false|\.#i', $match[4], $type); 608 609 switch (strtolower($type[0])) 610 { 611 case 'true': 612 case 'false': 613 $match[4] = strtoupper($match[4]); 614 break; 615 616 case '.': 617 $match[4] = doubleval($match[4]); 618 break; 619 620 default: 621 $match[4] = intval($match[4]); 622 break; 623 } 624 } 625 626 return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $match[4] . ';'; 627 } 628 629 /** 630 * Compile INCLUDE tag 631 * @access private 632 */ 633 function compile_tag_include($tag_args) 634 { 635 // Process dynamic includes 636 if ($tag_args[0] == '$') 637 { 638 return "if (isset($tag_args)) { \$this->_tpl_include($tag_args); }"; 639 } 640 641 return "\$this->_tpl_include('$tag_args');"; 642 } 643 644 /** 645 * Compile INCLUDE_PHP tag 646 * @access private 647 */ 648 function compile_tag_include_php($tag_args) 649 { 650 return "\$this->_php_include('$tag_args');"; 651 } 652 653 /** 654 * parse expression 655 * This is from Smarty 656 * @access private 657 */ 658 function _parse_is_expr($is_arg, $tokens) 659 { 660 $expr_end = 0; 661 $negate_expr = false; 662 663 if (($first_token = array_shift($tokens)) == 'not') 664 { 665 $negate_expr = true; 666 $expr_type = array_shift($tokens); 667 } 668 else 669 { 670 $expr_type = $first_token; 671 } 672 673 switch ($expr_type) 674 { 675 case 'even': 676 if (@$tokens[$expr_end] == 'by') 677 { 678 $expr_end++; 679 $expr_arg = $tokens[$expr_end++]; 680 $expr = "!(($is_arg / $expr_arg) % $expr_arg)"; 681 } 682 else 683 { 684 $expr = "!($is_arg & 1)"; 685 } 686 break; 687 688 case 'odd': 689 if (@$tokens[$expr_end] == 'by') 690 { 691 $expr_end++; 692 $expr_arg = $tokens[$expr_end++]; 693 $expr = "(($is_arg / $expr_arg) % $expr_arg)"; 694 } 695 else 696 { 697 $expr = "($is_arg & 1)"; 698 } 699 break; 700 701 case 'div': 702 if (@$tokens[$expr_end] == 'by') 703 { 704 $expr_end++; 705 $expr_arg = $tokens[$expr_end++]; 706 $expr = "!($is_arg % $expr_arg)"; 707 } 708 break; 709 } 710 711 if ($negate_expr) 712 { 713 $expr = "!($expr)"; 714 } 715 716 array_splice($tokens, 0, $expr_end, $expr); 717 718 return $tokens; 719 } 720 721 /** 722 * Generates a reference to the given variable inside the given (possibly nested) 723 * block namespace. This is a string of the form: 724 * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' 725 * It's ready to be inserted into an "echo" line in one of the templates. 726 * NOTE: expects a trailing "." on the namespace. 727 * @access private 728 */ 729 function generate_block_varref($namespace, $varname, $echo = true, $defop = false) 730 { 731 // Strip the trailing period. 732 $namespace = substr($namespace, 0, -1); 733 734 // Get a reference to the data block for this namespace. 735 $varref = $this->generate_block_data_ref($namespace, true, $defop); 736 // Prepend the necessary code to stick this in an echo line. 737 738 // Append the variable reference. 739 $varref .= "['$varname']"; 740 $varref = ($echo) ? "<?php echo $varref; ?>" : ((isset($varref)) ? $varref : ''); 741 742 return $varref; 743 } 744 745 /** 746 * Generates a reference to the array of data values for the given 747 * (possibly nested) block namespace. This is a string of the form: 748 * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] 749 * 750 * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. 751 * NOTE: does not expect a trailing "." on the blockname. 752 * @access private 753 */ 754 function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) 755 { 756 // Get an array of the blocks involved. 757 $blocks = explode('.', $blockname); 758 $blockcount = sizeof($blocks) - 1; 759 760 // DEFINE is not an element of any referenced variable, we must use _tpldata to access it 761 if ($defop) 762 { 763 $varref = '$this->_tpldata[\'DEFINE\']'; 764 // Build up the string with everything but the last child. 765 for ($i = 0; $i < $blockcount; $i++) 766 { 767 $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; 768 } 769 // Add the block reference for the last child. 770 $varref .= "['" . $blocks[$blockcount] . "']"; 771 // Add the iterator for the last child if requried. 772 if ($include_last_iterator) 773 { 774 $varref .= '[$_' . $blocks[$blockcount] . '_i]'; 775 } 776 return $varref; 777 } 778 else if ($include_last_iterator) 779 { 780 return '$_'. $blocks[$blockcount] . '_val'; 781 } 782 else 783 { 784 return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; 785 } 786 } 787 788 /** 789 * Write compiled file to cache directory 790 * @access private 791 */ 792 function compile_write($handle, $data) 793 { 794 global $phpEx; 795 796 $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx; 797 798 $data = "<?php if (!defined('IN_PHPBB')) exit;" . ((strpos($data, '<?php') === 0) ? substr($data, 5) : ' ?>' . $data); 799 800 if ($fp = @fopen($filename, 'wb')) 801 { 802 @flock($fp, LOCK_EX); 803 @fwrite ($fp, $data); 804 @flock($fp, LOCK_UN); 805 @fclose($fp); 806 807 phpbb_chmod($filename, CHMOD_READ | CHMOD_WRITE); 808 } 809 810 return; 811 } 812 } 813 814 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Oct 2 15:03:47 2013 | Cross-referenced by PHPXref 0.7.1 |