Fresh install of version: 10 RC11 on NameCheap servers

Post

Posted
Rating:
#785 (In Topic #200)
It's always a bit challenging to make big changes in software, I'd imagine, especially if it might require some heavy debugging afterward. So break out the coffee (or tea if you live in the UK?), and take a look at this error. I keep this NameCheap server around just to goof around with, so the error isn't an issue for me. 

First, I mass-deleted the html directory. Even got rid or .htaccss. I blasted the old database completely, and reassigned a new user to it, with a new passwd. Fresh install of 10 RC11.

Everything went perfectly with the install, until I got to the last page that told me the site was installed, and that I could now add some pages to the site, of just Go To The Site. In this install, I decided not to have a forum, or forum users, so I said "None" on the Add Forum page early in the installation. Also, the kind of site I installed was a basic type. I forgot the name, now, but it was the bare bones selection. For the options on the next few pages, I only decided to add a newsletter. Nothing else. No Wiki, no forum, no avatar stuff…just bare bones stuff.

When I clicked Take Me To The Website after the install was complete, I got the following error page…hope this helps. Unlike other errors, this error prevents even a login after a logout.

(EDIT: after running the installer again, and not selecting Minimalistic Site, but instead selecting Brocuhre type site, it does not have errors anymore. Something to do with Minimalistic site type?)

An error has occurred

PHP NOTICE [8] Undefined offset: 0 in sources/tempcode.php on line 1125 (version: 10 RC11, PHP version: 5.6.22, URL: /index.php?page=start)

Here is the stack trace:

Below is a stack trace revealing the state Composr was in when the error occurred. If this represents a bug in the unmodified software, you may want to check Composr website for a fix, and if there isn't one, report this as a bug. Please note that merely posting a stack trace is not sufficient for us to solve your problem; the stack trace is just an aid that presents us with additional information. We still need to know the error message, what you tried to do, how you tried to do it, version numbers, and any other appropriate information.
We apologise for this problem and if it's a bug we hope you will work with us so that we can fix it for you promptly.

File    '/home/witcbxzr/public_html/sources/failure.php'
Line    983
Function    'get_html_trace'
Args    
File    '/home/witcbxzr/public_html/sources/global2.php'
Line    910
Function    '_fatal_exit'
Args    
'PHP NOTICE [8] Undefined offset: 0 in sources/tempcode.php on line 1125'
File    '/home/witcbxzr/public_html/sources/failure.php'
Line    281
Function    'fatal_exit'
Args    
'PHP NOTICE [8] Undefined offset: 0 in sources/tempcode.php on line 1125'
File    '/home/witcbxzr/public_html/sources/global2.php'
Line    781
Function    '_composr_error_handler'
Args    
'notice'

8

'Undefined offset: 0'

'sources/tempcode.php'

1,125

5
File    '/home/witcbxzr/public_html/sources/tempcode.php'
Line    1,125
Function    'composr_error_handler'
Args    
8

'Undefined offset: 0'

'/home/witcbxzr/public_html/sources/tempcode.php'

1,125

a:3:{s:8:"seq_part";a:4:{i:0;a:0:{}i:1;i:0;i:2;s:11:"REQUIRE_CSS";i:3;a:0:{}}s:8:"children";N;s:5:"param";a:0:{}}
File    '/home/witcbxzr/public_html/sources/tempcode.php'
Line    1,780
Function    'handle_symbol_preprocessing'
Args    
a:4:{i:0;a:0:{}i:1;i:0;i:2;s:11:"REQUIRE_CSS";i:3;a:0:{}}

NULL
File    '/home/witcbxzr/public_html/sources/tempcode.php'
Line    1,182
Function    'handle_symbol_preprocessing'
Class    'Tempcode'
Object    Tempcode -> …
Type    '->'
Args    
File    '/home/witcbxzr/public_html/sources/tempcode.php'
Line    1,780
Function    'handle_symbol_preprocessing'
Args    
array

NULL
File    '/home/witcbxzr/public_html/sources/site.php'
Line    877
Function    'handle_symbol_preprocessing'
Class    'Tempcode'
Object    Tempcode -> …
Type    '->'
Args    
File    '/home/witcbxzr/public_html/index.php'
Line    73
Function    'do_site'
Args    

The site is closed, but you have special access.
Commandr: the Composr command line environment  Admin Zone  Chat with other Composr users (Select page rendering tool)
Sitemap Rules Privacy Feedback   Mobile version Witches Press Keyboard shortcuts
Copyright © 2016 ( Witches.Press ) A A A
Critical error – bailing out

This is an error that has been elevated to critical error status because it occurred during the primary error mechanism reporting system itself (possibly due to it occurring within the standard output framework). It may be masking a secondary error that occurred before this, but was never output - if so, it is likely strongly related to this one, thus fixing this will fix the other.
A template file is missing: (themes/default/templates/.tpl or an overridden equivalent to this path) (version: 10 RC11, PHP version: 5.6.22, URL: /index.php?page=start)
Stack trace…
File -> 'sources/failure.php'
Line -> 975
Function -> 'die_html_trace'
Args -> a:1:{i:0;s:191:"A template file is missing: <kbd></kbd> (<kbd>themes/default/templates/.tpl</kbd> or an overridden equivalent to this path) (version: 10 RC11, PHP version: 5.6.22, URL: /index.php?page=start)";}
File -> 'sources/global2.php'
Line -> 910
Function -> '_fatal_exit'
Args -> array
File -> 'sources/tempcode.php'
Line -> 830
Function -> 'fatal_exit'
Args -> array
File -> 'sources/mail.php'
Line -> 1,242
Function -> 'do_template'
Args -> a:8:{i:0;s:0:"";i:1;N;i:2;s:2:"EN";i:3;b:0;i:4;N;i:5;s:4:".css";i:6;s:3:"css";i:7;s:13:"Witches_Press";}
File -> 'sources/web_resources.php'
Line -> 449
Function -> 'filter_css'
Args -> array
File -> 'sources/web_resources.php'
Line -> 407
Function -> '_css_tempcode'
Args -> array
File -> 'sources/mail.php'
Line -> 753
Function -> 'css_tempcode'
Args -> array
File -> 'sources/failure.php'
Line -> 1,110
Function -> 'mail_wrap'
Args -> array
File -> 'sources/failure.php'
Line -> 1,009
Function -> 'relay_error_notification'
Args -> array
File -> 'sources/global2.php'
Line -> 910
Function -> '_fatal_exit'
Args -> a:1:{i:0;s:71:"PHP NOTICE [8] Undefined offset: 0 in sources/tempcode.php on line 1125";}
File -> 'sources/failure.php'
Line -> 281
Function -> 'fatal_exit'
Args -> a:1:{i:0;s:71:"PHP NOTICE [8] Undefined offset: 0 in sources/tempcode.php on line 1125";}
File -> 'sources/global2.php'
Line -> 781
Function -> '_composr_error_handler'
Args -> a:6:{i:0;s:6:"notice";i:1;i:8;i:2;s:19:"Undefined offset: 0";i:3;s:20:"sources/tempcode.php";i:4;i:1125;i:5;i:5;}
File -> 'sources/tempcode.php'
Line -> 1,125
Function -> 'composr_error_handler'
Args -> a:5:{i:0;i:8;i:1;s:19:"Undefined offset: 0";i:2;s:47:"sources/tempcode.php";i:3;i:1125;i:4;a:3:{s:8:"seq_part";a:4:{i:0;a:0:{}i:1;i:0;i:2;s:11:"REQUIRE_CSS";i:3;a:0:{}}s:8:"children";N;s:5:"param";a:0:{}}}
File -> 'sources/tempcode.php'
Line -> 1,780
Function -> 'handle_symbol_preprocessing'
Args -> a:2:{i:0;a:4:{i:0;a:0:{}i:1;i:0;i:2;s:11:"REQUIRE_CSS";i:3;a:0:{}}i:1;N;}
File -> 'sources/tempcode.php'
Line -> 1,182
Function -> 'handle_symbol_preprocessing'
Class -> 'Tempcode'
Object -> Tempcode -> …
Type -> '->'
Args -> a:0:{}
File -> 'sources/tempcode.php'
Line -> 1,780
Function -> 'handle_symbol_preprocessing'
Args -> array
File -> 'sources/site.php'
Line -> 877
Function -> 'handle_symbol_preprocessing'
Class -> 'Tempcode'
Object -> Tempcode -> …
Type -> '->'
Args -> a:0:{}
File -> 'index.php'
Line -> 73
Function -> 'do_site'
Args -> a:0:{}
 

Last edit: by Malatesa

Post

Posted
Rating:
#797
I have the same issue after an upgrade from RC10 to RC11, site is now dead in the water, including adminzone:

Code

PHP NOTICE [8] Undefined offset: 0 in sources/tempcode.php on line 1125 (version: 10 RC11, PHP version: 7.0.4-7ubuntu2.1, URL: /adminzone/index.php?page=start)

UPDATE: commenting out line 1125 in sources/tempcode.php has solved the problem with no apparent ramifications but I'll continue to watch for side effects

Code

//            require_css($param[0]);

Last edit: by SoccerDad


Post

Posted
Rating:
#798
This obviously will need to be looked at carefully, but please try this quick fix:

Code (php)

  1.  

Sorry for the delayed reply Malatesa.

Post

Posted
Rating:
#799
Posted tempcode.php has also addressed the problem, thanx Chris!

I'm glad I finally have some time to return to playing with Composr, it's been a while. I see your response to the community has not changed, topnotch!

Post

