relocate some files
[phpbb.git] / phpBB / includes / classes / template_compile.php
blob471ca5eca3e6bbaf1ef8a77604d12a2b6ec40853
1 <?php
2 /**
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
9 */
11 /**
12 * @ignore
14 if (!defined('IN_PHPBB'))
16 exit;
19 /**
20 * The template filter that does the actual compilation
21 * @see template_compile
22 * @package phpBB3
25 class template_filter extends php_user_filter
27 /**
28 * @var string Replaceable tokens regex
30 private $regex = '~<!-- ([A-Z][A-Z_0-9]+)(?: (.*?) ?)?-->|{((?:[a-z][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~';
32 /**
33 * @var array
35 private $block_names = array();
37 /**
38 * @var array
40 private $block_else_level = array();
42 /**
43 * @var string
45 private $chunk;
47 public function filter($in, $out, &$consumed, $closing)
49 $written = false;
51 while ($bucket = stream_bucket_make_writeable($in))
53 $consumed += $bucket->datalen;
55 $data = $this->chunk . $bucket->data;
56 $last_nl = strrpos($data, "\n");
57 $this->chunk = substr($data, $last_nl);
58 $data = substr($data, 0, $last_nl);
60 if (!strlen($data))
62 continue;
65 $written = true;
67 $bucket->data = $this->compile($data);
68 $bucket->datalen = strlen($bucket->data);
69 stream_bucket_append($out, $bucket);
72 if ($closing && strlen($this->chunk))
74 $written = true;
75 $bucket = stream_bucket_new($this->stream, $this->compile($this->chunk));
76 stream_bucket_append($out, $bucket);
79 return $written ? PSFS_PASS_ON : PSFS_FEED_ME;
82 public function onCreate()
84 $this->chunk = '';
85 return true;
88 private function compile($data)
90 $data = preg_replace('#<(?:[\\?%]|script)#s', '<?php echo\'\\0\';?>', $data);
91 return str_replace('?><?php', '', preg_replace_callback($this->regex, array($this, 'replace'), $data));
94 private function replace($matches)
96 global $config;
98 if (isset($matches[3]))
100 return $this->compile_var_tags($matches[0]);
103 switch ($matches[1])
105 case 'BEGIN':
106 $this->block_else_level[] = false;
107 return '<?php ' . $this->compile_tag_block($matches[2]) . ' ?>';
108 break;
110 case 'BEGINELSE':
111 $this->block_else_level[sizeof($this->block_else_level) - 1] = true;
112 return '<?php }} else { ?>';
113 break;
115 case 'END':
116 array_pop($this->block_names);
117 return '<?php ' . ((array_pop($this->block_else_level)) ? '}' : '}}') . ' ?>';
118 break;
120 case 'IF':
121 return '<?php ' . $this->compile_tag_if($matches[2], false) . ' ?>';
122 break;
124 case 'ELSE':
125 return '<?php } else { ?>';
126 break;
128 case 'ELSEIF':
129 return '<?php ' . $this->compile_tag_if($matches[2], true) . ' ?>';
130 break;
132 case 'ENDIF':
133 return '<?php } ?>';
134 break;
136 case 'DEFINE':
137 return '<?php ' . $this->compile_tag_define($matches[2], true) . ' ?>';
138 break;
140 case 'UNDEFINE':
141 return '<?php ' . $this->compile_tag_define($matches[2], false) . ' ?>';
142 break;
144 case 'INCLUDE':
145 return '<?php ' . $this->compile_tag_include($matches[2]) . ' ?>';
146 break;
148 case 'INCLUDEPHP':
149 return ($config['tpl_allow_php']) ? '<?php ' . $this->compile_tag_include_php($matches[2]) . ' ?>' : '';
150 break;
152 case 'PHP':
153 return ($config['tpl_allow_php']) ? '<?php ' : '<!-- ';
154 break;
156 case 'ENDPHP':
157 return ($config['tpl_allow_php']) ? ' ?>' : ' -->';
158 break;
160 default:
161 return $matches[0];
162 break;
165 return '';
169 * Compile variables
170 * @access private
172 private function compile_var_tags(&$text_blocks)
174 // change template varrefs into PHP varrefs
175 $varrefs = array();
177 // This one will handle varrefs WITH namespaces
178 preg_match_all('#\{((?:[a-z0-9\-_]+\.)+)(\$)?([A-Z0-9\-_]+)\}#', $text_blocks, $varrefs, PREG_SET_ORDER);
180 foreach ($varrefs as $var_val)
182 $namespace = $var_val[1];
183 $varname = $var_val[3];
184 $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]);
186 $text_blocks = str_replace($var_val[0], $new, $text_blocks);
189 // This will handle the remaining root-level varrefs
190 // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array
191 if (strpos($text_blocks, '{L_') !== false)
193 $text_blocks = preg_replace('#\{L_([a-z0-9\-_]*)\}#is', "<?php echo ((isset(\$_rootref['L_\\1'])) ? \$_rootref['L_\\1'] : ((isset(\$_lang['\\1'])) ? \$_lang['\\1'] : '{ \\1 }')); ?>", $text_blocks);
196 // Handle addslashed language variables prefixed with LA_
197 // If a template variable already exist, it will be used in favor of it...
198 if (strpos($text_blocks, '{LA_') !== false)
200 $text_blocks = preg_replace('#\{LA_([a-z0-9\-_]*)\}#is', "<?php echo ((isset(\$_rootref['LA_\\1'])) ? \$_rootref['LA_\\1'] : ((isset(\$_rootref['L_\\1'])) ? addslashes(\$_rootref['L_\\1']) : ((isset(\$_lang['\\1'])) ? addslashes(\$_lang['\\1']) : '{ \\1 }'))); ?>", $text_blocks);
203 // Handle remaining varrefs
204 $text_blocks = preg_replace('#\{([a-z0-9\-_]*)\}#is', "<?php echo (isset(\$_rootref['\\1'])) ? \$_rootref['\\1'] : ''; ?>", $text_blocks);
205 $text_blocks = preg_replace('#\{\$([a-z0-9\-_]*)\}#is', "<?php echo (isset(\$_tpldata['DEFINE']['.']['\\1'])) ? \$_tpldata['DEFINE']['.']['\\1'] : ''; ?>", $text_blocks);
207 return $text_blocks;
211 * Compile blocks
212 * @access private
214 private function compile_tag_block($tag_args)
216 $no_nesting = false;
218 // Is the designer wanting to call another loop in a loop?
219 // <!-- BEGIN loop -->
220 // <!-- BEGIN !loop2 -->
221 // <!-- END !loop2 -->
222 // <!-- END loop -->
223 // 'loop2' is actually on the same nesting level as 'loop' you assign
224 // variables to it with template->assign_block_vars('loop2', array(...))
225 if (strpos($tag_args, '!') === 0)
227 // Count the number if ! occurrences (not allowed in vars)
228 $no_nesting = substr_count($tag_args, '!');
229 $tag_args = substr($tag_args, $no_nesting);
232 // Allow for control of looping (indexes start from zero):
233 // foo(2) : Will start the loop on the 3rd entry
234 // foo(-2) : Will start the loop two entries from the end
235 // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth
236 // foo(3,-4) : Will start the loop on the fourth entry and end it four from last
237 $match = array();
238 if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match))
240 $tag_args = $match[1];
242 if ($match[2] < 0)
244 $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')';
246 else
248 $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')';
251 if (strlen($match[3]) < 1 || $match[3] == -1)
253 $loop_end = '$_' . $tag_args . '_count';
255 else if ($match[3] >= 0)
257 $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')';
259 else //if ($match[3] < -1)
261 $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1);
264 else
266 $loop_start = 0;
267 $loop_end = '$_' . $tag_args . '_count';
270 $tag_template_php = '';
271 array_push($this->block_names, $tag_args);
273 if ($no_nesting !== false)
275 // We need to implode $no_nesting times from the end...
276 $block = array_slice($this->block_names, -$no_nesting);
278 else
280 $block = $this->block_names;
283 if (sizeof($block) < 2)
285 // Block is not nested.
286 $tag_template_php = '$_' . $tag_args . "_count = (isset(\$_tpldata['$tag_args'])) ? sizeof(\$_tpldata['$tag_args']) : 0;";
287 $varref = "\$_tpldata['$tag_args']";
289 else
291 // This block is nested.
292 // Generate a namespace string for this block.
293 $namespace = implode('.', $block);
295 // Get a reference to the data array for this block that depends on the
296 // current indices of all parent blocks.
297 $varref = $this->generate_block_data_ref($namespace, false);
299 // Create the for loop code to iterate over this block.
300 $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;';
303 $tag_template_php .= 'if ($_' . $tag_args . '_count) {';
306 * 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
307 * <code>
308 * if (!$offset)
310 * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){';
312 * </code>
315 $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){';
316 $tag_template_php .= '$_'. $tag_args . '_val = &' . $varref . '[$_'. $tag_args. '_i];';
318 return $tag_template_php;
322 * Compile a general expression - much of this is from Smarty with
323 * some adaptions for our block level methods
324 * @access private
326 private function compile_expression($tag_args)
328 $match = array();
329 preg_match_all('/(?:
330 "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
331 \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' |
332 [(),] |
333 [^\s(),]+)/x', $tag_args, $match);
335 $tokens = $match[0];
336 $is_arg_stack = array();
338 for ($i = 0, $size = sizeof($tokens); $i < $size; $i++)
340 $token = &$tokens[$i];
342 switch ($token)
344 case '!==':
345 case '===':
346 case '<<':
347 case '>>':
348 case '|':
349 case '^':
350 case '&':
351 case '~':
352 case ')':
353 case ',':
354 case '+':
355 case '-':
356 case '*':
357 case '/':
358 case '@':
359 break;
361 case '==':
362 case 'eq':
363 $token = '==';
364 break;
366 case '!=':
367 case '<>':
368 case 'ne':
369 case 'neq':
370 $token = '!=';
371 break;
373 case '<':
374 case 'lt':
375 $token = '<';
376 break;
378 case '<=':
379 case 'le':
380 case 'lte':
381 $token = '<=';
382 break;
384 case '>':
385 case 'gt':
386 $token = '>';
387 break;
389 case '>=':
390 case 'ge':
391 case 'gte':
392 $token = '>=';
393 break;
395 case '&&':
396 case 'and':
397 $token = '&&';
398 break;
400 case '||':
401 case 'or':
402 $token = '||';
403 break;
405 case '!':
406 case 'not':
407 $token = '!';
408 break;
410 case '%':
411 case 'mod':
412 $token = '%';
413 break;
415 case '(':
416 array_push($is_arg_stack, $i);
417 break;
419 case 'is':
420 $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1;
421 $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
423 $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
425 array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens);
427 $i = $is_arg_start;
429 // no break
431 default:
432 $varrefs = array();
433 if (preg_match('#^((?:[a-z0-9\-_]+\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs))
435 if (!empty($varrefs[1]))
437 $namespace = substr($varrefs[1], 0, -1);
438 $namespace = (strpos($namespace, '.') === false) ? $namespace : strrchr($namespace, '.');
440 // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows
441 // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM
442 switch ($varrefs[3])
444 case 'S_ROW_NUM':
445 case 'S_ROW_COUNT':
446 $token = "\$_${namespace}_i";
447 break;
449 case 'S_NUM_ROWS':
450 $token = "\$_${namespace}_count";
451 break;
453 case 'S_FIRST_ROW':
454 $token = "(\$_${namespace}_i == 0)";
455 break;
457 case 'S_LAST_ROW':
458 $token = "(\$_${namespace}_i == \$_${namespace}_count - 1)";
459 break;
461 case 'S_BLOCK_NAME':
462 $token = "'$namespace'";
463 break;
465 default:
466 $token = $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']';
467 break;
470 else
472 $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']';
475 else if (preg_match('#^\.((?:[a-z0-9\-_]+\.?)+)$#s', $token, $varrefs))
477 // Allow checking if loops are set with .loopname
478 // It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example
479 $blocks = explode('.', $varrefs[1]);
481 // If the block is nested, we have a reference that we can grab.
482 // If the block is not nested, we just go and grab the block from _tpldata
483 if (sizeof($blocks) > 1)
485 $block = array_pop($blocks);
486 $namespace = implode('.', $blocks);
487 $varref = $this->generate_block_data_ref($namespace, true);
489 // Add the block reference for the last child.
490 $varref .= "['" . $block . "']";
492 else
494 $varref = '$_tpldata';
496 // Add the block reference for the last child.
497 $varref .= "['" . $blocks[0] . "']";
499 $token = "isset($varref) && sizeof($varref)";
502 break;
506 return $tokens;
510 private function compile_tag_if($tag_args, $elseif)
512 $tokens = $this->compile_expression($tag_args);
513 return (($elseif) ? '} else if (' : 'if (') . (implode(' ', $tokens) . ') { ');
517 * Compile DEFINE tags
518 * @access private
520 private function compile_tag_define($tag_args, $op)
522 $match = array();
523 preg_match('#^((?:[a-z0-9\-_]+\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (.*?))?$#', $tag_args, $match);
525 if (empty($match[2]) || (!isset($match[3]) && $op))
527 return '';
530 if (!$op)
532 return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');';
535 $parsed_statement = implode(' ', $this->compile_expression($match[3]));
537 return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';';
541 * Compile INCLUDE tag
542 * @access private
544 private function compile_tag_include($tag_args)
546 return "\$this->_tpl_include('$tag_args');";
550 * Compile INCLUDE_PHP tag
551 * @access private
553 private function compile_tag_include_php($tag_args)
555 return "include('" . $tag_args . "');";
559 * parse expression
560 * This is from Smarty
561 * @access private
563 private function _parse_is_expr($is_arg, $tokens)
565 $expr_end = 0;
566 $negate_expr = false;
568 if (($first_token = array_shift($tokens)) == 'not')
570 $negate_expr = true;
571 $expr_type = array_shift($tokens);
573 else
575 $expr_type = $first_token;
578 switch ($expr_type)
580 case 'even':
581 if (@$tokens[$expr_end] == 'by')
583 $expr_end++;
584 $expr_arg = $tokens[$expr_end++];
585 $expr = "!(($is_arg / $expr_arg) & 1)";
587 else
589 $expr = "!($is_arg & 1)";
591 break;
593 case 'odd':
594 if (@$tokens[$expr_end] == 'by')
596 $expr_end++;
597 $expr_arg = $tokens[$expr_end++];
598 $expr = "(($is_arg / $expr_arg) & 1)";
600 else
602 $expr = "($is_arg & 1)";
604 break;
606 case 'div':
607 if (@$tokens[$expr_end] == 'by')
609 $expr_end++;
610 $expr_arg = $tokens[$expr_end++];
611 $expr = "!($is_arg % $expr_arg)";
613 break;
616 if ($negate_expr)
618 $expr = "!($expr)";
621 array_splice($tokens, 0, $expr_end, $expr);
623 return $tokens;
627 * Generates a reference to the given variable inside the given (possibly nested)
628 * block namespace. This is a string of the form:
629 * ' . $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
630 * It's ready to be inserted into an "echo" line in one of the templates.
632 * @access private
633 * @param string $namespace Namespace to access (expects a trailing "." on the namespace)
634 * @param string $varname Variable name to use
635 * @param bool $echo If true return an echo statement, otherwise a reference to the internal variable
636 * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable
637 * @return string Code to access variable or echo it if $echo is true
639 private function generate_block_varref($namespace, $varname, $echo = true, $defop = false)
641 // Strip the trailing period.
642 $namespace = substr($namespace, 0, -1);
644 $expr = true;
646 // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows
647 // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM
648 switch ($varname)
650 case 'S_ROW_NUM':
651 case 'S_ROW_COUNT':
652 $varref = "\$_${namespace}_i";
653 break;
655 case 'S_NUM_ROWS':
656 $varref = "\$_${namespace}_count";
657 break;
659 case 'S_FIRST_ROW':
660 $varref = "(\$_${namespace}_i == 0)";
661 break;
663 case 'S_LAST_ROW':
664 $varref = "(\$_${namespace}_i == \$_${namespace}_count - 1)";
665 break;
667 case 'S_BLOCK_NAME':
668 $varref = "'$namespace'";
669 break;
671 default:
672 // Get a reference to the data block for this namespace.
673 $varref = $this->generate_block_data_ref($namespace, true, $defop);
674 // Prepend the necessary code to stick this in an echo line.
676 // Append the variable reference.
677 $varref .= "['$varname']";
679 $expr = false;
680 break;
682 // @todo Test the !$expr more
683 $varref = ($echo) ? "<?php echo $varref; ?>" : (($expr || isset($varref)) ? $varref : '');
685 return $varref;
689 * Generates a reference to the array of data values for the given
690 * (possibly nested) block namespace. This is a string of the form:
691 * $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
693 * @access private
694 * @param string $blockname Block to access (does not expect a trailing "." on the blockname)
695 * @param bool $include_last_iterator If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
696 * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable
697 * @return string Code to access variable
699 private function generate_block_data_ref($blockname, $include_last_iterator, $defop = false)
701 // Get an array of the blocks involved.
702 $blocks = explode('.', $blockname);
703 $blockcount = sizeof($blocks) - 1;
705 // DEFINE is not an element of any referenced variable, we must use _tpldata to access it
706 if ($defop)
708 $varref = '$_tpldata[\'DEFINE\']';
709 // Build up the string with everything but the last child.
710 for ($i = 0; $i < $blockcount; $i++)
712 $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]';
714 // Add the block reference for the last child.
715 $varref .= "['" . $blocks[$blockcount] . "']";
716 // Add the iterator for the last child if requried.
717 if ($include_last_iterator)
719 $varref .= '[$_' . $blocks[$blockcount] . '_i]';
721 return $varref;
723 else if ($include_last_iterator)
725 return '$_'. $blocks[$blockcount] . '_val';
727 else
729 return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']';
734 stream_filter_register('template', 'template_filter');
737 * Extension of template class - Functions needed for compiling templates only.
739 * psoTFX, phpBB Development Team - Completion of file caching, decompilation
740 * routines and implementation of conditionals/keywords and associated changes
742 * The interface was inspired by PHPLib templates, and the template file (formats are
743 * quite similar)
745 * The keyword/conditional implementation is currently based on sections of code from
746 * the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released
747 * (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code
748 * derived from an LGPL application may be relicenced under the GPL, this applies
749 * to this source
751 * DEFINE directive inspired by a request by Cyberalien
753 * @package phpBB3
754 * @uses template_filter As a PHP stream filter to perform compilation of templates
756 class template_compile
759 * @var template Reference to the {@link template template} object performing compilation
761 private $template;
764 * Constructor
765 * @param template $template {@link template Template} object performing compilation
767 function __construct(template $template)
769 $this->template = $template;
773 * Load template source from file
774 * @access public
775 * @param string $handle Template handle we wish to load
776 * @return bool Return true on success otherwise false
778 public function _tpl_load_file($handle)
780 // Try and open template for read
781 if (!file_exists($this->template->files[$handle]))
783 trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR);
786 // Actually compile the code now.
787 return $this->compile_write($handle, $this->template->files[$handle]);
791 * Load template source from file
792 * @access public
793 * @param string $handle Template handle we wish to compile
794 * @return string|bool Return compiled code on successful compilation otherwise false
796 public function _tpl_gen_src($handle)
798 // Try and open template for read
799 if (!file_exists($this->template->files[$handle]))
801 trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR);
804 // Actually compile the code now.
805 return $this->compile_gen($this->template->files[$handle]);
809 * Write compiled file to cache directory
810 * @access private
811 * @param string $handle Template handle to compile
812 * @param string $source_file Source template file
813 * @return bool Return true on success otherwise false
815 private function compile_write($handle, $source_file)
817 $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . PHP_EXT;
819 $source_handle = @fopen($source_file, 'rb');
820 $destination_handle = @fopen($filename, 'wb');
822 if (!$source_handle || !$destination_handle)
824 return false;
827 @flock($destination_handle, LOCK_EX);
829 stream_filter_append($source_handle, 'template');
830 stream_copy_to_stream($source_handle, $destination_handle);
832 @fclose($source_handle);
833 @flock($destination_handle, LOCK_UN);
834 @fclose($destination_handle);
836 phpbb_chmod($filename, CHMOD_WRITE);
838 clearstatcache();
840 return true;
844 * Generate source for eval()
845 * @access private
846 * @param string $source_file Source template file
847 * @return string|bool Return compiled code on successful compilation otherwise false
849 private function compile_gen($source_file)
851 $source_handle = @fopen($source_file, 'rb');
852 $destination_handle = @fopen('php://temp' ,'r+b');
854 if (!$source_handle || !$destination_handle)
856 return false;
859 stream_filter_append($source_handle, 'template');
860 stream_copy_to_stream($source_handle, $destination_handle);
862 @fclose($source_handle);
864 rewind($destination_handle);
865 return stream_get_contents($destination_handle);