Exemplo n.º 1
0
 /**
  * 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();
 }