Posted
Rating:
#802
Ok guys, a few of you received this problem. Sorry for the inconvenience. A recent optimisation interacted with a recent mail fix, to create an issue that only affected sites with mail queueing enabled (which isn't the dev environment).

I have properly tracked it down, and the following files fully fix it:

Code (php)

  1.  

Code (php)

  1.  

Code (php)

  1. <?php /*
  2.  
  3.  Composr
  4.  Copyright (c) ocProducts, 2004-2016
  5.  
  6.  See text/EN/licence.txt for full licencing information.
  7.  
  8.  
  9.  NOTE TO PROGRAMMERS:
  10.    Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
  11.    **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****
  12.  
  13. */
  14.  
  15. /**
  16.  * @license    http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
  17.  * @copyright  ocProducts Ltd
  18.  * @package    core
  19.  */
  20.  
  21. /**
  22.  * Standard code module initialisation function.
  23.  *
  24.  * @ignore
  25.  */
  26. function init__tempcode()
  27. {
  28.     if (defined('ENTITY_ESCAPED')) {
  29.         return;
  30.     }
  31.  
  32.     define('ENTITY_ESCAPED', 1); // HTML entities
  33.     define('SQ_ESCAPED', 2); // Single quotes
  34.     define('DQ_ESCAPED', 3); // Double quotes
  35.     define('NL_ESCAPED', 4); // New lines disappear
  36.     define('CC_ESCAPED', 5); // Comcode
  37.     define('UL_ESCAPED', 6); // URL
  38.     define('JSHTML_ESCAPED', 7); // JavaScript </ -> <\/
  39.     define('NL2_ESCAPED', 8); // New lines go to \n
  40.     define('ID_ESCAPED', 9); // Strings to to usable IDs
  41.     define('NAUGHTY_ESCAPED', 10); // Used as a JavaScript variable name, for example... to prevent code injection
  42.     define('NULL_ESCAPED', 11); // This is useful to mark something that takes strings but does not need escaping (usually because it is escaped further down the line)
  43.     define('FORCIBLY_ENTITY_ESCAPED', 12); // To force a language string to be escaped
  44.     define('CSS_ESCAPED', 13); // To stop CSS injection
  45.     define('UL2_ESCAPED', 14); // rawurlencode
  46.     define('PURE_STRING', 16); // Used to indicating we just put something directly into the output. Works with __toString or normal strings. Does no escaping.
  47.  
  48.     define('TC_SYMBOL', 0);
  49.     define('TC_KNOWN', 1); // Either Tempcode or string
  50.     define('TC_LANGUAGE_REFERENCE', 2);
  51.     define('TC_PARAMETER', 3); // A late parameter for a compiled template
  52.     define('TC_DIRECTIVE', 4);
  53.  
  54.     global $XHTML_SPIT_OUT, $NO_EVAL_CACHE, $MEMORY_OVER_SPEED, $TEMPLATE_DISK_ORIGIN_CACHE, $REQUEST_BLOCK_NEST_LEVEL, $LOADED_TPL_CACHE, $KEEP_TPL_FUNCS;
  55.     $XHTML_SPIT_OUT = null;
  56.     $NO_EVAL_CACHE = false;
  57.     $MEMORY_OVER_SPEED = (get_param_integer('keep_memory_over_speed', 0) == 1);
  58.     $TEMPLATE_DISK_ORIGIN_CACHE = array();
  59.     $REQUEST_BLOCK_NEST_LEVEL = 0;
  60.     $LOADED_TPL_CACHE = array();
  61.     $KEEP_TPL_FUNCS = array();
  62.  
  63.     global $RECORD_TEMPLATES_USED, $RECORDED_TEMPLATES_USED, $RECORD_TEMPLATES_TREE, $POSSIBLY_IN_SAFE_MODE_CACHE, $SCREEN_TEMPLATE_CALLED, $TITLE_CALLED;
  64.     $RECORD_TEMPLATES_USED = false;
  65.     $RECORDED_TEMPLATES_USED = array();
  66.     $RECORD_TEMPLATES_TREE = false;
  67.     /** The name of a template that was called to render the current screen (null: not rendering a screen), auto-populated within the template system. This is tracked during dev mode to confirm that each screen really does wrap itself in a proper screen template.
  68.      *
  69.      * @global ?ID_TEXT $SCREEN_TEMPLATE_CALLED
  70.      */
  71.     $SCREEN_TEMPLATE_CALLED = null;
  72.     /** Whether a title has been called.
  73.      *
  74.      * @global boolean $TITLE_CALLED
  75.      */
  76.     $TITLE_CALLED = false;
  77.     $POSSIBLY_IN_SAFE_MODE_CACHE = (get_param_integer('keep_safe_mode', 0) == 1);
  78.  
  79.     global $SIMPLE_ESCAPED, $XSS_DETECT;
  80.     $SIMPLE_ESCAPED = array(ENTITY_ESCAPED);
  81.     if ($XSS_DETECT) {
  82.         $SIMPLE_ESCAPED = array(12345); // Don't allow $SIMPLE_ESCAPED to work, as we need to work through full manual escaping
  83.     }
  84.  
  85.     require_code('symbols');
  86.  
  87.     global $FULL_RESET_VAR_CODE, $RESET_VAR_CODE;
  88.     // && substr($x, 0, 6) == \'bound_\' removed from the below for performance, not really needed
  89.     $FULL_RESET_VAR_CODE = 'foreach(get_defined_vars() as $x => $_) { if ($x[0]==\'b\' && $x[1]==\'o\') unset($$x); } extract($parameters,EXTR_PREFIX_ALL,\'bound\');';
  90.     $RESET_VAR_CODE = 'extract($parameters,EXTR_PREFIX_ALL,\'bound\');';
  91.  
  92.     global $IS_TEMPLATE_PREVIEW_OP_CACHE;
  93.     $IS_TEMPLATE_PREVIEW_OP_CACHE = null;
  94.  
  95.     /** Whether output streaming mode is active.
  96.      *
  97.      * @global boolean $OUTPUT_STREAMING
  98.      */
  99.     global $OUTPUT_STREAMING;
  100.     $OUTPUT_STREAMING = (function_exists('get_option')) && (get_option('output_streaming') == '1') && (get_param_integer('keep_no_output_streaming', 0) == 0);
  101.     if ($GLOBALS['SMART_CACHE'] === null || !$GLOBALS['SMART_CACHE']->get_initial_status('CSSS')) {
  102.         $OUTPUT_STREAMING = false;
  103.     } elseif (get_param_string('special_page_type', 'view') != 'view') {
  104.         $OUTPUT_STREAMING = false;
  105.     } elseif (get_param_integer('keep_markers', 0) == 1) {
  106.         $OUTPUT_STREAMING = false;
  107.     } elseif (get_param_integer('show_edit_links', 0) == 1) {
  108.         $OUTPUT_STREAMING = false;
  109.     }
  110.  
  111.     global $STOP_IF_STUCK, $STUCK_ABORT_SIGNAL, $TEMPCODE_OUTPUT_STARTED, $CSS_OUTPUT_STARTED, $JS_OUTPUT_STARTED, $TEMPCODE_CURRENT_PAGE_OUTPUTTING;
  112.     $STOP_IF_STUCK = false;
  113.     $STUCK_ABORT_SIGNAL = false;
  114.     $TEMPCODE_OUTPUT_STARTED = false;
  115.     $CSS_OUTPUT_STARTED = false;
  116.     $JS_OUTPUT_STARTED = false;
  117.     $TEMPCODE_CURRENT_PAGE_OUTPUTTING = null;
  118. }
  119.  
  120. /**
  121.  * Simple function to evaluate some Tempcode. Very rarely to be used, only if you can't call a method (e.g. you are copying direct into an array, such as in block caching).
  122.  *
  123.  * @param  Tempcode $ob Tempcode object
  124.  * @return string Evaluated string
  125.  */
  126. function static_evaluate_tempcode($ob)
  127. {
  128.     return $ob->evaluate();
  129. }
  130.  
  131. /**
  132.  * Escape a string to fit within PHP double quotes TWICE. Needed sometimes when generating code. This function exists for performance reasons.
  133.  *
  134.  * @param  string $in String in
  135.  * @return string Resultant string
  136.  */
  137. function php_addslashes_twice($in)
  138. {
  139.     $in2 = php_addslashes($in);
  140.     return ($in === $in2) ? $in : php_addslashes($in2);
  141.  
  142.     // This code does not work, provides awfully confusing Tempcode errors...
  143.  
  144.     /*
  145.     global $PHP_REP_FROM, $PHP_REP_TO_TWICE;
  146.     return str_replace($PHP_REP_FROM, $PHP_REP_TO_TWICE, $in);
  147.     //return str_replace("\n", '\n', str_replace('$', '\$', str_replace('\\\'', '\'', addslashes($in))));
  148.     */
  149. }
  150.  
  151. /**
  152.  * Create a unique identifer.
  153.  *
  154.  * @return string Unique Identifier
  155.  */
  156. function fast_uniqid()
  157. {
  158.     return uniqid('', true);
  159. }
  160.  
  161. /**
  162.  * Get a string (natural for Tempcode's stream-based processing-model) representation of a bound Tempcode construct
  163.  *
  164.  * @param  mixed $var Construct (or null if not set)
  165.  * @param  ID_TEXT $origin Where this parameter is referenced, in a compressed reference form
  166.  * @return string Value
  167.  */
  168. function otp($var, $origin = '')
  169. {
  170.     switch (gettype($var)) {
  171.         case 'NULL':
  172.             if ($GLOBALS['STOP_IF_STUCK']) {
  173.                 $GLOBALS['STUCK_ABORT_SIGNAL'] = true;
  174.                 return '';
  175.             }
  176.             return missing_template_parameter($origin);
  177.         case 'string':
  178.             return $var;
  179.         case 'object':
  180.             return $var->evaluate();
  181.         case 'boolean':
  182.             return $var ? '1' : '0';
  183.     }
  184.     // Assuming array
  185.     $cnt = count($var);
  186.     return ($cnt === 0) ? '' : strval($cnt);
  187. }
  188.  
  189. /**
  190.  * Give an error about a missing template parameter
  191.  *
  192.  * @param  ID_TEXT $origin Where this parameter is referenced, in a slash-combined reference form
  193.  * @return string Always ""
  194.  */
  195. function missing_template_parameter($origin)
  196. {
  197.     list($parameter, $template_name) = ($origin == '') ? array(do_lang('UNKNOWN'), do_lang('UNKNOWN')) : explode('/', $origin, 2);
  198.     if (strtolower($template_name) != $template_name && (!is_file(get_file_base() . '/themes/default/templates/' . $template_name . '.tpl'))) {
  199.         return ''; // Some kind of custom template, will be error prone
  200.     }
  201.     attach_message(do_lang_tempcode('MISSING_TEMPLATE_PARAMETER', $parameter, ($template_name == '') ? '???' : $template_name), 'warn');
  202.     return '';
  203. }
  204.  
  205. /**
  206.  * Build a conventional Tempcode object
  207.  *
  208.  * @param  integer $type The type of symbol this is (TC_SYMBOL, TC_LANGUAGE_REFERENCE)
  209.  * @set    0 2
  210.  * @param  ID_TEXT $name The name of the symbol
  211.  * @param  ?array $parameters Parameters to the symbol (null: none). In same format as expected by ecv.
  212.  * @param  ?array $escaping Escaping for the symbol (null: none)
  213.  * @return Tempcode Tempcode object.
  214.  */
  215. function build_closure_tempcode($type, $name, $parameters, $escaping = null)
  216. {
  217.     if ($escaping === null) {
  218.         $_escaping = 'array()';
  219.     } else {
  220.         $_escaping = 'array(' . @implode(',', $escaping) . ')';
  221.     }
  222.  
  223.     $_type = strval($type);
  224.     if (preg_match('#^[\w\-]*$#', $name) === 0) {
  225.         $_name = php_addslashes_twice($name);
  226.     } else {
  227.         $_name = $name;
  228.     }
  229.  
  230.     static $generator_base = null;
  231.     static $generator_num = 0;
  232.     if ($generator_base === null) {
  233.         $generator_base = uniqid('', true);
  234.     }
  235.     $generator_num++;
  236.  
  237.     $has_tempcode = false;
  238.     foreach ($parameters as $parameter) {
  239.         if (isset($parameter->codename)/*faster than is_object*/) {
  240.             $has_tempcode = true;
  241.         }
  242.     }
  243.  
  244.     $myfunc = 'do_runtime_' . $generator_base . '_' . strval($generator_num)/*We'll inline it actually rather than calling, for performance   fast_uniqid()*/
  245.     ;
  246.     if ($name === '?' && $type === TC_SYMBOL) {
  247.         $name = 'TERNARY';
  248.     }
  249.  
  250.     if ($has_tempcode) {
  251.         $funcdef = "\$tpl_funcs['$myfunc']=\"foreach (\\\$parameters as \\\$i=>\\\$p) { if (is_object(\\\$p)) \\\$parameters[\\\$i]=\\\$p->evaluate(); } echo ";
  252.         if (($type === TC_SYMBOL) && (function_exists('ecv_' . $name))) {
  253.             $funcdef .= "ecv_" . $name . "(\\\$cl," . ($_escaping) . ",\\\$parameters);\";\n";
  254.         } else {
  255.             $funcdef .= "ecv(\\\$cl," . ($_escaping) . "," . ($_type) . ",\\\"" . ($_name) . "\\\",\\\$parameters);\";\n";
  256.         }
  257.     } else {
  258.         $_parameters = '';
  259.         if ($parameters !== null) {
  260.             foreach ($parameters as $parameter) {
  261.                 if ($_parameters != '') {
  262.                     $_parameters .= ',';
  263.                 }
  264.                 if (is_bool($parameter)) {
  265.                     $_parameters .= "\\\"" . ($parameter ? '1' : '0') . "\\\"";
  266.                 } else {
  267.                     $_parameters .= "\\\"" . php_addslashes_twice($parameter) . "\\\"";
  268.                 }
  269.             }
  270.         }
  271.  
  272.         $funcdef = "\$tpl_funcs['$myfunc']=\"echo ";
  273.         if (($type === TC_SYMBOL) && (function_exists('ecv_' . $name))) {
  274.             $funcdef .= "ecv_" . $name . "(\\\$cl," . ($_escaping) . ",array(" . $_parameters . "));\";\n";
  275.         } else {
  276.             $funcdef .= "ecv(\\\$cl," . ($_escaping) . "," . ($_type) . ",\\\"" . ($_name) . "\\\",array(" . $_parameters . "));\";\n";
  277.         }
  278.  
  279.         switch ($_name) {
  280.             // Needs parameters for preprocessing, so we won't throw them out
  281.             case 'REQUIRE_CSS':
  282.             case 'REQUIRE_JAVASCRIPT':
  283.             case 'FACILITATE_AJAX_BLOCK_CALL':
  284.             case 'JS_TEMPCODE':
  285.             case 'CSS_TEMPCODE':
  286.             case 'SET':
  287.             case 'SET_TITLE':
  288.             case 'BLOCK':
  289.             case 'PAGE_LINK':
  290.             case 'LOAD_PAGE':
  291.             case 'LOAD_PANEL':
  292.                 break;
  293.  
  294.             default:
  295.                 $parameters = array();
  296.                 break;
  297.         }
  298.     }
  299.  
  300.     $ret = new Tempcode(array(array($myfunc => $funcdef), array(array(array($myfunc, ($parameters === null) ? array() : $parameters, $type, $name, '')))));
  301.     if ($type === TC_LANGUAGE_REFERENCE) {
  302.         $ret->pure_lang = true;
  303.     }
  304.     return $ret;
  305. }
  306.  
  307. /**
  308.  * This will create a new Tempcode object that is containing a single specifed symbol
  309.  *
  310.  * @param  ID_TEXT $symbol The ID of the symbol to use
  311.  * @param  ?array $parameters Symbol parameters (null: none)
  312.  * @param  ?array $escape Escaping (null: none)
  313.  * @return Tempcode A symbol Tempcode object
  314.  */
  315. function symbol_tempcode($symbol, $parameters = null, $escape = null)
  316. {
  317.     if ($parameters === null) {
  318.         $parameters = array();
  319.     }
  320.  
  321.     return build_closure_tempcode(TC_SYMBOL, $symbol, $parameters, $escape);
  322. }
  323.  
  324. /**
  325.  * This will create a new Tempcode object that is containing a single specifed directive
  326.  *
  327.  * @param  ID_TEXT $directive The ID of the directive to use
  328.  * @param  mixed $content The contents (Tempcode or string)
  329.  * @param  ?array $parameters Directive parameters (null: none)
  330.  * @return Tempcode A directive Tempcode object
  331.  */
  332. function directive_tempcode($directive, $content, $parameters = null)
  333. {
  334.     if ($parameters === null) {
  335.         $parameters = array();
  336.     }
  337.     $parameters[] = $content;
  338.  
  339.     return build_closure_tempcode(TC_DIRECTIVE, $directive, $parameters);
  340. }
  341.  
  342. /**
  343.  * Perform a simple loop, that can be inlined in an expression.
  344.  *
  345.  * @param  array $args The template bound parameters
  346.  * @param  array $control_function The loop control function
  347.  * @param  array $main_function The loop execution function
  348.  * @return string Result
  349.  */
  350. function closure_while_loop($args, $control_function, $main_function)
  351. {
  352.     $out = '';
  353.     while (call_user_func_array($control_function, $args)) {
  354.         $out .= call_user_func_array($main_function, $args);
  355.     }
  356.     return $out;
  357. }
  358.  
  359. /**
  360.  * Evaluate some PHP code to put the result into an expression (code is allowed to have side effects).
  361.  *
  362.  * @param  string $code The code
  363.  * @param  array $parameters Template parameters
  364.  * @return string Result
  365.  */
  366. function closure_eval($code, $parameters)
  367. {
  368.     if (get_value('allow_php_in_templates') !== '1') {
  369.         return do_lang('NO_PHP_IN_TEMPLATES');
  370.     }
  371.  
  372.     $ret = /*$GLOBALS['DEV_MODE']?debug_eval($code):*/
  373.         eval($code);
  374.     if (!is_string($ret)) {
  375.         $ret = @strval($ret);
  376.     }
  377.     return $ret;
  378. }
  379.  
  380. /**
  381.  * Perform a simple loop, that can be inlined in an expression.
  382.  *
  383.  * @param  array $param The template bound parameters
  384.  * @param  array $args The loop directive parameters
  385.  * @param  string $main_function The loop execution function
  386.  * @return string Result
  387.  */
  388. function closure_loop($param, $args, $main_function)
  389. {
  390.     $value = '';
  391.  
  392.     if (isset($param[0])) {
  393.         $array_key = $param[0];
  394.         if ((is_numeric($array_key)) || (strpos($array_key, ',') !== false) || (strpos($array_key, '=') !== false)) {
  395.             $array = array();
  396.             foreach (explode(',', $array_key) as $x) {
  397.                 if (strpos($x, '=') !== false) {
  398.                     list($key, $val) = explode('=', $x, 2);
  399.                     if (($GLOBALS['XSS_DETECT']) && (ocp_is_escaped($x))) {
  400.                         ocp_mark_as_escaped($key);
  401.                         ocp_mark_as_escaped($val);
  402.                     }
  403.                     if ($key === '' && isset($array[$key])) {
  404.                         $array[] = $val; // Empty keys: which are done to allow "="s in strings by putting in an empty key
  405.                     } else {
  406.                         $array[$key] = $val;
  407.                     }
  408.                 } else {
  409.                     if (($GLOBALS['XSS_DETECT']) && (ocp_is_escaped($x))) {
  410.                         ocp_mark_as_escaped($x);
  411.                     }
  412.                     $array[] = $x;
  413.                 }
  414.             }
  415.         } else {
  416.             $array = isset($param['vars'][$array_key]) ? $param['vars'][$array_key] : array();
  417.         }
  418.         if (!is_array($array)) {
  419.             return do_lang('TEMPCODE_NOT_ARRAY'); // Must have this, otherwise will loop over the Tempcode object
  420.         }
  421.         if (isset($param[1 + 1])) { /* NB: +1 is due to there being a non-numeric index here too */
  422.             $columns = intval($param[1]);
  423.             if ($columns == 0) {
  424.                 $columns = 1;
  425.             }
  426.             $row_starter = isset($param[2 + 1]) ? $param[2] : '<tr>';
  427.             $row_terminator = isset($param[3 + 1]) ? $param[3] : '</tr>';
  428.             if ($array != array()) {
  429.                 $value .= $row_starter;
  430.             }
  431.  
  432.             // Sorting
  433.             if (isset($param[4 + 1])) {
  434.                 $sort_key = $param[4];
  435.  
  436.                 $rev = ((isset($param[5 + 1])) && ($param[5] == 'DESC'));
  437.                 if ($sort_key != '') {
  438.                     sort_maps_by($array, $sort_key);
  439.                 }
  440.                 if ($rev) {
  441.                     $array = array_reverse($array);
  442.                 }
  443.             }
  444.         }
  445.         $col = 0;
  446.  
  447.         $first = true;
  448.         $max_index = count($array) - 1;
  449.         foreach ($array as $go_key => $go) {
  450.             if (!is_array($go)) {
  451.                 $go = array('_loop_var' => $go);
  452.             } else {
  453.                 $go['_loop_var'] = '(array)'; // In case it's not a list of maps, but just a list
  454.             }
  455.  
  456.             if ((isset($param[2])) && ($col % $columns == 0) && ($col != 0)) {
  457.                 $value .= $row_starter;
  458.             }
  459.  
  460.             $ps = $go + array('_loop_key' => is_integer($go_key) ? strval($go_key) : $go_key, '_i' => strval($col), '_first' => $first, '_last' => $col == $max_index);
  461.             $args[0] = $ps + $args[0];
  462.             $args[0]['vars'] = $args[0];
  463.             $value .= call_user_func_array($main_function, $args);
  464.  
  465.             ++$col;
  466.             if ((isset($param[3])) && ($col % $columns == 0)) {
  467.                 $value .= $row_terminator;
  468.             }
  469.             $first = false;
  470.         }
  471.         if ((isset($param[2])) && ($col % $columns != 0)) {
  472.             $value .= $row_terminator;
  473.         }
  474.     }
  475.  
  476.     return $value;
  477. }
  478.  
  479. /**
  480.  * Convert a string to Tempcode.
  481.  *
  482.  * @param  string $string String
  483.  * @return Tempcode Tempcode
  484.  */
  485. function make_string_tempcode($string)
  486. {
  487.     static $generator_base = null;
  488.     static $generator_num = 0;
  489.     if ($generator_base === null) {
  490.         $generator_base = uniqid('', true);
  491.     }
  492.     $generator_num++;
  493.  
  494.     $myfunc = 'string_attach_' . $generator_base . '_' . strval($generator_num)/*We'll inline it actually rather than calling, for performance   fast_uniqid()*/
  495.     ;
  496.     $code_to_preexecute = array($myfunc => "\$tpl_funcs['$myfunc']=\"echo \\\"" . php_addslashes_twice($string) . "\\\";\";\n");
  497.     $seq_parts = array(array(array($myfunc, array(), TC_KNOWN, '', '')));
  498.     return new Tempcode(array($code_to_preexecute, $seq_parts));
  499. }
  500.  
  501. /**
  502.  * Add entity entity escaping to a string/Tempcode.
  503.  *
  504.  * @param  mixed $data String
  505.  * @return Tempcode Tempcode
  506.  */
  507. function escape_html_tempcode($data)
  508. {
  509.     // This is a bit of a hack, but it works. We don't want to have to have a route for altering Tempcode structure (because that has a performance hit, so we piggy-back on recursing through a null language string and add escaping when we do it)
  510.         return build_closure_tempcode(TC_LANGUAGE_REFERENCE, 'dont_escape_trick', array($data), array(FORCIBLY_ENTITY_ESCAPED));
  511. }
  512.  
  513. /**
  514.  * Apply whatever escaping is requested to the given value.
  515.  *
  516.  * @param  array $escaped A list of escaping to do
  517.  * @param  string $value The string to apply the escapings to
  518.  * @return string Output string (you do not need to collect this, as $value is pass-by-reference -- but this is useful for chaining)
  519.  */
  520. function apply_tempcode_escaping($escaped, &$value)
  521. {
  522.     static $charset = null;
  523.     if ($charset === null) {
  524.         $charset = get_charset();
  525.     }
  526.  
  527.     global $ESCAPE_HTML_OUTPUT;
  528.     foreach ($escaped as $escape) {
  529.         if ($escape === ENTITY_ESCAPED) {
  530.             if ((!isset($ESCAPE_HTML_OUTPUT[$value])/*not already auto-escaped once*/) || (!function_exists('has_solemnly_declared')) || (has_solemnly_declared(I_UNDERSTAND_XSS)/*no auto-escape*/)) {
  531.                 $value = htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
  532.             }
  533.         } elseif ($escape === FORCIBLY_ENTITY_ESCAPED) {
  534.             $value = htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
  535.         } elseif ($escape === SQ_ESCAPED) {
  536.             $value = str_replace('&#039;', '\&#039;', str_replace('\'', '\\\'', str_replace('\\', '\\\\', $value)));
  537.         } elseif ($escape === DQ_ESCAPED) {
  538.             $value = str_replace('&quot;', '\&quot;', str_replace('"', '\\"', str_replace('\\', '\\\\', $value)));
  539.         } elseif ($escape === NL_ESCAPED) {
  540.             $value = str_replace(array("\r", "\n"), array('', ''), $value);
  541.         } elseif ($escape === NL2_ESCAPED) {
  542.             $value = str_replace(array("\r", "\n"), array('', '\n'), $value);
  543.         } elseif ($escape === CC_ESCAPED) {
  544.             $value = str_replace('[', '\\[', str_replace('\\', '\\\\', $value));
  545.         } elseif ($escape === UL_ESCAPED) {
  546.             $value = cms_url_encode($value);
  547.         } elseif ($escape === UL2_ESCAPED) {
  548.             $value = rawurlencode($value);
  549.         } elseif ($escape === JSHTML_ESCAPED) {
  550.             $value = str_replace(']]>', ']]\'+\'>', str_replace('</', '<\/', $value));
  551.         } elseif ($escape === ID_ESCAPED) {
  552.             $value = fix_id($value);
  553.         } elseif ($escape === CSS_ESCAPED) {
  554.             $value = preg_replace('#[^\w\#\.\-\%]#', '_', $value);
  555.         } elseif ($escape === NAUGHTY_ESCAPED) {
  556.             $value = filter_naughty_harsh($value, true);
  557.         }
  558.     }
  559.     if (($GLOBALS['XSS_DETECT']) && ($escaped !== array())) {
  560.         ocp_mark_as_escaped($value);
  561.     }
  562.  
  563.     return $value;
  564. }
  565.  
  566. /**
  567.  * Apply whatever escaping is requested to the given value.
  568.  *
  569.  * @param  array $escaped A list of escaping to do
  570.  * @param  string $value The string to apply the escapings to
  571.  * @return string Output string
  572.  */
  573. function apply_tempcode_escaping_inline($escaped, $value)
  574. {
  575.     static $charset = null;
  576.     if ($charset === null) {
  577.         $charset = get_charset();
  578.     }
  579.  
  580.     global $ESCAPE_HTML_OUTPUT;
  581.     foreach ($escaped as $escape) {
  582.         if ($escape === ENTITY_ESCAPED) {
  583.             if ((!isset($ESCAPE_HTML_OUTPUT[$value])/*not already auto-escaped once*/) || (!function_exists('has_solemnly_declared')) || (has_solemnly_declared(I_UNDERSTAND_XSS)/*no auto-escape*/)) {
  584.                 $value = htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
  585.             }
  586.         } elseif ($escape === FORCIBLY_ENTITY_ESCAPED) {
  587.             $value = htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
  588.         } elseif ($escape === SQ_ESCAPED) {
  589.             $value = str_replace('&#039;', '\&#039;', str_replace('\'', '\\\'', str_replace('\\', '\\\\', $value)));
  590.         } elseif ($escape === DQ_ESCAPED) {
  591.             $value = str_replace('&quot;', '\&quot;', str_replace('"', '\\"', str_replace('\\', '\\\\', $value)));
  592.         } elseif ($escape === NL_ESCAPED) {
  593.             $value = str_replace(array("\r", "\n"), array('', ''), $value);
  594.         } elseif ($escape === NL2_ESCAPED) {
  595.             $value = str_replace(array("\r", "\n"), array('', '\n'), $value);
  596.         } elseif ($escape === CC_ESCAPED) {
  597.             $value = str_replace('[', '\\[', str_replace('\\', '\\\\', $value));
  598.         } elseif ($escape === UL_ESCAPED) {
  599.             $value = cms_url_encode($value);
  600.         } elseif ($escape === UL2_ESCAPED) {
  601.             $value = rawurlencode($value);
  602.         } elseif ($escape === JSHTML_ESCAPED) {
  603.             $value = str_replace(']]>', ']]\'+\'>', str_replace('</', '<\/', $value));
  604.         } elseif ($escape === ID_ESCAPED) {
  605.             $value = fix_id($value);
  606.         } elseif ($escape === CSS_ESCAPED) {
  607.             $value = preg_replace('#[^\w\#\.\-\%]#', '_', $value);
  608.         } elseif ($escape === NAUGHTY_ESCAPED) {
  609.             $value = filter_naughty_harsh($value, true);
  610.         }
  611.     }
  612.     if (($GLOBALS['XSS_DETECT']) && ($escaped !== array())) {
  613.         ocp_mark_as_escaped($value);
  614.     }
  615.  
  616.     return $value;
  617. }
  618.  
  619. /**
  620.  * This will create a new Tempcode object that is containing a single specifed language string ID
  621.  *
  622.  * @param  ID_TEXT $lang_string The ID of the language string to use
  623.  * @param  ?mixed $token1 The first token [string or Tempcode] (replaces {1}) (null: none)
  624.  * @param  ?mixed $token2 The second token [string or Tempcode] (replaces {2}) (null: none)
  625.  * @param  ?mixed $token3 The third token (replaces {3}). May be an array of [of string], to allow any number of additional args (null: none)
  626.  * @return Tempcode A language Tempcode object
  627.  */
  628. function do_lang_tempcode($lang_string, $token1 = null, $token2 = null, $token3 = null)
  629. {
  630.     $parameters = array();
  631.     if (isset($token1)) {
  632.         $parameters[] = $token1;
  633.     }
  634.     if (isset($token2)) {
  635.         $parameters[] = $token2;
  636.     }
  637.     if (isset($token3)) {
  638.         if (!is_array($token3)) {
  639.             $parameters[] = $token3;
  640.         } else {
  641.             $parameters = array_merge($parameters, $token3);
  642.         }
  643.     }
  644.  
  645.     return build_closure_tempcode(TC_LANGUAGE_REFERENCE, $lang_string, $parameters);
  646. }
  647.  
  648. /**
  649.  * Provide automatic escaping for a template call.
  650.  *
  651.  * @param  array $parameters Template parameters
  652.  */
  653. function kid_gloves_html_escaping(&$parameters)
  654. {
  655.     global $KNOWN_TRUE_HTML;
  656.  
  657.     $param = mixed();
  658.     foreach ($parameters as &$param) {
  659.         if (is_string($param)) {
  660.             if ((strpos($param, "'") !== false) || (strpos($param, '"') !== false) || (strpos($param, '<') !== false) || (strpos($param, '>') !== false)) {
  661.                 if (!isset($KNOWN_TRUE_HTML[$param])) {
  662.                     $param = escape_html($param);
  663.                 }
  664.             }
  665.         } elseif (is_array($param)) {
  666.             kid_gloves_html_escaping($param);
  667.         }
  668.     }
  669. }
  670.  
  671. /**
  672.  * Provide automatic escaping for a particular parameter.
  673.  *
  674.  * @param  string $param Parameter
  675.  */
  676. function kid_gloves_html_escaping_singular(&$param)
  677. {
  678.     global $KNOWN_TRUE_HTML;
  679.  
  680.     if ((strpos($param, "'") !== false) || (strpos($param, '"') !== false) || (strpos($param, '<') !== false) || (strpos($param, '>') !== false)) {
  681.         if (!isset($KNOWN_TRUE_HTML[$param])) {
  682.             $param = escape_html($param);
  683.         }
  684.     }
  685. }
  686.  
  687. /**
  688.  * Work out if we're doing a template preview op.
  689.  */
  690. function fill_template_preview_op_cache()
  691. {
  692.     global $IS_TEMPLATE_PREVIEW_OP_CACHE;
  693.     $IS_TEMPLATE_PREVIEW_OP_CACHE = array_key_exists('template_preview_op', $_POST) && ($_POST['template_preview_op'] == '1') && ((get_page_name() != 'admin_themes') || (get_param_string('type', '') == 'view'));
  694. }
  695.  
  696. /**
  697.  * Get a Tempcoded version of a Composr template. It is perhaps the most common Composr function to load up templates using do_template, and then attach them together either as parameters to each other, or via the Tempcode attach method.
  698.  *
  699.  * @param  ID_TEXT $codename The codename of the template being loaded
  700.  * @param  ?array $parameters A map of parameters for the template (key to value); you can have any number of parameters of any name, there is no set standard; having a _GUID parameter of random value is a convention (null: no parameters)
  701.  * @param  ?LANGUAGE_NAME $lang The language to load the template in (templates can embed language references) (null: users own language)
  702.  * @param  boolean $light_error Whether to not produce a stack dump if the template is missing
  703.  * @param  ?ID_TEXT $fallback Alternate template to use if the primary one does not exist (null: none)
  704.  * @param  string $suffix File type suffix of template file (e.g. .tpl)
  705.  * @set    .tpl .js .xml .txt .css
  706.  * @param  string $directory Subdirectory type to look in
  707.  * @set    templates javascript xml text css
  708.  * @param  ?ID_TEXT $theme Theme to use (null: current theme)
  709.  * @return Tempcode The Tempcode for this template
  710.  */
  711. function do_template($codename, $parameters = null, $lang = null, $light_error = false, $fallback = null, $suffix = '.tpl', $directory = 'templates', $theme = null)
  712. {
  713.     if (empty($lang)) {
  714.         global $USER_LANG_CACHED;
  715.         $lang = isset($USER_LANG_CACHED) ? $USER_LANG_CACHED : (function_exists('user_lang') ? user_lang() : 'EN');
  716.     }
  717.  
  718.     if ($GLOBALS['SEMI_DEV_MODE']) {
  719.         if (($codename === strtolower($codename)) && ($directory === 'templates')) {
  720.             fatal_exit('Template names should be in upper case, and the files should be stored in upper case (' . $codename . ').');
  721.         }
  722.  
  723.         if ($codename !== 'MENU_BRANCH_dropdown'/*optimisation*/) {
  724.             if ((substr($codename, -7) === '_SCREEN') || (substr($codename, -8) === '_OVERLAY') || ($codename === 'POOR_XHTML_WRAPPER')) {
  725.                 $GLOBALS['SCREEN_TEMPLATE_CALLED'] = $codename;
  726.             }
  727.         }
  728.     }
  729.  
  730.     if (($parameters !== null) && (function_exists('has_solemnly_declared')) && (!has_solemnly_declared(I_UNDERSTAND_XSS))) {
  731.         kid_gloves_html_escaping($parameters);
  732.     }
  733.  
  734.     global $IS_TEMPLATE_PREVIEW_OP_CACHE, $RECORD_TEMPLATES_USED, $RECORD_TEMPLATES_TREE, $RECORDED_TEMPLATES_USED, $FILE_ARRAY, $KEEP_MARKERS, $SHOW_EDIT_LINKS, $XHTML_SPIT_OUT, $CACHE_TEMPLATES, $FORUM_DRIVER, $POSSIBLY_IN_SAFE_MODE_CACHE, $USER_THEME_CACHE, $TEMPLATE_DISK_ORIGIN_CACHE, $LOADED_TPL_CACHE;
  735.     if ($IS_TEMPLATE_PREVIEW_OP_CACHE === null) {
  736.         fill_template_preview_op_cache();
  737.     }
  738.     $special_treatment = ((($KEEP_MARKERS) || ($SHOW_EDIT_LINKS)) && ($XHTML_SPIT_OUT === null));
  739.  
  740.     if ($RECORD_TEMPLATES_USED) {
  741.         $RECORDED_TEMPLATES_USED[] = $directory . '/' . $codename . $suffix;
  742.     }
  743.  
  744.     // Variables we'll need
  745.     if (!isset($theme)) {
  746.         $theme = isset($USER_THEME_CACHE) ? $USER_THEME_CACHE : (((isset($FORUM_DRIVER)) && (is_object($FORUM_DRIVER)) && (method_exists($FORUM_DRIVER, 'get_theme'))) ? filter_naughty($FORUM_DRIVER->get_theme()) : 'default');
  747.     }
  748.     $prefix_default = get_file_base() . '/themes/';
  749.     $prefix = get_custom_file_base() . '/themes/';
  750.  
  751.     // Is it structurally cached on disk yet?
  752.     if (!isset($TEMPLATE_DISK_ORIGIN_CACHE[$codename][$lang][$theme][$suffix][$directory])) {
  753.         $loaded_this_once = false;
  754.     } else {
  755.         $loaded_this_once = true;
  756.     }
  757.     $_data = mixed();
  758.     $_data = false;
  759.     if (($CACHE_TEMPLATES) && (/*the following relates to ensuring a full recompile for INCLUDEs except for CSS and JS*/
  760.             ($parameters === null) || ((!$RECORD_TEMPLATES_USED) && (!$RECORD_TEMPLATES_TREE))) && (!$IS_TEMPLATE_PREVIEW_OP_CACHE) && ((!$POSSIBLY_IN_SAFE_MODE_CACHE) || (isset($GLOBALS['SITE_INFO']['safe_mode'])) || (!in_safe_mode()))
  761.     ) {
  762.         if (!isset($TEMPLATE_DISK_ORIGIN_CACHE[$codename][$lang][$theme][$suffix][$directory])) {
  763.             $found = find_template_place($codename, $lang, $theme, $suffix, $directory);
  764.             $TEMPLATE_DISK_ORIGIN_CACHE[$codename][$lang][$theme][$suffix][$directory] = $found;
  765.         } else {
  766.             $found = $TEMPLATE_DISK_ORIGIN_CACHE[$codename][$lang][$theme][$suffix][$directory];
  767.         }
  768.  
  769.         if ($found !== null) {
  770.             $tcp_path = $prefix . $theme . '/templates_cached/' . $lang . '/' . $codename . $found[2] . '.tcp';
  771.  
  772.             if ($loaded_this_once) {
  773.                 if (isset($LOADED_TPL_CACHE[$codename][$theme])) {
  774.                     $_data = $LOADED_TPL_CACHE[$codename][$theme];
  775.                 } else {
  776.                     $_data = new Tempcode();
  777.                     $test = $_data->from_assembly_executed($tcp_path, array($codename, $codename, $lang, $theme, $suffix, $directory, $fallback));
  778.                     if (!$test) {
  779.                         $_data = false; // failed
  780.                     }
  781.                 }
  782.             } else {
  783.                 global $SITE_INFO;
  784.                 $support_smart_decaching = support_smart_decaching();
  785.                 if ($support_smart_decaching) {
  786.                     if (get_custom_file_base() !== get_file_base()) {
  787.                         $file_path = get_custom_file_base() . '/themes/' . $found[0] . $found[1] . $codename . $found[2];
  788.                         if (!is_file($file_path)) {
  789.                             $file_path = get_file_base() . '/themes/' . $found[0] . $found[1] . $codename . $found[2];
  790.                         }
  791.                     } else {
  792.                         $file_path = get_custom_file_base() . '/themes/' . $found[0] . $found[1] . $codename . $found[2];
  793.                     }
  794.                     if (GOOGLE_APPENGINE) {
  795.                         gae_optimistic_cache(true);
  796.                     }
  797.                     $tcp_time = @filemtime($tcp_path);
  798.                     if (GOOGLE_APPENGINE) {
  799.                         gae_optimistic_cache(false);
  800.                     }
  801.                 }
  802.                 if ((!$support_smart_decaching) || (($tcp_time !== false) && (is_file($file_path)))/*if in install can be found yet no file at path due to running from data.cms*/ && ($found !== null)) {
  803.                     if ((!$support_smart_decaching) || ((filemtime($file_path) < $tcp_time) && ((empty($SITE_INFO['dependency__' . $file_path])) || (dependencies_are_good(explode(',', $SITE_INFO['dependency__' . $file_path]), $tcp_time))))) {
  804.                         $_data = new Tempcode();
  805.                         $test = $_data->from_assembly_executed($tcp_path, array($codename, $codename, $lang, $theme, $suffix, $directory, $fallback));
  806.                         if (!$test) {
  807.                             $_data = false; // failed
  808.                         }
  809.                     }
  810.                 }
  811.             }
  812.         } else {
  813.             $_data = false;
  814.         }
  815.     }
  816.     if ($_data === false) { // No, it's not
  817.         if (!isset($TEMPLATE_DISK_ORIGIN_CACHE[$codename][$lang][$theme][$suffix][$directory])) {
  818.             $found = find_template_place($codename, $lang, $theme, $suffix, $directory);
  819.             $TEMPLATE_DISK_ORIGIN_CACHE[$codename][$lang][$theme][$suffix][$directory] = $found;
  820.         } else {
  821.             $found = $TEMPLATE_DISK_ORIGIN_CACHE[$codename][$lang][$theme][$suffix][$directory];
  822.         }
  823.  
  824.         unset($TEMPLATE_DISK_ORIGIN_CACHE[$codename][$lang][$theme][$suffix][$directory]);
  825.         if ($found === null) {
  826.             if ($fallback === null) {
  827.                 if ($light_error) {
  828.                     return paragraph(do_lang_tempcode('MISSING_TEMPLATE_FILE', escape_html($codename)), '34rwefwfdee');
  829.                 }
  830.                 fatal_exit(do_lang_tempcode('MISSING_TEMPLATE_FILE', escape_html($codename)));
  831.             } else {
  832.                 $result = do_template($fallback, $parameters, $lang);
  833.                 return $result;
  834.             }
  835.         } else {
  836.             require_code('tempcode_compiler');
  837.             $_data = _do_template($found[0], $found[1], $codename, $codename, $lang, $found[2], $theme);
  838.         }
  839.     }
  840.  
  841.     if ($loaded_this_once) {// On 3rd load (and onwards) it will be fully cached
  842.         $LOADED_TPL_CACHE[$codename][$theme] = $_data;
  843.     }
  844.  
  845.     if (!isset($parameters)) { // Streamlined if no parameters involved
  846.         $out = new Tempcode();
  847.         $out->codename = $codename;
  848.         $out->code_to_preexecute = $_data->code_to_preexecute;
  849.         if (!$GLOBALS['OUTPUT_STREAMING']) {
  850.             $out->preprocessable_bits = $_data->preprocessable_bits;
  851.         }
  852.         $out->seq_parts = $_data->seq_parts;
  853.  
  854.         foreach ($out->seq_parts as &$seq_parts_group) {
  855.             foreach ($seq_parts_group as &$seq_part) {
  856.                 if ($seq_part[1] !== array()) {
  857.                     $seq_part[1] = array();
  858.                 }
  859.             }
  860.         }
  861.  
  862.         return $out;
  863.     }
  864.  
  865.     $ret = $_data->bind($parameters, $codename);
  866.     if ($special_treatment) {
  867.         $ret->codename = '(mixed)'; // Stop optimisation that assumes the codename represents the sole content of it
  868.     }
  869.  
  870.     if ($special_treatment) {
  871.         if ($KEEP_MARKERS) {
  872.             $__data = new Tempcode();
  873.             $__data->attach('<!-- START-TEMPLATE=' . escape_html($codename) . ' -->');
  874.             $__data->attach($ret);
  875.             $__data->attach('<!-- END-TEMPLATE=' . escape_html($codename) . ' -->');
  876.             $ret = $__data;
  877.         }
  878.         if (($SHOW_EDIT_LINKS) && ($codename !== 'PARAM_INFO') && ($codename !== 'TEMPLATE_EDIT_LINK') && ($codename !== 'GLOBAL_HTML_WRAP'/*For some obscure reason letting this go through causes content to disappear, maybe because it has already started output streaming*/)) {
  879.             $edit_url = build_url(array('page' => 'admin_themes', 'type' => '_edit_templates', 'theme' => $theme, 'f0file' => $directory . '/' . $codename . $suffix), 'adminzone');
  880.  
  881.             $parameters2 = array();
  882.             foreach ($parameters as $k => $v) {
  883.                 if (is_array($v)) {
  884.                     $parameters2[$k] = '(array)';
  885.                 } elseif (!is_object($v)) {
  886.                     $parameters2[$k] = $v;
  887.                 } else {
  888.                     $parameters2[$k] = $v->evaluate();
  889.                     if (strlen($parameters2[$k]) > 100) {
  890.                         $parameters2[$k] = substr($parameters2[$k], 0, 100) . '...';
  891.                     }
  892.                 }
  893.             }
  894.             $param_info = do_template('PARAM_INFO', array('_GUID' => '0070acad5e82e0877ad49e25283d342e', 'MAP' => $parameters2));
  895.  
  896.             $ret = do_template('TEMPLATE_EDIT_LINK', array('_GUID' => '511ae911d31a5b237a4371ff22fc78fd', 'PARAM_INFO' => $param_info, 'CONTENTS' => $ret, 'CODENAME' => $codename, 'EDIT_URL' => $edit_url));
  897.         }
  898.     }
  899.  
  900.     return $ret;
  901. }
  902.  
  903. /**
  904.  * Do a smart decache dependency check for the case of multiple files.
  905.  *
  906.  * @param  array $dep Dependent files (full file paths)
  907.  * @param  TIME $tcp_time Time of cache file
  908.  * @return boolean Whether decache is NOT needed
  909.  */
  910. function dependencies_are_good($dep, $tcp_time)
  911. {
  912.     foreach ($dep as $d) {
  913.         if (@filemtime($d) > $tcp_time) {
  914.             return false;
  915.         }
  916.     }
  917.     return true;
  918. }
  919.  
  920. /**
  921.  * Certain symbols need preprocessing, before the output stream is made.
  922.  *
  923.  * @param  array $seq_part Symbol details
  924.  * @param  array $children Where we store children stuff
  925.  */
  926. function handle_symbol_preprocessing($seq_part, &$children)
  927. {
  928.     switch ($seq_part[2]) {
  929.         case 'PAGE_LINK':
  930.             $param = $seq_part[3];
  931.  
  932.             if (isset($param[0])) {
  933.                 if (isset($param[0]->codename/*faster than is_object*/)) {
  934.                     $param[0] = $param[0]->evaluate();
  935.                 }
  936.  
  937.                 list(, $url_parts,) = page_link_decode($param[0]);
  938.  
  939.                 if ((!isset($url_parts['id'])) && (!array_key_exists('id', $url_parts))) {
  940.                     return;
  941.                 }
  942.                 if ((!isset($url_parts['type'])) && (!array_key_exists('type', $url_parts))) {
  943.                     $url_parts['type'] = 'browse';
  944.                 }
  945.                 if ($url_parts['type'] === null) {
  946.                     $url_parts['type'] = 'browse'; // null means "do not take from environment"; so we default it to 'browse' (even though it might actually be left out when URL Schemes are off, we know it cannot be for URL Schemes)
  947.                 }
  948.                 if (!array_key_exists('page', $url_parts)) {
  949.                     return;
  950.                 }
  951.                 if ($url_parts['id'] === null) {
  952.                     $url_parts['id'] = strval(db_get_first_id());
  953.                 }
  954.  
  955.                 // Does this URL arrangement support monikers?
  956.                 global $LOADED_MONIKERS_CACHE;
  957.                 if (!isset($LOADED_MONIKERS_CACHE[$url_parts['type']][$url_parts['page']][$url_parts['id']])) {
  958.                     global $CONTENT_OBS;
  959.                     load_moniker_hooks();
  960.                     $found = false;
  961.                     $looking_for = '_SEARCH:' . $url_parts['page'] . ':' . $url_parts['type'] . ':_WILD';
  962.  
  963.                     $ob_info = isset($CONTENT_OBS[$looking_for]) ? $CONTENT_OBS[$looking_for] : null;
  964.                     if ($ob_info !== null) {
  965.                         $LOADED_MONIKERS_CACHE[$url_parts['type']][$url_parts['page']][$url_parts['id']] = true; // Indicator to preload this
  966.                     }
  967.                 }
  968.             }
  969.             return;
  970.  
  971.         case 'INCLUDE':
  972.             if ($GLOBALS['RECORD_TEMPLATES_USED'] || $GLOBALS['RECORD_TEMPLATES_TREE']) {
  973.                 $param = $seq_part[3];
  974.  
  975.                 if (!isset($param[1])) {
  976.                     $param[1] = make_string_tempcode('.tpl');
  977.                 }
  978.                 if (!isset($param[2])) {
  979.                     $param[2] = make_string_tempcode('templates');
  980.                 }
  981.  
  982.                 $tpl_path_descrip = (is_object($param[2]) ? $param[2]->evaluate() : $param[2]) . '/' . (is_object($param[0]) ? $param[0]->evaluate() : $param[0]) . (is_object($param[1]) ? $param[1]->evaluate() : $param[1]);
  983.  
  984.                 if ($GLOBALS['RECORD_TEMPLATES_USED']) {
  985.                     $GLOBALS['RECORDED_TEMPLATES_USED'][] = $tpl_path_descrip;
  986.                 }
  987.  
  988.                 if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  989.                     $param = $seq_part[3];
  990.                     $children[] = array(
  991.                         $tpl_path_descrip,
  992.                         isset($param[1]->children) ? $param[1]->children : array(),
  993.                         isset($param[1]->fresh) ? $param[1]->fresh : false
  994.                     );
  995.                 }
  996.             }
  997.             return;
  998.  
  999.         case 'SET_TITLE':
  1000.             $param = $seq_part[3];
  1001.  
  1002.             if (array_key_exists(0, $param)) {
  1003.                 get_screen_title(is_object($param[0]) ? $param[0]->evaluate() : $param[0], false);
  1004.             }
  1005.             return;
  1006.  
  1007.         case 'SET':
  1008.             $param = $seq_part[3];
  1009.  
  1010.             if (isset($param[1])) {
  1011.                 global $TEMPCODE_SETGET;
  1012.                 $param_copy = array();
  1013.                 foreach ($param as $i => $x) {
  1014.                     if ($i !== 0) {
  1015.                         $param_copy[] = isset($x->codename/*faster than is_object*/) ? $x->evaluate() : $x;
  1016.                     }
  1017.                 }
  1018.                 $TEMPCODE_SETGET[isset($param[0]->codename/*faster than is_object*/) ? $param[0]->evaluate() : $param[0]] = implode(',', $param_copy);
  1019.                 if (($GLOBALS['RECORD_TEMPLATES_TREE']) && (is_object($param[1]))) {
  1020.                     $children[] = array(':set: ' . (is_object($param[0]) ? $param[0]->evaluate() : $param[0]), isset($param[1]->children) ? $param[1]->children : array(), isset($param[1]->fresh) ? $param[1]->fresh : false);
  1021.                 }
  1022.             }
  1023.             return;
  1024.  
  1025.         case 'BLOCK':
  1026.             $param = $seq_part[3];
  1027.  
  1028.             foreach ($param as $i => $p) {
  1029.                 if (isset($p->codename/*faster than is_object*/)) {
  1030.                     $param[$i] = $p->evaluate();
  1031.                 }
  1032.             }
  1033.  
  1034.             if ((count($param) == 1) && (strpos($param[0], ',') !== false)) { // NB: This code is also in symbols.php
  1035.                 $param = block_params_str_to_arr($param[0], true);
  1036.             }
  1037.  
  1038.             if (in_array('defer=1', $param)) {
  1039.                 // Nothing has to be done here, except preparing for AJAX
  1040.                 require_javascript('ajax');
  1041.             } else {
  1042.                 global $REQUEST_BLOCK_NEST_LEVEL;
  1043.  
  1044.                 global $BLOCKS_CACHE;
  1045.                 if (isset($BLOCKS_CACHE[serialize($param)])) {
  1046.                     $REQUEST_BLOCK_NEST_LEVEL--;
  1047.                     return;
  1048.                 }
  1049.  
  1050.                 $REQUEST_BLOCK_NEST_LEVEL++;
  1051.                 if ($REQUEST_BLOCK_NEST_LEVEL > 40) { // 100 caused xdebug error, but Composr will have some overhead in both error handler and other code to get to here. We want xdebug error to not show, but of course to provide the same benefits as that error.
  1052.                     $REQUEST_BLOCK_NEST_LEVEL = 0;
  1053.                     $BLOCKS_CACHE[serialize($param)] = do_lang_tempcode('INTERNAL_ERROR');
  1054.                     attach_message(do_lang_tempcode('STOPPED_RECURSIVE_RESOURCE_INCLUDE', escape_html(is_string($param[0]) ? $param[0] : 'block'), escape_html(do_lang('BLOCK'))), 'warn');
  1055.                     return;
  1056.                 }
  1057.  
  1058.                 $block_parms = array();
  1059.                 foreach ($param as $_param) {
  1060.                     $block_parts = explode('=', $_param, 2);
  1061.                     if (!isset($block_parts[1])) {
  1062.                         $BLOCKS_CACHE[serialize($param)] = make_string_tempcode(do_lang('INTERNAL_ERROR') . ' (bad block parameter: ' . escape_html($_param) . ')');
  1063.                         return;
  1064.                     }
  1065.                     list($key, $val) = $block_parts;
  1066.                     $block_parms[$key] = $val;
  1067.                 }
  1068.  
  1069.                 if ((isset($_GET['keep_show_loading'])) && ($_GET['keep_show_loading'] == '1')) {
  1070.                     require_code('files');
  1071.                     $before = memory_get_usage();
  1072.                 }
  1073.                 if (isset($block_parms['block'])) {
  1074.                     $b_value = do_block($block_parms['block'], $block_parms);
  1075.                     if ((isset($_GET['keep_show_loading'])) && ($_GET['keep_show_loading'] == '1')) {
  1076.                         if (function_exists('attach_message')) {
  1077.                             attach_message('block: ' . $block_parms['block'] . ' (' . clean_file_size(memory_get_usage() - $before) . ' bytes used, now at ' . integer_format(memory_get_usage()) . ')', 'inform');
  1078.                         } else {
  1079.                             @ob_end_flush();
  1080.                             @ob_end_flush();
  1081.                             @ob_end_flush();
  1082.                             print('<!-- block: ' . htmlentities($block_parms['block']) . ' (' . htmlentities(clean_file_size(memory_get_usage() - $before)) . ' bytes used, now at ' . htmlentities(integer_format(memory_get_usage())) . ') -->' . "\n");
  1083.                             flush();
  1084.                         }
  1085.                     }
  1086.  
  1087.                     if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1088.                         $children[] = array(':block: ' . $block_parms['block'], array(array($b_value->codename, isset($b_value->children) ? $b_value->children : array(), isset($b_value->fresh) ? $b_value->fresh : false)), true);
  1089.                     }
  1090.                     $b_value->handle_symbol_preprocessing();
  1091.  
  1092.                     $BLOCKS_CACHE[serialize($param)] = $b_value;
  1093.                 }
  1094.  
  1095.                 $REQUEST_BLOCK_NEST_LEVEL--;
  1096.             }
  1097.  
  1098.             return;
  1099.  
  1100.         case 'REQUIRE_JAVASCRIPT':
  1101.             if (isset($param[0])) {
  1102.                 $param = $seq_part[3];
  1103.                 foreach ($param as $i => $p) {
  1104.                     if (is_object($p)) {
  1105.                         $param[$i] = $p->evaluate();
  1106.                     }
  1107.                 }
  1108.  
  1109.                 require_javascript($param[0]);
  1110.             }
  1111.             return;
  1112.  
  1113.         case 'FACILITATE_AJAX_BLOCK_CALL':
  1114.             require_javascript('ajax');
  1115.             return;
  1116.  
  1117.         case 'CSS_INHERIT':
  1118.  
  1119.         case 'REQUIRE_CSS':
  1120.             if (isset($param[0])) {
  1121.                 $param = $seq_part[3];
  1122.                 foreach ($param as $i => $p) {
  1123.                     if (is_object($p)) {
  1124.                         $param[$i] = $p->evaluate();
  1125.                     }
  1126.                 }
  1127.  
  1128.                 require_css($param[0]);
  1129.             }
  1130.             return;
  1131.  
  1132.         case 'TRIM':
  1133.         case 'PARAGRAPH':
  1134.             $param = $seq_part[3];
  1135.             if ((isset($param[0])) && (is_object($param[0]))) {
  1136.                 if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1137.                     $param[0]->handle_symbol_preprocessing();
  1138.                     $children[] = array(':trim', isset($param[0]->children) ? $param[0]->children : array(), isset($param[0]->fresh) ? $param[0]->fresh : false, true);
  1139.                 }
  1140.             }
  1141.             break;
  1142.  
  1143.         case 'LOAD_PANEL':
  1144.             $param = $seq_part[3];
  1145.             foreach ($param as $i => $p) {
  1146.                 if (is_object($p)) {
  1147.                     $param[$i] = $p->evaluate();
  1148.                 }
  1149.             }
  1150.  
  1151.             global $PANELS_CACHE;
  1152.             if (isset($PANELS_CACHE[serialize($param)])) {
  1153.                 return;
  1154.             }
  1155.  
  1156.             if (array_key_exists(0, $param)) {
  1157.                 if (substr(get_page_name(), 0, 6) !== 'panel_') {
  1158.                     if (strpos($param[0], ':') !== false) {
  1159.                         $param = array_reverse(explode(':', $param[0], 2));
  1160.                     }
  1161.                     if (substr($param[0], 0, 6) == 'panel_') {
  1162.                         $param[0] = substr($param[0], 6);
  1163.                     }
  1164.  
  1165.                     global $ZONE;
  1166.                     $wide_high = is_wide_high();
  1167.                     $wide = is_wide();
  1168.                     if ((($wide == 0) || (($wide_high == 0) && (($param[0] == 'bottom') || ($param[0] == 'top')))) && ((get_option('site_closed') == '0') || ($GLOBALS['IS_ACTUALLY_ADMIN']) || (has_privilege(get_member(), 'access_closed_site')))) {
  1169.                         if ((isset($_GET['keep_show_loading'])) && ($_GET['keep_show_loading'] == '1')) {
  1170.                             require_code('files');
  1171.                             $before = memory_get_usage();
  1172.                         }
  1173.                         $tp_value = request_page('panel_' . $param[0], false, array_key_exists(1, $param) ? $param[1] : null, null);
  1174.                         if ((isset($_GET['keep_show_loading'])) && ($_GET['keep_show_loading'] == '1')) {
  1175.                             if (function_exists('attach_message')) {
  1176.                                 attach_message('panel: ' . 'panel_' . $param[0] . ' (' . clean_file_size(memory_get_usage() - $before) . ' bytes used, now at ' . number_format(memory_get_usage()) . ')', 'inform');
  1177.                             } else {
  1178.                                 @ob_end_flush();
  1179.                                 @ob_end_flush();
  1180.                                 @ob_end_flush();
  1181.                                 print('<!-- panel: ' . htmlentities('panel_' . $param[0]) . ' (' . htmlentities(clean_file_size(memory_get_usage() - $before)) . ' bytes used, now at ' . htmlentities(number_format(memory_get_usage())) . ') -->' . "\n");
  1182.                                 flush();
  1183.                             }
  1184.                         }
  1185.  
  1186.                         $tp_value->handle_symbol_preprocessing();
  1187.                         if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1188.                             $children[] = array(':panel: ' . $param[0], array(array($tp_value->codename, isset($tp_value->children) ? $tp_value->children : array(), isset($tp_value->fresh) ? $tp_value->fresh : false)), true);
  1189.                         }
  1190.  
  1191.                         $value = $tp_value->evaluate();
  1192.                     } else {
  1193.                         $value = '';
  1194.                     }
  1195.                 } else {
  1196.                     $value = '';
  1197.                 }
  1198.             } else {
  1199.                 $value = '';
  1200.             }
  1201.  
  1202.             $PANELS_CACHE[serialize($param)] = $value;
  1203.  
  1204.             return;
  1205.  
  1206.         case 'JS_TEMPCODE':
  1207.             if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1208.                 $param = $seq_part[3];
  1209.                 foreach ($param as $i => $p) {
  1210.                     if (is_object($p)) {
  1211.                         $param[$i] = $p->evaluate();
  1212.                     }
  1213.                 }
  1214.  
  1215.                 $temp = javascript_tempcode(array_key_exists(0, $param) ? $param[0] : null);
  1216.  
  1217.                 $children[] = array(':container', isset($temp->children) ? $temp->children : array(), isset($temp->fresh) ? $temp->fresh : false);
  1218.             }
  1219.             return;
  1220.  
  1221.         case 'CSS_TEMPCODE':
  1222.             if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1223.                 $param = $seq_part[3];
  1224.  
  1225.                 $temp = css_tempcode();
  1226.  
  1227.                 $children[] = array(':container', isset($temp->children) ? $temp->children : array(), isset($temp->fresh) ? $temp->fresh : false);
  1228.             }
  1229.             return;
  1230.  
  1231.         case 'LOAD_PAGE':
  1232.             $param = $seq_part[3];
  1233.             foreach ($param as $i => $p) {
  1234.                 if (is_object($p)) {
  1235.                     $param[$i] = $p->evaluate();
  1236.                 }
  1237.             }
  1238.  
  1239.             global $PAGES_CACHE;
  1240.             if (array_key_exists(serialize($param), $PAGES_CACHE)) {
  1241.                 return;
  1242.             }
  1243.  
  1244.             if (array_key_exists(0, $param)) {
  1245.                 if (strpos($param[0], ':') !== false) {
  1246.                     $param = array_reverse(explode(':', $param[0], 2));
  1247.                 }
  1248.  
  1249.                 $being_included = (!array_key_exists(2, $param)) || ($param[2] == '1');
  1250.                 $virtual_state = (array_key_exists(3, $param)) && ($param[3] == '1');
  1251.  
  1252.                 if ((isset($_GET['keep_show_loading'])) && ($_GET['keep_show_loading'] == '1')) {
  1253.                     require_code('files');
  1254.                     $before = memory_get_usage();
  1255.                 }
  1256.  
  1257.                 $page = $param[0];
  1258.                 $zone = array_key_exists(1, $param) ? $param[1] : get_comcode_zone($param[0], false);
  1259.  
  1260.                 if ($virtual_state) {
  1261.                     // Virtualised state, so that any nested main_comcode_page_children blocks execute correctly
  1262.                     require_code('urls2');
  1263.                     list($old_get, $old_zone, $old_current_script) = set_execution_context(
  1264.                         array('page' => $page),
  1265.                         $zone
  1266.                     );
  1267.                 }
  1268.  
  1269.                 $tp_value = request_page($page, false, $zone, null, $being_included);
  1270.  
  1271.                 if ($virtual_state) {
  1272.                     $tp_value = make_string_tempcode($tp_value->evaluate());
  1273.  
  1274.                     // Get things back to prior state
  1275.                     set_execution_context(
  1276.                         $old_get,
  1277.                         $old_zone,
  1278.                         $old_current_script,
  1279.                         false
  1280.                     );
  1281.                 }
  1282.  
  1283.                 if ((isset($_GET['keep_show_loading'])) && ($_GET['keep_show_loading'] == '1')) {
  1284.                     if (function_exists('attach_message')) {
  1285.                         attach_message('page: ' . $param[0] . ' (' . clean_file_size(memory_get_usage() - $before) . ' bytes used, now at ' . number_format(memory_get_usage()) . ')', 'inform');
  1286.                     } else {
  1287.                         @ob_end_flush();
  1288.                         @ob_end_flush();
  1289.                         @ob_end_flush();
  1290.                         print('<!-- page: ' . htmlentities($param[0]) . ' (' . htmlentities(clean_file_size(memory_get_usage() - $before)) . ' bytes used, now at ' . htmlentities(number_format(memory_get_usage())) . ') -->' . "\n");
  1291.                         flush();
  1292.                     }
  1293.                 }
  1294.                 if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1295.                     $children[] = array(':page: ' . $param[0], isset($tp_value->children) ? $tp_value->children : array(), isset($tp_value->fresh) ? $tp_value->fresh : false);
  1296.                 }
  1297.             } else {
  1298.                 $tp_value = new Tempcode();
  1299.             }
  1300.  
  1301.             $PAGES_CACHE[serialize($param)] = $tp_value;
  1302.  
  1303.             return;
  1304.  
  1305.         case 'FRACTIONAL_EDITABLE':
  1306.             require_javascript('ajax');
  1307.             require_javascript('fractional_edit');
  1308.             return;
  1309.     }
  1310. }
  1311.  
  1312. /**
  1313.  * Tempcode (compiled implementation).
  1314.  *
  1315.  * @package    core
  1316.  */
  1317. class Tempcode
  1318. {
  1319.     public $code_to_preexecute;
  1320.     public $seq_parts; // List of list of closure pairs: (0) function name, and (1) parameters, (2) type, (3) name         We use a 2D list to make attach ops very fast
  1321.     public $preprocessable_bits; // List of tuples: escape (ignored), type (e.g. TC_SYMBOL), name, parameters
  1322.     public $pure_lang;
  1323.     public $evaluate_echo_offset_group = 0;
  1324.     public $evaluate_echo_offset_inner = 0;
  1325.  
  1326.     public $codename = ':container'; // The name of the template it came from
  1327.  
  1328.     public $preprocessed = false;
  1329.     public $cached_output;
  1330.  
  1331.     public $children = null, $fresh = null;
  1332.  
  1333.     /**
  1334.      * Constructor of Tempcode
  1335.      *
  1336.      * @param  ?array $details Pair: Code to preexecute, Initialisation seq-parts (null: start as empty)
  1337.      */
  1338.     public function __construct($details = null)
  1339.     {
  1340.         $this->cached_output = null;
  1341.  
  1342.         if (!isset($details)) {
  1343.             $this->preprocessable_bits = array();
  1344.             $this->seq_parts = array();
  1345.             $this->code_to_preexecute = array();
  1346.         } else {
  1347.             $this->code_to_preexecute = $details[0];
  1348.             $this->seq_parts = $details[1];
  1349.  
  1350.             if (!$GLOBALS['OUTPUT_STREAMING']) {
  1351.                 $pp_bits = array();
  1352.  
  1353.                 foreach ($this->seq_parts as $seq_parts_group) {
  1354.                     foreach ($seq_parts_group as $seq_part) {
  1355.                         if ($seq_part[2] === TC_SYMBOL) {
  1356.                             switch ($seq_part[3]) {
  1357.                                 case 'REQUIRE_CSS':
  1358.                                 case 'REQUIRE_JAVASCRIPT':
  1359.                                 case 'FACILITATE_AJAX_BLOCK_CALL':
  1360.                                 case 'JS_TEMPCODE':
  1361.                                 case 'CSS_TEMPCODE':
  1362.                                 case 'SET':
  1363.                                 case 'SET_TITLE':
  1364.                                 case 'BLOCK':
  1365.                                 case 'PAGE_LINK':
  1366.                                 case 'LOAD_PAGE':
  1367.                                 case 'LOAD_PANEL':
  1368.                                     $pp_bits[] = array(array(), TC_SYMBOL, $seq_part[3], $seq_part[1]);
  1369.                                     break;
  1370.                             }
  1371.                         } elseif ($seq_part[2] === TC_DIRECTIVE) {
  1372.                             switch ($seq_part[3]) {
  1373.                                 case 'INCLUDE':
  1374.                                 case 'FRACTIONAL_EDITABLE':
  1375.                                     $pp_bits[] = array(array(), TC_DIRECTIVE, $seq_part[3], $seq_part[1]);
  1376.                                     break;
  1377.                             }
  1378.                         }
  1379.                         foreach ($seq_part[1] as $param) {
  1380.                             if (isset($param->preprocessable_bits)) { // If is a Tempcode object
  1381.                                 foreach ($param->preprocessable_bits as $b) {
  1382.                                     $pp_bits[] = $b;
  1383.                                 }
  1384.                             }
  1385.                         }
  1386.                     }
  1387.                 }
  1388.  
  1389.                 $this->preprocessable_bits = $pp_bits;
  1390.             } else {
  1391.                 $this->preprocessable_bits = array();
  1392.             }
  1393.         }
  1394.  
  1395.         if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1396.             $this->fresh = true;
  1397.             $this->children = array();
  1398.         }
  1399.     }
  1400.  
  1401.     /**
  1402.      * PHP magic function to handle serialisation.
  1403.      *
  1404.      * @return array What is to be serialised
  1405.      */
  1406.     public function __sleep()
  1407.     {
  1408.         return array('code_to_preexecute', 'seq_parts', 'preprocessable_bits', 'pure_lang', 'codename');
  1409.     }
  1410.  
  1411.     /**
  1412.      * Remove any internal evaluation cachings within the object.
  1413.      */
  1414.     public function decache()
  1415.     {
  1416.         foreach ($this->seq_parts as &$seq_parts_group) {
  1417.             foreach ($seq_parts_group as &$seq_part) {
  1418.                 foreach ($seq_part[1] as $val) {
  1419.                     if (isset($val->codename/*faster than is_object*/)) {
  1420.                         $val->decache();
  1421.                     }
  1422.                 }
  1423.             }
  1424.         }
  1425.         $this->cached_output = null;
  1426.     }
  1427.  
  1428.     /**
  1429.      * Parse a single symbol from an input stream and append it.
  1430.      *
  1431.      * @param  string $code Code string (input stream)
  1432.      * @param  integer $pos Start position of input string
  1433.      * @param  integer $len End position of input string
  1434.      */
  1435.     public function parse_from(&$code, &$pos, &$len)
  1436.     {
  1437.         $this->cached_output = null;
  1438.         require_code('tempcode_compiler');
  1439.         $temp = template_to_tempcode(substr($code, $pos, $len - $pos), 0, false, '');
  1440.         $this->code_to_preexecute = $temp->code_to_preexecute;
  1441.         $this->seq_parts = $temp->seq_parts;
  1442.         $this->preprocessable_bits = $temp->preprocessable_bits;
  1443.     }
  1444.  
  1445.     /**
  1446.      * Attach the specified Tempcode to the right of the current Tempcode object.
  1447.      *
  1448.      * @param  mixed $attach The Tempcode/string to attach
  1449.      * @param  boolean $avoid_child_merge If we've already merged the children from what we're attaching into the child tree (at bind stage)
  1450.      */
  1451.     public function attach($attach, $avoid_child_merge = false)
  1452.     {
  1453.         if ($attach === '') {
  1454.             return;
  1455.         }
  1456.  
  1457.         unset($this->is_empty);
  1458.  
  1459.         $this->cached_output = null;
  1460.  
  1461.         if (isset($attach->codename)/*faster than is_object*/) { // Consider it another piece of Tempcode
  1462.             foreach ($attach->seq_parts as $seq_part_group) {
  1463.                 $this->seq_parts[] = $seq_part_group;
  1464.             }
  1465.  
  1466.             $this->code_to_preexecute += $attach->code_to_preexecute;
  1467.  
  1468.             if (!$GLOBALS['OUTPUT_STREAMING']) {
  1469.                 foreach ($attach->preprocessable_bits as $b) {
  1470.                     $this->preprocessable_bits[] = $b;
  1471.                 }
  1472.             }
  1473.  
  1474.             if ((!$avoid_child_merge) && ($GLOBALS['RECORD_TEMPLATES_TREE'])) {
  1475.                 $this->children[] = array($attach->codename, isset($attach->children) ? $attach->children : array(), isset($attach->fresh) ? $attach->fresh : false);
  1476.             }
  1477.         } else { // Consider it a string
  1478.             if (end($this->seq_parts) !== false) {
  1479.                 $end = &$this->seq_parts[key($this->seq_parts)];
  1480.                 if (end($end) !== false) {
  1481.                     $_end = &$end[key($end)];
  1482.                     if (($_end[2] === TC_KNOWN) && ($_end[1] === array())) { // Optimisation to save memory/storage-space/evaluation-time -- we can just append text
  1483.                         $myfunc = $_end[0];
  1484.                         if (isset($this->code_to_preexecute[$myfunc])) {
  1485.                             $code = $this->code_to_preexecute[$myfunc];
  1486.                             $pos2 = strpos($code, "\";\n");
  1487.                             if ($pos2 !== false) {
  1488.                                 $code = substr($code, 0, $pos2) . " echo \\\"" . php_addslashes_twice($attach) . "\\\";" . substr($code, $pos2);
  1489.                                 $this->code_to_preexecute[$myfunc] = $code;
  1490.                                 return;
  1491.                             }
  1492.                         }
  1493.                     }
  1494.                 }
  1495.             } else {
  1496.                 $this->seq_parts[] = array();
  1497.                 $end = &$this->seq_parts[0];
  1498.             }
  1499.  
  1500.             static $generator_base = null;
  1501.             static $generator_num = 0;
  1502.             if ($generator_base === null) {
  1503.                 $generator_base = uniqid('', true);
  1504.             }
  1505.             $generator_num++;
  1506.  
  1507.             $myfunc = 'string_attach_' . $generator_base . '_' . strval($generator_num);/*We'll inline it actually rather than calling, for performance   fast_uniqid()*/
  1508.             $funcdef = "\$tpl_funcs['$myfunc']=\"echo \\\"" . php_addslashes_twice($attach) . "\\\";\";\n";
  1509.             $this->code_to_preexecute[$myfunc] = $funcdef;
  1510.             $end[] = array($myfunc, array(), TC_KNOWN, '', '');
  1511.         }
  1512.  
  1513.         $this->codename = '(mixed)';
  1514.     }
  1515.  
  1516.     /**
  1517.      * Assemble the current Tempcode object into a single serialised (compiled) Tempcode storage representation (parameters and certain symbols and not evaluated). The output of the function is language-tied.
  1518.      *
  1519.      * @return string The assembly result
  1520.      */
  1521.     public function to_assembly()
  1522.     {
  1523.         require_code('tempcode_optimiser');
  1524.         optimise_tempcode($this);
  1525.  
  1526.         return 'return unserialize("' . php_addslashes(serialize(array($this->seq_parts, $this->preprocessable_bits, $this->codename, $this->pure_lang, $this->code_to_preexecute))) . '");' . "\n";
  1527.     }
  1528.  
  1529.     /**
  1530.      * The opposite of to_assembly - it decodes a Tempcode storage representation and turns it into a proper Tempcode object. This version handles the result of evaled code.
  1531.      *
  1532.      * @param  PATH $file The file to load
  1533.      * @param  array $forced_reload_details List of parameters for a forced reload if required
  1534.      * @return boolean Success status (it can fail, if the compiled cache file is corrupt)
  1535.      */
  1536.     public function from_assembly_executed($file, $forced_reload_details)
  1537.     {
  1538.         if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1539.             $this->fresh = false;
  1540.             $this->children = array();
  1541.         }
  1542.  
  1543.         $result = tempcode_include($file); // We don't eval on this because we want it to potentially be op-code cached by e.g. Zend Accelerator
  1544.         if (!is_array($result)) {
  1545.             return false; // May never get here, as PHP fatal errors can't be suppressed or skipped over
  1546.         }
  1547.  
  1548.         $this->cached_output = null;
  1549.         list($this->seq_parts, $this->preprocessable_bits, $this->codename, $this->pure_lang, $this->code_to_preexecute) = $result;
  1550.         if ($GLOBALS['OUTPUT_STREAMING']) {
  1551.             $this->preprocessable_bits = array();
  1552.         }
  1553.  
  1554.         if ($forced_reload_details[6] === null) {
  1555.             $forced_reload_details[6] = '';
  1556.         }
  1557.         if ((count($this->code_to_preexecute) > 10) && ($GLOBALS['CACHE_TEMPLATES'])) {
  1558.             // We don't actually use $code_to_preexecute, because it uses too much RAM and DB space throwing full templates into the caching. Instead we rewrite to custom load it whenever it's needed. This isn't inefficient due to normal opcode caching and optimizer opcode caching, and because we cache Tempcode object's evaluations at runtime so it can only happen once per screen view.
  1559.             $_file = (strpos($file, '\'') === false) ? $file : php_addslashes($file);
  1560.             $this->code_to_preexecute[] = 'if (($result=tempcode_include(\'' . $_file . '\'))===false) { $tmp=do_template(\'' . php_addslashes($forced_reload_details[0]) . '\',null,\'' . ((strpos($forced_reload_details[2], '\'') === false) ? $forced_reload_details[2] : php_addslashes($forced_reload_details[2])) . '\',false,\'' . (($forced_reload_details[6] === '') ? '' : ((strpos($forced_reload_details[6], '\'') === false) ? $forced_reload_details[6] : php_addslashes($forced_reload_details[6]))) . '\',\'' . ($forced_reload_details[4]) . '\',\'' . ($forced_reload_details[5]) . '\'); clearstatcache(); $tmp2=$GLOBALS[\'CACHE_TEMPLATES\']; if (!@is_file(\'' . $_file . '\')) { $GLOBALS[\'CACHE_TEMPLATES\']=false; } /*$GLOBALS[\'DEV_MODE\']?debug_eval($tmp->code_to_preexecute):*/eval($tmp->code_to_preexecute); $GLOBALS[\'CACHE_TEMPLATES\']=$tmp2; unset($tmp); }
  1561.            else { debug_eval($result[4]); unset($result); }';
  1562.             // NB: $GLOBALS[\'CACHE_TEMPLATES\']=false; is in case the template cache has been detected as broken, it prevents this branch running as it would fail again
  1563.         }
  1564.  
  1565.         if ($GLOBALS['XSS_DETECT']) {
  1566.             //$this->_mark_all_as_escaped();
  1567.         }
  1568.  
  1569.         return true;
  1570.     }
  1571.  
  1572.     /**
  1573.      * Recursively mark all parameters in this Tempcode as escaped. This is needed when loading from cache, as escape tainting data would have been lost.
  1574.      *
  1575.      * @param  boolean $top_level Whether this is the top-level call
  1576.      */
  1577.     protected function _mark_all_as_escaped($top_level = true)
  1578.     {
  1579.         static $done = array();
  1580.  
  1581.         foreach ($this->seq_parts as &$seq_parts_group) {
  1582.             foreach ($seq_parts_group as &$seq_part) {
  1583.                 if (!isset($seq_part[1]['_escaped'])) {
  1584.                     foreach ($seq_part[1] as &$val) {
  1585.                         if (is_string($val)) {
  1586.                             ocp_mark_as_escaped($val);
  1587.                         } elseif (is_object($val)) {
  1588.                             $val->_mark_all_as_escaped(false);
  1589.                         }
  1590.                     }
  1591.                     if (!isset($seq_part[1][0])) { // Only if it's a parameter map, not a parameter list
  1592.                         $seq_part[1]['_escaped'] = true; // Temporarily mark as escaped. Many seq_parts share a referenced list of parameters, and its naive/slow to re-mark for each
  1593.                     }
  1594.                     $done[] = &$seq_part[1];
  1595.                 }
  1596.             }
  1597.         }
  1598.  
  1599.         if ($top_level) {
  1600.             // Remove the escaping markers, as the escaping marking does not persist with serialisation
  1601.             foreach ($done as $d) {
  1602.                 unset($d['_escaped']);
  1603.             }
  1604.             $done = array();
  1605.         }
  1606.     }
  1607.  
  1608.     /**
  1609.      * The opposite of to_assembly - it decodes a Tempcode storage representation and turns it into a proper Tempcode object.
  1610.      *
  1611.      * @param  string $raw_data The assembled Tempcode
  1612.      * @param  boolean $allow_failure Return error code on failure, rather than exiting
  1613.      * @return boolean Success status (it can fail, if the compiled cache file is corrupt)
  1614.      */
  1615.     public function from_assembly(&$raw_data, $allow_failure = false)
  1616.     {
  1617.         if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1618.             $this->fresh = false;
  1619.             $this->children = array();
  1620.         }
  1621.  
  1622.         $result = /*$GLOBALS['DEV_MODE']?debug_eval($raw_data):*/@eval($raw_data);
  1623.         if ($result === false) {
  1624.             if ($allow_failure) {
  1625.                 return false;
  1626.             }
  1627.             fatal_exit(@strval($php_errormsg));
  1628.         }
  1629.  
  1630.         $this->cached_output = null;
  1631.         list($this->seq_parts, $this->preprocessable_bits, $this->codename, $this->pure_lang, $this->code_to_preexecute) = $result;
  1632.         if ($GLOBALS['OUTPUT_STREAMING']) {
  1633.             $this->preprocessable_bits = array();
  1634.         }
  1635.  
  1636.         if ($GLOBALS['XSS_DETECT']) {
  1637.             $this->_mark_all_as_escaped();
  1638.         }
  1639.  
  1640.         return true;
  1641.     }
  1642.  
  1643.     /**
  1644.      * Find whether a construct within this Tempcode is parameterless.
  1645.      *
  1646.      * @param  integer $at Offset to the construct
  1647.      * @return boolean Whether it is parameterless
  1648.      */
  1649.     public function parameterless($at)
  1650.     {
  1651.         $i = 0;
  1652.         foreach ($this->seq_parts as $seq_parts_group) {
  1653.             foreach ($seq_parts_group as $seq_part) {
  1654.                 if ($i === $at) {
  1655.                     return ($seq_part[1] === array());
  1656.                 }
  1657.                 $i++;
  1658.             }
  1659.         }
  1660.         return false;
  1661.     }
  1662.  
  1663.     /**
  1664.      * Bind the parameter bits, or recursively bind children (doesn't change self, returns a bound Tempcode object)
  1665.      *
  1666.      * @param  array $parameters Map of parameters to bind parameter bits to
  1667.      * @param  ID_TEXT $codename The codename of the template this Tempcode is from
  1668.      * @return Tempcode The new bound Tempcode object
  1669.      */
  1670.     public function bind(&$parameters, $codename)
  1671.     {
  1672.         if (!isset($parameters['_GUID'])) {
  1673.             $parameters['_GUID'] = '';
  1674.  
  1675.             $trace = debug_backtrace();
  1676.             $parameters['_GUID'] = isset($trace[3]) ? ($trace[3]['function'] . '/' . $trace[2]['function']) : (isset($trace[2]) ? $trace[2]['function'] : $trace[1]['function']);
  1677.         }
  1678.  
  1679.         $out = new Tempcode();
  1680.         $out->codename = $codename;
  1681.         $out->code_to_preexecute = $this->code_to_preexecute;
  1682.         if (!$GLOBALS['OUTPUT_STREAMING']) {
  1683.             foreach ($this->preprocessable_bits as $preprocessable_bit) {
  1684.                 foreach ($preprocessable_bit[3] as $i => $param) {
  1685.                     if ((($preprocessable_bit[2] !== 'SET') || (($i >= 1))) && (isset($param->codename/*faster than is_object*/))) {
  1686.                         $preprocessable_bit[3][$i] = $param->bind($parameters, '<' . $codename . '>');
  1687.                     }
  1688.                 }
  1689.                 $out->preprocessable_bits[] = $preprocessable_bit;
  1690.             }
  1691.         }
  1692.  
  1693.         if ($GLOBALS['RECORD_TEMPLATES_TREE']) {
  1694.             $out->children = isset($this->children) ? $this->children : array();
  1695.             foreach ($parameters as $key => $parameter) {
  1696.                 if (is_object($parameter)) {
  1697.                     if (count($parameter->preprocessable_bits) !== 0) {
  1698.                         $parameter->handle_symbol_preprocessing(); // Needed to force children to be populated. Otherwise it is possible but not definite that evaluation will result in children being pushed down.
  1699.                     }
  1700.                     $out->children[] = array($parameter->codename, isset($parameter->children) ? $parameter->children : array(), isset($parameter->fresh) ? $parameter->fresh : false);
  1701.                 } elseif ((is_string($parameter)) && ($key === '_GUID')) {
  1702.                     $out->children[] = array(':guid', array(array(':' . $parameter, array(), true)), true);
  1703.                 }
  1704.             }
  1705.         }
  1706.         foreach ($parameters as $key => $parameter) {
  1707.             $p_type = gettype($parameter);
  1708.             if ($p_type === 'string') {
  1709.                 // Performance, this is most likely
  1710.             } elseif ($p_type === 'object') {
  1711.                 if (isset($parameter->preprocessable_bits[0])) {
  1712.                     if (!$GLOBALS['OUTPUT_STREAMING']) {
  1713.                         foreach ($parameter->preprocessable_bits as $b) {
  1714.                             $out->preprocessable_bits[] = $b;
  1715.                         }
  1716.                     }
  1717.                 } elseif ($parameter->is_empty_shell()) {
  1718.                     $parameters[$key] = ''; // Little optimisation to save memory
  1719.                 }
  1720.             } elseif ($p_type === 'boolean') {
  1721.                 $parameters[$key] = $parameter ? '1' : '0';
  1722.             } elseif (($p_type !== 'array') && ($p_type !== 'NULL')) {
  1723.                 critical_error('PASSON', do_lang('NO_INTEGERS_TEMPLATE', escape_html($key)));
  1724.             }
  1725.         }
  1726.  
  1727.         $out->seq_parts[0] = array();
  1728.         foreach ($this->seq_parts as $seq_parts_group) {
  1729.             foreach ($seq_parts_group as $seq_part) {
  1730.                 if ((($seq_part[0][0] !== 's') || (substr($seq_part[0], 0, 14) !== 'string_attach_')) && ($seq_part[2] !== TC_LANGUAGE_REFERENCE)) {
  1731.                     $seq_part[1] = &$parameters; // & is to preserve memory
  1732.                 }
  1733.                 $out->seq_parts[0][] = $seq_part;
  1734.             }
  1735.         }
  1736.  
  1737.         return $out;
  1738.     }
  1739.  
  1740.     /**
  1741.      * Replace the named parameter with a specific value. Hardly used, but still important. Note that this will bind to all kinds of things that might not normally take named parameters, like symbols; this should not cause problems though.
  1742.      *
  1743.      * @param  string $parameter Named parameter
  1744.      * @param  Tempcode $value Specific value
  1745.      */
  1746.     public function singular_bind($parameter, $value)
  1747.     {
  1748.         $this->cached_output = null;
  1749.  
  1750.         if ($this->seq_parts === array()) {
  1751.             return;
  1752.         }
  1753.  
  1754.         foreach ($this->seq_parts as &$seq_parts_group) {
  1755.             foreach ($seq_parts_group as &$seq_part) {
  1756.                 if ((($seq_part[0][0] !== 's') || (substr($seq_part[0], 0, 14) !== 'string_attach_')) && ($seq_part[2] !== TC_LANGUAGE_REFERENCE)) {
  1757.                     $seq_part[1][$parameter] = $value;
  1758.                 }
  1759.             }
  1760.         }
  1761.  
  1762.         if (!$GLOBALS['OUTPUT_STREAMING']) {
  1763.             if (isset($value->preprocessable_bits)) { // Is Tempcode
  1764.                 foreach ($value->preprocessable_bits as $b) {
  1765.                     $this->preprocessable_bits[] = $b;
  1766.                 }
  1767.             }
  1768.         }
  1769.     }
  1770.  
  1771.     /**
  1772.      * Scan this Tempcode for anything that needs to be symbol-preprocessed
  1773.      */
  1774.     public function handle_symbol_preprocessing()
  1775.     {
  1776.         if ($GLOBALS['OUTPUT_STREAMING']) {
  1777.             return;
  1778.         }
  1779.         if (isset($this->preprocessed) && $this->preprocessed) {
  1780.             return;
  1781.         }
  1782.  
  1783.         foreach ($this->preprocessable_bits as $seq_part) {
  1784.             handle_symbol_preprocessing($seq_part, $this->children);
  1785.         }
  1786.  
  1787.         $this->preprocessed = true;
  1788.     }
  1789.  
  1790.     /**
  1791.      * Find whether the Tempcode object entirely empty (devoid of anything evaluable), not just evaluates as empty. This is also useful if you want to avoid early evaluation, which will mess up GET/SET flow.
  1792.      * Does not perform an evaluation, so will not trigger any early pre-processing or out-of-order evaluation.
  1793.      *
  1794.      * @return boolean Whether it is entirely empty
  1795.      */
  1796.     public function is_empty_shell()
  1797.     {
  1798.         foreach ($this->seq_parts as $seq_parts_group) {
  1799.             if (isset($seq_parts_group[0])) {
  1800.                 return false;
  1801.             }
  1802.         }
  1803.         return true;
  1804.     }
  1805.  
  1806.     /**
  1807.      * Find whether the Tempcode object is blank or not.
  1808.      *
  1809.      * @return boolean Whether the Tempcode object is empty
  1810.      */
  1811.     public function is_empty()
  1812.     {
  1813.         if ($this->cached_output !== null) {
  1814.             return strlen($this->cached_output) === 0;
  1815.         }
  1816.         if (isset($this->is_empty)) {
  1817.             return $this->is_empty;
  1818.         }
  1819.  
  1820.         if ($this->is_empty_shell()) { // Optimisation: empty
  1821.             $this->is_empty = true;
  1822.             return true;
  1823.         }
  1824.  
  1825.         ob_start();
  1826.  
  1827.         global $NO_EVAL_CACHE, $XSS_DETECT, $USER_LANG_CACHED, $KEEP_TPL_FUNCS, $MEMORY_OVER_SPEED, $FULL_RESET_VAR_CODE, $RESET_VAR_CODE, $DEV_MODE;
  1828.  
  1829.         if ($XSS_DETECT) {
  1830.             $before = @ini_get('ocproducts.xss_detect');
  1831.             safe_ini_set('ocproducts.xss_detect', '0');
  1832.         }
  1833.  
  1834.         $no_eval_cache_before = $NO_EVAL_CACHE;
  1835.  
  1836.         if (isset($USER_LANG_CACHED)) {
  1837.             $current_lang = $USER_LANG_CACHED;
  1838.         } else {
  1839.             if (!function_exists('user_lang')) {
  1840.                 require_code('lang');
  1841.             }
  1842.             $current_lang = user_lang();
  1843.         }
  1844.         $cl = $current_lang;
  1845.  
  1846.         $first_of_long = isset($this->seq_parts[0][3]) || isset($this->seq_parts[3]); // We set this to know not to dig right through to determine emptiness, as this wastes cache memory (it's a tradeoff)
  1847.         $tpl_funcs = $KEEP_TPL_FUNCS;
  1848.  
  1849.         foreach ($this->seq_parts as $seq_parts_group) {
  1850.             foreach ($seq_parts_group as $seq_part) {
  1851.                 $seq_part_0 = $seq_part[0];
  1852.                 /*if ($DEV_MODE) {
  1853.                     if (!isset($tpl_funcs[$seq_part_0])) {
  1854.                         debug_eval($this->code_to_preexecute[$seq_part_0], $tpl_funcs);
  1855.                     }
  1856.                     if (($tpl_funcs[$seq_part_0][0] !== 'e') && (function_exists($tpl_funcs[$seq_part_0]))) {
  1857.                         debug_call_user_func($tpl_funcs[$seq_part_0], $seq_part[1], $current_lang, $seq_part[4]);
  1858.                     } else {
  1859.                         $parameters = $seq_part[1];
  1860.                         debug_eval($tpl_funcs[$seq_part_0], $tpl_funcs, $parameters, $cl);
  1861.                     }
  1862.                 } else {*/
  1863.                 if (!isset($tpl_funcs[$seq_part_0])) {
  1864.                     eval($this->code_to_preexecute[$seq_part_0]);
  1865.                 }
  1866.                 if (($tpl_funcs[$seq_part_0][0] !== 'e'/*for echo*/) && (function_exists($tpl_funcs[$seq_part_0]))) {
  1867.                     call_user_func($tpl_funcs[$seq_part_0], $seq_part[1], $current_lang, $seq_part[4]);
  1868.                 } else {
  1869.                     $parameters = $seq_part[1];
  1870.                     eval($tpl_funcs[$seq_part_0]);
  1871.                 }
  1872.                 //}
  1873.  
  1874.                 if ((($first_of_long) || ($MEMORY_OVER_SPEED)) && (ob_get_length() > 0)) { // We only quick exit on the first iteration, as we know we likely didn't spend much time getting to it- anything more and we finish so that we can cache for later use by evaluate/evaluate_echo
  1875.                     @ob_end_clean();
  1876.                     if (!$no_eval_cache_before) {
  1877.                         $NO_EVAL_CACHE = $no_eval_cache_before;
  1878.                     }
  1879.                     if ($XSS_DETECT) {
  1880.                         safe_ini_set('ocproducts.xss_detect', $before);
  1881.                     }
  1882.                     $this->is_empty = false;
  1883.                     return false;
  1884.                 }
  1885.  
  1886.                 $first_of_long = false;
  1887.             }
  1888.         }
  1889.  
  1890.         $tmp = ob_get_clean();
  1891.         if ((!$MEMORY_OVER_SPEED) && (!$NO_EVAL_CACHE) && (!$GLOBALS['STUCK_ABORT_SIGNAL'])) {
  1892.             $this->cached_output = $tmp; // Optimisation to store it in here. We don't do the same for evaluate_echo as that's a final use case and hence it would be unnecessarily inefficient to store the result
  1893.  
  1894.             global $DECLARATIONS_STATE, $KNOWN_TRUE_HTML;
  1895.             if (defined('I_UNDERSTAND_XSS') && !$DECLARATIONS_STATE[I_UNDERSTAND_XSS]) {
  1896.                 $KNOWN_TRUE_HTML[$tmp] = true;
  1897.             }
  1898.         }
  1899.         if (!$no_eval_cache_before) {
  1900.             $NO_EVAL_CACHE = $no_eval_cache_before;
  1901.         }
  1902.         if ($XSS_DETECT) {
  1903.             safe_ini_set('ocproducts.xss_detect', $before);
  1904.         }
  1905.         $ret = ($tmp === '');
  1906.         $this->is_empty = $ret;
  1907.         return $ret;
  1908.     }
  1909.  
  1910.     /**
  1911.      * Parses the current Tempcode object, then return the parsed string
  1912.      *
  1913.      * @return string The evaluated thing.
  1914.      */
  1915.     public function __toString()
  1916.     {
  1917.         return $this->evaluate();
  1918.     }
  1919.  
  1920.     /**
  1921.      * Parses the current Tempcode object, then return the parsed string
  1922.      *
  1923.      * @param  ?LANGUAGE_NAME $current_lang The language to evaluate with (null: current user's language)
  1924.      * @return string The evaluated thing. Voila, it's all over!
  1925.      */
  1926.     public function evaluate($current_lang = null)
  1927.     {
  1928.         if (isset($this->cached_output)) {
  1929.             return $this->cached_output;
  1930.         }
  1931.         if ($this->is_empty_shell()) { // Optimisation: empty
  1932.             $this->cached_output = '';
  1933.             return '';
  1934.         }
  1935.  
  1936.         global $NO_EVAL_CACHE, $MEMORY_OVER_SPEED, $USER_LANG_CACHED, $XSS_DETECT, $KEEP_TPL_FUNCS, $FULL_RESET_VAR_CODE, $RESET_VAR_CODE, $DEV_MODE, $KNOWN_TRUE_HTML, $DECLARATIONS_STATE;
  1937.  
  1938.         ob_start();
  1939.  
  1940.         if ($XSS_DETECT) {
  1941.             $before = @ini_get('ocproducts.xss_detect');
  1942.             safe_ini_set('ocproducts.xss_detect', '0');
  1943.         }
  1944.  
  1945.         if ($current_lang === null) {
  1946.             if (isset($USER_LANG_CACHED)) {
  1947.                 $current_lang = $USER_LANG_CACHED;
  1948.             } else {
  1949.                 if (!function_exists('user_lang')) {
  1950.                     require_code('lang');
  1951.                 }
  1952.                 $current_lang = user_lang();
  1953.             }
  1954.         }
  1955.         $cl = $current_lang;
  1956.  
  1957.         $tpl_funcs = $KEEP_TPL_FUNCS;
  1958.         $no_eval_cache_before = $NO_EVAL_CACHE;
  1959.         foreach ($this->seq_parts as $seq_parts_group) {
  1960.             foreach ($seq_parts_group as $seq_part) {
  1961.                 $seq_part_0 = $seq_part[0];
  1962.                 /*if ($DEV_MODE) {
  1963.                     if (!isset($tpl_funcs[$seq_part_0])) {
  1964.                         debug_eval($this->code_to_preexecute[$seq_part_0], $tpl_funcs);
  1965.                     }
  1966.                     if (($tpl_funcs[$seq_part_0][0] !== 'e') && (function_exists($tpl_funcs[$seq_part_0]))) {
  1967.                         debug_call_user_func($tpl_funcs[$seq_part_0], $seq_part[1], $current_lang, $seq_part[4]);
  1968.                     } else {
  1969.                         $parameters = $seq_part[1];
  1970.                         debug_eval($tpl_funcs[$seq_part_0], $tpl_funcs, $parameters, $cl);
  1971.                     }
  1972.                 } else {*/
  1973.                 if (!isset($tpl_funcs[$seq_part_0])) {
  1974.                     eval($this->code_to_preexecute[$seq_part_0]);
  1975.                 }
  1976.                 if (($tpl_funcs[$seq_part_0][0] !== 'e'/*for echo*/) && (function_exists($tpl_funcs[$seq_part_0]))) {
  1977.                     call_user_func($tpl_funcs[$seq_part_0], $seq_part[1], $current_lang, $seq_part[4]);
  1978.                 } else {
  1979.                     $parameters = $seq_part[1];
  1980.                     eval($tpl_funcs[$seq_part_0]);
  1981.                 }
  1982.                 //}
  1983.             }
  1984.         }
  1985.  
  1986.         if ($XSS_DETECT) {
  1987.             safe_ini_set('ocproducts.xss_detect', $before);
  1988.         }
  1989.  
  1990.         $ret = ob_get_clean();
  1991.  
  1992.         if ((!$MEMORY_OVER_SPEED) && (!$NO_EVAL_CACHE) && (!$GLOBALS['STUCK_ABORT_SIGNAL'])) {
  1993.             $this->cached_output = $ret; // Optimisation to store it in here. We don't do the same for evaluate_echo as that's a final use case and hence it would be unnecessarily inefficient to store the result
  1994.         }
  1995.  
  1996.         if (!$no_eval_cache_before) {
  1997.             $NO_EVAL_CACHE = $no_eval_cache_before;
  1998.         }
  1999.  
  2000.         if (defined('I_UNDERSTAND_XSS') && !$DECLARATIONS_STATE[I_UNDERSTAND_XSS]) {
  2001.             $KNOWN_TRUE_HTML[$ret] = true;
  2002.         }
  2003.  
  2004.         return $ret;
  2005.     }
  2006.  
  2007.     /**
  2008.      * Parse the current Tempcode object, then echo it to the browser.
  2009.      *
  2010.      * @param  ?LANGUAGE_NAME $current_lang The language to evaluate with (null: current users language)
  2011.      * @param  boolean $stop_if_stuck Whether to stop if we are stuck of a seq_part with parameters yet-unbound, and to continue from last resume point
  2012.      * @return string Blank string. Allows chaining within echo statements
  2013.      */
  2014.     public function evaluate_echo($current_lang = null, $stop_if_stuck = false)
  2015.     {
  2016.         if (cms_srv('REQUEST_METHOD') === 'HEAD') {
  2017.             return '';
  2018.         }
  2019.  
  2020.         if ($this->cached_output !== null) {
  2021.             echo $this->cached_output;
  2022.             $this->cached_output = null; // Won't be needed again
  2023.             return '';
  2024.         }
  2025.         if ($this->is_empty_shell()) { // Optimisation: empty
  2026.             $this->cached_output = '';
  2027.             return '';
  2028.         }
  2029.  
  2030.         $cl = $current_lang;
  2031.         if ($cl === null) {
  2032.             $cl = user_lang();
  2033.         }
  2034.  
  2035.         global $KEEP_TPL_FUNCS, $FULL_RESET_VAR_CODE, $RESET_VAR_CODE, $STOP_IF_STUCK, $STUCK_ABORT_SIGNAL, $DEV_MODE, $TEMPCODE_OUTPUT_STARTED;
  2036.         $TEMPCODE_OUTPUT_STARTED = true;
  2037.         $tpl_funcs = $KEEP_TPL_FUNCS;
  2038.         $seq_parts_group_cnt = count($this->seq_parts);
  2039.         $i = &$this->evaluate_echo_offset_group; // A reference, so evaluate_echo_offset_group will go up naturally via looping of $i
  2040.         if ($stop_if_stuck) {
  2041.             $stop_if_stuck_bak = $STOP_IF_STUCK;
  2042.             $STOP_IF_STUCK = true;
  2043.             ob_start();
  2044.         }
  2045.         $first_i = true;
  2046.         for (; $i < $seq_parts_group_cnt; $i++) {
  2047.             $seq_parts_group = $this->seq_parts[$i];
  2048.  
  2049.             $seq_parts_cnt = count($seq_parts_group);
  2050.             if ($first_i) {
  2051.                 $j = &$this->evaluate_echo_offset_inner;
  2052.                 $first_i = false;
  2053.             } else {
  2054.                 $j = 0;
  2055.             }
  2056.             for (; $j < $seq_parts_cnt; $j++) {
  2057.                 $seq_part = $seq_parts_group[$j];
  2058.  
  2059.                 $seq_part_0 = $seq_part[0];
  2060.                 /*if ($DEV_MODE) {
  2061.                     if (!isset($tpl_funcs[$seq_part_0])) {
  2062.                         debug_eval($this->code_to_preexecute[$seq_part_0], $tpl_funcs);
  2063.                     }
  2064.                     if (($tpl_funcs[$seq_part_0][0] !== 'e') && (function_exists($tpl_funcs[$seq_part_0]))) {
  2065.                         debug_call_user_func($tpl_funcs[$seq_part_0], $seq_part[1], $current_lang, $seq_part[4]);
  2066.                     } else {
  2067.                         $parameters = $seq_part[1];
  2068.                         debug_eval($tpl_funcs[$seq_part_0], $tpl_funcs, $parameters, $cl);
  2069.                     }
  2070.                 } else {*/
  2071.                 if (!isset($tpl_funcs[$seq_part_0])) {
  2072.                     eval($this->code_to_preexecute[$seq_part_0]);
  2073.                 }
  2074.                 if (($tpl_funcs[$seq_part_0][0] !== 'e'/*for echo*/) && (function_exists($tpl_funcs[$seq_part_0]))) {
  2075.                     call_user_func($tpl_funcs[$seq_part_0], $seq_part[1], $current_lang, $seq_part[4]);
  2076.                 } else {
  2077.                     $parameters = $seq_part[1];
  2078.                     eval($tpl_funcs[$seq_part_0]);
  2079.                 }
  2080.                 //}
  2081.  
  2082.                 if ($stop_if_stuck) {
  2083.                     if ($STUCK_ABORT_SIGNAL) {
  2084.                         $STUCK_ABORT_SIGNAL = false;
  2085.                         ob_clean();
  2086.                         break 2;
  2087.                     } else {
  2088.                         ob_flush();
  2089.                     }
  2090.                 }
  2091.             }
  2092.         }
  2093.  
  2094.         if ($stop_if_stuck) {
  2095.             $STOP_IF_STUCK = $stop_if_stuck_bak;
  2096.             ob_end_flush();
  2097.         }
  2098.  
  2099.         flush();
  2100.  
  2101.         return '';
  2102.     }
  2103. }
  2104.  
  2105. /**
  2106.  * A template has not been structurally cached, so compile it and store in the cache.
  2107.  *
  2108.  * @param  string $id A randomised unique ID
  2109.  * @param  string $parameters Parameters
  2110.  * @param  string $code Function code
  2111.  * @return string The function reference
  2112.  *
  2113.  * @ignore
  2114.  */
  2115. function recall_named_function($id, $parameters, $code)
  2116. {
  2117.     $k = 'TEMPCODE_FUNCTION__' . $id;
  2118.     if (!isset($GLOBALS[$k])) {
  2119.         $GLOBALS[$k] = create_function($parameters, $code);
  2120.     }
  2121.     return $GLOBALS[$k];
  2122. }
  2123.  
  2124. /**
  2125.  * Include and evaluate the specified Tempcode file.
  2126.  *
  2127.  * @param  PATH $filepath The filename of the file to include.
  2128.  * @return mixed Success status or returned value.
  2129.  *
  2130.  * @ignore
  2131.  */
  2132. function tempcode_include($filepath)
  2133. {
  2134.     if (GOOGLE_APPENGINE) {
  2135.         gae_optimistic_cache(true);
  2136.         $ret = @include($filepath);
  2137.         gae_optimistic_cache(false);
  2138.     } else {
  2139.         $ret = @include($filepath);
  2140.     }
  2141.  
  2142.     return $ret;
  2143. }
  2144.  
  2145. /**
  2146.  * Evaluate some PHP, with ability to better debug.
  2147.  * In a way this can also quash problems, so only use when debugging. The "@" before eval turns off attach_message.
  2148.  *
  2149.  * @param  ?string $code Code to evaluate (null: code not found)
  2150.  * @param  ?array $tpl_funcs Evaluation code context (null: N/A)
  2151.  * @param  ?array $parameters Evaluation parameters (null: N/A)
  2152.  * @param  ?ID_TEXT $cl Language (null: N/A)
  2153.  * @return string Result
  2154.  *
  2155.  * @ignore
  2156.  */
  2157. function debug_eval($code, &$tpl_funcs = null, $parameters = null, $cl = null)
  2158. {
  2159.     global $NO_EVAL_CACHE, $XSS_DETECT, $KEEP_TPL_FUNCS, $FULL_RESET_VAR_CODE, $RESET_VAR_CODE;
  2160.  
  2161.     if ($code === null) {
  2162.         return ''; // HHVM issue
  2163.     }
  2164.     if ($code === '') {
  2165.         return ''; // Blank eval returns false
  2166.     }
  2167.     $result = @eval($code);
  2168.     if ($result === false) {
  2169.         if ($GLOBALS['DEV_MODE']) {
  2170.             $message = (isset($php_errormsg) ? ($php_errormsg . ' - ') : '') . $code;
  2171.             //@ob_end_clean(); @exit('!' . $message . '!');
  2172.             fatal_exit($message);
  2173.         }
  2174.         $result = '';
  2175.     }
  2176.     return $result;
  2177. }
  2178.  
  2179. /**
  2180.  * Call a PHP function, with ability to better debug.
  2181.  *
  2182.  * @param  string $function Function to call
  2183.  * @param  mixed $a First parameter
  2184.  * @param  ?mixed $b Second parameter (null: null/none)
  2185.  * @param  ?mixed $c Third parameter (null: null/none)
  2186.  * @return string Result
  2187.  *
  2188.  * @ignore
  2189.  */
  2190. function debug_call_user_func($function, $a, $b = null, $c = null)
  2191. {
  2192.     return call_user_func($function, $a, $b, $c);
  2193. }
  2194.  

Post

Posted
Rating:
#831
Guest user
Is this implemented on the upgrade now???


Brat Rat

Post

Posted
Rating:
#832
Yes
0 guests and 0 members have recently viewed this.