/** * Parse the template * * @param boolean $from_original * @param mixed $index_item * @param integer $min_level * @return string */ public final function parse($from_original = true, $index_item = null, $min_level = 1) { // Generate internal and random ignore tag (security reasons) if (is_null($this->__ignore_secret_tag)) { $this->__ignore_secret_tag = uniqid(); } self::createAuxiliarEngine($this); self::$__parse_level++; if (self::$__log_mode) { $this->logger("Parsing all..."); } $time_start = microtime(true); self::repairSubparsers(); // Calling the beforeParse hook $this->beforeParse(); if ($from_original == true) { if (self::$__log_mode) { $this->logger("Parsing from the original source"); } if (is_null($this->__src_original)) { $this->__src_original = $this->__src; } else { $this->__src = $this->__src_original; } } $subparsers_restore = array(); if (trim($this->__src) != "") { if (!is_null($index_item)) { if (self::$__log_mode) { $this->logger("Parsing with '{$index_item}' index of __items"); } $items = $this->__items[$index_item]; } else { $items = $this->__items; } if (is_null($items)) { $items = array(); } // Add global vars (self::$globals) foreach (self::$__globals as $var => $value) { if (!isset($items[$var])) { $items[$var] = $value; } } $items = array_merge($items, self::$__globals_design); $items = array_merge($items, self::getSystemData()); // Add properties $props = get_object_vars($this); foreach ($props as $prop => $value) { if (substr($prop, 0, 2) != "__") { $items[$prop] = $value; } } // Reserved vars if (!isset($items['_empty'])) { $items['_empty'] = array(); } if (!isset($items['_'])) { $items['_'] = array(); } if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false) { $this->parseSubParsers($items, array('moment' => DIV_MOMENT_BEFORE_PARSE)); } // Template's properties $this->loadTemplateProperties(); // Preparing dialect $this->__src = $this->prepareDialect(); if (strpos($this->__src, DIV_TAG_IGNORE_BEGIN) !== false || strpos($this->__src, '{' . $this->__ignore_secret_tag . '}') !== false) { $this->parseIgnore(); } if (strpos($this->__src, DIV_TAG_COMMENT_BEGIN) !== false) { $this->parseComments(); } if (strpos($this->__src, DIV_TAG_FRIENDLY_BEGIN) !== false) { $this->parseFriendly(); } $cycles2 = 0; $this->memory($items); $msg_infinite_cycle = 'Too many iterations of the parser: possible infinite cycle. Review your template code.'; $last_action = false; do { $cycles1 = 0; $cycles2++; if ($cycles2 > DIV_MAX_PARSE_CYCLES) { $this->error($msg_infinite_cycle, "FATAL"); } do { $checksum = crc32($this->__src); $this->__crc = $checksum; if (self::$__log_mode === true) { $this->logger('Template | size: ' . strlen($this->__src)); if (isset($this->__src[100])) { $this->logger('Template [checksum=' . $checksum . ']:' . htmlentities(str_replace("\n", " ", substr($this->__src, 0, 100)) . "..." . substr($this->__src, strlen($this->__src) - 100))); } else { $this->logger('Template [checksum=' . $checksum . ']: ' . htmlentities($this->__src)); } } $cycles1++; if ($cycles1 > DIV_MAX_PARSE_CYCLES) { $this->error($msg_infinite_cycle, "FATAL"); } $this->memory($items); // Conditional if (strpos($this->__src, DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX) !== false || strpos($this->__src, DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX) !== false) { $this->parseConditional($items); } // Conditions if (strpos($this->__src, DIV_TAG_CONDITIONS_BEGIN_PREFIX) !== false) { $this->parseConditions($items); } // Include if (strpos($this->__src, DIV_TAG_INCLUDE_BEGIN) !== false) { $this->parseInclude($items); if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false) { $this->parseSubParsers($items, array('moment' => DIV_MOMENT_AFTER_INCLUDE)); } if (strpos($this->__src, DIV_TAG_IGNORE_BEGIN) !== false || strpos($this->__src, '{' . $this->__ignore_secret_tag . '}') !== false) { $this->parseIgnore(); } if (strpos($this->__src, DIV_TAG_COMMENT_BEGIN) !== false) { $this->parseComments(); } if (strpos($this->__src, DIV_TAG_FRIENDLY_BEGIN) !== false) { $this->parseFriendly(); } $this->memory($items); } // Multiple variable's modifiers if (strpos($this->__src, DIV_TAG_MULTI_MODIFIERS_PREFIX) !== false && strpos($this->__src, DIV_TAG_MULTI_MODIFIERS_SUFFIX) !== false) { $this->parseMultipleModifiers(); } // Data in templates if (strpos($this->__src, DIV_TAG_TPLVAR_BEGIN) !== false) { if (strpos($this->__src, DIV_TAG_TPLVAR_END) !== false) { $items = array_merge($this->__memory, $items); $this->parseData($items); $this->memory($items); } } // Number format if (strpos($this->__src, DIV_TAG_NUMBER_FORMAT_PREFIX) !== false) { $this->parseNumberFormat($items); } // Preprocessed if (strpos($this->__src, DIV_TAG_PREPROCESSED_BEGIN) !== false) { $this->parsePreprocessed($items); $this->memory($items); } $items = array_merge($items, self::$__globals_design); // Default values in templates if (strpos($this->__src, DIV_TAG_DEFAULT_REPLACEMENT_BEGIN) !== false) { $this->parseDefaults($items); } // Macros if (strpos($this->__src, DIV_TAG_MACRO_BEGIN) !== false) { $items = array_merge($this->__memory, $items); $items = $this->parseMacros($items, $last_action); $this->memory($items); } // Lists if (strpos($this->__src, DIV_TAG_LOOP_BEGIN_PREFIX) !== false) { if (strpos($this->__src, DIV_TAG_LOOP_END_PREFIX) !== false) { if (strpos($this->__src, DIV_TAG_LOOP_END_SUFFIX) !== false) { $this->parseList($items); } } } $items = array_merge($items, self::$__globals_design); // Capsules if (strpos($this->__src, DIV_TAG_CAPSULE_BEGIN_PREFIX) !== false) { if (strpos($this->__src, DIV_TAG_CAPSULE_END_SUFFIX) !== false) { $this->parseCapsules($items); } } $items = array_merge($items, self::$__globals_design); // Make it again if (isset(self::$__remember[$checksum])) { $this->makeItAgain($checksum, $items); if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false) { $this->parseSubParsers($items, array('moment' => DIV_MOMENT_AFTER_REPLACE)); } } // Sub-Matches if (self::atLeastOneString($this->__src, self::$__modifiers)) { $this->parseSubmatches($items); } // Matches if (self::atLeastOneString($this->__src, self::$__modifiers) || strpos($this->__src, DIV_TAG_NUMBER_FORMAT_PREFIX) !== false && strpos($this->__src, DIV_TAG_NUMBER_FORMAT_SUFFIX) !== false) { $this->parseMatches($items, $last_action); } // Discard literal vars if (strpos($this->__src, DIV_TAG_IGNORE_BEGIN) !== false || strpos($this->__src, '{' . $this->__ignore_secret_tag . '}') !== false) { $this->parseIgnore(); } // Subparse: after replace if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false) { $this->parseSubParsers($items, array('moment' => DIV_MOMENT_AFTER_REPLACE)); } // Iterations if (strpos($this->__src, DIV_TAG_ITERATION_BEGIN_PREFIX) !== false) { if (strpos($this->__src, DIV_TAG_ITERATION_END) !== false) { $this->parseIterations($items); } } $nowcrc = crc32($this->__src); if ($checksum != $nowcrc) { $last_action = false; } } while ($checksum != $nowcrc); // Computing if (strpos($this->__src, DIV_TAG_FORMULA_BEGIN) !== false) { if (strpos($this->__src, DIV_TAG_FORMULA_END) !== false) { $this->parseFormulas($items); } } // Date format if (strpos($this->__src, DIV_TAG_DATE_FORMAT_PREFIX) !== false) { if (strpos($this->__src, DIV_TAG_DATE_FORMAT_SUFFIX) !== false) { $this->parseDateFormat($items); } } // Multiple replacements if (strpos($this->__src, DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX) !== false) { if (strpos($this->__src, DIV_TAG_MULTI_REPLACEMENT_END_PREFIX) !== false) { if (strpos($this->__src, DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX) !== false) { $this->parseMultiReplace($items); } } } // Searching orphan parts (conditions) if (strpos($this->__src, DIV_TAG_CONDITIONS_BEGIN_PREFIX) !== false) { $this->parseConditions($items, true); } // Div 4.5: One more time? Parsing orphans's parts while checksum not change. // (do it because the orphan's parts stop the parser and the results are ugly) // TODO: research best solution for this! (this is the second solution found) if ($checksum == crc32($this->__src) && self::$__parse_level <= $min_level) { $this->parseOrphanParts(); } $nowcrc = crc32($this->__src); // Last action? $last_action = $last_action === false && $nowcrc == $checksum; } while ($checksum != $nowcrc || $last_action === true); // Searching orphan parts (conditionals) if (strpos($this->__src, DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX) !== false || strpos($this->__src, DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX) !== false) { $this->parseOrphanParts(); } if (strpos($this->__src, DIV_TAG_IGNORE_BEGIN) !== false || strpos($this->__src, '{' . $this->__ignore_secret_tag . '}') !== false) { $this->parseIgnore(); } if (strpos($this->__src, DIV_TAG_COMMENT_BEGIN) !== false) { $this->parseComments(); } if (strpos($this->__src, DIV_TAG_FRIENDLY_BEGIN) !== false) { $this->parseFriendly(); } // Locations if (strpos($this->__src, DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX) !== false) { if (strpos($this->__src, DIV_TAG_LOCATION_BEGIN) !== false) { $this->parseLocations(); } } // Clear location's tags $allitems = null; if (strpos($this->__src, DIV_TAG_LOCATION_BEGIN) !== false) { $allitems = $this->getAllItems($items); $clear = self::getVarValue('div' . DIV_TAG_VAR_MEMBER_DELIMITER . 'clear_locations', $allitems); if (is_null($clear)) { $clear = true; } if ($clear) { $this->clearLocations(); } } // Restoring parsers requests foreach ($this->__restore as $restore_id => $rest) { $this->__src = str_replace('{' . $restore_id . '}', $rest, $this->__src); } $this->clean(); // The last action if (self::$__parse_level <= 1) { // Clear location's tags if (strpos($this->__src, DIV_TAG_LOCATION_BEGIN) !== false) { $this->clearLocations(); } $this->parseSpecialChars(); // Restoring ignored parts foreach (self::$__ignored_parts as $id => $ignore) { foreach (self::$__sub_parsers as $subparser => $function) { $tempunique = uniqid(); $rcount = 0; $tagsearch = DIV_TAG_SUBPARSER_BEGIN_PREFIX . $subparser . DIV_TAG_SUBPARSER_BEGIN_SUFFIX; $tagreplace = DIV_TAG_SUBPARSER_BEGIN_PREFIX . $tempunique . DIV_TAG_SUBPARSER_BEGIN_SUFFIX; $ignore = str_replace($tagsearch, $tagreplace, $ignore, $rcount); if ($rcount > 0) { $subparsers_restore[$tagsearch] = $tagreplace; } } $this->__src = str_replace('{' . $id . '}', $ignore, $this->__src); } // Restoring ignored parts inside values $items = $this->__memory; $vars = $this->getVars($items); foreach ($vars as $var) { $exp = self::getVarValue($var, $items); if (is_string($exp)) { foreach (self::$__ignored_parts as $id => $ignore) { $exp = str_replace('{' . $id . '}', $ignore, $exp); } self::setVarValue($var, $exp, $items); } } $this->__memory = $items; } } $this->txt(); if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false) { $items = array_merge($this->__memory, $items); $this->parseSubParsers($items, array('moment' => DIV_MOMENT_AFTER_PARSE, 'level' => self::$__parse_level)); $this->memory($items); } // Restore subparsers ignored foreach ($subparsers_restore as $tagsearch => $tag_replace) { $this->__src = str_replace($tagreplace, $tagsearch); } $time_end = microtime(true); if (self::$__log_mode) { $this->logger("Parser duration: " . number_format($time_end - $time_start, 5) . " secs"); } self::$__parse_duration = $time_end - $time_start; self::$__parse_level--; if (self::$__parse_level == 0) { $this->__items = array_merge($this->__items, $this->__memory); $this->__items = array_merge($this->__items, self::$__globals_design); self::$__globals_design = array(); self::$__globals_design_protected = array(); } // Calling the afterParse hook $this->afterParse(); }