PageRenderTime 50ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

/php-lib/div.php

https://github.com/pragres/cubay
PHP | 7863 lines | 6206 code | 802 blank | 855 comment | 1077 complexity | 196bfc3d1ac8a7d77e5a643527217da6 MD5 | raw file
  1. <?php
  2. /**
  3. * [[]] Div PHP Template Engine
  4. *
  5. * Div (division) is a template engine for PHP 5.x or higher and it is a social project
  6. * without spirit of lucre financed by Pragres (http://pragres.com)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  14. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  15. * for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program as the file LICENSE.txt; if not, please see
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  20. *
  21. * @author Rafael Rodriguez Ramirez <rafa@pragres.com>
  22. * @version : 4.5
  23. * @link http://divengine.com
  24. */
  25. /**
  26. * Constants
  27. *
  28. * PACKAGES The path of templates's root directory.
  29. * DIV_DEFAULT_TPL_FILE_EXT The default extension for template files
  30. * DIV_DEFAULT_DATA_FILE_EXT The default extension for data files
  31. * DIV_MAX_PARSE_CYCLES The max number of cycles of the parser (to prevent infinite loop and more)
  32. * DIV_MAX_FILENAME_SIZE The max size of file name or dir name in your operating system
  33. */
  34. if (! defined('PACKAGES'))
  35. define('PACKAGES', './');
  36. if (! defined('DIV_DEFAULT_TPL_FILE_EXT'))
  37. define('DIV_DEFAULT_TPL_FILE_EXT', 'tpl');
  38. if (! defined('DIV_DEFAULT_DATA_FILE_EXT'))
  39. define('DIV_DEFAULT_DATA_FILE_EXT', 'json');
  40. if (! defined('DIV_MAX_PARSE_CYCLES'))
  41. define('DIV_MAX_PARSE_CYCLES', 100);
  42. if (! defined('DIV_MAX_FILENAME_SIZE'))
  43. define('DIV_MAX_FILENAME_SIZE', 250);
  44. define('DIV_PHP_ALLOWED_FUNCTIONS', 'isset,empty,is_null,is_numeric,is_bool,is_integer,is_double,' . 'sizeof,is_finite,is_float,is_infinite,is_int,is_long,is_nan,' . 'is_real,is_scalar,is_string,mt_rand,mt_srand,mt_getrandmax,' . 'rand,urlencode,urldecode,uniqid,date,time,intval,htmlspecialchars,' . 'htmlspecialchars_decode,strtr,strpos,str_replace,str_ireplace,' . 'substr,sprintf,abs,acos,acosh,asin,atan2,atanh,base_convert,' . 'bindec,ceil,cos,cosh,decbin,dechex,decoct,deg2rad,exp,expm1,' . 'floor,fmod,getrandmax,hexdec,hypot,lcg_value,log10,log1p,log,' . 'max,min,octdec,pi,pow,rad2deg,rand,round,sin,sinh,sqrt,srand,' . 'tan,tanh,cal_days_in_month,cal_from_jd,cal_info,cal_to_jd,' . 'easter_date,easter_days,frenchtojd,gregoriantojd,jddayofweek,' . 'jdmonthname,jdtofrench,jdtogregorian,jdtojewish,jdtojulian,' . 'jdtounix,jewishtojd,jewishtojd,unixtojd,checkdate,' . 'date_default_timezone_get,strtotime,date_sunset,gmdate,gmmktime,' . 'gmstrftime,idate,microtime,mktime,strftime,strptime,strtotime,' . 'timezone_name_from_abbr,timezone_version_get,bcadd,bccomp,' . 'bcdiv,bcmod,bcmul,bcpow,bcpowmod,bcscale,bcsqrt,bcsub,addcslashes,' . 'addslashes,bin2hex,chop,chr,chunk_split,convert_cyr_string,' . 'convert_uudecode,convert_uuencode,count,count_chars,crc32,crypt,' . 'hebrev,hebrevc,hex2bin,html_entity_decode,htmlentities,' . 'htmlspecialchars_decode,htmlspecialchars,lcfirst,levenshtein,' . 'ltrim,md5,metaphone,money_format,nl_langinfo,nl2br,number_format,' . 'ord,quoted_printable_decode,quoted_printable_encode,quotemeta,' . 'rtrim,sha1,similar_text,soundex,sprintf,str_pad,str_repeat,' . 'str_rot13,str_shuffle,strcasecmp,strchr,strcmp,strcoll,strcspn,' . 'strip_tags,stripcslashes,stripos,stripslashes,stristr,strlen,' . 'strnatcasecmp,strnatcmp,strncasecmp,strncmp,strpbrk,strrchr,' . 'strrev,strripos,strrpos,strspn,strtolower,strtoupper,strtr,' . 'substr_compare,substr_count,substr_replace,trim,ucfirst,ucwords,' . 'wordwrap,floatval,strval,implode,explode');
  45. define('DIV_PHP_VALID_TOKENS_FOR_EXPRESSIONS', 'T_ARRAY,T_ARRAY_CAST,T_BOOLEAN_AND,T_BOOLEAN_OR,T_BOOL_CAST,' . 'T_CHARACTER,T_CONSTANT_ENCAPSED_STRING,T_DNUMBER,T_DOUBLE_CAST,' . 'T_EMPTY,T_INT_CAST,T_ISSET,T_IS_EQUAL,T_IS_GREATER_OR_EQUAL,' . 'T_SR,T_IS_IDENTICAL,T_IS_NOT_EQUAL,T_IS_NOT_IDENTICAL,' . 'T_IS_SMALLER_OR_EQUAL,T_LNUMBER,T_LOGICAL_AND,T_LOGICAL_OR,T_LOGICAL_XOR,' . 'T_SL,T_SL_EQUAL,T_SR_EQUAL,T_STRING_CAST,T_STRING_VARNAME,T_VARIABLE,' . 'T_WHITESPACE,T_CURLY_OPEN,T_INC,T_COMMENT,T_DOUBLE_ARROW,' . 'T_ENCAPSED_AND_WHITESPACE');
  46. define('DIV_PHP_VALID_TOKENS_FOR_MACROS', 'T_AS,T_DO,T_DOUBLE_COLON,T_ECHO,T_ELSE,T_ELSEIF,T_FOR,T_FOREACH,T_IF,' . 'T_MOD_EQUAL,T_MUL_EQUAL,T_OBJECT_OPERATOR,T_NUM_STRING,T_OR_EQUAL,' . 'T_PAAMAYIM_NEKUDOTAYIM,T_PLUS_EQUAL,T_PRINT,' . 'T_START_HEREDOC,T_SWITCH,T_WHILE,' . 'T_ENDIF,T_ENDFOR,T_ENDFOREACH,T_ENDSWITCH,T_ENDWHILE,T_END_HEREDOC,' . 'T_PAAMAYIM_NEKUDOTAYIM');
  47. define('DIV_PHP_ALLOWED_METHODS', 'getRanges,asThis,atLeastOneString,getLastKeyOfArray,getCountOfParagraphs,getCountOfSentences,getCountOfWords,' . 'htmlToText,isArrayOfArray,isArrayOfObjects,isCli,isNumericList,jsonDecode,jsonEncode,isString,mixedBool');
  48. define('DIV_ERROR_WARNING', 'WARNING');
  49. define('DIV_ERROR_FATAL', 'FATAL');
  50. define('DIV_METHOD_NOT_EXISTS', 'DIV_METHOD_NOT_EXISTS');
  51. define('DIV_UNICODE_ERROR', - 1);
  52. define('DIV_MOMENT_BEFORE_PARSE', 'DIV_MOMENT_BEFORE_PARSE');
  53. define('DIV_MOMENT_AFTER_PARSE', 'DIV_MOMENT_AFTER_PARSE');
  54. define('DIV_MOMENT_AFTER_INCLUDE', 'DIV_MOMENT_AFTER_INCLUDE');
  55. define('DIV_MOMENT_AFTER_REPLACE', 'DIV_MOMENT_AFTER_REPLACE');
  56. // ------------------------------------- D E F A U L T D I A L E C T --------------------------------------//
  57. if (! defined('DIV_TAG_REPLACEMENT_PREFIX'))
  58. define('DIV_TAG_REPLACEMENT_PREFIX', '{'); // Variables
  59. if (! defined('DIV_TAG_REPLACEMENT_SUFFIX'))
  60. define('DIV_TAG_REPLACEMENT_SUFFIX', '}');
  61. if (! defined('DIV_TAG_MULTI_MODIFIERS_PREFIX'))
  62. define('DIV_TAG_MULTI_MODIFIERS_PREFIX', '{$');
  63. if (! defined('DIV_TAG_MULTI_MODIFIERS_OPERATOR'))
  64. define('DIV_TAG_MULTI_MODIFIERS_OPERATOR', '|');
  65. if (! defined('DIV_TAG_MULTI_MODIFIERS_SEPARATOR'))
  66. define('DIV_TAG_MULTI_MODIFIERS_SEPARATOR', '|');
  67. if (! defined('DIV_TAG_MULTI_MODIFIERS_SUFFIX'))
  68. define('DIV_TAG_MULTI_MODIFIERS_SUFFIX', '|}');
  69. if (! defined('DIV_TAG_SUBMATCH_SEPARATOR'))
  70. define('DIV_TAG_SUBMATCH_SEPARATOR', ':');
  71. if (! defined('DIV_TAG_MODIFIER_SIMPLE'))
  72. define('DIV_TAG_MODIFIER_SIMPLE', '$'); // Variable's modifiers
  73. if (! defined('DIV_TAG_MODIFIER_CAPITALIZE_FIRST'))
  74. define('DIV_TAG_MODIFIER_CAPITALIZE_FIRST', '^');
  75. if (! defined('DIV_TAG_MODIFIER_CAPITALIZE_WORDS'))
  76. define('DIV_TAG_MODIFIER_CAPITALIZE_WORDS', '^^');
  77. if (! defined('DIV_TAG_MODIFIER_UPPERCASE'))
  78. define('DIV_TAG_MODIFIER_UPPERCASE', '^^^');
  79. if (! defined('DIV_TAG_MODIFIER_LOWERCASE'))
  80. define('DIV_TAG_MODIFIER_LOWERCASE', '_');
  81. if (! defined('DIV_TAG_MODIFIER_LENGTH'))
  82. define('DIV_TAG_MODIFIER_LENGTH', '%');
  83. if (! defined('DIV_TAG_MODIFIER_COUNT_WORDS'))
  84. define('DIV_TAG_MODIFIER_COUNT_WORDS', '%%');
  85. if (! defined('DIV_TAG_MODIFIER_COUNT_SENTENCES'))
  86. define('DIV_TAG_MODIFIER_COUNT_SENTENCES', '%%%');
  87. if (! defined('DIV_TAG_MODIFIER_COUNT_PARAGRAPHS'))
  88. define('DIV_TAG_MODIFIER_COUNT_PARAGRAPHS', '%%%%');
  89. if (! defined('DIV_TAG_MODIFIER_ENCODE_URL'))
  90. define('DIV_TAG_MODIFIER_ENCODE_URL', '&');
  91. if (! defined('DIV_TAG_MODIFIER_ENCODE_RAW_URL'))
  92. define('DIV_TAG_MODIFIER_ENCODE_RAW_URL', '&&');
  93. if (! defined('DIV_TAG_MODIFIER_ENCODE_JSON'))
  94. define('DIV_TAG_MODIFIER_ENCODE_JSON', 'json:');
  95. if (! defined('DIV_TAG_MODIFIER_HTML_ENTITIES'))
  96. define('DIV_TAG_MODIFIER_HTML_ENTITIES', 'html:');
  97. if (! defined('DIV_TAG_MODIFIER_NL2BR'))
  98. define('DIV_TAG_MODIFIER_NL2BR', 'br:');
  99. if (! defined('DIV_TAG_MODIFIER_TRUNCATE'))
  100. define('DIV_TAG_MODIFIER_TRUNCATE', '~');
  101. if (! defined('DIV_TAG_MODIFIER_WORDWRAP'))
  102. define('DIV_TAG_MODIFIER_WORDWRAP', '/');
  103. if (! defined('DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR'))
  104. define('DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR', ',');
  105. if (! defined('DIV_TAG_MODIFIER_SINGLE_QUOTES'))
  106. define('DIV_TAG_MODIFIER_SINGLE_QUOTES', "'");
  107. if (! defined('DIV_TAG_MODIFIER_JS'))
  108. define('DIV_TAG_MODIFIER_JS', "js:");
  109. if (! defined('DIV_TAG_MODIFIER_FORMAT'))
  110. define('DIV_TAG_MODIFIER_FORMAT', '');
  111. if (! defined('DIV_TAG_DATE_FORMAT_PREFIX'))
  112. define('DIV_TAG_DATE_FORMAT_PREFIX', '{/'); // Data format
  113. if (! defined('DIV_TAG_DATE_FORMAT_SUFFIX'))
  114. define('DIV_TAG_DATE_FORMAT_SUFFIX', '/}');
  115. if (! defined('DIV_TAG_DATE_FORMAT_SEPARATOR'))
  116. define('DIV_TAG_DATE_FORMAT_SEPARATOR', ':');
  117. if (! defined('DIV_TAG_NUMBER_FORMAT_PREFIX'))
  118. define('DIV_TAG_NUMBER_FORMAT_PREFIX', '{#');
  119. if (! defined('DIV_TAG_NUMBER_FORMAT_SUFFIX'))
  120. define('DIV_TAG_NUMBER_FORMAT_SUFFIX', '#}');
  121. if (! defined('DIV_TAG_NUMBER_FORMAT_SEPARATOR'))
  122. define('DIV_TAG_NUMBER_FORMAT_SEPARATOR', ':');
  123. if (! defined('DIV_TAG_FORMULA_BEGIN'))
  124. define('DIV_TAG_FORMULA_BEGIN', '(#'); // Formulas
  125. if (! defined('DIV_TAG_FORMULA_END'))
  126. define('DIV_TAG_FORMULA_END', '#)');
  127. if (! defined('DIV_TAG_FORMULA_FORMAT_SEPARATOR'))
  128. define('DIV_TAG_FORMULA_FORMAT_SEPARATOR', ':');
  129. if (! defined('DIV_TAG_SUBPARSER_BEGIN_PREFIX'))
  130. define('DIV_TAG_SUBPARSER_BEGIN_PREFIX', '{'); // Sub-parsers
  131. if (! defined('DIV_TAG_SUBPARSER_BEGIN_SUFFIX'))
  132. define('DIV_TAG_SUBPARSER_BEGIN_SUFFIX', '}');
  133. if (! defined('DIV_TAG_SUBPARSER_END_PREFIX'))
  134. define('DIV_TAG_SUBPARSER_END_PREFIX', '{/');
  135. if (! defined('DIV_TAG_SUBPARSER_END_SUFFIX'))
  136. define('DIV_TAG_SUBPARSER_END_SUFFIX', '}');
  137. if (! defined('DIV_TAG_IGNORE_BEGIN'))
  138. define('DIV_TAG_IGNORE_BEGIN', '{ignore}'); // Ignored parts
  139. if (! defined('DIV_TAG_IGNORE_END'))
  140. define('DIV_TAG_IGNORE_END', '{/ignore}');
  141. if (! defined('DIV_TAG_COMMENT_BEGIN'))
  142. define('DIV_TAG_COMMENT_BEGIN', '<!--{'); // Comments
  143. if (! defined('DIV_TAG_COMMENT_END'))
  144. define('DIV_TAG_COMMENT_END', '}-->');
  145. if (! defined('DIV_TAG_TXT_BEGIN'))
  146. define('DIV_TAG_TXT_BEGIN', '{txt}'); // HTML to Plain text
  147. if (! defined('DIV_TAG_TXT_END'))
  148. define('DIV_TAG_TXT_END', '{/txt}');
  149. if (! defined('DIV_TAG_TXT_WIDTH_SEPARATOR'))
  150. define('DIV_TAG_TXT_WIDTH_SEPARATOR', '=>');
  151. if (! defined('DIV_TAG_STRIP_BEGIN'))
  152. define('DIV_TAG_STRIP_BEGIN', '{strip}'); // Strip
  153. if (! defined('DIV_TAG_STRIP_END'))
  154. define('DIV_TAG_STRIP_END', '{/strip}');
  155. if (! defined('DIV_TAG_LOOP_BEGIN_PREFIX'))
  156. define('DIV_TAG_LOOP_BEGIN_PREFIX', '[$'); // Loops
  157. if (! defined('DIV_TAG_LOOP_BEGIN_SUFFIX'))
  158. define('DIV_TAG_LOOP_BEGIN_SUFFIX', ']');
  159. if (! defined('DIV_TAG_LOOP_END_PREFIX'))
  160. define('DIV_TAG_LOOP_END_PREFIX', '[/$');
  161. if (! defined('DIV_TAG_LOOP_END_SUFFIX'))
  162. define('DIV_TAG_LOOP_END_SUFFIX', ']');
  163. if (! defined('DIV_TAG_EMPTY'))
  164. define('DIV_TAG_EMPTY', '@empty@');
  165. if (! defined('DIV_TAG_BREAK'))
  166. define('DIV_TAG_BREAK', '@break@');
  167. if (! defined('DIV_TAG_LOOP_VAR_SEPARATOR'))
  168. define('DIV_TAG_LOOP_VAR_SEPARATOR', '=>');
  169. if (! defined('DIV_TAG_ITERATION_BEGIN_PREFIX'))
  170. define('DIV_TAG_ITERATION_BEGIN_PREFIX', '[:'); // Iterations
  171. if (! defined('DIV_TAG_ITERATION_BEGIN_SUFFIX'))
  172. define('DIV_TAG_ITERATION_BEGIN_SUFFIX', ':]');
  173. if (! defined('DIV_TAG_ITERATION_END'))
  174. define('DIV_TAG_ITERATION_END', '[/]');
  175. if (! defined('DIV_TAG_ITERATION_PARAM_SEPARATOR'))
  176. define('DIV_TAG_ITERATION_PARAM_SEPARATOR', ',');
  177. if (! defined('DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX'))
  178. define('DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX', '?$'); // Conditional parts
  179. if (! defined('DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX'))
  180. define('DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX', '');
  181. if (! defined('DIV_TAG_CONDITIONAL_TRUE_END_PREFIX'))
  182. define('DIV_TAG_CONDITIONAL_TRUE_END_PREFIX', '$');
  183. if (! defined('DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX'))
  184. define('DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX', '?');
  185. if (! defined('DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX'))
  186. define('DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX', '!$');
  187. if (! defined('DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX'))
  188. define('DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX', '');
  189. if (! defined('DIV_TAG_CONDITIONAL_FALSE_END_PREFIX'))
  190. define('DIV_TAG_CONDITIONAL_FALSE_END_PREFIX', '$');
  191. if (! defined('DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX'))
  192. define('DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX', '!');
  193. if (! defined('DIV_TAG_ELSE'))
  194. define('DIV_TAG_ELSE', '@else@');
  195. if (! defined('DIV_TAG_CONDITIONS_BEGIN_PREFIX'))
  196. define('DIV_TAG_CONDITIONS_BEGIN_PREFIX', '{?('); // Conditions
  197. if (! defined('DIV_TAG_CONDITIONS_BEGIN_SUFFIX'))
  198. define('DIV_TAG_CONDITIONS_BEGIN_SUFFIX', ')?}');
  199. if (! defined('DIV_TAG_CONDITIONS_END'))
  200. define('DIV_TAG_CONDITIONS_END', '{/?}');
  201. if (! defined('DIV_TAG_TPLVAR_BEGIN'))
  202. define('DIV_TAG_TPLVAR_BEGIN', '{='); // Template vars
  203. if (! defined('DIV_TAG_TPLVAR_END'))
  204. define('DIV_TAG_TPLVAR_END', '=}');
  205. if (! defined('DIV_TAG_TPLVAR_ASSIGN_OPERATOR'))
  206. define('DIV_TAG_TPLVAR_ASSIGN_OPERATOR', ':');
  207. if (! defined('DIV_TAG_TPLVAR_PROTECTOR'))
  208. define('DIV_TAG_TPLVAR_PROTECTOR', '*');
  209. if (! defined('DIV_TAG_DEFAULT_REPLACEMENT_BEGIN'))
  210. define('DIV_TAG_DEFAULT_REPLACEMENT_BEGIN', '{@'); // Default replacement
  211. if (! defined('DIV_TAG_DEFAULT_REPLACEMENT_END'))
  212. define('DIV_TAG_DEFAULT_REPLACEMENT_END', '@}');
  213. if (! defined('DIV_TAG_INCLUDE_BEGIN'))
  214. define('DIV_TAG_INCLUDE_BEGIN', '{% '); // Includes
  215. if (! defined('DIV_TAG_INCLUDE_END'))
  216. define('DIV_TAG_INCLUDE_END', ' %}');
  217. if (! defined('DIV_TAG_PREPROCESSED_BEGIN'))
  218. define('DIV_TAG_PREPROCESSED_BEGIN', '{%% '); // Pre-processed
  219. if (! defined('DIV_TAG_PREPROCESSED_END'))
  220. define('DIV_TAG_PREPROCESSED_END', ' %%}');
  221. if (! defined('DIV_TAG_CAPSULE_BEGIN_PREFIX'))
  222. define('DIV_TAG_CAPSULE_BEGIN_PREFIX', '[['); // Capsules
  223. if (! defined('DIV_TAG_CAPSULE_BEGIN_SUFFIX'))
  224. define('DIV_TAG_CAPSULE_BEGIN_SUFFIX', '');
  225. if (! defined('DIV_TAG_CAPSULE_END_PREFIX'))
  226. define('DIV_TAG_CAPSULE_END_PREFIX', '');
  227. if (! defined('DIV_TAG_CAPSULE_END_SUFFIX'))
  228. define('DIV_TAG_CAPSULE_END_SUFFIX', ']]');
  229. if (! defined('DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX'))
  230. define('DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX', '{:'); // Multi replacements
  231. if (! defined('DIV_TAG_MULTI_REPLACEMENT_BEGIN_SUFFIX'))
  232. define('DIV_TAG_MULTI_REPLACEMENT_BEGIN_SUFFIX', '}');
  233. if (! defined('DIV_TAG_MULTI_REPLACEMENT_END_PREFIX'))
  234. define('DIV_TAG_MULTI_REPLACEMENT_END_PREFIX', '{:/');
  235. if (! defined('DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX'))
  236. define('DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX', '}');
  237. if (! defined('DIV_TAG_FRIENDLY_BEGIN'))
  238. define('DIV_TAG_FRIENDLY_BEGIN', '<!--|'); // Friendly tags
  239. if (! defined('DIV_TAG_FRIENDLY_END'))
  240. define('DIV_TAG_FRIENDLY_END', '|-->');
  241. if (! defined('DIV_TAG_AGGREGATE_FUNCTION_COUNT'))
  242. define('DIV_TAG_AGGREGATE_FUNCTION_COUNT', 'count'); // Aggregate functions
  243. if (! defined('DIV_TAG_AGGREGATE_FUNCTION_MAX'))
  244. define('DIV_TAG_AGGREGATE_FUNCTION_MAX', 'max');
  245. if (! defined('DIV_TAG_AGGREGATE_FUNCTION_MIN'))
  246. define('DIV_TAG_AGGREGATE_FUNCTION_MIN', 'min');
  247. if (! defined('DIV_TAG_AGGREGATE_FUNCTION_SUM'))
  248. define('DIV_TAG_AGGREGATE_FUNCTION_SUM', 'sum');
  249. if (! defined('DIV_TAG_AGGREGATE_FUNCTION_AVG'))
  250. define('DIV_TAG_AGGREGATE_FUNCTION_AVG', 'avg');
  251. if (! defined('DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR'))
  252. define('DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR', ':');
  253. if (! defined('DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR'))
  254. define('DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR', '-');
  255. if (! defined('DIV_TAG_LOCATION_BEGIN'))
  256. define('DIV_TAG_LOCATION_BEGIN', '(( '); // Locations
  257. if (! defined('DIV_TAG_LOCATION_END'))
  258. define('DIV_TAG_LOCATION_END', ' ))');
  259. if (! defined('DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX'))
  260. define('DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX', '{{');
  261. if (! defined('DIV_TAG_LOCATION_CONTENT_BEGIN_SUFFIX'))
  262. define('DIV_TAG_LOCATION_CONTENT_BEGIN_SUFFIX', '');
  263. if (! defined('DIV_TAG_LOCATION_CONTENT_END_PREFIX'))
  264. define('DIV_TAG_LOCATION_CONTENT_END_PREFIX', '');
  265. if (! defined('DIV_TAG_LOCATION_CONTENT_END_SUFFIX'))
  266. define('DIV_TAG_LOCATION_CONTENT_END_SUFFIX', '}}');
  267. if (! defined('DIV_TAG_MACRO_BEGIN'))
  268. define('DIV_TAG_MACRO_BEGIN', '<?'); // Macros
  269. if (! defined('DIV_TAG_MACRO_END'))
  270. define('DIV_TAG_MACRO_END', '?>');
  271. if (! defined('DIV_TAG_SPECIAL_REPLACE_NEW_LINE'))
  272. define('DIV_TAG_SPECIAL_REPLACE_NEW_LINE', '{\n}'); // Special replacements
  273. if (! defined('DIV_TAG_SPECIAL_REPLACE_CAR_RETURN'))
  274. define('DIV_TAG_SPECIAL_REPLACE_CAR_RETURN', '{\r}');
  275. if (! defined('DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB'))
  276. define('DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB', '{\t}');
  277. if (! defined('DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB'))
  278. define('DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB', '{\v}');
  279. if (! defined('DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE'))
  280. define('DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE', '{\f}');
  281. if (! defined('DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL'))
  282. define('DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL', '{\$}');
  283. if (! defined('DIV_TAG_TEASER_BREAK'))
  284. define('DIV_TAG_TEASER_BREAK', '<!--break-->');
  285. define('DIV_DEFAULT_DIALECT', '{
  286. \'DIV_TAG_REPLACEMENT_PREFIX\' : \'{\', \'DIV_TAG_REPLACEMENT_SUFFIX\' : \'}\',
  287. \'DIV_TAG_MULTI_MODIFIERS_PREFIX\' : \'{$\', \'DIV_TAG_MULTI_MODIFIERS_SEPARATOR\' : \'|\',
  288. \'DIV_TAG_MULTI_MODIFIERS_OPERATOR\' : \'|\', \'DIV_TAG_MULTI_MODIFIERS_SUFFIX\' : \'|}\',
  289. \'DIV_TAG_SUBMATCH_SEPARATOR\' : \':\', \'DIV_TAG_MODIFIER_SIMPLE\' : \'$\',
  290. \'DIV_TAG_MODIFIER_CAPITALIZE_FIRST\' : \'^\', \'DIV_TAG_MODIFIER_CAPITALIZE_WORDS\' : \'^^\',
  291. \'DIV_TAG_MODIFIER_UPPERCASE\' : \'^^^\', \'DIV_TAG_MODIFIER_LOWERCASE\' : \'_\',
  292. \'DIV_TAG_MODIFIER_LENGTH\' : \'%\', \'DIV_TAG_MODIFIER_COUNT_WORDS\' : \'%%\',
  293. \'DIV_TAG_MODIFIER_COUNT_SENTENCES\' : \'%%%\', \'DIV_TAG_MODIFIER_COUNT_PARAGRAPHS\' : \'%%%%\',
  294. \'DIV_TAG_MODIFIER_ENCODE_URL\' : \'&\', \'DIV_TAG_MODIFIER_ENCODE_RAW_URL\' : \'&&\',
  295. \'DIV_TAG_MODIFIER_ENCODE_JSON\' : \'json:\', \'DIV_TAG_MODIFIER_HTML_ENTITIES\' : \'html:\',
  296. \'DIV_TAG_MODIFIER_NL2BR\' : \'br:\', \'DIV_TAG_MODIFIER_TRUNCATE\' : \'~\',
  297. \'DIV_TAG_MODIFIER_WORDWRAP\' : \'/\', \'DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR\' : \',\',
  298. \'DIV_TAG_MODIFIER_SINGLE_QUOTES\' : "\'", \'DIV_TAG_MODIFIER_JS\' : \'js:\',
  299. \'DIV_TAG_MODIFIER_FORMAT\' : \'\', \'DIV_TAG_DATE_FORMAT_PREFIX\' : \'{/\',
  300. \'DIV_TAG_DATE_FORMAT_SUFFIX\' : \'/}\', \'DIV_TAG_DATE_FORMAT_SEPARATOR\' : \':\',
  301. \'DIV_TAG_NUMBER_FORMAT_PREFIX\' : \'{#\', \'DIV_TAG_NUMBER_FORMAT_SUFFIX\' : \'#}\',
  302. \'DIV_TAG_NUMBER_FORMAT_SEPARATOR\' : \':\', \'DIV_TAG_FORMULA_BEGIN\' : \'(#\',
  303. \'DIV_TAG_FORMULA_END\' : \'#)\', \'DIV_TAG_FORMULA_FORMAT_SEPARATOR\' : \':\',
  304. \'DIV_TAG_SUBPARSER_BEGIN_PREFIX\' : \'{\', \'DIV_TAG_SUBPARSER_BEGIN_SUFFIX\' : \'}\',
  305. \'DIV_TAG_SUBPARSER_END_PREFIX\' : \'{/\', \'DIV_TAG_SUBPARSER_END_SUFFIX\' : \'}\',
  306. \'DIV_TAG_IGNORE_BEGIN\' : \'{ignore}\', \'DIV_TAG_IGNORE_END\' : \'{/ignore}\',
  307. \'DIV_TAG_COMMENT_BEGIN\' : \'<!--{\', \'DIV_TAG_COMMENT_END\' : \'}-->\',
  308. \'DIV_TAG_TXT_BEGIN\' : \'{txt}\', \'DIV_TAG_TXT_END\' : \'{/txt}\',
  309. \'DIV_TAG_TXT_WIDTH_SEPARATOR\' : \'=>\', \'DIV_TAG_STRIP_BEGIN\' : \'{strip}\',
  310. \'DIV_TAG_STRIP_END\' : \'{/strip}\', \'DIV_TAG_LOOP_BEGIN_PREFIX\' : \'[$\',
  311. \'DIV_TAG_LOOP_BEGIN_SUFFIX\' : \']\', \'DIV_TAG_LOOP_END_PREFIX\' : \'[/$\',
  312. \'DIV_TAG_LOOP_END_SUFFIX\' : \']\', \'DIV_TAG_EMPTY\' : \'@empty@\',
  313. \'DIV_TAG_BREAK\' : \'@break@\', \'DIV_TAG_LOOP_VAR_SEPARATOR\' : \'=>\',
  314. \'DIV_TAG_ITERATION_BEGIN_PREFIX\' : \'[:\', \'DIV_TAG_ITERATION_BEGIN_SUFFIX\' : \':]\',
  315. \'DIV_TAG_ITERATION_END\' : \'[/]\', \'DIV_TAG_ITERATION_PARAM_SEPARATOR\' : \',\',
  316. \'DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX\' : \'?$\', \'DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX\' : \'\',
  317. \'DIV_TAG_CONDITIONAL_TRUE_END_PREFIX\' : \'$\', \'DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX\' : \'?\',
  318. \'DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX\' : \'!$\', \'DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX\' : \'\',
  319. \'DIV_TAG_CONDITIONAL_FALSE_END_PREFIX\' : \'$\', \'DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX\' : \'!\',
  320. \'DIV_TAG_ELSE\' : \'@else@\', \'DIV_TAG_CONDITIONS_BEGIN_PREFIX\' : \'{?(\',
  321. \'DIV_TAG_CONDITIONS_BEGIN_SUFFIX\' : \')?}\', \'DIV_TAG_CONDITIONS_END\' : \'{/?}\',
  322. \'DIV_TAG_TPLVAR_BEGIN\' : \'{=\', \'DIV_TAG_TPLVAR_END\' : \'=}\',
  323. \'DIV_TAG_TPLVAR_ASSIGN_OPERATOR\' : \':\', \'DIV_TAG_TPLVAR_PROTECTOR\' : \'*\',
  324. \'DIV_TAG_DEFAULT_REPLACEMENT_BEGIN\' : \'{@\', \'DIV_TAG_DEFAULT_REPLACEMENT_END\' : \'@}\',
  325. \'DIV_TAG_INCLUDE_BEGIN\' : \'{% \', \'DIV_TAG_INCLUDE_END\' : \' %}\',
  326. \'DIV_TAG_PREPROCESSED_BEGIN\' : \'{%% \', \'DIV_TAG_PREPROCESSED_END\' : \' %%}\',
  327. \'DIV_TAG_CAPSULE_BEGIN_PREFIX\' : \'[[\', \'DIV_TAG_CAPSULE_BEGIN_SUFFIX\' : \'\',
  328. \'DIV_TAG_CAPSULE_END_PREFIX\' : \'\', \'DIV_TAG_CAPSULE_END_SUFFIX\' : \']]\',
  329. \'DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX\' : \'{:\', \'DIV_TAG_MULTI_REPLACEMENT_BEGIN_SUFFIX\' : \'}\',
  330. \'DIV_TAG_MULTI_REPLACEMENT_END_PREFIX\' : \'{:/\', \'DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX\' : \'}\',
  331. \'DIV_TAG_FRIENDLY_BEGIN\' : \'<!--|\', \'DIV_TAG_FRIENDLY_END\' : \'|-->\',
  332. \'DIV_TAG_AGGREGATE_FUNCTION_COUNT\' : \'count\', \'DIV_TAG_AGGREGATE_FUNCTION_MAX\' : \'max\',
  333. \'DIV_TAG_AGGREGATE_FUNCTION_MIN\' : \'min\', \'DIV_TAG_AGGREGATE_FUNCTION_SUM\' : \'sum\',
  334. \'DIV_TAG_AGGREGATE_FUNCTION_AVG\' : \'avg\', \'DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR\' : \':\',
  335. \'DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR\' : \'-\', \'DIV_TAG_LOCATION_BEGIN\' : \'(( \',
  336. \'DIV_TAG_LOCATION_END\' : \' ))\', \'DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX\' : \'{{\',
  337. \'DIV_TAG_LOCATION_CONTENT_BEGIN_SUFFIX\' : \'\', \'DIV_TAG_LOCATION_CONTENT_END_PREFIX\' : \'\',
  338. \'DIV_TAG_LOCATION_CONTENT_END_SUFFIX\' : \'}}\', \'DIV_TAG_MACRO_BEGIN\' : \'<?\',
  339. \'DIV_TAG_MACRO_END\' : \'?>\', \'DIV_TAG_SPECIAL_REPLACE_NEW_LINE\' : \'{\\n}\',
  340. \'DIV_TAG_SPECIAL_REPLACE_CAR_RETURN\' : \'{\\r}\', \'DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB\' : \'{\\t}\',
  341. \'DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB\' : \'{\\v}\', \'DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE\' : \'{\\f}\',
  342. \'DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL\' : \'{\\$}\', \'DIV_TAG_TEASER_BREAK\' : \'<!--break-->\'
  343. }');
  344. // --------------------------------------------------------------------------------------------------------------------------------------//
  345. define('DIV_TEMPLATE_FOR_DOCS', '
  346. @_DIALECT = ' . uniqid() . '
  347. <html>
  348. <head>
  349. <title>{$title}</title>
  350. <style type="text/css">
  351. body {background: #656565; font-family: Verdana;}
  352. div.section {background: white; margin-top: 20px; padding: 10px; width: 780px;}
  353. .section h2 {color: white; font-size: 24px;font-weight: bold; margin-left: -30px;padding-bottom: 5px; padding-left: 30px;padding-top: 5px; background: black; border-left: 10px solid gray;}
  354. h1 {color: white;}
  355. table.data td {padding: 5px;border-bottom: 1px solid gray; border-right: 1px solid gray;}
  356. table.data th {padding: 5px;color: white; background: black;}
  357. .code {padding: 0px; margin: 0px; background: #eeeeee; color: black; font-family: "Courier New"; text-align: left; font-size: 13px;}
  358. .code .line {text-align:right; background: gray; color: white; border-right: 2px solid black; padding-right: 5px;}
  359. table.index, table.index a, table.index a:visited {color:white;}
  360. div.header {color: white;}
  361. .template-description{background: #eeeeee; padding: 10px;}
  362. </style>
  363. </head>
  364. <body>
  365. <label><a href="#header" style="position: fixed; bottom: 5px; right: 5px;color: white;">Index</a></label>
  366. <table width="750" align="center"><tr><td valign="top">
  367. <div id = "header" class = "header">
  368. <h1>{$title}</h1>
  369. <p>Generated by Div at {/div.now:Y-m-d H:i:s/}</p>
  370. <h2>Index</h2>
  371. <table class="index data" width="100%">
  372. <tr><th></th><th>Name</th><th>Description</th><th>Version</th></tr>
  373. [$docs]
  374. <tr><td>{$_order}</td>
  375. <td><a href="#{$_key}">?$name {$name} $name?</a></td>
  376. <td>?$description {$description} $description?</td>
  377. <td>?$version {$version} $version?</td></tr>
  378. [/$docs]
  379. </table>
  380. </div>
  381. {= repl1: [["<",""],[">",""]] =}
  382. [$docs]
  383. <div class="section">
  384. <h2 id = "{$_key}">?$icon {$icon} $icon? {$name}</h2>
  385. <table width="100%">
  386. <tr><td align="right">Path:</td><td>{$_key} </td></tr>
  387. ?$type <tr><td align="right" width="150">Type:</td><td><b>{$type}</b></td></tr>$type?
  388. ?$author <tr><td align="right" width="150">Author:</td><td><b>{html:author}</b></td></tr> $author?
  389. ?$version <tr><td align="right" width="150">Version:</td><td><b>{$version}</b></td></tr> $version?
  390. ?$update <tr><td align="right" width="150">Last update:</td><td>{$update} </td></tr>$update?
  391. </table>
  392. <br/>
  393. ?$description <p class="template-description">{$description}</p>$description?
  394. ?$vars
  395. <h3>Template\'s Variables ({$vars})</h3>
  396. <table class="data">
  397. <tr><th></th><th></th><th>Type</th><th>Name</th><th>Description</th></tr>
  398. [$vars]
  399. {?( trim("{\'value}") !== "" )?}
  400. <?
  401. $value = trim(str_replace(array("\t","\n","\r")," ", $value));
  402. while(strpos($value, " ")) $value = str_replace(" "," ", $value);
  403. $pars = explode(" ", $value, 4);
  404. ?>
  405. <tr>
  406. <td>{$_order}</td>
  407. [$pars]
  408. <td>{:repl1}{$value}{:/repl1}</td>
  409. [/$pars]
  410. </tr>
  411. {/?}
  412. [/$vars]
  413. </table>
  414. $vars?
  415. ?$include
  416. <h3>Include:</h3>
  417. [$include]
  418. {$_order}. <a href="#{$value}">{$value}</a><br/>
  419. [/$include]
  420. $include?
  421. ?$example
  422. <h3>Example:</h3>
  423. <table width = "100%" class="code" cellspacing="0" cellpadding="0">
  424. [$example]
  425. <tr>
  426. <td class="line" width="30">{$_order}</td>
  427. <td><pre class="code">{html_wysiwyg:afterReplace}{$value}{/html_wysiwyg:afterReplace}</pre></td>
  428. </tr>
  429. [/$example]
  430. </table>
  431. $example?
  432. </div>
  433. [/$docs]
  434. </td></tr></table>
  435. </body>
  436. </html>');
  437. /**
  438. * The div class is the complete implementation of Div.
  439. *
  440. * See the following example:
  441. *
  442. * echo new div('Hello {$name}', array('name' => 'Peter Pan'));
  443. */
  444. class div {
  445. // Public
  446. public $__src = null;
  447. // template source
  448. public $__src_original = null;
  449. // original template source
  450. public $__items = array();
  451. // template variables
  452. public $__items_orig = array();
  453. // original template variables
  454. public $__memory = array();
  455. // to remember the template variables
  456. public $__path = '';
  457. // path to current template file
  458. public $__ignore = array();
  459. // template variables to ignore
  460. public $__restore = array();
  461. // template's parts to restore after parse
  462. public $__packages = PACKAGES;
  463. // path of current templates's root folder
  464. public $__properties = array();
  465. // properties of the template
  466. // Private
  467. private $__id = null;
  468. // template id
  469. private $__temp = array();
  470. // temporal vars
  471. private $__crc = null;
  472. // template cheksum
  473. // Globals
  474. private static $__custom_modifiers = array();
  475. // custom variable's modifiers
  476. private static $__globals = array();
  477. // global template's variables
  478. private static $__globals_design = array();
  479. // global template's variables defined in the design
  480. private static $__globals_design_protected = array();
  481. // global and protected template variables defined in the design
  482. private static $__defaults = array();
  483. // default value for another value
  484. private static $__defaults_by_var = array();
  485. // default value for another value by variable
  486. private static $__system_data = null;
  487. // system data
  488. private static $__system_data_allowed = array(
  489. 'div.version' => true,
  490. 'div.post' => true,
  491. 'div.get' => true,
  492. 'div.now' => true
  493. );
  494. private static $__discard_file_system = false;
  495. // do not load code from files
  496. private static $__allowed_functions = array();
  497. // list of allowed custom functions
  498. private static $__allowed_methods = null;
  499. // list of allowed class's methods
  500. private static $__sub_parsers = array();
  501. // list of subparsers
  502. private static $__docs = array();
  503. // template's documentation
  504. private static $__docs_on = false;
  505. // on/off documentation
  506. private static $__includes_historial = array();
  507. // includes's historial
  508. // Internals
  509. private static $__version = '4.5';
  510. // current version of Div
  511. private static $__super_class = null;
  512. // name of the super class
  513. private static $__parent_method_names = array();
  514. // name of parent class's methods
  515. private static $__method_names = null;
  516. // name of current methods
  517. private static $__parse_duration = null;
  518. // duration of parser
  519. private static $__parse_level = 0;
  520. // current level of parser
  521. private static $__engine = null;
  522. // auxiliary engine
  523. private static $__modifiers = array( // variable's modifiers
  524. DIV_TAG_MODIFIER_SIMPLE,
  525. DIV_TAG_MODIFIER_CAPITALIZE_FIRST,
  526. DIV_TAG_MODIFIER_CAPITALIZE_WORDS,
  527. DIV_TAG_MODIFIER_UPPERCASE,
  528. DIV_TAG_MODIFIER_LOWERCASE,
  529. DIV_TAG_MODIFIER_LENGTH,
  530. DIV_TAG_MODIFIER_COUNT_WORDS,
  531. DIV_TAG_MODIFIER_COUNT_SENTENCES,
  532. DIV_TAG_MODIFIER_COUNT_PARAGRAPHS,
  533. DIV_TAG_MODIFIER_ENCODE_URL,
  534. DIV_TAG_MODIFIER_ENCODE_RAW_URL,
  535. DIV_TAG_MODIFIER_HTML_ENTITIES,
  536. DIV_TAG_MODIFIER_NL2BR,
  537. DIV_TAG_MODIFIER_ENCODE_JSON,
  538. DIV_TAG_MODIFIER_SINGLE_QUOTES,
  539. DIV_TAG_MODIFIER_JS
  540. );
  541. private static $__dialect_checked = false;
  542. // is current dialect checked?
  543. private static $__allowed_php_functions = null;
  544. // allowed PHP functions
  545. private static $__log_mode = false;
  546. // is log mode?
  547. private static $__log_file = null;
  548. // the log filename
  549. private static $__is_cli = null;
  550. // is PHP cli?
  551. private static $__ignored_parts = array();
  552. // ignored parts
  553. private static $__last_id = 0;
  554. // last template id
  555. private static $__remember = array();
  556. // remember previous work
  557. private static $__dont_remember_it = array();
  558. // do not remember it work
  559. private static $__errors = array();
  560. // errors historial
  561. private static $__include_paths = null;
  562. private static $__packages_by_class = array();
  563. /**
  564. * Constructor
  565. *
  566. * @param string $src
  567. * @param mixed $items
  568. * @param array $ignore
  569. * @return div
  570. */
  571. public function __construct($src = null, $items = null, $ignore = array()){
  572. // Validate the current dialect
  573. if (self::$__dialect_checked == false) {
  574. $r = self::isValidCurrentDialect();
  575. if ($r !== true)
  576. self::error('Current dialect is invalid: ' . $r, DIV_ERROR_FATAL);
  577. self::$__dialect_checked = true;
  578. }
  579. $classname = get_class($this);
  580. self::$__packages_by_class[$classname] = $this->__packages;
  581. if (is_null(self::$__super_class))
  582. self::$__super_class = $this->getSuperParent();
  583. if (is_null(self::$__parent_method_names))
  584. self::$__parent_method_names = get_class_methods(self::$__super_class);
  585. $this->__id = ++ self::$__last_id;
  586. if (self::$__log_mode)
  587. $this->logger('Building instance #' . $this->__id . ' of ' . $classname . '...');
  588. // Calling the beforeBuild hook
  589. $this->beforeBuild($src, $items);
  590. if (is_null($items) && ! is_null($this->__items))
  591. $items = $this->__items;
  592. $this->__items_orig = $items;
  593. $decode = true;
  594. $discardfs = self::$__discard_file_system;
  595. if (is_null($src)) {
  596. if ($classname != self::$__super_class && is_null($this->__src))
  597. $src = $classname;
  598. if (! is_null($this->__src))
  599. $src = $this->__src;
  600. }
  601. if (is_null($items)) {
  602. $items = $src;
  603. $items = str_replace('.' . DIV_DEFAULT_TPL_FILE_EXT, '', $items);
  604. $decode = false;
  605. }
  606. if (! $discardfs) {
  607. if (self::isString($items))
  608. if (strlen($items . '.' . DIV_DEFAULT_DATA_FILE_EXT) < 255) {
  609. $exists = false;
  610. if (self::fileExists($items)) {
  611. $items = self::getFileContents($items);
  612. $exists = true;
  613. } elseif (self::fileExists($items . '.' . DIV_DEFAULT_DATA_FILE_EXT)) {
  614. $items = self::getFileContents($items . '.' . DIV_DEFAULT_DATA_FILE_EXT);
  615. $exists = true;
  616. }
  617. if ($exists === true || $decode === true)
  618. $items = self::jsonDecode($items);
  619. if ($exists === true)
  620. break;
  621. }
  622. }
  623. if (is_object($items)) {
  624. if (method_exists($items, '__toString')) {
  625. $itemstr = "$items";
  626. if (! isset($items->value))
  627. $items->value = $itemstr;
  628. $items->_to_string = $itemstr;
  629. }
  630. $items = get_object_vars($items);
  631. }
  632. if (! $discardfs)
  633. $src = $this->loadTemplate($src);
  634. if (! is_array($items))
  635. $items = array();
  636. $this->__src = $src;
  637. $this->__src_original = $src;
  638. $this->__items = $items;
  639. if (self::isString($ignore))
  640. $ignore = explode(',', $ignore);
  641. if (isset($ignore[0]))
  642. foreach ( $ignore as $key => $val )
  643. $this->__ignore[$val] = true;
  644. // Calling the afterBuild hook
  645. $this->afterBuild();
  646. // Enabling methods
  647. if (is_null(self::$__allowed_methods)) {
  648. $keys = explode(",", DIV_PHP_ALLOWED_METHODS);
  649. ;
  650. self::$__allowed_methods = array_combine($keys, $keys);
  651. if (self::$__super_class != $classname) {
  652. $keys = array_diff(get_class_methods($classname), get_class_methods(self::$__super_class));
  653. if (isset($keys[0]))
  654. self::$__allowed_methods = array_merge(self::$__allowed_methods, array_combine($keys, $keys));
  655. }
  656. }
  657. // Pre-defined subparsers
  658. self::setSubParser('parse', 'subParse_parse');
  659. self::setSubParser('html_wysiwyg', 'subParse_html_wysiwyg');
  660. }
  661. /**
  662. * Return a list of include_path setting + the PACKAGES
  663. *
  664. * @return array
  665. */
  666. final static function getIncludePaths($packages = PACKAGES){
  667. if (is_null(self::$__include_paths)) {
  668. $os = self::getOperatingSystem();
  669. self::$__include_paths = explode(($os == "win32" ? ";" : ":"), ini_get("include_path"));
  670. self::$__include_paths[] = $packages;
  671. }
  672. return self::$__include_paths;
  673. }
  674. /**
  675. * Return the current operating system
  676. *
  677. * @return string (win32/linux/unix)
  678. */
  679. final static function getOperatingSystem(){
  680. if (isset($_SERVER['SERVER_SOFTWARE'])) {
  681. if (isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') !== FALSE)
  682. return "win32";
  683. if (! isset($_SERVER['WINDIR']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Linux') !== FALSE)
  684. return "linux";
  685. }
  686. if (file_exists("C:\Windows"))
  687. return "win32";
  688. return "unix";
  689. }
  690. /**
  691. * Return the super parent class name
  692. *
  693. * @param string $classname
  694. * @return string
  695. */
  696. final public function getSuperParent($classname = null){
  697. if (is_null($classname))
  698. $classname = get_class($this);
  699. $parent = get_parent_class($classname);
  700. if ($parent === false)
  701. return $classname;
  702. return $this->getSuperParent($parent);
  703. ;
  704. }
  705. /**
  706. * Return the current template's id
  707. *
  708. * @return integer
  709. */
  710. final public function getId(){
  711. return $this->__id;
  712. }
  713. /**
  714. * Create an auxiliar instance (as singleton)
  715. *
  716. * @param string $classname
  717. */
  718. final static function createAuxiliarEngine(&$from = null){
  719. if (is_null($from))
  720. $classname = self::$__super_class;
  721. else
  722. $classname = get_class($from);
  723. if (! is_null(self::$__engine))
  724. if (get_class(self::$__engine) != $classname)
  725. self::$__engine = null;
  726. if (is_null(self::$__engine)) {
  727. if (self::$__log_mode)
  728. self::log("createAuxiliarEngine: A new $classname instance will be created ...");
  729. $tmp = self::$__discard_file_system;
  730. self::$__discard_file_system = true;
  731. self::$__engine = new $classname("", array());
  732. if (! is_null($from)) {
  733. self::$__engine->__items = $from->__items;
  734. self::$__engine->__items_orig = $from->__items_orig;
  735. }
  736. self::$__discard_file_system = $tmp;
  737. }
  738. }
  739. /**
  740. * Create a clone of auxiliary
  741. *
  742. * @return div
  743. */
  744. final static function getAuxiliaryEngineClone(&$items = null, &$items_orig = null){
  745. $obj = clone self::$__engine;
  746. if (self::$__log_mode)
  747. self::log("getAuxiliaryEngineClone: New auxiliary #" . $obj->getId());
  748. if (! is_null($items))
  749. $obj->__items = $items;
  750. if (! is_null($items_orig))
  751. $obj->__items_orig = $items_orig;
  752. return $obj;
  753. }
  754. /**
  755. * Save parser's operationsd
  756. *
  757. * @param array $params
  758. */
  759. final public function saveOperation($params = array()){
  760. if (! isset(self::$__remember[$this->__crc]))
  761. self::$__remember[$this->__crc] = array();
  762. $id = crc32(serialize($params));
  763. if (! isset(self::$__remember[$this->__crc][$id]))
  764. self::$__remember[$this->__crc][$id] = $params;
  765. }
  766. /**
  767. * Add a custom variable's modifier
  768. *
  769. * @param string $prefix
  770. * @param string $function
  771. */
  772. final static function addCustomModifier($prefix, $function){
  773. self::$__custom_modifiers[$prefix] = array(
  774. $prefix,
  775. $function
  776. );
  777. self::$__modifiers[] = $prefix;
  778. }
  779. /**
  780. * Enable system var for utility
  781. *
  782. * @param string $var
  783. */
  784. final static function enableSystemVar($var){
  785. self::$__system_data_allowed[$var] = true;
  786. }
  787. /**
  788. * Disable system var for performance
  789. *
  790. * @param string $var
  791. */
  792. final static function disableSystemVar($var){
  793. if (isset(self::$__system_data_allowed[$var]))
  794. unset(self::$__system_data_allowed[$var]);
  795. }
  796. /**
  797. * Return the loaded data from the system
  798. *
  799. * @return array
  800. */
  801. final static function getSystemData(){
  802. if (self::$__system_data == null) {
  803. self::$__system_data = array();
  804. if (isset(self::$__system_data_allowed['div.ascii'])) {
  805. $ascii = array();
  806. for($i = 0; $i <= 255; $i ++)
  807. $ascii[$i] = chr($i);
  808. self::$__system_data['div.ascii'] = $ascii;
  809. }
  810. if (isset(self::$__system_data_allowed['div.now']))
  811. self::$__system_data['div.now'] = time();
  812. if (isset(self::$__system_data_allowed['div.post']))
  813. self::$__system_data['div.post'] = $_POST;
  814. if (isset(self::$__system_data_allowed['div.get']))
  815. self::$__system_data['div.get'] = $_GET;
  816. if (isset(self::$__system_data_allowed['div.server']))
  817. self::$__system_data['div.server'] = $_SERVER;
  818. if (isset(self::$__system_data_allowed['div.session']))
  819. self::$__system_data['div.session'] = isset($_SESSION) ? $_SESSION : array();
  820. if (isset(self::$__system_data_allowed['div.version']))
  821. self::$__system_data['div.version'] = self::$__version;
  822. if (isset(self::$__system_data_allowed['div.script_name'])) {
  823. $script_name = explode('/', $_SERVER['SCRIPT_NAME']);
  824. $script_name = $script_name[count($script_name) - 1];
  825. self::$__system_data['div.script_name'] = $script_name;
  826. }
  827. }
  828. return self::$__system_data;
  829. }
  830. /**
  831. * Set allowed function
  832. *
  833. * @param string $funcname
  834. */
  835. final static function setAllowedFunction($funcname){
  836. self::$__allowed_functions[$funcname] = true;
  837. }
  838. /**
  839. * Unset allowed function
  840. *
  841. * @param string $funcname
  842. */
  843. final static function unsetAllowedFunction($funcname){
  844. self::$__allowed_functions[$funcname] = false;
  845. }
  846. /**
  847. * Add or set a global var
  848. *
  849. * @param string $var
  850. * @param mixed $value
  851. */
  852. final static function setGlobal($var, $value){
  853. self::$__globals[$var] = $value;
  854. }
  855. /**
  856. * Remove a global var
  857. *
  858. * @param string $var
  859. */
  860. final static function delGlobal($var){
  861. unset(self::$__globals[$var]);
  862. }
  863. /**
  864. * Add or set a default replacement of value
  865. *
  866. * @param mixed $search
  867. * @param mixed $replace
  868. */
  869. final static function setDefault($search, $replace){
  870. self::$__defaults[serialize($search)] = $replace;
  871. }
  872. /**
  873. * Add or set a default replacement of value for a specific var
  874. *
  875. * @param string $var
  876. * @param mixed $search
  877. * @param mixed $replace
  878. * @param boolean $update
  879. */
  880. final static function setDefaultByVar($var, $search, $replace, $update = true){
  881. $id = serialize($search);
  882. if (! isset(self::$__defaults_by_var[$var]))
  883. self::$__defaults_by_var[$var] = array();
  884. if (! isset(self::$__defaults_by_var[$var][$id]) && $update === true)
  885. self::$__defaults_by_var[$var][$id] = $replace;
  886. }
  887. /**
  888. * Set a sub-parser
  889. *
  890. * @param string $name
  891. * @param string $function
  892. */
  893. final static function setSubParser($name, $function = null){
  894. if (is_array($name)) {
  895. if (is_null($function)) {
  896. foreach ( $name as $key => $value ) {
  897. if (is_numeric($key))
  898. self::$__sub_parsers[$value] = $value;
  899. else
  900. self::$__sub_parsers[$key] = $value;
  901. }
  902. } elseif (is_array($function)) {
  903. foreach ( $name as $key => $value )
  904. self::$__sub_parsers[$value] = $function[$key];
  905. } else {
  906. foreach ( $name as $key => $value )
  907. self::$__sub_parsers[$value] = $function;
  908. }
  909. } else {
  910. if (is_null($function))
  911. $function = $name;
  912. self::$__sub_parsers[$name] = $function;
  913. }
  914. self::repairSubparsers();
  915. }
  916. /**
  917. * Repair the subparsers and their events
  918. */
  919. final static function repairSubparsers(){
  920. $events = array(
  921. 'beforeParse',
  922. 'afterInclude',
  923. 'afterParse',
  924. 'afterReplace'
  925. );
  926. $news = array();
  927. foreach ( self::$__sub_parsers as $parser => $function ) {
  928. $arr = explode(":", $parser);
  929. if (isset($arr[1])) {
  930. $last = array_pop($arr);
  931. if (array_search($last, $events) !== false)
  932. continue;
  933. }
  934. foreach ( $events as $event )
  935. if (! isset(self::$__sub_parsers["$parser:$event"])) {
  936. $news["$parser:$event"] = $function;
  937. }
  938. }
  939. self::$__sub_parsers = array_merge(self::$__sub_parsers, $news);
  940. }
  941. /**
  942. * Load template from filesystem
  943. *
  944. * @param string $path
  945. * @return string
  946. */
  947. final public function loadTemplate($path){
  948. if (self::$__log_mode === true)
  949. $this->logger("Loading the template: $path");
  950. $src = $path;
  951. if (strlen($path) < 255) {
  952. $paths = array(
  953. $path,
  954. $path . '.' . DIV_DEFAULT_TPL_FILE_EXT,
  955. $path,
  956. $path . '.' . DIV_DEFAULT_TPL_FILE_EXT
  957. );
  958. foreach ( $paths as $pathx ) {
  959. if (strlen($pathx) < 255)
  960. if (self::fileExists($pathx)) {
  961. $src = self::getFileContents($pathx);
  962. $this->__path = $pathx;
  963. break;
  964. }
  965. }
  966. }
  967. return $src;
  968. }
  969. /**
  970. * Change the template and the original template
  971. *
  972. * @param string $src
  973. */
  974. final public function changeTemplate($src = null){
  975. $decode = true;
  976. $classname = get_class($this);
  977. $discardfs = self::$__discard_file_system;
  978. if (is_null($src)) {
  979. if ($classname != self::$__super_class && is_null($this->__src))
  980. $src = $classname;
  981. if (! is_null($this->__src))
  982. $src = $this->__src;
  983. }
  984. if (! $discardfs)
  985. $src = $this->loadTemplate($src);
  986. $this->__src = $src;
  987. $this->__src_original = $src;
  988. }
  989. /**
  990. * Return the code of current template
  991. *
  992. * @return string
  993. */
  994. final public function getTemplate(){
  995. return $this->__src;
  996. }
  997. /**
  998. * Return the original code of template
  999. *
  1000. * @return string
  1001. */
  1002. final public function getOriginalTemplate(){
  1003. return $this->__src_original;
  1004. }
  1005. /**
  1006. * Remove a default replacement
  1007. *
  1008. * @param mixed $search
  1009. */
  1010. final static function delDefault($search){
  1011. $id = serialize($search);
  1012. if (isset(self::$__defaults[$id]))
  1013. unset(self::$__defaults[$id]);
  1014. }
  1015. /**
  1016. * Remove a default replacement by var
  1017. *
  1018. * @param string $var
  1019. * @param mixed $search
  1020. */
  1021. final static function delDefaultByVar($var, $search){
  1022. if (isset(self::$__defaults_by_var[$var])) {
  1023. $id = serialize($search);
  1024. if (isset(self::$__defaults_by_var[$var][$id]))
  1025. unset(self::$__defaults_by_var[$var][$id]);
  1026. }
  1027. }
  1028. /**
  1029. * Add or Set item of information
  1030. *
  1031. * @param string $var
  1032. * @param mixed $value
  1033. * @return mixed
  1034. */
  1035. final public function setItem($var, $value = null){
  1036. if (is_array($var)) {
  1037. $r = array();
  1038. foreach ( $var as $idx => $val ) {
  1039. if (self::issetVar($idx, $this->__items))
  1040. $r[$idx] = self::getVarValue($idx, $this->__items);
  1041. else
  1042. $r[$idx] = null;
  1043. self::setVarValue($idx, $val, $this->__items);
  1044. }
  1045. return $r;
  1046. }
  1047. if (self::issetVar($var, $this->__items))
  1048. $item = self::getVarValue($var, $this->__items);
  1049. else
  1050. $item = null;
  1051. self::setVarValue($var, $value, $this->__items);
  1052. return $item;
  1053. }
  1054. /**
  1055. * Delete an item of information
  1056. *
  1057. * @param string $var
  1058. * @return boolean
  1059. */
  1060. final public function delItem($var){
  1061. return self::unsetVar($var, $this->__items);
  1062. }
  1063. /**
  1064. * Return an item
  1065. *
  1066. * @param array $array
  1067. * @param mixed $index
  1068. * @param mixed $default
  1069. * @return mixed
  1070. */
  1071. final public function getItem($var, $default = null){
  1072. if (! self::issetVar($var, $this->__items))
  1073. return $default;
  1074. return self::getVarValue($var, $this->__items);
  1075. }
  1076. /**
  1077. * Return a list of block's ranges
  1078. *
  1079. * @param string $tagini
  1080. * @param string $tagend
  1081. * @param boolean $onlyfirst
  1082. * @param integer $pos
  1083. * @return array
  1084. */
  1085. final public function getRanges($tagini, $tagend, $src = null, $onlyfirst = false, $pos = 0){
  1086. $ranges = array();
  1087. if (is_null($src))
  1088. if (isset($this))
  1089. $src = $this->__src;
  1090. if (! is_null($src))
  1091. if (isset($src[0]) && ! empty($src)) {
  1092. $ltagini = strlen($tagini);
  1093. $ltagend = strlen($tagend);
  1094. do {
  1095. $ini = strpos($src, $tagini, $pos);
  1096. if ($ini !== false) {
  1097. if (isset($src[$ini + $ltagini])) {
  1098. $fin = strpos($src, $tagend, $ini + $ltagini);
  1099. if ($fin !== false) {
  1100. $l = strlen($src);
  1101. $last_pos = - 1;
  1102. while ( true ) {
  1103. $ini = strpos($src, $tagini, $pos);
  1104. if ($ini === false || ($ini !== false && $pos == $last_pos))
  1105. break;
  1106. $end = false;
  1107. $plus = 1;
  1108. $posi = $ini + $ltagini;
  1109. $last_posi = $posi - 1;
  1110. while ( true ) {
  1111. $open = strpos($src, $tagini, $posi);
  1112. $close = strpos($src, $tagend, $posi);
  1113. if ($open === false && $close === false)
  1114. break; // not open and not close
  1115. if ($open === false && $close !== false && $posi === $last_posi)
  1116. break; // close and not open
  1117. if ($open !== false && $close === false && $posi === $last_posi)
  1118. break; // open and not close
  1119. if ($open !== false || $close !== false) { // open or close
  1120. if (($close < $open || $open === false) && $close !== false) { // close if is closed and before open or not open
  1121. $last_posi = $posi;
  1122. $posi = $close + $ltagend;
  1123. $plus --;
  1124. // IMPORTANT! Don't separate elseif
  1125. } elseif (($open < $close || $close === false) && $open !== false) { // open if is opened and before close or not close
  1126. $last_posi = $posi;
  1127. $posi = $open + $ltagini;
  1128. $plus ++;
  1129. }
  1130. }
  1131. if ($plus === 0) { // all opens are closed
  1132. $end = $close;
  1133. break;
  1134. }
  1135. if ($open >= $l)
  1136. break;
  1137. }
  1138. $last_pos = $pos;
  1139. if ($end != false) {
  1140. $ranges[] = array(
  1141. $ini,
  1142. $end
  1143. );
  1144. if ($onlyfirst == true)
  1145. break;
  1146. $pos = $ini + $ltagini;
  1147. continue;
  1148. }
  1149. }
  1150. }
  1151. }
  1152. }
  1153. if (! isset($ranges[0]) && $ini !== false) {
  1154. if (self::$__log_mode)
  1155. if (isset($this)) {
  1156. foreach ( $this->__items as $key => $value )
  1157. if (strpos($tagini, $key) !== false) {
  1158. $this->logger('Unclosed tag ' . $tagini . ' at ' . $ini . ' character', DIV_ERROR_WARNING);
  1159. break;
  1160. }
  1161. }
  1162. $pos = $ini + 1;
  1163. continue;
  1164. }
  1165. break;
  1166. } while ( true );
  1167. }
  1168. return $ranges;
  1169. }
  1170. /**
  1171. * Return a list of ranges of blocks
  1172. *
  1173. * @param string $src
  1174. * @param string $begin_prefix
  1175. * @param string $begin_suffix
  1176. * @param string $end_prefix
  1177. * @param string $end_suffix
  1178. * @param integer $after
  1179. * @param integer $before
  1180. * @return array
  1181. */
  1182. final public function getBlockRanges($src = null, $begin_prefix = '{', $begin_suffix = '}', $end_prefix = '{/', $end_suffix = '}', $after = 0, $before = null, $onlyfirst = false){
  1183. if (is_null($src))
  1184. $src = $this->__src;
  1185. if (! is_null($before))
  1186. $src = substr($src, 0, $before);
  1187. $l = strlen($src);
  1188. $l1 = strlen($begin_prefix);
  1189. $tagsya = array();
  1190. $ranges = array();
  1191. $from = $after;
  1192. do {
  1193. $prefix_pos = strpos($src, $begin_prefix, $from);
  1194. if ($prefix_pos !== false) {
  1195. if (isset($src[$prefix_pos + 1])) {
  1196. if ($begin_suffix != '' && ! is_null($begin_suffix)) {
  1197. $suffix_pos = strpos($src, $begin_suffix, $prefix_pos + 1);
  1198. } else {
  1199. $stopchars = array(
  1200. ' ',
  1201. "\n",
  1202. "\r",
  1203. "\t",
  1204. "<",
  1205. ">"
  1206. );
  1207. $stoppos = array();
  1208. foreach ( $stopchars as $k => $v ) {
  1209. $pp = strpos($src, $v, $prefix_pos);
  1210. if ($pp === false)
  1211. continue;
  1212. $stoppos[] = $pp;
  1213. }
  1214. $suffix_pos = false;
  1215. if (count($stoppos) > 0)
  1216. $suffix_pos = min($stoppos);
  1217. }
  1218. $key = '';
  1219. if ($suffix_pos < $l && $suffix_pos !== false) {
  1220. $key = substr($src, $prefix_pos + $l1, $suffix_pos - $prefix_pos - $l1);
  1221. }
  1222. if ($key !== '' && ! isset($tagsya[$key])) {
  1223. $tag_begin = $begin_prefix . $key . $begin_suffix;
  1224. $tag_end = $end_prefix . $key . $end_suffix;
  1225. $rs = $this->getRanges($tag_begin, $tag_end, $src, $onlyfirst, $from);
  1226. $l2 = strlen($tag_begin);
  1227. foreach ( $rs as $k => $v ) {
  1228. $rs[$k][2] = $key;
  1229. $rs[$k][3] = substr($src, $v[0] + $l2, $v[1] - $v[0] - $l2);
  1230. }
  1231. $ranges = array_merge($ranges, $rs);
  1232. // Only the first...
  1233. if ($onlyfirst)
  1234. if (isset($ranges[0]))
  1235. break;
  1236. $tagsya[$key] = true;
  1237. }
  1238. }
  1239. $from = $prefix_pos + 1;
  1240. }
  1241. } while ( $prefix_pos !== false );
  1242. return $ranges;
  1243. }
  1244. /**
  1245. * Return a default replacement of value
  1246. *
  1247. * @param mixed $value
  1248. * @return mixed
  1249. */
  1250. final static function getDefault($value){
  1251. $id = serialize($value);
  1252. if (isset(self::$__defaults[$id]))
  1253. return self::$__defaults[$id];
  1254. return $value;
  1255. }
  1256. /**
  1257. * Return a default replacement of value by var
  1258. *
  1259. * @param string $var
  1260. * @param mixed $value
  1261. * @return mixed
  1262. */
  1263. final static function getDefaultByVar($var, $value){
  1264. if (isset(self::$__defaults_by_var[$var])) {
  1265. $id = serialize($value);
  1266. if (isset(self::$__defaults_by_var[$var][$id]))
  1267. return self::$__defaults_by_var[$var][$id];
  1268. }
  1269. return $value;
  1270. }
  1271. // ------------------------------------------- SEARCHERS ----------------------------------------- //
  1272. /**
  1273. * Search a position in a list of ranges
  1274. *
  1275. * @param array $ranges
  1276. * @param integer $pos
  1277. * @return boolean
  1278. */
  1279. final public function searchInRanges($ranges, $pos){
  1280. foreach ( $ranges as $range ) {
  1281. if ($pos >= $range[0] && $pos <= $range[1])
  1282. return true;
  1283. }
  1284. return false;
  1285. }
  1286. /**
  1287. * Search $pos in the ranges of lists/loops in current source
  1288. *
  1289. * @param array $items
  1290. * @return boolean
  1291. */
  1292. final public function searchInListRanges($pos = 0){
  1293. $rangs = $this->getBlockRanges(null, DIV_TAG_LOOP_BEGIN_PREFIX, DIV_TAG_LOOP_BEGIN_SUFFIX, DIV_TAG_LOOP_END_PREFIX, DIV_TAG_LOOP_END_SUFFIX);
  1294. foreach ( $rangs as $rang )
  1295. if ($pos > $rang[0] && $pos < $rang[1])
  1296. return true;
  1297. return false;
  1298. }
  1299. /**
  1300. * Search $pos before the frist range of lists/loops in current source
  1301. *
  1302. * @param array $items
  1303. * @param integer $pos
  1304. * @return boolean
  1305. */
  1306. final public function searchPreviousLoops($pos = 0){
  1307. $rangs = $this->getBlockRanges(null, DIV_TAG_LOOP_BEGIN_PREFIX, DIV_TAG_LOOP_BEGIN_SUFFIX, DIV_TAG_LOOP_END_PREFIX, DIV_TAG_LOOP_END_SUFFIX);
  1308. foreach ( $rangs as $rang )
  1309. if ($pos > $rang[0])
  1310. return $rang[0];
  1311. return false;
  1312. }
  1313. /**
  1314. * Return true if pos is after first range
  1315. *
  1316. * @param string $tag_begin
  1317. * @param string $tag_end
  1318. * @param integer $pos
  1319. * @return boolean
  1320. */
  1321. final public function searchPosAfterRange($tag_begin, $tag_end, $pos){
  1322. $rangs = $this->getRanges($tag_begin, $tag_end, null, true);
  1323. if (isset($rangs[0]))
  1324. if ($rangs[0][0] < $pos)
  1325. return true;
  1326. return false;
  1327. }
  1328. /**
  1329. * Return true if pos is in the ranges of capsules of current source
  1330. *
  1331. * @param array $items
  1332. * @return array
  1333. */
  1334. final public function searchInCapsuleRanges(&$items = null, $pos = 0){
  1335. if (is_null($items))
  1336. $items = &$this->__items;
  1337. foreach ( $items as $key => $value ) {
  1338. $rangs = $this->getRanges(DIV_TAG_CAPSULE_BEGIN_PREFIX . $key, DIV_TAG_CAPSULE_END_PREFIX . $key);
  1339. foreach ( $rangs as $rang )
  1340. if ($pos >= $rang[0] && $pos <= $rang[1])
  1341. return true;
  1342. }
  1343. return false;
  1344. }
  1345. // -------------------------------------------------------------------------------------------------- //
  1346. /**
  1347. * Return any value as a boolean
  1348. *
  1349. * @param mixed $value
  1350. * @return boolean
  1351. */
  1352. final static function mixedBool($value){
  1353. if (is_bool($value))
  1354. return $value;
  1355. if (is_object($value))
  1356. return count(get_object_vars($value)) > 0;
  1357. if (is_array($value))
  1358. return count($value) > 0;
  1359. if (self::isString($value)) {
  1360. if (strtolower($value) == 'false' || $value == '0')
  1361. return false;
  1362. if (strtolower($value) == 'true' || $value == '1')
  1363. return true;
  1364. return strlen(trim($value)) > 0;
  1365. }
  1366. if (is_numeric($value))
  1367. return $value > 0;
  1368. if (is_null($value))
  1369. return false;
  1370. return $value;
  1371. }
  1372. /**
  1373. * Return the correct @else@ tag of conditional block
  1374. *
  1375. * @param string $subsrc
  1376. * @return mixed
  1377. */
  1378. final public function getElseTag($subsrc){
  1379. $else = false;
  1380. $range_conditions = $this->getRanges(DIV_TAG_CONDITIONS_BEGIN_PREFIX, DIV_TAG_CONDITIONS_END, $subsrc);
  1381. $range_conditionals = $this->getConditionalRanges(true, $subsrc);
  1382. $rangesx = array_merge($range_conditions, $range_conditionals);
  1383. $pelse = 0;
  1384. $ls = strlen($subsrc);
  1385. do {
  1386. $continue = false;
  1387. if ($pelse < $ls)
  1388. $else = strpos($subsrc, DIV_TAG_ELSE, $pelse);
  1389. else
  1390. $else = false;
  1391. // checking that the tag doesn't belong to another IF inside this IF
  1392. if ($else !== false) {
  1393. foreach ( $rangesx as $r )
  1394. if ($else >= $r[0] && $else <= $r[1]) {
  1395. $pelse = $r[1] + 1;
  1396. $else = false;
  1397. $continue = true;
  1398. break;
  1399. }
  1400. }
  1401. } while ( $continue == true );
  1402. return $else;
  1403. }
  1404. /**
  1405. * Return the correct DIV_TAG_EMPTY tag of list block
  1406. *
  1407. * @param string $subsrc
  1408. * @return mixed
  1409. */
  1410. final public function getEmptyTag($subsrc){
  1411. $else = false;
  1412. $rangesx = $this->getRanges(DIV_TAG_LOOP_BEGIN_PREFIX, DIV_TAG_LOOP_END_PREFIX, $subsrc);
  1413. $pempty = 0;
  1414. $ls = strlen($subsrc);
  1415. do {
  1416. $continue = false;
  1417. if ($pempty < $ls)
  1418. $empty = strpos($subsrc, DIV_TAG_EMPTY, $pempty);
  1419. else
  1420. $empty = false;
  1421. // checking that the tag doesn't belong to another list block inside this list block
  1422. if ($empty !== false) {
  1423. foreach ( $rangesx as $r )
  1424. if ($empty >= $r[0] && $empty <= $r[1]) {
  1425. $pempty = $r[1] + 1;
  1426. $empty = false;
  1427. $continue = true;
  1428. break;
  1429. }
  1430. }
  1431. } while ( $continue == true );
  1432. return $empty;
  1433. }
  1434. /**
  1435. * Parse conditional blocks
  1436. *
  1437. * @param string $src
  1438. * @param string $key
  1439. * @param mixed $value
  1440. * @return string
  1441. */
  1442. final public function parseConditionalBlock($key, $value){
  1443. if (self::$__log_mode)
  1444. $this->logger('Parsing conditional block: ' . $key);
  1445. if (isset($this->__ignore[$key]))
  1446. return false;
  1447. $src = &$this->__src;
  1448. if (is_array($value) || is_object($value)) {
  1449. $vars = $value;
  1450. if (is_object($vars))
  1451. $vars = get_object_vars($vars);
  1452. foreach ( $vars as $k => $val ) {
  1453. if (is_numeric($k))
  1454. break;
  1455. $this->parseConditionalBlock($key . '.' . $k, $val);
  1456. }
  1457. }
  1458. $value = self::mixedBool($value);
  1459. $passes = array(
  1460. false,
  1461. true
  1462. );
  1463. $pos = 0;
  1464. foreach ( $passes as $flag ) {
  1465. if ($flag === false) {
  1466. $tag_begin = DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX . $key . DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX;
  1467. $tag_end = DIV_TAG_CONDITIONAL_TRUE_END_PREFIX . $key . DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX;
  1468. } else {
  1469. $tag_begin = DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX . $key . DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX;
  1470. $tag_end = DIV_TAG_CONDITIONAL_FALSE_END_PREFIX . $key . DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX;
  1471. }
  1472. $l = strlen($tag_begin);
  1473. $l2 = strlen($tag_end);
  1474. $lelse = strlen(DIV_TAG_ELSE);
  1475. while ( true ) {
  1476. if (strpos($src, $tag_begin) === false)
  1477. break;
  1478. $ranges = $this->getRanges($tag_begin, $tag_end, $src, true, $pos);
  1479. if (count($ranges) > 0) {
  1480. $ini = $ranges[0][0];
  1481. $fin = $ranges[0][1];
  1482. // Controlling injected vars
  1483. // _is_last _is_first _is_odd _is_even
  1484. if (array_search($key, array(
  1485. "_is_last",
  1486. "_is_first",
  1487. "_is_odd",
  1488. "_id_even"
  1489. )) !== false) {
  1490. if ($this->isBlockInsideBlock(DIV_TAG_LOOP_BEGIN_PREFIX, DIV_TAG_LOOP_END_PREFIX, $ini, $fin)) {
  1491. $pos = $fin + 1;
  1492. if (self::$__log_mode)
  1493. $this->logger("Ignore the injected var inside another list block: $key..");
  1494. continue;
  1495. }
  1496. }
  1497. if ($this->searchPosAfterRange(DIV_TAG_TPLVAR_BEGIN, DIV_TAG_TPLVAR_END, $ini)) {
  1498. $pos = $fin + 1;
  1499. continue;
  1500. }
  1501. $subsrc = substr($src, $ini + $l, $fin - ($ini + $l));
  1502. $else = $this->getElseTag($subsrc);
  1503. if ($value === $flag) {
  1504. if ($else !== false) {
  1505. $con = substr($src, $ini + $l + $else + $lelse, $fin - ($ini + $l + $else + $lelse));
  1506. if ($con[0] == ' ')
  1507. $con = substr($con, 1);
  1508. if (substr($con, - 1) == ' ')
  1509. $con = substr_replace($con, "", - 1);
  1510. $src = substr($src, 0, $ini) . $con . substr($src, $fin + $l2);
  1511. } else
  1512. $src = substr($src, 0, $ini) . substr($src, $fin + $l2);
  1513. } else {
  1514. if ($else !== false) {
  1515. $con = substr($src, $ini + $l, $else);
  1516. if ($con[0] == ' ')
  1517. $con = substr($con, 1);
  1518. if (substr($con, - 1) == ' ')
  1519. $con = substr_replace($con, "", - 1);
  1520. $src = substr($src, 0, $ini) . $con . substr($src, $fin + $l2);
  1521. } else {
  1522. $con = substr($src, $ini + $l, $fin - ($ini + $l));
  1523. if ($con[0] == ' ')
  1524. $con = substr($con, 1);
  1525. if (substr($con, - 1) == ' ')
  1526. $con = substr_replace($con, "", - 1);
  1527. $src = substr($src, 0, $ini) . $con . substr($src, $fin + $l2);
  1528. }
  1529. }
  1530. $pos = $ini + 1;
  1531. } else {
  1532. break;
  1533. }
  1534. }
  1535. }
  1536. }
  1537. /**
  1538. * Format for number
  1539. *
  1540. * @param string $key
  1541. * @param string $src
  1542. * @return string
  1543. */
  1544. final public function numberFormat($key, $value){
  1545. if (isset($this->__ignore[$key]))
  1546. return false;
  1547. $tag_begin = DIV_TAG_NUMBER_FORMAT_PREFIX . $key . DIV_TAG_NUMBER_FORMAT_SEPARATOR;
  1548. $tag_end = DIV_TAG_NUMBER_FORMAT_SUFFIX;
  1549. $l1 = strlen($tag_begin);
  1550. $l2 = strlen($tag_end);
  1551. if (strpos($this->__src, $tag_begin) === false)
  1552. return false;
  1553. if (strpos($this->__src, $tag_end) === false)
  1554. return false;
  1555. $p1 = strpos($this->__src, DIV_TAG_TPLVAR_BEGIN);
  1556. $pos = 0;
  1557. while ( true ) {
  1558. $ranges = $this->getRanges($tag_begin, $tag_end, null, true, $pos);
  1559. if (count($ranges) < 1)
  1560. break;
  1561. $ini = $ranges[0][0];
  1562. $fin = $ranges[0][1];
  1563. if (self::$__log_mode)
  1564. $this->logger("Formatting number $key = $value");
  1565. if ($ini > $p1 && $p1 !== false)
  1566. return true;
  1567. if ($this->searchPosAfterRange(DIV_TAG_TPLVAR_BEGIN, DIV_TAG_TPLVAR_END, $ini)) {
  1568. $pos = $ini + 1;
  1569. continue;
  1570. }
  1571. $format = substr($this->__src, $ini + $l1, $fin - ($ini + $l1));
  1572. if (trim($format) == "")
  1573. $format = "0.";
  1574. if (! is_numeric($value)) {
  1575. $this->__src = substr($this->__src, 0, $ini) . DIV_TAG_NUMBER_FORMAT_PREFIX . $value . DIV_TAG_NUMBER_FORMAT_SEPARATOR . $format . DIV_TAG_NUMBER_FORMAT_SUFFIX . substr($this->__src, $fin + $l2);
  1576. return true;
  1577. }
  1578. $separator = ".";
  1579. $miles_sep = "";
  1580. if (! is_numeric(substr($format, strlen($format) - 1))) {
  1581. $separator = substr($format, strlen($format) - 1);
  1582. $format = substr($format, 0, strlen($format) - 1);
  1583. }
  1584. if (! is_numeric(substr($format, strlen($format) - 1))) {
  1585. $miles_sep = $separator;
  1586. $separator = substr($format, strlen($format) - 1);
  1587. $format = substr($format, 0, strlen($format) - 1);
  1588. }
  1589. $decimals = intval($format);
  1590. $this->__src = substr($this->__src, 0, $ini) . number_format($value, $decimals, $separator, $miles_sep) . substr($this->__src, $fin + $l2);
  1591. }
  1592. }
  1593. /**
  1594. * Parse submatch
  1595. *
  1596. * @param mixed $items
  1597. * @param string $key
  1598. * @param mixed $value
  1599. * @param string $modifiers
  1600. * @return boolean
  1601. */
  1602. final public function parseSubmatch(&$items, $key, $value, $modifiers = array()){
  1603. if (isset($this->__ignore[$key]))
  1604. return false;
  1605. if (strpos($this->__src, $key . DIV_TAG_SUBMATCH_SEPARATOR) !== false)
  1606. foreach ( $modifiers as $modifier )
  1607. while ( true ) {
  1608. $tag_begin = DIV_TAG_REPLACEMENT_PREFIX . $modifier . $key . DIV_TAG_SUBMATCH_SEPARATOR;
  1609. $ranges = $this->getRanges($tag_begin, DIV_TAG_REPLACEMENT_SUFFIX, null, true);
  1610. $l = strlen($tag_begin);
  1611. if (count($ranges) < 1)
  1612. break;
  1613. if (self::$__log_mode)
  1614. $this->logger("Parsing submatch $tag_begin");
  1615. // User wrote ....
  1616. $r = substr($this->__src, $ranges[0][0] + $l, $ranges[0][1] - ($ranges[0][0] + $l));
  1617. // Interpreted by Div ...
  1618. $arr = explode(DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR, $r);
  1619. if (count($arr) < 2)
  1620. $arr = array(
  1621. 0,
  1622. $arr[0]
  1623. );
  1624. $arr[0] = trim($arr[0]);
  1625. $arr[1] = trim($arr[1]);
  1626. $nkey = str_replace(".", "", uniqid("submatch", true));
  1627. self::$__dont_remember_it[$nkey] = true;
  1628. if (! is_numeric($arr[0]) || ! is_numeric($arr[1])) {
  1629. if (substr("{$arr[1]}", 0, 1) == DIV_TAG_MODIFIER_TRUNCATE) {
  1630. $items[$nkey] = self::teaser("{$value}", intval(substr($arr[1], 1)));
  1631. $this->saveOperation(array(
  1632. "o" => "replace_submatch_teaser",
  1633. "key" => $key,
  1634. "modifier" => $modifier,
  1635. "param" => $r
  1636. ));
  1637. } elseif (substr("{$arr[1]}", 0, 1) == DIV_TAG_MODIFIER_WORDWRAP) {
  1638. $items[$nkey] = wordwrap("{$value}", intval(substr($arr[1], 1)), "\n", 1);
  1639. $this->saveOperation(array(
  1640. "o" => "replace_submatch_wordwrap",
  1641. "key" => $key,
  1642. "modifier" => $modifier,
  1643. "param" => $r
  1644. ));
  1645. } elseif (substr("{$arr[1]}", 0, 1) == DIV_TAG_MODIFIER_FORMAT || DIV_TAG_MODIFIER_FORMAT == '') {
  1646. $items[$nkey] = sprintf($arr[1], $value);
  1647. $this->saveOperation(array(
  1648. "o" => "replace_submatch_sprintf",
  1649. "key" => $key,
  1650. "modifier" => $modifier,
  1651. "param" => $r
  1652. ));
  1653. }
  1654. } else {
  1655. $items[$nkey] = substr("$value", $arr[0], $arr[1]);
  1656. $this->saveOperation(array(
  1657. "o" => "replace_submatch_substr",
  1658. "key" => $key,
  1659. "modifier" => $modifier,
  1660. "param" => $r,
  1661. "from" => $arr[0],
  1662. "for" => $arr[1]
  1663. ));
  1664. }
  1665. $right = "";
  1666. if ($ranges[0][1] + 1 < strlen($this->__src))
  1667. $right = substr($this->__src, $ranges[0][1] + strlen(DIV_TAG_REPLACEMENT_SUFFIX));
  1668. $this->__src = substr($this->__src, 0, $ranges[0][0]) . DIV_TAG_REPLACEMENT_PREFIX . "{$modifier}$nkey" . DIV_TAG_REPLACEMENT_SUFFIX . $right;
  1669. }
  1670. if (strpos($this->__src, "$key.") !== false) {
  1671. if (is_object($value)) {
  1672. $vars = get_object_vars($value);
  1673. foreach ( $vars as $kk => $v )
  1674. $this->parseSubmatch($items, "$key.$kk", $v, $modifiers);
  1675. }
  1676. if (is_array($value))
  1677. foreach ( $value as $kk => $v )
  1678. $this->parseSubmatch($items, "$key.$kk", $v, $modifiers);
  1679. }
  1680. return true;
  1681. }
  1682. /**
  1683. * Parsing sub matches
  1684. *
  1685. * @param mixed $items
  1686. */
  1687. final public function parseSubmatches(&$items = null){
  1688. if (self::$__log_mode)
  1689. $this->logger("Parsing submatches...");
  1690. if (is_null($items))
  1691. $items = &$this->__items;
  1692. $modifiers = array();
  1693. foreach ( self::$__modifiers as $m )
  1694. if (strpos($this->__src, DIV_TAG_REPLACEMENT_PREFIX . $m) !== false)
  1695. $modifiers[] = $m;
  1696. foreach ( $items as $key => $value )
  1697. $this->parseSubmatch($items, $key, $value, $modifiers);
  1698. }
  1699. /**
  1700. * Parse IDE's friendly marks
  1701. */
  1702. final public function parseFriendly(){
  1703. $l1 = strlen(DIV_TAG_FRIENDLY_BEGIN);
  1704. $l2 = strlen(DIV_TAG_FRIENDLY_END);
  1705. while ( true ) {
  1706. $r = $this->getRanges(DIV_TAG_FRIENDLY_BEGIN, DIV_TAG_FRIENDLY_END, null, true);
  1707. if (count($r) < 1)
  1708. break;
  1709. $ini = $r[0][0];
  1710. $fin = $r[0][1];
  1711. $this->__src = substr($this->__src, 0, $ini) . substr($this->__src, $ini + $l1, $fin - ($ini + $l1)) . substr($this->__src, $fin + $l2);
  1712. }
  1713. }
  1714. /**
  1715. * Parse matches
  1716. *
  1717. * @param string $src
  1718. * @param string $key
  1719. * @param mixed $value
  1720. */
  1721. final public function parseMatch($key, $value, &$engine){
  1722. if (isset($this->__ignore[$key]))
  1723. return false;
  1724. $value = self::getDefault($value);
  1725. $value = self::getDefaultByVar($key, $value);
  1726. if (is_bool($value))
  1727. $value = $value ? "true" : "false";
  1728. $is_string = self::isString($value);
  1729. if ($is_string)
  1730. $value = "$value";
  1731. $prefix = DIV_TAG_REPLACEMENT_PREFIX;
  1732. $suffix = DIV_TAG_REPLACEMENT_SUFFIX;
  1733. if ($is_string || is_numeric($value)) {
  1734. $p1 = strpos($this->__src, DIV_TAG_TPLVAR_BEGIN);
  1735. $p2 = strpos($this->__src, DIV_TAG_MACRO_BEGIN);
  1736. if ($p1 === false && $p2 === false)
  1737. $substr = $this->__src;
  1738. elseif ($p1 !== false && $p2 !== false) {
  1739. $min = min($p1, $p2);
  1740. $substr = substr($this->__src, 0, $min);
  1741. $p1 = $min;
  1742. } elseif ($p1 !== false && $p2 === false)
  1743. $substr = substr($this->__src, 0, $p1);
  1744. else {
  1745. $substr = substr($this->__src, 0, $p2);
  1746. $p1 = $p2;
  1747. }
  1748. if (strpos($value, $prefix . DIV_TAG_MODIFIER_SIMPLE . $key . $suffix) !== false) {
  1749. $value = str_replace($prefix . DIV_TAG_MODIFIER_SIMPLE . $key . $suffix, "", $value);
  1750. self::error("Was detected an infinite loop in recursive replacement of $$rk.", DIV_ERROR_WARNING);
  1751. }
  1752. $px = false;
  1753. foreach ( self::$__modifiers as $lm ) {
  1754. $py = strpos($substr, $prefix . $lm . $key . $suffix);
  1755. if ($py !== false) {
  1756. $px = $py;
  1757. break;
  1758. }
  1759. }
  1760. if ($px !== false) {
  1761. $rcount = 0;
  1762. if (self::$__log_mode)
  1763. $this->logger("Parsing match: $key in '" . substr($substr, 0, 50) . "'");
  1764. $value = trim("$value");
  1765. if (trim($value) != "") {
  1766. $crc = crc32($value);
  1767. $engine->__src = $value;
  1768. $engine->__items = $this->__items;
  1769. $engine->parseInclude($this->__items);
  1770. $engine->parsePreprocessed($this->__items);
  1771. $value = $engine->__src;
  1772. if (self::issetVar($key, $this->__items) && crc32($value) != $crc) {
  1773. if (gettype(self::getVarValue($key, $this->__items)) == "string")
  1774. self::setVarValue($key, $value, $this->__items);
  1775. }
  1776. }
  1777. $mod = DIV_TAG_MODIFIER_SIMPLE;
  1778. $substr = str_replace($prefix . $mod . $key . $suffix, $value, $substr, $rcount); // simple replacement
  1779. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1780. $this->saveOperation(array(
  1781. 'o' => 'simple_replacement',
  1782. 'key' => $key,
  1783. 'modifier' => $mod,
  1784. 'before' => $p1
  1785. ));
  1786. $mod = DIV_TAG_MODIFIER_CAPITALIZE_FIRST;
  1787. if (strpos($substr, $prefix . $mod) !== false) {
  1788. $substr = str_replace(DIV_TAG_REPLACEMENT_PREFIX . $mod . $key . $suffix, ucfirst($value), $substr, $rcount);
  1789. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1790. $this->saveOperation(array(
  1791. "o" => 'simple_replacement',
  1792. 'key' => $key,
  1793. 'modifier' => $mod,
  1794. 'before' => $p1
  1795. ));
  1796. }
  1797. $mod = DIV_TAG_MODIFIER_CAPITALIZE_WORDS;
  1798. if (strpos($substr, $prefix . $mod) !== false) {
  1799. $substr = str_replace($prefix . $mod . $key . $suffix, ucwords($value), $substr, $rcount);
  1800. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1801. $this->saveOperation(array(
  1802. 'o' => 'simple_replacement',
  1803. 'key' => $key,
  1804. 'modifier' => $mod,
  1805. 'before' => $p1
  1806. ));
  1807. }
  1808. $mod = DIV_TAG_MODIFIER_UPPERCASE;
  1809. if (strpos($substr, $prefix . $mod) !== false) {
  1810. $substr = str_replace($prefix . $mod . $key . $suffix, strtoupper($value), $substr, $rcount);
  1811. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1812. $this->saveOperation(array(
  1813. 'o' => 'simple_replacement',
  1814. 'key' => $key,
  1815. 'modifier' => DIV_TAG_MODIFIER_UPPERCASE,
  1816. 'before' => $p1
  1817. ));
  1818. }
  1819. $mod = DIV_TAG_MODIFIER_LENGTH;
  1820. if (strpos($substr, $prefix . $mod) !== false) {
  1821. $substr = str_replace($prefix . $mod . $key . $suffix, strlen($value), $substr, $rcount);
  1822. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1823. $this->saveOperation(array(
  1824. 'o' => 'simple_replacement',
  1825. 'key' => $key,
  1826. 'modifier' => $mod,
  1827. 'before' => $p1
  1828. ));
  1829. }
  1830. $mod = DIV_TAG_MODIFIER_COUNT_WORDS;
  1831. if (strpos($substr, $prefix . $mod) !== false) {
  1832. $substr = str_replace($prefix . $mod . $key . $suffix, self::getCountOfWords($value), $substr, $rcount);
  1833. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1834. $this->saveOperation(array(
  1835. 'o' => 'simple_replacement',
  1836. 'key' => $key,
  1837. 'modifier' => $mod,
  1838. 'before' => $p1
  1839. ));
  1840. }
  1841. $mod = DIV_TAG_MODIFIER_COUNT_SENTENCES;
  1842. if (strpos($substr, $prefix . $mod) !== false) {
  1843. $substr = str_replace($prefix . $mod . $key . $suffix, self::getCountOfSentences($value), $substr, $rcount);
  1844. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1845. $this->saveOperation(array(
  1846. 'o' => 'simple_replacement',
  1847. 'key' => $key,
  1848. 'modifier' => $mod,
  1849. 'before' => $p1
  1850. ));
  1851. }
  1852. $mod = DIV_TAG_MODIFIER_COUNT_PARAGRAPHS;
  1853. if (strpos($substr, $prefix . $mod) !== false) {
  1854. $substr = str_replace($prefix . $mod . $key . $suffix, self::getCountOfParagraphs($value), $substr, $rcount);
  1855. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1856. $this->saveOperation(array(
  1857. 'o' => 'simple_replacement',
  1858. 'key' => $key,
  1859. 'modifier' => $mod,
  1860. 'before' => $p1
  1861. ));
  1862. }
  1863. $mod = DIV_TAG_MODIFIER_ENCODE_URL;
  1864. if (strpos($substr, $prefix . $mod) !== false) {
  1865. $substr = str_replace($prefix . $mod . $key . $suffix, urlencode($value), $substr, $rcount);
  1866. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1867. $this->saveOperation(array(
  1868. 'o' => 'simple_replacement',
  1869. 'key' => $key,
  1870. 'modifier' => $mod,
  1871. 'before' => $p1
  1872. ));
  1873. }
  1874. $mod = DIV_TAG_MODIFIER_ENCODE_RAW_URL;
  1875. if (strpos($substr, $prefix . $mod) !== false) {
  1876. $substr = str_replace($prefix . $mod . $key . $suffix, rawurlencode($value), $substr, $rcount);
  1877. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1878. $this->saveOperation(array(
  1879. 'o' => 'simple_replacement',
  1880. 'key' => $key,
  1881. 'modifier' => $mod,
  1882. 'before' => $p1
  1883. ));
  1884. }
  1885. $substr = str_replace(array(
  1886. $prefix . DIV_TAG_MODIFIER_LOWERCASE . $key . $suffix, // lower case
  1887. $prefix . DIV_TAG_MODIFIER_HTML_ENTITIES . $key . $suffix, // html entities
  1888. $prefix . DIV_TAG_MODIFIER_NL2BR . $key . $suffix, // convert newlines to <br/>
  1889. $prefix . DIV_TAG_MODIFIER_SINGLE_QUOTES . $key . $suffix, // escape unescaped single quotes,
  1890. $prefix . DIV_TAG_MODIFIER_JS . $key . $suffix // escape quotes and backslashes, newlines, etc.
  1891. ), array(
  1892. strtolower($value),
  1893. htmlentities($value),
  1894. nl2br($value),
  1895. preg_replace(array(
  1896. "%(?<!\\\\\\\\)'%",
  1897. "%(?<!\\\\\\\\)\"%"
  1898. ), array(
  1899. "\\'",
  1900. "\\\""
  1901. ), $value),
  1902. strtr($value, array(
  1903. "\\" => "\\\\",
  1904. "'" => "\\'",
  1905. "\"" => "\\\"",
  1906. "\r" => "\\r",
  1907. "\n" => "\\n",
  1908. "</" => "<\/"
  1909. ))
  1910. ), $substr);
  1911. foreach ( self::$__custom_modifiers as $modifier ) {
  1912. $proced = false;
  1913. if (function_exists($modifier[1]))
  1914. $proced = true;
  1915. else {
  1916. if (strpos($modifier[1], "::")) {
  1917. $temp = explode("::", $modifier[1]);
  1918. if (class_exists($temp[0])) {
  1919. if (method_exists($temp[0], $temp[1]))
  1920. $proced = true;
  1921. }
  1922. }
  1923. }
  1924. if ($proced)
  1925. if (strpos($substr, $modifier[0]) !== false) {
  1926. eval('$vvalue = ' . $modifier[1] . '($value);');
  1927. $substr = str_replace($prefix . $modifier[0] . $key . $suffix, $vvalue, $substr);
  1928. }
  1929. }
  1930. if ($p1 !== false)
  1931. $this->__src = $substr . substr($this->__src, $p1);
  1932. else
  1933. $this->__src = $substr;
  1934. }
  1935. }
  1936. $mod = DIV_TAG_MODIFIER_ENCODE_JSON;
  1937. if (strpos($this->__src, $prefix . $mod . $key . $suffix) !== false) {
  1938. $this->__src = str_replace($prefix . $mod . $key . $suffix, self::jsonEncode($value), $this->__src, $rcount);
  1939. if ($rcount > 0 && ! isset(self::$__dont_remember_it[$key]))
  1940. $this->saveOperation(array(
  1941. 'o' => 'json_encode',
  1942. 'key' => $key,
  1943. 'before' => false
  1944. ));
  1945. }
  1946. }
  1947. /**
  1948. * Parse iterations
  1949. *
  1950. * @param mixed $items
  1951. * @param string $src
  1952. */
  1953. final public function parseIterations(&$items, &$src = null){
  1954. $l1 = strlen(DIV_TAG_ITERATION_BEGIN_PREFIX);
  1955. $l2 = strlen(DIV_TAG_ITERATION_END);
  1956. if (self::$__log_mode)
  1957. $this->logger("Parsing iterations...");
  1958. if (is_null($src))
  1959. $src = &$this->__src;
  1960. $continue = true;
  1961. $p = 0;
  1962. $last_ranges = array(
  1963. array(
  1964. - 99
  1965. )
  1966. );
  1967. while ( true ) {
  1968. $ranges = $this->getRanges(DIV_TAG_ITERATION_BEGIN_PREFIX, DIV_TAG_ITERATION_END, $src, true);
  1969. if (count($ranges) < 1)
  1970. break;
  1971. if ($ranges[0][0] === $last_ranges[0][0])
  1972. break;
  1973. $last_ranges = $ranges;
  1974. $p = $ranges[0][0];
  1975. $p2 = $ranges[0][1];
  1976. $p1 = strpos($src, DIV_TAG_ITERATION_BEGIN_SUFFIX, $p + 1);
  1977. $s = substr($src, $p + $l1, $p1 - ($p + $l1));
  1978. $range = explode(DIV_TAG_ITERATION_PARAM_SEPARATOR, $s);
  1979. $c = count($range);
  1980. if ($c < 2) {
  1981. $range[1] = $range[0];
  1982. $range[0] = 1;
  1983. }
  1984. $itervar = "value";
  1985. $step = 1;
  1986. if ($c == 3) {
  1987. if (is_numeric($range[2]))
  1988. $step = trim($range[2]) * 1;
  1989. else
  1990. $itervar = trim($range[2]);
  1991. }
  1992. if ($c == 4) {
  1993. $itervar = $range[2];
  1994. $step = trim($range[3]) * 1;
  1995. }
  1996. if (is_numeric($range[0]) && is_numeric($range[1])) {
  1997. $range[0] = trim($range[0]) * 1;
  1998. $range[1] = trim($range[1]) * 1;
  1999. $key = uniqid();
  2000. $l = strlen($key);
  2001. $subsrc = substr($src, $p1 + $l1, $p2 - ($p1 + $l1));
  2002. $sitervar = " $itervar " . DIV_TAG_LOOP_VAR_SEPARATOR;
  2003. if (strpos($subsrc, DIV_TAG_LOOP_VAR_SEPARATOR))
  2004. $sitervar = '';
  2005. $src = substr($src, 0, $p) . DIV_TAG_LOOP_BEGIN_PREFIX . $key . DIV_TAG_LOOP_BEGIN_SUFFIX . $sitervar . $subsrc . DIV_TAG_LOOP_END_PREFIX . $key . DIV_TAG_LOOP_END_SUFFIX . substr($src, $p2 + $l2);
  2006. $items[$key] = array();
  2007. if ($range[1] >= $range[0])
  2008. for($i = $range[0]; $i >= $range[0] && $i <= $range[1]; $i = $i + $step)
  2009. $items[$key][] = $i;
  2010. else
  2011. for($i = $range[0]; $i >= $range[1] && $i <= $range[0]; $i = $i - $step)
  2012. $items[$key][] = $i;
  2013. }
  2014. }
  2015. }
  2016. /**
  2017. * Return true if a block is inside another block
  2018. *
  2019. * @param string $tagini
  2020. * @param string $tagend
  2021. * @param integer $pos1
  2022. * @param integer $pos2
  2023. * @return boolean
  2024. */
  2025. final public function isBlockInsideBlock($tagini, $tagend, $pos1, $pos2, $rangs = null){
  2026. if (is_null($rangs))
  2027. $rangs = $this->getRanges($tagini, $tagend);
  2028. foreach ( $rangs as $rang )
  2029. if ($rang[0] < $pos1 && $rang[1] > $pos2)
  2030. return true;
  2031. return false;
  2032. }
  2033. /**
  2034. * Parse list block
  2035. *
  2036. * @param mixed $value
  2037. * @param string $key
  2038. * @param mixed $items
  2039. */
  2040. final public function parseListBlock($value, $key, $items){
  2041. if (isset($this->__ignore[$key]))
  2042. return false;
  2043. $tag_begin = DIV_TAG_LOOP_BEGIN_PREFIX . $key . DIV_TAG_LOOP_BEGIN_SUFFIX;
  2044. $tag_end = DIV_TAG_LOOP_END_PREFIX . $key . DIV_TAG_LOOP_END_SUFFIX;
  2045. if (strpos($this->__src, $tag_begin) === false)
  2046. return false;
  2047. $l1 = strlen($tag_begin);
  2048. $l2 = strlen($tag_end);
  2049. $ranges = array();
  2050. $classname = get_class($this);
  2051. $pos = 0;
  2052. $total = 0;
  2053. $subtotal = 0;
  2054. while ( true ) {
  2055. $lists = $this->getRanges($tag_begin, $tag_end, null, true, $pos);
  2056. if (count($lists) < 1)
  2057. break;
  2058. if (self::$__log_mode)
  2059. $this->logger("Parsing the list: $key..");
  2060. $list = $lists[0];
  2061. $p1 = $list[0];
  2062. $p2 = $list[1];
  2063. // Checking logical order ...
  2064. $r = $this->checkLogicalOrder($p1, "", false, false, false, true);
  2065. if ($r !== false) {
  2066. $pos = $p2 + 1;
  2067. continue;
  2068. }
  2069. // Check if list is inside another list block ...
  2070. if ($this->searchInListRanges($p1)) {
  2071. $pos = $p2 + 1;
  2072. continue;
  2073. }
  2074. $ranges[] = $list;
  2075. if ($p2 > $p1) {
  2076. $minihtml = substr($this->__src, $p1 + $l1, $p2 - $p1 - $l1);
  2077. $itemkey = "value";
  2078. // The itemkey/itervar can't have space or newline chararters
  2079. if (strpos($minihtml, DIV_TAG_LOOP_VAR_SEPARATOR) !== false) {
  2080. $arr = explode(DIV_TAG_LOOP_VAR_SEPARATOR, $minihtml, 2);
  2081. if (strpos($arr[0], "\n") === false) {
  2082. $arr[0] = trim($arr[0]);
  2083. if (strpos($arr[0], ' ') === false) {
  2084. if ($itemkey != "")
  2085. $itemkey = $arr[0];
  2086. $minihtml = $arr[1];
  2087. }
  2088. }
  2089. }
  2090. $ii = 0;
  2091. $randoms = array();
  2092. $count = count($value);
  2093. $ii = 0;
  2094. $keys = array_keys($value);
  2095. $ckeys = count($keys);
  2096. $go_index = strpos($minihtml, '_index') !== false;
  2097. $go_key = strpos($minihtml, '_key') !== false;
  2098. $go_index_random = strpos($minihtml, '_index_random') !== false;
  2099. $go_is_odd = strpos($minihtml, '_is_odd') !== false;
  2100. $go_is_even = strpos($minihtml, '_is_even') !== false;
  2101. $go_is_first = strpos($minihtml, '_is_first') !== false;
  2102. $go_is_last = strpos($minihtml, '_is_last') !== false;
  2103. $go_list = strpos($minihtml, '_list') !== false;
  2104. $go_item = strpos($minihtml, '_item') !== false;
  2105. $go_order = strpos($minihtml, '_order') !== false;
  2106. $go_previous = strpos($minihtml, '_previous') !== false;
  2107. $go_next = strpos($minihtml, '_next') !== false;
  2108. $xitems = array();
  2109. $xitems_orig = array();
  2110. // Preparing xitems data
  2111. $previous = null;
  2112. $next = null;
  2113. $empty = $this->getEmptyTag($minihtml);
  2114. if ($empty !== false) {
  2115. $body_parts = array(
  2116. substr($minihtml, 0, $empty),
  2117. substr($minihtml, $empty + strlen(DIV_TAG_EMPTY))
  2118. );
  2119. } else
  2120. $body_parts = array(
  2121. $minihtml,
  2122. ""
  2123. );
  2124. $h = "";
  2125. if (empty($value))
  2126. $h = $body_parts[1];
  2127. else {
  2128. $minihtml = $body_parts[0];
  2129. foreach ( $value as $kk => $item ) {
  2130. if (isset($keys[$ii + 1])) {
  2131. $next = $value[$keys[$ii + 1]];
  2132. } else
  2133. $next = null;
  2134. $ii ++;
  2135. $anothers = array();
  2136. $item_orig = $item;
  2137. if ($go_index)
  2138. $anothers['_index'] = $ii - 1;
  2139. if ($go_key)
  2140. $anothers['_key'] = $kk;
  2141. if ($go_index_random) {
  2142. do {
  2143. $random = rand(1, $count);
  2144. } while ( isset($randoms[$random]) );
  2145. $randoms[$random] = true;
  2146. $anothers['_index_random'] = $random - 1;
  2147. }
  2148. if ($go_is_odd)
  2149. $anothers['_is_odd'] = ($ii % 2 != 0);
  2150. if ($go_is_even)
  2151. $anothers['_is_even'] = ($ii % 2 == 0);
  2152. if ($go_is_first)
  2153. $anothers['_is_first'] = ($ii === 1);
  2154. if ($go_is_last)
  2155. $anothers['_is_last'] = ($ii == $ckeys);
  2156. if ($go_list)
  2157. $anothers['_list'] = $key;
  2158. if ($go_item) {
  2159. if (is_object($item))
  2160. $anothers['_item'] = clone $item;
  2161. else
  2162. $anothers['_item'] = $item;
  2163. }
  2164. if ($go_order)
  2165. $anothers['_order'] = $ii;
  2166. if ($go_previous) {
  2167. if (is_object($previous))
  2168. $anothers['_previous'] = clone $previous;
  2169. else
  2170. $anothers['_previous'] = $previous;
  2171. }
  2172. if ($go_next) {
  2173. if (is_object($next))
  2174. $anothers['_next'] = clone $next;
  2175. else
  2176. $anothers['_next'] = $next;
  2177. }
  2178. $previous = $item;
  2179. if (is_object($item))
  2180. if (self::isString($item)) {
  2181. $itemstr = "$item";
  2182. if (! isset($item->value))
  2183. $item->value = $itemstr;
  2184. if (! isset($item->_to_string))
  2185. $item->_to_string = $itemstr;
  2186. }
  2187. if (is_object($item))
  2188. $item = get_object_vars($item);
  2189. $isscalar = false;
  2190. if (! is_array($item) || is_scalar($value)) {
  2191. $item = array(
  2192. $itemkey => $item
  2193. );
  2194. $isscalar = true;
  2195. } else if ($itemkey != "value") {
  2196. $item[$itemkey] = $item;
  2197. }
  2198. $item = array_merge($item, $anothers);
  2199. $xitems[] = $item;
  2200. $xitems_orig[] = self::cop($item_orig, $anothers);
  2201. }
  2202. // Parsing ...
  2203. $h = "";
  2204. $engine = self::getAuxiliaryEngineClone($xitems);
  2205. $engine->__src_original = $minihtml;
  2206. $engine->__memory = $this->__memory;
  2207. $globals_design = self::$__globals_design;
  2208. foreach ( $xitems as $xkey => $item ) {
  2209. $tempglobal = array(); // priority to item's properties
  2210. // Save similar global design vars
  2211. $tempglobal = self::$__globals_design;
  2212. foreach ( $item as $kkk => $vvv )
  2213. if (isset(self::$__globals_design[$kkk])) {
  2214. unset(self::$__globals_design[$kkk]);
  2215. }
  2216. if (self::$__log_mode)
  2217. $this->logger("Parsing item $xkey of the list '$key'...");
  2218. $engine->__items[$xkey] = array_merge($items, $item);
  2219. $engine->__items_orig = $xitems_orig[$xkey];
  2220. $engine->parse(true, $xkey);
  2221. $engine->__items[$xkey] = $item;
  2222. self::$__globals_design = array_merge($tempglobal, self::$__globals_design);
  2223. $break = strpos($engine->__src, DIV_TAG_BREAK);
  2224. if ($break !== false) {
  2225. $engine->__src = substr($engine->__src, 0, $break);
  2226. $h .= $engine->__src;
  2227. break;
  2228. }
  2229. $h .= $engine->__src;
  2230. }
  2231. // Restore global design vars
  2232. self::$__globals_design = $globals_design;
  2233. }
  2234. // Replace
  2235. $this->__src = substr($this->__src, 0, $p1) . $h . substr($this->__src, $p2 + $l2);
  2236. }
  2237. }
  2238. }
  2239. /**
  2240. * Parse list
  2241. *
  2242. * @param mixed $items
  2243. * @param string $superkey
  2244. */
  2245. final public function parseList($items = null, $superkey = ""){
  2246. if (self::$__log_mode)
  2247. $this->logger("Parsing loops, SUPERKEY = '$superkey'...");
  2248. if (isset($this->__ignore[$superkey]))
  2249. return false;
  2250. if (is_null($items))
  2251. $items = $this->__items;
  2252. if (! is_array($items))
  2253. if (is_object($items)) {
  2254. $items = get_object_vars($items);
  2255. } else
  2256. continue;
  2257. if ($superkey != "")
  2258. $superkey .= ".";
  2259. if (strpos($this->__src, DIV_TAG_LOOP_BEGIN_PREFIX . $superkey) !== false)
  2260. foreach ( $items as $key => $value ) {
  2261. $key = $superkey . $key;
  2262. if (strpos($this->__src, DIV_TAG_LOOP_BEGIN_PREFIX . "$key.") !== false) {
  2263. if (! is_array($value))
  2264. if (is_object($value)) {
  2265. $value = get_object_vars($value);
  2266. } else
  2267. continue;
  2268. $this->parseList($value, $key);
  2269. }
  2270. }
  2271. $pos = array();
  2272. foreach ( $items as $key => $value ) {
  2273. $p = strpos($this->__src, DIV_TAG_LOOP_BEGIN_PREFIX . $superkey . $key . DIV_TAG_LOOP_BEGIN_SUFFIX);
  2274. if ($p !== false)
  2275. $pos[$key] = $p;
  2276. }
  2277. asort($pos);
  2278. foreach ( $pos as $key => $v ) {
  2279. $value = $items[$key];
  2280. if (is_scalar($value))
  2281. $value = "$value";
  2282. if (self::isString($value))
  2283. $value = str_split($value);
  2284. if (! is_array($value))
  2285. if (is_object($value)) {
  2286. $value = get_object_vars($value);
  2287. } else
  2288. continue;
  2289. $this->parseListBlock($value, $superkey . $key, $items);
  2290. }
  2291. }
  2292. /**
  2293. * Ignore parts of template
  2294. *
  2295. * @return array
  2296. */
  2297. final public function parseIgnore(){
  2298. if (self::$__log_mode)
  2299. $this->logger("Parsing ignore's blocks...");
  2300. $l1 = strlen(DIV_TAG_IGNORE_BEGIN);
  2301. $l2 = strlen(DIV_TAG_IGNORE_END);
  2302. $pos = 0;
  2303. while ( true ) {
  2304. $ranges = $this->getRanges(DIV_TAG_IGNORE_BEGIN, DIV_TAG_IGNORE_END, null, true, $pos);
  2305. if (count($ranges) < 1)
  2306. break;
  2307. if (self::searchInRanges($this->getRanges(DIV_TAG_COMMENT_BEGIN, DIV_TAG_COMMENT_END), $ranges[0][0]) !== false) {
  2308. $pos = $ranges[0][1] + 1;
  2309. continue;
  2310. }
  2311. $id = uniqid();
  2312. self::$__ignored_parts[$id] = substr($this->__src, $ranges[0][0] + $l1, $ranges[0][1] - $ranges[0][0] - $l1);
  2313. $this->__src = substr($this->__src, 0, $ranges[0][0]) . '{' . $id . '}' . substr($this->__src, $ranges[0][1] + $l2);
  2314. $pos = $ranges[0][0] + 1;
  2315. }
  2316. return self::$__ignored_parts;
  2317. }
  2318. /**
  2319. * Return the resolved path for include and preprocessed
  2320. *
  2321. * @param string $path
  2322. * @return string
  2323. */
  2324. final public function getTplPath($path){
  2325. $return = null;
  2326. if (self::fileExists($path . "." . DIV_DEFAULT_TPL_FILE_EXT))
  2327. $path .= "." . DIV_DEFAULT_TPL_FILE_EXT;
  2328. $path = str_replace("." . DIV_DEFAULT_TPL_FILE_EXT . "." . DIV_DEFAULT_TPL_FILE_EXT, "." . DIV_DEFAULT_TPL_FILE_EXT, $path);
  2329. // Relative path
  2330. if (! self::fileExists($path)) {
  2331. if ($this->__path != "") {
  2332. if (self::fileExists($this->__path)) {
  2333. $folder = self::getFolderOf($this->__path);
  2334. if (self::fileExists($folder . "/" . $path . "." . DIV_DEFAULT_TPL_FILE_EXT))
  2335. $path .= "." . DIV_DEFAULT_TPL_FILE_EXT;
  2336. if (self::fileExists($folder . "/" . $path)) {
  2337. $return = $folder . "/" . $path;
  2338. }
  2339. }
  2340. }
  2341. }
  2342. if (is_null($return)) {
  2343. // Resolving with the historial ...
  2344. $max = 0;
  2345. $return = $path;
  2346. foreach ( self::$__includes_historial as $ih ) {
  2347. $folder = self::getFolderOf($ih);
  2348. $fullpath = $folder . "/" . $path;
  2349. if (self::fileExists($fullpath . "." . DIV_DEFAULT_TPL_FILE_EXT))
  2350. $fullpath .= "." . DIV_DEFAULT_TPL_FILE_EXT;
  2351. else if (self::fileExists($fullpath . "." . DIV_DEFAULT_TPL_FILE_EXT))
  2352. $fullpath .= "." . DIV_DEFAULT_TPL_FILE_EXT;
  2353. $similar = similar_text($ih, $fullpath);
  2354. if ((self::fileExists($fullpath) || self::fileExists($fullpath)) && $similar >= $max)
  2355. $return = $fullpath;
  2356. }
  2357. }
  2358. if (! self::fileExists($return))
  2359. return null;
  2360. return $return;
  2361. }
  2362. /**
  2363. * Detect recursive inclusion
  2364. *
  2365. * @param array $exclusion
  2366. * @param string $path
  2367. * @param integer $ini
  2368. * @return boolean
  2369. */
  2370. final static function detectRecursiveInclusion($exclusion, $path, $ini){
  2371. foreach ( $exclusion as $exc ) {
  2372. $p = $exc['path'];
  2373. $i = $exc['ini'];
  2374. $f = $exc['end'];
  2375. if ($p == $path && $ini >= $i && $ini <= $f)
  2376. return true;
  2377. }
  2378. return false;
  2379. }
  2380. /**
  2381. * Secure is_string
  2382. *
  2383. * @param mixed $value
  2384. * @return boolean
  2385. */
  2386. final static function isString($value){
  2387. if (is_string($value))
  2388. return true;
  2389. if (is_object($value))
  2390. if (method_exists($value, "__toString"))
  2391. return true;
  2392. return false;
  2393. }
  2394. /**
  2395. * Include others templates
  2396. *
  2397. * @param mixed $items
  2398. */
  2399. final public function parseInclude(&$items){
  2400. if (self::$__log_mode)
  2401. $this->logger("Parsing includes...");
  2402. $prefix = DIV_TAG_INCLUDE_BEGIN;
  2403. $suffix = DIV_TAG_INCLUDE_END;
  2404. if (is_object($items))
  2405. $items = get_object_vars($items);
  2406. if (is_array($items))
  2407. foreach ( $items as $key => $value ) {
  2408. if (isset($this->__ignore[$key]))
  2409. continue;
  2410. if (strpos($this->__src, $prefix . $key . $suffix) !== false && self::isString($value)) {
  2411. if (self::fileExists($value . "." . DIV_DEFAULT_TPL_FILE_EXT))
  2412. $value .= "." . DIV_DEFAULT_TPL_FILE_EXT;
  2413. $this->__src = str_replace($prefix . $key . $suffix, $prefix . $value . $suffix, $this->__src);
  2414. }
  2415. }
  2416. $restore = array();
  2417. $pos = 0;
  2418. $exclusion = array();
  2419. $l1 = strlen($prefix);
  2420. $l2 = strlen($suffix);
  2421. while ( true ) {
  2422. $ranges = $this->getRanges($prefix, $suffix, null, true, $pos);
  2423. if (count($ranges) < 1)
  2424. break;
  2425. $ini = $ranges[0][0];
  2426. $fin = $ranges[0][1];
  2427. $rangex = $this->getRanges(DIV_TAG_TPLVAR_BEGIN, DIV_TAG_TPLVAR_END);
  2428. $procede = true;
  2429. foreach ( $rangex as $rx ) {
  2430. if ($ini >= $rx[0] && $ini <= $rx[1]) {
  2431. $pos = $fin + 1;
  2432. $procede = false;
  2433. break;
  2434. }
  2435. }
  2436. if (! $procede)
  2437. continue;
  2438. if (self::searchInRanges($this->getRanges(DIV_TAG_COMMENT_BEGIN, DIV_TAG_COMMENT_END), $ranges[0][0]) !== false) {
  2439. $pos = $fin + 1;
  2440. continue;
  2441. }
  2442. $path = trim(substr($this->__src, $ini + $l1, $fin - $ini - $l1));
  2443. $path = $this->getTplPath($path);
  2444. if (self::$__log_mode)
  2445. $this->logger("Trying to include $path");
  2446. if ($path != $this->__path && ! self::detectRecursiveInclusion($exclusion, $path, $ini)) {
  2447. if (self::fileExists($path)) {
  2448. $c = "";
  2449. if (! is_dir($path)) {
  2450. self::$__includes_historial[] = $path;
  2451. $c = self::getFileContents($path);
  2452. $tpl_prop = $this->getTemplateProperties($c);
  2453. $c = $this->prepareDialect($c, $tpl_prop);
  2454. if (self::$__docs_on) {
  2455. if (self::fileExists($this->__path) || self::fileExists(PACKAGES . $this->__path)) {
  2456. $section = trim($this->__path);
  2457. $contained = trim($path);
  2458. if (substr($section, 0, 2) == './')
  2459. $section = substr($this->__path, 2);
  2460. if (substr($contained, 0, 2) == './')
  2461. $contained = substr($path, 2);
  2462. self::$__docs[$contained] = array();
  2463. if (! isset(self::$__docs[$section]))
  2464. self::$__docs[$section] = array();
  2465. if (! isset(self::$__docs[$section]['include']))
  2466. self::$__docs[$section]['include'] = array();
  2467. self::$__docs[$section]['include'][$contained] = $contained;
  2468. $engine = self::getAuxiliaryEngineClone($items);
  2469. $engine->__src = $c;
  2470. $engine->parseComments($path);
  2471. $c = $engine->__src;
  2472. unset($engine);
  2473. }
  2474. }
  2475. } else {
  2476. self::error("Template '$path' not found or is not a template", DIV_ERROR_WARNING);
  2477. }
  2478. $lenc = strlen($c);
  2479. foreach ( $exclusion as $idx => $exc ) {
  2480. if ($exc['ini'] > $ini)
  2481. $exclusion[$idx]['ini'] += $lenc;
  2482. if ($exc['end'] > $ini)
  2483. $exclusion[$idx]['end'] += $lenc;
  2484. }
  2485. $exclusion["inclusion-" . $this->__path] = array(
  2486. "path" => $path,
  2487. "ini" => $ini,
  2488. "end" => $ini + $lenc
  2489. );
  2490. $this->__src = substr($this->__src, 0, $ini) . $c . substr($this->__src, $fin + $l2);
  2491. } else {
  2492. $id = uniqid();
  2493. $restore[$id] = substr($this->__src, $ini, $fin + $l2 - $ini);
  2494. $this->__src = substr($this->__src, 0, $ini) . $id . substr($this->__src, $fin + $l2);
  2495. }
  2496. } else {
  2497. $c = '';
  2498. self::error("Recursive inclusion of template $path is not allowed", DIV_ERROR_WARNING);
  2499. $this->__src = substr($this->__src, 0, $ini) . $c . substr($this->__src, $fin + $l2);
  2500. }
  2501. }
  2502. foreach ( $restore as $id => $restor )
  2503. $this->__src = str_replace($id, $restor, $this->__src);
  2504. }
  2505. /**
  2506. * Parsing preprocessed templates
  2507. *
  2508. * @param mixed $items
  2509. */
  2510. final public function parsePreprocessed($items){
  2511. $prefix = DIV_TAG_PREPROCESSED_BEGIN;
  2512. $suffix = DIV_TAG_PREPROCESSED_END;
  2513. $l1 = strlen($prefix);
  2514. $l2 = strlen($suffix);
  2515. if (self::$__log_mode)
  2516. $this->logger("Parsing preprocessed...");
  2517. $classname = get_class($this);
  2518. if (is_object($items))
  2519. $items = get_object_vars($items);
  2520. if (is_array($items))
  2521. foreach ( $items as $key => $value ) {
  2522. if (isset($this->__ignore[$key]))
  2523. continue;
  2524. if (strpos($this->__src, $prefix . $key . $suffix) !== false) {
  2525. if (self::fileExists($value . "." . DIV_DEFAULT_TPL_FILE_EXT))
  2526. $value .= "." . DIV_DEFAULT_TPL_FILE_EXT;
  2527. $this->__src = str_replace($prefix . $key . $suffix, $prefix . $value . $suffix, $pre);
  2528. }
  2529. }
  2530. $restore = array();
  2531. $pos = 0;
  2532. while ( true ) {
  2533. $ranges = $this->getRanges($prefix, $suffix, null, true, $pos);
  2534. if (count($ranges) < 1)
  2535. break;
  2536. $ini = $ranges[0][0];
  2537. $fin = $ranges[0][1];
  2538. $path = trim(substr($this->__src, $ini + $l1, $fin - $ini - $l1));
  2539. $rangex = $this->getRanges(DIV_TAG_TPLVAR_BEGIN, DIV_TAG_TPLVAR_END);
  2540. $procede = true;
  2541. foreach ( $rangex as $rx ) {
  2542. if ($ini >= $rx[0] && $ini <= $rx[1]) {
  2543. $pos = $ini + 1;
  2544. $procede = false;
  2545. break;
  2546. }
  2547. }
  2548. if (! $procede)
  2549. continue;
  2550. $path = $this->getTplPath($path);
  2551. if (self::fileExists($path)) {
  2552. $c = self::getFileContents($path);
  2553. $engine = self::getAuxiliaryEngineClone($items);
  2554. $engine->__src = $c;
  2555. if (self::$__docs_on) {
  2556. if (self::fileExists($this->__path)) {
  2557. $section = trim($this->__path);
  2558. $contained = trim($path);
  2559. if (substr($section, 0, 2) == './')
  2560. $section = substr($this->__path, 2);
  2561. if (substr($contained, 0, 2) == './')
  2562. $contained = substr($path, 2);
  2563. self::$__docs[$contained] = array();
  2564. if (! isset(self::$__docs[$section]))
  2565. self::$__docs[$section] = array();
  2566. if (! isset(self::$__docs[$section]['preprocess']))
  2567. self::$__docs[$section]['include'] = array();
  2568. self::$__docs[$section]['preprocess'][] = $contained;
  2569. }
  2570. }
  2571. $engine->__path = $path;
  2572. self::$__includes_historial[] = $path;
  2573. $engine->parse(false);
  2574. $pre = $engine->__src;
  2575. $this->__src = substr($this->__src, 0, $ini) . $pre . substr($this->__src, $fin + $l2);
  2576. } else {
  2577. $id = uniqid();
  2578. $restore[$id] = substr($this->__src, $ini, $fin + $l2 - $ini);
  2579. $this->__src = substr($this->__src, 0, $ini) . $id . substr($this->__src, $fin + $l2);
  2580. }
  2581. }
  2582. foreach ( $restore as $id => $restor )
  2583. $this->__src = str_replace($id, $restor, $this->__src);
  2584. }
  2585. /**
  2586. * Parse comments
  2587. *
  2588. * @param string $section
  2589. */
  2590. final public function parseComments($section = null){
  2591. if (is_null($section))
  2592. $section = trim($this->__path);
  2593. if ($section == '')
  2594. $section = uniqid();
  2595. if (substr($section, 0, 2) == './')
  2596. $section = substr($section, 2);
  2597. if (self::$__log_mode)
  2598. $this->logger("Parsing comments...");
  2599. $lbegin = strlen(DIV_TAG_COMMENT_BEGIN);
  2600. while ( true ) {
  2601. $ranges = $this->getRanges(DIV_TAG_COMMENT_BEGIN, DIV_TAG_COMMENT_END, null, true);
  2602. if (count($ranges) < 1)
  2603. break;
  2604. // Parse template's docs
  2605. if (self::$__docs_on) {
  2606. $subsrc = substr($this->__src, $ranges[0][0] + $lbegin, $ranges[0][1] - $ranges[0][0] - $lbegin);
  2607. $arr = explode("\n", $subsrc);
  2608. $last_prop = '';
  2609. $last_tab = 0;
  2610. foreach ( $arr as $line ) {
  2611. $orig = $line;
  2612. $line = str_replace("\r\n", "\n", $line);
  2613. $line = trim($line);
  2614. $line = str_replace("\t", " ", $line);
  2615. if ($last_prop !== '')
  2616. if (isset($orig[0]) && $line == '')
  2617. $line = " ";
  2618. if (isset($line[0])) {
  2619. if ($last_prop !== '')
  2620. if ($line[0] !== '@')
  2621. $line = '@' . $last_prop . ': ' . substr($orig, $last_tab);
  2622. if ($line[0] == '@') {
  2623. $multiline = false;
  2624. $p = strpos($line, " ");
  2625. if ($p !== false) {
  2626. $prop = substr($line, 1, $p - 1);
  2627. $value = substr($line, $p);
  2628. } else {
  2629. $prop = substr($line, 1);
  2630. $value = "";
  2631. }
  2632. $l = strlen($prop);
  2633. if ($prop[$l - 1] == ":") {
  2634. $multiline = true;
  2635. $prop = substr($prop, 0, $l - 1);
  2636. }
  2637. if (! isset(self::$__docs[$section]))
  2638. self::$__docs[$section] = array();
  2639. if (isset(self::$__docs[$section][$prop])) {
  2640. if (! is_array(self::$__docs[$section][$prop])) {
  2641. if (trim(self::$__docs[$section][$prop]) !== '')
  2642. self::$__docs[$section][$prop] = array(
  2643. self::$__docs[$section][$prop]
  2644. );
  2645. }
  2646. if (isset(self::$__docs[$section][$prop][0]) || (! isset(self::$__docs[$section][$prop][0]) && trim($value) !== ''))
  2647. self::$__docs[$section][$prop][] = $value;
  2648. } else
  2649. self::$__docs[$section][$prop] = $value;
  2650. if ($multiline)
  2651. $last_prop = $prop;
  2652. else
  2653. $last_prop = '';
  2654. $ppp = strpos($orig, '@' . $prop);
  2655. if ($ppp !== false)
  2656. $last_tab = $ppp;
  2657. }
  2658. }
  2659. }
  2660. }
  2661. // Extract
  2662. $this->__src = substr($this->__src, 0, $ranges[0][0]) . substr($this->__src, $ranges[0][1] + strlen(DIV_TAG_COMMENT_END));
  2663. }
  2664. }
  2665. /**
  2666. * Isset template var in items?
  2667. *
  2668. * @param string $var
  2669. * @param mixed $items
  2670. * @return boolean
  2671. */
  2672. final static function issetVar($var, $items){
  2673. if (isset($items[$var]))
  2674. return true;
  2675. $var = trim($var);
  2676. $parts = explode(".", $var);
  2677. $current = $items;
  2678. foreach ( $parts as $part ) {
  2679. if (trim($part) == "")
  2680. return false;
  2681. if (is_array($current)) {
  2682. if (isset($current[$part])) {
  2683. $current = $current[$part];
  2684. } else
  2685. return false;
  2686. } elseif (is_object($current)) {
  2687. if (isset($current->$part)) {
  2688. $current = $current->$part;
  2689. } else
  2690. return false;
  2691. }
  2692. }
  2693. return true;
  2694. }
  2695. /**
  2696. * Return a list of all template vars
  2697. *
  2698. * @param mixed $items
  2699. * @param string $superkey
  2700. * @return array
  2701. */
  2702. final static function getVars($items, $superkey = ''){
  2703. $vars = array();
  2704. $itemsx = array();
  2705. if (is_object($items))
  2706. $itemsx = get_object_vars($items);
  2707. elseif (is_array($items))
  2708. $itemsx = $items;
  2709. foreach ( $itemsx as $key => $value ) {
  2710. $vars[] = $superkey . $key;
  2711. if (! is_scalar($itemsx[$key]))
  2712. $vars = array_merge($vars, self::getVars($itemsx[$key], $superkey . $key . '.'));
  2713. }
  2714. return $vars;
  2715. }
  2716. /**
  2717. * Unset template var
  2718. *
  2719. * @param string $var
  2720. * @param mixed $items
  2721. * @return boolean
  2722. */
  2723. final static function unsetVar($var, &$items){
  2724. $unset = false;
  2725. if (isset($items[$var])) {
  2726. $unset = true;
  2727. unset($items[$var]);
  2728. }
  2729. $var = trim($var);
  2730. $parts = explode(".", $var);
  2731. if (! isset($parts[0]))
  2732. return $unset;
  2733. $current = $items;
  2734. $code = '$items';
  2735. foreach ( $parts as $part ) {
  2736. if (trim($part) == "")
  2737. return $unset;
  2738. if (is_array($current)) {
  2739. if (isset($current[$part])) {
  2740. $current = $current[$part];
  2741. $code .= '["' . $part . '"]';
  2742. } else
  2743. return $unset;
  2744. } elseif (is_object($current)) {
  2745. if (isset($current->$part)) {
  2746. $current = $current->$part;
  2747. $code .= '->' . $part;
  2748. } else
  2749. return $unset;
  2750. }
  2751. }
  2752. eval("unset($code);");
  2753. return true;
  2754. }
  2755. /**
  2756. * Return value of template var
  2757. *
  2758. * @param string $var
  2759. * @param mixed $items
  2760. * @return value
  2761. */
  2762. final static function getVarValue($var, $items){
  2763. $itemsx = array();
  2764. if (is_object($items))
  2765. $itemsx = get_object_vars($items);
  2766. elseif (is_array($items))
  2767. $itemsx = $items;
  2768. if (isset($itemsx[$var]))
  2769. return $itemsx[$var];
  2770. $var = trim($var);
  2771. $parts = explode(".", $var);
  2772. $current = $itemsx;
  2773. foreach ( $parts as $part ) {
  2774. if (trim($part) == "")
  2775. return null;
  2776. if (is_array($current)) {
  2777. if (isset($current[$part])) {
  2778. $current = $current[$part];
  2779. } else {
  2780. $current = null;
  2781. break;
  2782. }
  2783. } elseif (is_object($current)) {
  2784. if (isset($current->$part)) {
  2785. $current = $current->$part;
  2786. } else {
  2787. $current = null;
  2788. break;
  2789. }
  2790. }
  2791. }
  2792. if (is_null($current)) {
  2793. $s = '';
  2794. foreach ( $parts as $part ) {
  2795. if (isset($itemsx[$s . $part])) {
  2796. $current = self::getVarValue(substr($var, strlen($s . $part) + 1), $itemsx[$s . $part]);
  2797. if (! is_null($current))
  2798. break;
  2799. }
  2800. $s .= $part . ".";
  2801. }
  2802. }
  2803. return $current;
  2804. }
  2805. /**
  2806. * Set value of template var
  2807. *
  2808. * @param string $var
  2809. * @param mixed $value
  2810. * @param mixed $items
  2811. * @return mixed
  2812. */
  2813. final static function setVarValue($var, $value, &$items, $force = true){
  2814. if (isset($items[$var]))
  2815. $items[$var] = $value;
  2816. $var = trim($var);
  2817. $parts = explode(".", $var);
  2818. $current = $items;
  2819. $c = count($parts);
  2820. $i = 0;
  2821. $code = '$items';
  2822. foreach ( $parts as $part ) {
  2823. $i ++;
  2824. if (trim($part) == "" && is_object($current))
  2825. return null;
  2826. if (is_array($current)) {
  2827. if (isset($current[$part])) {
  2828. if ($i < $c) {
  2829. if ($part == "")
  2830. $code .= '[]';
  2831. else
  2832. $code .= '[\'' . addslashes($part) . '\']';
  2833. $current = $current[$part];
  2834. } else {
  2835. if ($part == "")
  2836. eval($code . '[] = $value;');
  2837. else
  2838. eval($code . '[$part] = $value;');
  2839. }
  2840. } else {
  2841. if ($i < $c) {
  2842. if ($part == "") {
  2843. eval($code . '[] = array();');
  2844. $current = array();
  2845. $code .= '[]';
  2846. } else {
  2847. eval($code . '[$part] = array();');
  2848. $current = array();
  2849. $code .= '[\'' . addslashes($part) . '\']';
  2850. }
  2851. } else {
  2852. if ($part == "")
  2853. eval($code . '[] = $value;');
  2854. else
  2855. eval($code . '[$part] = $value;');
  2856. }
  2857. }
  2858. } elseif (is_object($current)) {
  2859. if (self::isValidVarName($part)) {
  2860. $part = str_replace('$', '', $part);
  2861. if (isset($current->$part)) {
  2862. if ($i < $c) {
  2863. $code .= '->' . $part;
  2864. $current = $current->$part;
  2865. } else {
  2866. eval($code . '->$part = $value;');
  2867. }
  2868. } else {
  2869. if ($i < $c) {
  2870. eval($code . '->$part = new stdClass();');
  2871. $code .= '->' . $part;
  2872. $current = new stdClass();
  2873. } else {
  2874. eval($code . '->$part = $value;');
  2875. }
  2876. }
  2877. } else
  2878. break;
  2879. }
  2880. }
  2881. return $items;
  2882. }
  2883. /**
  2884. * Parse data
  2885. *
  2886. * @param array $items
  2887. */
  2888. final public function parseData(&$items){
  2889. if (self::$__log_mode)
  2890. $this->logger("Parsing data in templates...");
  2891. $varsya = array();
  2892. $pos = 0;
  2893. $tag_begin = DIV_TAG_TPLVAR_BEGIN;
  2894. $tag_end = DIV_TAG_TPLVAR_END;
  2895. $l1 = strlen($tag_begin);
  2896. $l2 = strlen($tag_end);
  2897. while ( true ) {
  2898. $ranges = $this->getRanges($tag_begin, $tag_end, null, true, $pos);
  2899. if (count($ranges) < 1)
  2900. break;
  2901. $ini = $ranges[0][0];
  2902. $fin = $ranges[0][1];
  2903. if ($this->searchInListRanges($ini)) {
  2904. $pos = $ini + 1;
  2905. continue;
  2906. }
  2907. if ($this->searchPosAfterRange(DIV_TAG_FORMULA_BEGIN, DIV_TAG_FORMULA_END, $ini)) {
  2908. $pos = $ini + 1;
  2909. continue;
  2910. }
  2911. if ($this->searchInRanges($this->getConditionalRanges(false), $ini)) {
  2912. $pos = $ini + 1;
  2913. continue;
  2914. }
  2915. if ($this->searchInCapsuleRanges($items, $ini)) {
  2916. $pos = $ini + 1;
  2917. continue;
  2918. }
  2919. if ($this->searchInRanges($this->getRanges(DIV_TAG_CONDITIONS_BEGIN_PREFIX, DIV_TAG_CONDITIONS_END), $ini)) {
  2920. $pos = $ini + 1;
  2921. continue;
  2922. }
  2923. $body = substr($this->__src, $ini + $l1, $fin - $ini - $l1);
  2924. $arr = explode(":", $body, 2);
  2925. $var = $arr[0];
  2926. if (isset($arr[1]))
  2927. $exp = $arr[1];
  2928. else
  2929. $exp = "";
  2930. $var = trim($var);
  2931. $var = str_replace(array(
  2932. "[",
  2933. "]"
  2934. ), array(
  2935. ".",
  2936. ""
  2937. ), $var);
  2938. $var = str_replace("->", ".", $var);
  2939. // Protect the variable
  2940. if (substr($var, 0, 1) == DIV_TAG_TPLVAR_PROTECTOR) {
  2941. $var = substr($var, 1);
  2942. self::$__globals_design_protected[$var] = true;
  2943. }
  2944. if ($this->searchPosAfterRange(DIV_TAG_MACRO_BEGIN, DIV_TAG_MACRO_END, $ini)) {
  2945. $pos = $ini + 1;
  2946. continue;
  2947. }
  2948. // Previous use
  2949. if (self::issetVar($var, $items)) {
  2950. $r = $this->checkLogicalOrder($ini, $var, true, true, true, false);
  2951. if ($r !== false) {
  2952. $pos = $r;
  2953. continue;
  2954. }
  2955. }
  2956. $setup = false;
  2957. // Check protection
  2958. if ((! isset(self::$__globals_design[$var]) || (isset(self::$__globals_design[$var]) && ! isset(self::$__globals_design_protected[$var])))) {
  2959. $exp = trim($exp);
  2960. if (substr($exp, 0, 2) == "->") { // parsing a method
  2961. $exp = substr($exp, 2);
  2962. $value = $this->getMethodResult($exp, $items);
  2963. $setup = $value != DIV_METHOD_NOT_EXISTS && (! self::issetVar($var, $items) || self::issetVar($var, self::$__globals_design));
  2964. } elseif (substr($exp, 0, 1) == "$") {
  2965. $varx = substr($exp, 1);
  2966. if (self::issetVar($varx, $items)) {
  2967. $value = self::getVarValue($varx, $items);
  2968. $setup = ! self::issetVar($var, $items) || self::issetVar($var, self::$__globals_design);
  2969. }
  2970. } else { // parsing a JSON code
  2971. $json = self::jsonDecode($exp, self::cop($this->__memory, $items));
  2972. if (is_null(self::compact($json))) {
  2973. $temp = uniqid();
  2974. $temp1 = uniqid();
  2975. $exp = str_replace(DIV_TAG_INCLUDE_BEGIN, $temp, $exp);
  2976. $exp = str_replace(DIV_TAG_PREPROCESSED_BEGIN, $temp1, $exp);
  2977. $engine = self::getAuxiliaryEngineClone($items);
  2978. $engine->__src = $exp;
  2979. $engine->parse(false);
  2980. $exp = $engine->__src;
  2981. $exp = str_replace($temp, DIV_TAG_INCLUDE_BEGIN, $exp);
  2982. $exp = str_replace($temp1, DIV_TAG_PREPROCESSED_BEGIN, $exp);
  2983. }
  2984. if (! self::issetVar($var, $items) || self::issetVar($var, self::$__globals_design)) {
  2985. if (self::fileExists($exp) && ! self::isDir($exp)) {
  2986. $fgc = self::getFileContents($exp);
  2987. if ($fgc != "")
  2988. $exp = $fgc;
  2989. } elseif (self::fileExists($exp . "." . DIV_DEFAULT_DATA_FILE_EXT) && ! self::isDir($exp . "." . DIV_DEFAULT_DATA_FILE_EXT)) {
  2990. $fgc = self::getFileContents($exp . "." . DIV_DEFAULT_DATA_FILE_EXT);
  2991. if ($fgc != "")
  2992. $exp = $fgc;
  2993. } elseif (self::fileExists($exp . "." . DIV_DEFAULT_TPL_FILE_EXT) && ! self::isDir($exp . "." . DIV_DEFAULT_TPL_FILE_EXT)) {
  2994. $fgc = self::getFileContents($exp . "." . DIV_DEFAULT_TPL_FILE_EXT);
  2995. if ($fgc != "")
  2996. $exp = $fgc;
  2997. }
  2998. if (isset($exp[0]))
  2999. $_exp = $exp[0];
  3000. else
  3001. $_exp = '';
  3002. if (($_exp != '{' && $_exp != "[" && ! is_numeric($_exp) && $_exp != '"' && $_exp != "'") || (substr($exp, 0, strlen(DIV_TAG_INCLUDE_BEGIN)) == DIV_TAG_INCLUDE_BEGIN && substr($exp, 0 - strlen(DIV_TAG_INCLUDE_END)) == DIV_TAG_INCLUDE_END) || (substr($exp, 0, strlen(DIV_TAG_PREPROCESSED_BEGIN)) == DIV_TAG_PREPROCESSED_BEGIN && substr($exp, 0 - strlen(DIV_TAG_PREPROCESSED_END)) == DIV_TAG_PREPROCESSED_END)) {
  3003. $exp = '"' . str_replace('"', '\"', $exp) . '"';
  3004. }
  3005. $value = self::jsonDecode($exp, self::cop($this->__memory, $items));
  3006. $remember['vars'] = array();
  3007. $vars = $value;
  3008. if (is_object($vars))
  3009. $vars = get_object_vars($vars);
  3010. if (is_array($vars)) {
  3011. foreach ( $vars as $kkk => $vvv ) {
  3012. if (self::isString($vvv)) {
  3013. $vvv = trim($vvv);
  3014. if (isset($vvv[0]))
  3015. if ($vvv[0] == "$") {
  3016. $varx = substr($vvv, 1);
  3017. if (self::issetVar($varx, $items)) {
  3018. if (is_array($value))
  3019. $value[$kkk] = self::getVarValue($varx, $items);
  3020. if (is_object($value))
  3021. $value->$kkk = self::getVarValue($varx, $items);
  3022. }
  3023. }
  3024. }
  3025. }
  3026. }
  3027. $setup = true;
  3028. }
  3029. }
  3030. }
  3031. if ($setup == true) {
  3032. self::setVarValue($var, $value, $items);
  3033. self::setVarValue($var, $value, self::$__globals_design);
  3034. }
  3035. $this->__src = substr($this->__src, 0, $ini) . substr($this->__src, $fin + $l2);
  3036. }
  3037. }
  3038. /**
  3039. * Parse defaults replacements
  3040. *
  3041. * @param array $items
  3042. */
  3043. final public function parseDefaults(&$items){
  3044. if (self::$__log_mode)
  3045. $this->logger("Parsing default replacements...");
  3046. $prefix = DIV_TAG_DEFAULT_REPLACEMENT_BEGIN;
  3047. $suffix = DIV_TAG_DEFAULT_REPLACEMENT_END;
  3048. $l1 = strlen($prefix);
  3049. $l2 = strlen($suffix);
  3050. while ( true ) {
  3051. $ranges = $this->getRanges($prefix, $suffix, null, true);
  3052. if (count($ranges) < 1)
  3053. break;
  3054. $ini = $ranges[0][0];
  3055. $fin = $ranges[0][1];
  3056. $body = substr($this->__src, $ini + $l1, $fin - $ini - $l1);
  3057. $arr = self::jsonDecode($body, self::cop($this->__memory, $items));
  3058. if (! isset($arr[0]) || ! isset($arr[1]))
  3059. self::error("Was detected an invalid JSON in default values: " . substr($body, 0, 80) . "...", DIV_ERROR_FATAL);
  3060. if (isset($arr[2])) {
  3061. // Default by var
  3062. $var = $arr[0];
  3063. $search = $arr[1];
  3064. $replace = $arr[2];
  3065. } else {
  3066. // Global default
  3067. $var = null;
  3068. $search = $arr[0];
  3069. $replace = $arr[1];
  3070. }
  3071. if (self::fileExists($replace) && ! self::isDir($search))
  3072. $replace = self::jsonDecode(self::getFileContents($replace), self::cop($this->__memory, $items));
  3073. if (self::fileExists($replace . "." . DIV_DEFAULT_DATA_FILE_EXT) && ! self::isDir($search . "." . DIV_DEFAULT_DATA_FILE_EXT))
  3074. $replace = self::jsonDecode(self::getFileContents($replace . "." . DIV_DEFAULT_DATA_FILE_EXT), self::cop($this->__memory, $items));
  3075. if (self::fileExists($search) && ! self::isDir($search))
  3076. $search = self::jsonDecode(self::getFileContents($search), self::cop($this->__memory, $items));
  3077. if (self::fileExists($search . "." . DIV_DEFAULT_DATA_FILE_EXT) && ! self::isDir($search . "." . DIV_DEFAULT_DATA_FILE_EXT))
  3078. $search = self::jsonDecode(self::getFileContents($search . "." . DIV_DEFAULT_DATA_FILE_EXT), self::cop($this->__memory, $items));
  3079. if (is_null($var)) {
  3080. self::setDefault($search, $replace);
  3081. } else {
  3082. self::setDefaultByVar($var, $search, $replace, false);
  3083. }
  3084. $this->__src = substr($this->__src, 0, $ini) . substr($this->__src, $fin + 2);
  3085. }
  3086. }
  3087. /**
  3088. * Parse number formats
  3089. *
  3090. * @param array $items
  3091. */
  3092. final public function parseNumberFormat(&$items = array()){
  3093. if (self::$__log_mode)
  3094. $this->logger("Parsing number's formats...");
  3095. $prefix = DIV_TAG_NUMBER_FORMAT_PREFIX;
  3096. $suffix = DIV_TAG_NUMBER_FORMAT_SUFFIX;
  3097. $ranges = $this->getRanges($prefix, $suffix);
  3098. $l1 = strlen($prefix);
  3099. $l2 = strlen($suffix);
  3100. foreach ( $ranges as $range ) {
  3101. $s = substr($this->__src, $ranges[0][0] + $l1, $ranges[0][1] - $ranges[0][0] - $l1);
  3102. $arr = explode(DIV_TAG_NUMBER_FORMAT_SEPARATOR, $s);
  3103. if (! isset($items[$arr[0]]) && is_numeric($arr[0]))
  3104. $items[$arr[0]] = (float) $arr[0];
  3105. }
  3106. if (is_array($items))
  3107. foreach ( $items as $key => $value ) {
  3108. if (is_numeric($value))
  3109. $this->numberFormat($key, "$value");
  3110. }
  3111. }
  3112. /**
  3113. * Scan matches and call parseMatch
  3114. *
  3115. * @param string $key
  3116. * @param mixed $value
  3117. */
  3118. final public function scanMatch($key, $value, $engine = null, &$items = null){
  3119. if (is_null($items))
  3120. $items = &$this->__items;
  3121. if (is_null($engine))
  3122. $engine = self::getAuxiliaryEngineClone($items);
  3123. // Scan child properties
  3124. if (strpos($this->__src, "$key.") !== false) {
  3125. $vars = false;
  3126. $vvv = $value;
  3127. if (is_scalar($vvv))
  3128. $vvv = "$value";
  3129. if (self::isString($vvv))
  3130. $vars = str_split($vvv);
  3131. elseif (is_object($vvv))
  3132. $vars = get_object_vars($vvv);
  3133. else
  3134. $vars = $vvv;
  3135. if (is_array($vars))
  3136. foreach ( $vars as $kk => $v )
  3137. $this->scanMatch("$key.$kk", $v, $engine, $items);
  3138. }
  3139. // Match this key
  3140. $this->parseMatch($key, $value, $engine);
  3141. // Match aggregate functions
  3142. if (is_object($value))
  3143. if (! method_exists($value, '__toString'))
  3144. $value = get_object_vars($value);
  3145. if (is_array($value)) {
  3146. $cant_values = count($value);
  3147. $this->parseMatch($key, $cant_values, $engine);
  3148. if ($cant_values > 0) {
  3149. if (strpos($this->__src, $key) !== false) {
  3150. if (self::isNumericList($value) === true) {
  3151. $sum = array_sum($value);
  3152. $keys = array_keys($value);
  3153. $sep = DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR;
  3154. $fmax = DIV_TAG_AGGREGATE_FUNCTION_MAX;
  3155. $fmin = DIV_TAG_AGGREGATE_FUNCTION_MIN;
  3156. if ($cant_values > 1) {
  3157. $this->parseMatch($fmax . $sep . $key, max($value), $engine);
  3158. $this->parseMatch($fmin . $sep . $key, min($value), $engine);
  3159. } else {
  3160. $this->parseMatch($fmax . $sep . $key, $value[$keys[0]], $engine);
  3161. $this->parseMatch($fmin . $sep . $key, $value[$keys[0]], $engine);
  3162. }
  3163. $this->parseMatch(DIV_TAG_AGGREGATE_FUNCTION_SUM . $sep . $key, $sum, $engine);
  3164. $this->parseMatch(DIV_TAG_AGGREGATE_FUNCTION_AVG . $sep . $key, $sum / $cant_values, $engine);
  3165. }
  3166. }
  3167. if (strpos($this->__src, $key . DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR) !== false) {
  3168. $functions = array(
  3169. "",
  3170. DIV_TAG_AGGREGATE_FUNCTION_COUNT,
  3171. DIV_TAG_AGGREGATE_FUNCTION_MAX,
  3172. DIV_TAG_AGGREGATE_FUNCTION_MIN,
  3173. DIV_TAG_AGGREGATE_FUNCTION_SUM,
  3174. DIV_TAG_AGGREGATE_FUNCTION_AVG
  3175. );
  3176. foreach ( $functions as $function ) {
  3177. if ($function == "")
  3178. $ff = "";
  3179. else
  3180. $ff = $function . DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR;
  3181. $tag_begin = $ff . $key . DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR;
  3182. $tag_end = DIV_TAG_REPLACEMENT_SUFFIX;
  3183. $l = strlen($tag_begin);
  3184. $result = array();
  3185. $p = 0;
  3186. while ( true ) {
  3187. $ranges = $this->getRanges($tag_begin, $tag_end, $this->__src, true, $p);
  3188. if (count($ranges) < 1)
  3189. break;
  3190. $range = $ranges[0];
  3191. $var = substr($this->__src, $range[0] + $l, $range[1] - ($range[0] + $l));
  3192. if (strpos($var, DIV_TAG_SUBMATCH_SEPARATOR) !== false) {
  3193. $var = explode(DIV_TAG_SUBMATCH_SEPARATOR, $var);
  3194. $var = $var[0];
  3195. } elseif (strpos($var, DIV_TAG_NUMBER_FORMAT_SEPARATOR) !== false) {
  3196. $var = explode(DIV_TAG_NUMBER_FORMAT_SEPARATOR, $var);
  3197. $var = $var[0];
  3198. }
  3199. if (! isset($result[$var])) {
  3200. $c = 0;
  3201. $result[$var] = array();
  3202. $max = null;
  3203. $min = null;
  3204. $sum = 0;
  3205. $avg = 0;
  3206. foreach ( $value as $v ) {
  3207. if (is_object($v))
  3208. $v = get_object_vars($v);
  3209. if (isset($v[$var])) {
  3210. if (is_bool($v[$var]) || self::isString($v[$var]))
  3211. $cant = 1;
  3212. if (is_numeric($v[$var]))
  3213. $cant = $v[$var];
  3214. switch ($function) {
  3215. case DIV_TAG_AGGREGATE_FUNCTION_MIN :
  3216. if ($min * 1 > $v[$var] * 1 || is_null($min))
  3217. $min = $v[$var] * 1;
  3218. break;
  3219. case DIV_TAG_AGGREGATE_FUNCTION_MAX :
  3220. if ($max * 1 < $v[$var] * 1 || is_null($max))
  3221. $max = $v[$var] * 1;
  3222. break;
  3223. case DIV_TAG_AGGREGATE_FUNCTION_SUM :
  3224. $sum += $cant;
  3225. break;
  3226. case DIV_TAG_AGGREGATE_FUNCTION_AVG :
  3227. $avg += $cant;
  3228. default :
  3229. if (self::mixedBool($v[$var]) === true)
  3230. $c ++;
  3231. }
  3232. }
  3233. }
  3234. $result[$var][DIV_TAG_AGGREGATE_FUNCTION_MIN] = $min;
  3235. $result[$var][DIV_TAG_AGGREGATE_FUNCTION_MAX] = $max;
  3236. $result[$var][DIV_TAG_AGGREGATE_FUNCTION_COUNT] = $c;
  3237. $result[$var][DIV_TAG_AGGREGATE_FUNCTION_SUM] = $sum;
  3238. if ($cant_values > 0)
  3239. $result[$var][DIV_TAG_AGGREGATE_FUNCTION_AVG] = $avg / $cant_values;
  3240. else
  3241. $result[$var][DIV_TAG_AGGREGATE_FUNCTION_AVG] = 0;
  3242. }
  3243. $res = $result[$var][$function == "" ? DIV_TAG_AGGREGATE_FUNCTION_COUNT : $function];
  3244. $var = $ff . $key . DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR . $var;
  3245. $items[$var] = $res;
  3246. $this->parseMatch($var, $res, $engine);
  3247. $p = $range[0] + 1;
  3248. }
  3249. }
  3250. }
  3251. }
  3252. }
  3253. }
  3254. /**
  3255. * Parsing multple variable's modifiers
  3256. */
  3257. final public function parseMultipleModifiers(){
  3258. $prefix = DIV_TAG_MULTI_MODIFIERS_PREFIX;
  3259. $suffix = DIV_TAG_MULTI_MODIFIERS_SUFFIX;
  3260. $l1 = strlen($prefix);
  3261. $l2 = strlen($suffix);
  3262. $p = 0;
  3263. while ( true ) {
  3264. $ranges = $this->getRanges($prefix, $suffix, null, true, $p);
  3265. if (count($ranges) > 0) {
  3266. $ini = $ranges[0][0];
  3267. $fin = $ranges[0][1];
  3268. $s = substr($this->__src, $ini + $l1, $fin - $ini - $l1);
  3269. $pp = strpos($s, DIV_TAG_MULTI_MODIFIERS_OPERATOR);
  3270. if ($pp === false) {
  3271. $p = $ini + 1;
  3272. continue;
  3273. }
  3274. $varname = trim(substr($s, 0, $pp));
  3275. $s = substr($s, $pp + 1);
  3276. $parts = explode(DIV_TAG_MULTI_MODIFIERS_SEPARATOR, $s);
  3277. $newcode = '';
  3278. if (count($parts) > 0) {
  3279. $newvar = "var" . uniqid();
  3280. self::$__dont_remember_it[$newvar] = true;
  3281. $newcode = DIV_TAG_STRIP_BEGIN . ' ' . DIV_TAG_TPLVAR_BEGIN . ' ' . $newvar . DIV_TAG_TPLVAR_ASSIGN_OPERATOR . ' $' . $varname . ' ' . DIV_TAG_TPLVAR_END . "\n";
  3282. $ignore = false;
  3283. foreach ( $parts as $part ) {
  3284. if (trim($part) !== "") {
  3285. if ($part[0] == DIV_TAG_MODIFIER_TRUNCATE || $part[0] == DIV_TAG_MODIFIER_WORDWRAP || strpos($part, ",") !== false) {
  3286. $newcode .= DIV_TAG_TPLVAR_BEGIN . ' ' . $newvar . DIV_TAG_TPLVAR_ASSIGN_OPERATOR . ' ' . DIV_TAG_REPLACEMENT_PREFIX . DIV_TAG_MODIFIER_SIMPLE . $newvar . DIV_TAG_SUBMATCH_SEPARATOR . $part . DIV_TAG_REPLACEMENT_SUFFIX . ' ' . DIV_TAG_TPLVAR_END . "\n";
  3287. } elseif (array_search($part . ':', self::$__modifiers)) {
  3288. $newcode .= DIV_TAG_TPLVAR_BEGIN . ' ' . $newvar . DIV_TAG_TPLVAR_ASSIGN_OPERATOR . ' ' . DIV_TAG_REPLACEMENT_PREFIX . DIV_TAG_MODIFIER_SIMPLE . $newvar . DIV_TAG_SUBMATCH_SEPARATOR . $part . DIV_TAG_REPLACEMENT_SUFFIX . ' ' . DIV_TAG_TPLVAR_END . "\n";
  3289. } elseif (array_search($part, self::$__modifiers) !== false) {
  3290. $newcode .= DIV_TAG_TPLVAR_BEGIN . ' ' . $newvar . DIV_TAG_TPLVAR_ASSIGN_OPERATOR . ' ' . DIV_TAG_REPLACEMENT_PREFIX . $part . $newvar . DIV_TAG_REPLACEMENT_SUFFIX . ' ' . DIV_TAG_TPLVAR_END . "\n";
  3291. } else {
  3292. $p = $ini + 1;
  3293. $ignore = true;
  3294. break;
  3295. }
  3296. }
  3297. }
  3298. if ($ignore)
  3299. continue;
  3300. $newcode .= DIV_TAG_REPLACEMENT_PREFIX . DIV_TAG_MODIFIER_SIMPLE . $newvar . DIV_TAG_REPLACEMENT_SUFFIX . ' ' . DIV_TAG_STRIP_END . "\n";
  3301. }
  3302. $this->__src = substr($this->__src, 0, $ini) . $newcode . substr($this->__src, $fin + $l2);
  3303. $p = $ini + 1;
  3304. } else
  3305. break;
  3306. }
  3307. }
  3308. /**
  3309. * Parse all matches
  3310. *
  3311. * @param array $items
  3312. */
  3313. final public function parseMatches(&$items = null){
  3314. if (self::$__log_mode)
  3315. $this->logger("Parsing matches...");
  3316. if (is_null($items))
  3317. $items = &$this->__items;
  3318. $restore = array();
  3319. $lastpos = 0;
  3320. if (strpos($this->__src, DIV_TAG_LOOP_BEGIN_PREFIX) !== false) {
  3321. $lprefix = strlen(DIV_TAG_LOOP_BEGIN_PREFIX);
  3322. $lsuffix = strlen(DIV_TAG_LOOP_BEGIN_SUFFIX);
  3323. while ( true ) {
  3324. if ($lastpos > strlen($this->__src) - 1)
  3325. break;
  3326. $ranges = $this->getBlockRanges(null, DIV_TAG_LOOP_BEGIN_PREFIX, DIV_TAG_LOOP_BEGIN_SUFFIX, DIV_TAG_LOOP_END_PREFIX, DIV_TAG_LOOP_END_SUFFIX, $lastpos, null, true);
  3327. if (! isset($ranges[0]))
  3328. break;
  3329. $ini = $ranges[0][0];
  3330. $fin = $ranges[0][1];
  3331. $lastpos = $ini + 1;
  3332. $ukey = uniqid();
  3333. $restore[$ukey] = $ranges[0][3];
  3334. $this->__src = substr($this->__src, 0, $ini + $lprefix + strlen($ranges[0][2]) + $lsuffix) . $ukey . substr($this->__src, $ranges[0][1]);
  3335. }
  3336. }
  3337. $engine = self::getAuxiliaryEngineClone($items);
  3338. if (is_array($items))
  3339. foreach ( $items as $key => $value )
  3340. $this->scanMatch($key, $value, $engine, $items);
  3341. foreach ( $restore as $ukey => $part )
  3342. $this->__src = str_replace($ukey, $part, $this->__src);
  3343. }
  3344. /**
  3345. * Parse formulas
  3346. *
  3347. * @param s array $items
  3348. */
  3349. final public function parseFormulas(&$items = array()){
  3350. if (self::$__log_mode)
  3351. $this->logger("Parsing formulas...");
  3352. $p1 = strpos($this->__src, DIV_TAG_TPLVAR_BEGIN);
  3353. $engine = self::getAuxiliaryEngineClone($items);
  3354. $lprefix = strlen(DIV_TAG_FORMULA_BEGIN);
  3355. $lsuffix = strlen(DIV_TAG_FORMULA_END);
  3356. while ( true ) {
  3357. $ranges = $this->getRanges(DIV_TAG_FORMULA_BEGIN, DIV_TAG_FORMULA_END, null, true);
  3358. if (count($ranges) > 0) {
  3359. $ini = $ranges[0][0];
  3360. $fin = $ranges[0][1];
  3361. if ($ini > $p1 && $p1 !== false)
  3362. return true;
  3363. $formula = substr($this->__src, $ini + $lprefix, $fin - ($ini + $lprefix));
  3364. $formula_orig = $formula;
  3365. if (self::$__log_mode)
  3366. $this->logger("Parsing the formula (from {$ini} to {$fin}): $formula");
  3367. $engine->__src = $formula;
  3368. $engine->parse(false);
  3369. $formula = $engine->__src;
  3370. // Get the number format
  3371. $pos = strrpos($formula, DIV_TAG_FORMULA_FORMAT_SEPARATOR);
  3372. $format = "";
  3373. if ($pos !== false && isset($formula[$pos + 1])) {
  3374. $format = trim(substr($formula, $pos + 1));
  3375. $formula = substr($formula, 0, $pos);
  3376. }
  3377. $r = null;
  3378. if (self::isValidExpression($formula)) {
  3379. if (! self::haveVarsThisCode($formula)) {
  3380. // Save the error reporting configurarion
  3381. $error_reporting = ini_get("error_reporting");
  3382. ini_set("error_reporting", ~ E_ALL);
  3383. eval('$r = ' . $formula . ";");
  3384. // Restore the error reporting configurarion
  3385. ini_set("error_reporting", $error_reporting);
  3386. $random_var = uniqid();
  3387. }
  3388. }
  3389. if (is_null($r)) {
  3390. $restore_id = uniqid();
  3391. $this->__restore[$restore_id] = DIV_TAG_FORMULA_BEGIN . ' ' . $formula_orig . DIV_TAG_FORMULA_END;
  3392. $this->__src = substr($this->__src, 0, $ini) . '{' . "$restore_id" . '}' . substr($this->__src, $fin + $lsuffix);
  3393. continue;
  3394. }
  3395. if ($format != "" && is_numeric($r)) {
  3396. $this->__src = substr($this->__src, 0, $ini) . DIV_TAG_NUMBER_FORMAT_PREFIX . $random_var . DIV_TAG_NUMBER_FORMAT_SEPARATOR . $format . DIV_TAG_NUMBER_FORMAT_SUFFIX . substr($this->__src, $fin + $lsuffix);
  3397. $this->numberFormat($random_var, $r);
  3398. } else
  3399. $this->__src = substr($this->__src, 0, $ini) . $r . substr($this->__src, $fin + $lsuffix);
  3400. } else
  3401. break;
  3402. }
  3403. }
  3404. /**
  3405. * Parse conditions
  3406. *
  3407. * @param array $items
  3408. * @param bool $cleanorphan
  3409. */
  3410. final public function parseConditions(&$items, $cleanorphan = false){
  3411. if (self::$__log_mode)
  3412. $this->logger("Parsing conditions...");
  3413. $classname = get_class($this);
  3414. $pos = 0;
  3415. $lprefix = strlen(DIV_TAG_CONDITIONS_BEGIN_PREFIX);
  3416. $lsuffix = strlen(DIV_TAG_CONDITIONS_BEGIN_SUFFIX);
  3417. $lend = strlen(DIV_TAG_CONDITIONS_END);
  3418. $lelse = strlen(DIV_TAG_ELSE);
  3419. while ( true ) {
  3420. $ranges = $this->getRanges(DIV_TAG_CONDITIONS_BEGIN_PREFIX, DIV_TAG_CONDITIONS_END, null, true, $pos);
  3421. if (count($ranges) > 0) {
  3422. $ini = $ranges[0][0];
  3423. $fin = $ranges[0][1];
  3424. if ($this->searchInListRanges($ini)) {
  3425. $pos = $ini + 1;
  3426. continue;
  3427. }
  3428. if ($this->searchInListRanges($this->getRanges(DIV_TAG_ITERATION_BEGIN_PREFIX, DIV_TAG_ITERATION_END), $ini)) {
  3429. $pos = $ini + 1;
  3430. continue;
  3431. }
  3432. $body = substr($this->__src, $ini + $lprefix, $fin - $ini - $lprefix);
  3433. $p = strpos($body, DIV_TAG_CONDITIONS_BEGIN_SUFFIX);
  3434. $condition = '';
  3435. if ($p !== false) {
  3436. $condition = substr($body, 0, $p);
  3437. $body = substr($body, $p + $lsuffix);
  3438. $else = $this->getElseTag($body);
  3439. if ($else != false) {
  3440. $body_parts = array(
  3441. substr($body, 0, $else),
  3442. substr($body, $else + $lelse)
  3443. );
  3444. } else
  3445. $body_parts = array(
  3446. $body,
  3447. ""
  3448. );
  3449. if ($body_parts[0] != "") {
  3450. if ($body_parts[0][0] == ' ')
  3451. $body_parts[0] = substr($body_parts[0], 1);
  3452. if (substr($body_parts[0], - 1) == ' ')
  3453. $body_parts[0] = substr_replace($body_parts[0], "", - 1);
  3454. }
  3455. if ($body_parts[1] != "") {
  3456. if ($body_parts[1][0] == ' ')
  3457. $body_parts[1] = substr($body_parts[1], 1);
  3458. if (substr($body_parts[1], - 1) == ' ')
  3459. $body_parts[1] = substr_replace($body_parts[1], "", - 1);
  3460. }
  3461. $r = false;
  3462. if (self::$__log_mode)
  3463. $this->logger("Parsing condition (from $ini to $fin): $condition");
  3464. $engine = self::getAuxiliaryEngineClone($items);
  3465. $engine->__src = $condition;
  3466. $engine->parse(false);
  3467. $condition = $engine->__src;
  3468. if (self::isValidExpression($condition)) {
  3469. if (! self::haveVarsThisCode($condition)) {
  3470. $error_reporting = ini_get("error_reporting");
  3471. ini_set("error_reporting", ~ E_ALL);
  3472. eval('$r = ' . $condition . ';');
  3473. $r = self::mixedBool($r);
  3474. ini_set("error_reporting", $error_reporting);
  3475. } else {
  3476. if ($cleanorphan === false) {
  3477. $pos = $ini + $lprefix;
  3478. continue;
  3479. }
  3480. }
  3481. } else {
  3482. if (self::$__log_mode)
  3483. $this->logger("The condition $condition is not valid");
  3484. $pos = $ini + $lprefix;
  3485. continue;
  3486. }
  3487. if ($r === true) {
  3488. $body = $body_parts[0];
  3489. if (self::$__log_mode)
  3490. $this->logger("The condition $condition is true");
  3491. } else {
  3492. $body = $body_parts[1];
  3493. if (self::$__log_mode)
  3494. $this->logger("The condition $condition is false");
  3495. }
  3496. $this->__src = substr($this->__src, 0, $ini) . $body . substr($this->__src, $fin + $lend);
  3497. } else
  3498. self::error("Parse error on <b>conditions</b>: " . substr($condition, 0, 50) . "...", DIV_ERROR_FATAL);
  3499. } else
  3500. break;
  3501. }
  3502. }
  3503. /**
  3504. * Parse conditional parts
  3505. *
  3506. * @param array $items
  3507. */
  3508. final public function parseConditional(&$items = array()){
  3509. if (self::$__log_mode)
  3510. $this->logger("Parsing conditional parts...");
  3511. $r = array_merge($this->getBlockRanges(null, DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX, DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX, DIV_TAG_CONDITIONAL_TRUE_END_PREFIX, DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX), $this->getBlockRanges(null, DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX, DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX, DIV_TAG_CONDITIONAL_FALSE_END_PREFIX, DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX));
  3512. $vars = array();
  3513. foreach ( $r as $tag ) {
  3514. if (self::issetVar($tag[2], $items)) {
  3515. $vars[$tag[2]] = self::getVarValue($tag[2], $items);
  3516. } else {
  3517. $arr = explode('-', $tag[2]);
  3518. if (isset($arr[1]) && ! isset($arr[2])) { // count($arr) == 2
  3519. if (self::issetVar($arr[0], $items)) {
  3520. $v = self::getVarValue($arr[0], $items);
  3521. if (is_object($v))
  3522. $v = get_object_vars($v);
  3523. if (is_array($v)) {
  3524. foreach ( $v as $kk => $iv ) {
  3525. $vv = self::getVarValue($arr[1], $iv);
  3526. $nv = $arr[0] . '-' . $arr[1];
  3527. if (isset($vars[$nv]))
  3528. $vars[$nv] = self::mixedBool($vars[$nv]) || self::mixedBool($vv);
  3529. else
  3530. $vars[$nv] = self::mixedBool($vv);
  3531. }
  3532. }
  3533. }
  3534. }
  3535. }
  3536. }
  3537. $varsx = $this->getActiveVars($items);
  3538. foreach ( $varsx as $var )
  3539. $vars[$var] = self::mixedBool(self::getVarValue($var, $items));
  3540. if (! empty($vars)) {
  3541. $keys = array_keys($vars);
  3542. $nkeys = array();
  3543. foreach ( $keys as $k => $v )
  3544. $nkeys[$v] = strlen($v);
  3545. arsort($nkeys);
  3546. foreach ( $nkeys as $var => $l )
  3547. $this->parseConditionalBlock($var, $vars[$var]);
  3548. }
  3549. }
  3550. /**
  3551. * Parse orphan parts
  3552. */
  3553. final public function parseOrphanParts(){
  3554. if (self::$__log_mode)
  3555. $this->logger("Parsing orphan parts...");
  3556. $keys = $this->getConditionalKeys();
  3557. foreach ( $keys as $key )
  3558. $this->parseConditionalBlock($key, false);
  3559. }
  3560. /**
  3561. * Return a list of conditional parts's tags
  3562. *
  3563. * @return array
  3564. */
  3565. final public function getConditionalKeys(){
  3566. $ranges = $this->getConditionalRanges();
  3567. $keys = array();
  3568. foreach ( $ranges as $rang )
  3569. $keys[] = $rang[2];
  3570. return $keys;
  3571. }
  3572. /**
  3573. * Return a list of conditional parts ranges
  3574. *
  3575. * @param boolean $orphans
  3576. * @return array
  3577. */
  3578. final public function getConditionalRanges($orphans = true, $src = null){
  3579. $ranges = $this->getBlockRanges($src, DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX, DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX, DIV_TAG_CONDITIONAL_FALSE_END_PREFIX, DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX);
  3580. $ranges = array_merge($ranges, $this->getBlockRanges($src, DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX, DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX, DIV_TAG_CONDITIONAL_TRUE_END_PREFIX, DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX));
  3581. if (! $orphans) {
  3582. $nranges = array();
  3583. foreach ( $ranges as $rang )
  3584. if (self::varExists($rang[2], $this->__items))
  3585. $nranges[] = $rang;
  3586. $ranges = $nranges;
  3587. }
  3588. return $ranges;
  3589. }
  3590. /**
  3591. * Parse date formats
  3592. *
  3593. * @param array $items
  3594. */
  3595. final public function parseDateFormat(&$items = array()){
  3596. if (self::$__log_mode)
  3597. $this->logger("Parsing date's formats...");
  3598. $lprefix = strlen(DIV_TAG_DATE_FORMAT_PREFIX);
  3599. $lsuffix = strlen(DIV_TAG_DATE_FORMAT_SUFFIX);
  3600. $ranges = $this->getRanges(DIV_TAG_DATE_FORMAT_PREFIX, DIV_TAG_DATE_FORMAT_SUFFIX);
  3601. $vars = array();
  3602. $temp = '{' . uniqid() . '}';
  3603. foreach ( $ranges as $range ) {
  3604. $s = substr($this->__src, $ranges[0][0] + $lprefix, $ranges[0][1] - $ranges[0][0] - $lprefix);
  3605. $s = str_replace('\\' . DIV_TAG_DATE_FORMAT_SEPARATOR, $temp, $s);
  3606. $p = strpos($s, DIV_TAG_DATE_FORMAT_SEPARATOR);
  3607. if ($p !== false) {
  3608. $var = substr($s, 0, $p);
  3609. if (! isset($items[$var]))
  3610. $items[$var] = $var;
  3611. $vars[] = $var;
  3612. }
  3613. }
  3614. foreach ( $vars as $var ) {
  3615. $value = $items[$var];
  3616. if (is_scalar($value))
  3617. $this->dateFormat($var, $value);
  3618. }
  3619. }
  3620. /**
  3621. * Giving formats to the dates
  3622. *
  3623. * @param string $key
  3624. * @param integer $value
  3625. * @return boolean
  3626. */
  3627. final public function dateFormat($key, $value){
  3628. $tag_begin = DIV_TAG_DATE_FORMAT_PREFIX . $key . DIV_TAG_DATE_FORMAT_SEPARATOR;
  3629. $tag_end = DIV_TAG_DATE_FORMAT_SUFFIX;
  3630. $l1 = strlen($tag_begin);
  3631. $l2 = strlen($tag_end);
  3632. if (strpos($this->__src, $tag_begin) === false)
  3633. return false;
  3634. if (strpos($this->__src, $tag_end) === false)
  3635. return false;
  3636. while ( true ) {
  3637. $ranges = $this->getRanges($tag_begin, $tag_end, null, true);
  3638. if (count($ranges) < 1)
  3639. break;
  3640. $ini = $ranges[0][0];
  3641. $fin = $ranges[0][1];
  3642. $format = substr($this->__src, $ini + $l1, $fin - ($ini + $l1));
  3643. if (trim($format) == "")
  3644. $format = "Y-m-d";
  3645. if (! is_numeric($value))
  3646. $value = @strtotime("$value");
  3647. $this->__src = substr($this->__src, 0, $ini) . date($format, $value) . substr($this->__src, $fin + $l2);
  3648. }
  3649. return true;
  3650. }
  3651. /**
  3652. * Parsing capsules
  3653. *
  3654. * @param array $items
  3655. */
  3656. final public function parseCapsules(&$items = array()){
  3657. if (self::$__log_mode)
  3658. $this->logger("Parsing capsules...");
  3659. $classname = get_class($this);
  3660. $pos = 0;
  3661. while ( true ) {
  3662. $ranges = $this->getBlockRanges(null, DIV_TAG_CAPSULE_BEGIN_PREFIX, DIV_TAG_CAPSULE_BEGIN_SUFFIX, DIV_TAG_CAPSULE_END_PREFIX, DIV_TAG_CAPSULE_END_SUFFIX, $pos, null, true);
  3663. if (count($ranges) < 1)
  3664. break;
  3665. $key = $ranges[0][2];
  3666. if (! isset($items[$key])) {
  3667. $pos = $ranges[0][0] + 1;
  3668. continue;
  3669. }
  3670. $value = $items[$key];
  3671. $ini = $ranges[0][0];
  3672. $fin = $ranges[0][1];
  3673. $subsrc = $ranges[0][3];
  3674. if (is_object($value)) {
  3675. if (method_exists($value, '__toString')) {
  3676. $itemstr = "$value";
  3677. if (! isset($value->value))
  3678. $value->value = $itemstr;
  3679. $value->_to_string = $itemstr;
  3680. }
  3681. $value = get_object_vars($value);
  3682. }
  3683. if (is_scalar($value))
  3684. $value = array(
  3685. "value" => $value
  3686. );
  3687. $value = array_merge($items, $value);
  3688. $tempglobal = self::$__globals_design; // priority to item's properties
  3689. // Save similar global design vars
  3690. if (is_array($value))
  3691. foreach ( $value as $kkk => $vvv )
  3692. if (isset(self::$__globals_design[$kkk])) {
  3693. unset(self::$__globals_design[$kkk]);
  3694. }
  3695. $engine = self::getAuxiliaryEngineClone($items);
  3696. $engine->__src = $subsrc;
  3697. $engine->__items = $value;
  3698. if (is_array($this->__items_orig)) {
  3699. if (isset($this->__items_orig[$key]))
  3700. $engine->__items_orig = $this->__items_orig[$key];
  3701. } elseif (is_object($this->__items_orig)) {
  3702. if (isset($this->__items_orig->$key))
  3703. $engine->__items_orig = $this->__items_orig->$key;
  3704. }
  3705. $engine->parse(false);
  3706. $hh = $engine->__src;
  3707. // Restore global design vars
  3708. self::$__globals_design = $tempglobal;
  3709. $this->__src = substr($this->__src, 0, $ini) . $hh . substr($this->__src, $fin + strlen(DIV_TAG_CAPSULE_END_PREFIX . $key . DIV_TAG_CAPSULE_END_SUFFIX));
  3710. $pos = $ini;
  3711. }
  3712. }
  3713. /**
  3714. * Parsing a code if method call and invoke the method
  3715. *
  3716. * @param string $code
  3717. * @param array $items
  3718. * @return mixed
  3719. */
  3720. final public function getMethodResult($code, &$items = null){
  3721. if (is_null($items))
  3722. $items = &$this->__items;
  3723. $variant = 0;
  3724. if (is_object($this->__items_orig)) {
  3725. $objs = array(
  3726. $this->__items_orig,
  3727. $this
  3728. );
  3729. } else {
  3730. $objs = array(
  3731. $this
  3732. );
  3733. }
  3734. foreach ( $objs as $obj ) {
  3735. $classname = get_class($obj);
  3736. $p = strpos($code, "(");
  3737. $method = substr($code, 0, $p);
  3738. $engine = self::getAuxiliaryEngineClone($items);
  3739. $engine->__src = $method;
  3740. $engine->parse(false);
  3741. $method = trim($engine->__src);
  3742. $methods = get_class_methods($classname);
  3743. $ms = array();
  3744. foreach ( $methods as $m )
  3745. if (array_search($m, self::$__parent_method_names) === false)
  3746. $ms[] = $m;
  3747. if (array_search($method, $ms) !== false) {
  3748. $params = substr($code, $p + 1);
  3749. $params = substr($params, 0, strlen($params) - 1);
  3750. $engine->__src = $params;
  3751. $engine->parse(false);
  3752. $params = trim($engine->__src);
  3753. if (substr($params, 0, 1) != "{" && substr($params, 0, 1) != "[") {
  3754. $r = null;
  3755. // Save the error reporting configurarion
  3756. $error_reporting = ini_get("error_reporting");
  3757. ini_set("error_reporting", ~ E_ALL);
  3758. eval('$r = $obj->' . $method . '(' . $params . ');');
  3759. // Restore the error reporting configurarion
  3760. ini_set("error_reporting", $error_reporting);
  3761. return $r;
  3762. } else {
  3763. $params = self::jsonDecode($params, self::cop($this->__memory, $items));
  3764. return $obj->$method($params);
  3765. }
  3766. }
  3767. }
  3768. return DIV_METHOD_NOT_EXISTS;
  3769. }
  3770. /**
  3771. * Return a list of vars that are active in template
  3772. *
  3773. * @param mixed $items
  3774. * @return array
  3775. */
  3776. final public function getActiveVars($items, $superkey = '', $src = null){
  3777. if (is_null($src))
  3778. $src = &$this->__src;
  3779. if ($superkey != '' && strpos($src, $superkey) === false)
  3780. return array();
  3781. if (is_object($items))
  3782. $itemsx = get_object_vars($items);
  3783. elseif (is_array($items))
  3784. $itemsx = $items;
  3785. else
  3786. return array();
  3787. $vars = array();
  3788. foreach ( $itemsx as $key => $value ) {
  3789. if ($superkey . $key !== '')
  3790. if (strpos($src, $superkey . $key) !== false) {
  3791. $vars[] = $superkey . $key;
  3792. if (! is_scalar($itemsx[$key]))
  3793. $vars = array_merge($vars, $this->getActiveVars($itemsx[$key], $superkey . $key . '.', $src));
  3794. }
  3795. }
  3796. return $vars;
  3797. }
  3798. /**
  3799. * Remember the inactive items
  3800. *
  3801. * @param array $memory
  3802. * @param array $items
  3803. */
  3804. final private function memory(&$items){
  3805. $vars = $this->getActiveVars($items);
  3806. foreach ( $vars as $var )
  3807. if (! isset($items[$var]) || strpos($var, '.') !== false)
  3808. $items[$var] = self::getVarValue($var, $items);
  3809. $this->__memory = array_merge($this->__memory, $items);
  3810. $items = array();
  3811. $vars = $this->getActiveVars($this->__memory);
  3812. foreach ( $vars as $var )
  3813. $items[$var] = self::getVarValue($var, $this->__memory);
  3814. }
  3815. /**
  3816. * Search the locations in the template
  3817. *
  3818. * @return array
  3819. */
  3820. final public function getLocations(){
  3821. $r = $this->getRanges(DIV_TAG_LOCATION_BEGIN, DIV_TAG_LOCATION_END);
  3822. $lprefix = strlen(DIV_TAG_LOCATION_BEGIN);
  3823. $lsuffix = strlen(DIV_TAG_LOCATION_END);
  3824. $locations = array();
  3825. $tags = array();
  3826. foreach ( $r as $item ) {
  3827. $tagname = substr($this->__src, $item[0] + $lprefix, $item[1] - $item[0] - $lprefix);
  3828. if (! isset($locations[$tagname]))
  3829. $locations[$tagname] = array();
  3830. $locations[$tagname][] = $item[0];
  3831. $tags[$tagname] = strlen($tagname);
  3832. }
  3833. arsort($tags);
  3834. $ntags = array();
  3835. foreach ( $tags as $tagname => $v )
  3836. $ntags[$tagname] = $locations[$tagname];
  3837. return $ntags;
  3838. }
  3839. /**
  3840. * Parse the locations in the template
  3841. */
  3842. final public function parseLocations(){
  3843. $locations = $this->getLocations();
  3844. $newcontent = array();
  3845. foreach ( $locations as $location => $posis ) {
  3846. $content = "";
  3847. $pos = 0;
  3848. while ( true ) {
  3849. $tag_begin = DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX . $location . DIV_TAG_LOCATION_CONTENT_BEGIN_SUFFIX;
  3850. $tag_end = DIV_TAG_LOCATION_CONTENT_END_PREFIX . $location . DIV_TAG_LOCATION_CONTENT_END_SUFFIX;
  3851. $l1 = strlen($tag_begin);
  3852. $l2 = strlen($tag_end);
  3853. $r = $this->getRanges($tag_begin, $tag_end, null, true, $pos);
  3854. if (count($r) == 0)
  3855. break;
  3856. $ini = $r[0][0];
  3857. $end = $r[0][1];
  3858. // Get the content
  3859. $newcontent = substr($this->__src, $ini + $l1, $end - $ini - $l1);
  3860. if ($newcontent != "") {
  3861. if ($newcontent[0] == ' ')
  3862. $newcontent = substr($newcontent, 1);
  3863. if (substr($newcontent, - 1) == ' ')
  3864. $newcontent = substr_replace($newcontent, "", - 1);
  3865. }
  3866. $content .= $newcontent;
  3867. // Remove declaration
  3868. $this->__src = substr($this->__src, 0, $ini) . substr($this->__src, $end + $l2);
  3869. // Update the locations (to left)
  3870. foreach ( $locations as $k => $v ) {
  3871. foreach ( $v as $kk => $p )
  3872. if ($p > $end)
  3873. $locations[$k][$kk] -= $l1 + $l2 + ($end - $ini - $l1);
  3874. }
  3875. }
  3876. // Inject the content in the locations
  3877. $tag = DIV_TAG_LOCATION_BEGIN . $location . DIV_TAG_LOCATION_END;
  3878. $this->__src = str_replace($tag, $content . $tag, $this->__src);
  3879. }
  3880. }
  3881. /**
  3882. * Clear location's tags
  3883. */
  3884. final private function clearLocations(){
  3885. $locations = $this->getLocations();
  3886. foreach ( $locations as $location => $posis ) {
  3887. $this->__src = str_replace(DIV_TAG_LOCATION_BEGIN . $location . DIV_TAG_LOCATION_END, '', $this->__src);
  3888. }
  3889. }
  3890. /**
  3891. * Parse the sub-parsers
  3892. */
  3893. final public function parseSubParsers(&$items = null, $flags = array()){
  3894. if (is_null($items))
  3895. $items = &$this->__items;
  3896. $itemsx = array_merge($this->__memory, $items);
  3897. if (! isset($flags['level']))
  3898. $flags['level'] = self::$__parse_level;
  3899. foreach ( self::$__sub_parsers as $parser => $function ) {
  3900. // Checking the moment/event
  3901. if (isset($flags['moment'])) {
  3902. $arr = explode(":", $parser);
  3903. if (isset($arr[1])) {
  3904. $last = array_pop($arr);
  3905. if ($last == 'beforeParse' && $flags['moment'] != DIV_MOMENT_BEFORE_PARSE)
  3906. continue;
  3907. if ($last == 'afterInclude' && $flags['moment'] != DIV_MOMENT_AFTER_INCLUDE)
  3908. continue;
  3909. if ($last == 'afterParse' && $flags['moment'] != DIV_MOMENT_AFTER_PARSE)
  3910. continue;
  3911. if ($last == 'afterReplace' && $flags['moment'] != DIV_MOMENT_AFTER_REPLACE)
  3912. continue;
  3913. }
  3914. }
  3915. $pini = DIV_TAG_SUBPARSER_BEGIN_PREFIX . $parser . DIV_TAG_SUBPARSER_BEGIN_SUFFIX;
  3916. $pfin = DIV_TAG_SUBPARSER_END_PREFIX . $parser . DIV_TAG_SUBPARSER_END_SUFFIX;
  3917. $lpini = strlen($pini);
  3918. $code = $function;
  3919. if (method_exists($this, $function))
  3920. $code = '$this->' . $function;
  3921. if (self::$__log_mode)
  3922. $this->logger("Parsing the subparser $parser ...");
  3923. $ignore = false;
  3924. $p = 0;
  3925. while ( true ) {
  3926. $ranges = $this->getRanges($pini, $pfin, null, true, $p);
  3927. if (count($ranges) < 1)
  3928. break;
  3929. $ini = $ranges[0][0];
  3930. $fin = $ranges[0][1];
  3931. if ($this->searchInListRanges($ini)) {
  3932. $p = $ini + 1;
  3933. $ignore = true;
  3934. continue;
  3935. }
  3936. if (DIV_TAG_SUBPARSER_BEGIN_SUFFIX == '' && strpos("\n\t <>", substr($this->__src, $ini + $pini, 1)) === false) {
  3937. $p = $ini + 1;
  3938. continue;
  3939. }
  3940. if (DIV_TAG_SUBPARSER_END_PREFIX == '' && strpos("\n\t <>", substr($this->__src, $fin - 1, 1)) === false) {
  3941. $p = $ini + 1;
  3942. continue;
  3943. }
  3944. $subsrc = substr($this->__src, $ini + $lpini, $fin - $ini - $lpini);
  3945. $r = "";
  3946. eval('$r = ' . $code . '($subsrc, $itemsx, $flags);');
  3947. if ($r !== false) {
  3948. $this->__src = substr($this->__src, 0, $ini) . $r . substr($this->__src, $fin + $lpini + 1);
  3949. $p = $ini;
  3950. } else {
  3951. $p = $ini + 1;
  3952. $ignore = true;
  3953. }
  3954. }
  3955. if (strpos($this->__src, $pini) !== false && ! $ignore) {
  3956. $r = "";
  3957. eval('$r = ' . $code . '(false, $itemsx, $flags);');
  3958. if ($r !== false)
  3959. $this->__src = str_replace($pini, $r, $this->__src, $rcount);
  3960. }
  3961. }
  3962. $this->memory($itemsx);
  3963. }
  3964. /**
  3965. * Checking logical order
  3966. *
  3967. * @param integer $ini
  3968. * @param string $var
  3969. * @param bool $chkloops
  3970. * @param bool $chkmatchs
  3971. * @param bool $chkformats
  3972. * @return mixed
  3973. */
  3974. final public function checkLogicalOrder($ini = 0, $var = "", $chkloops = false, $chkmatchs = false, $chkformats = false, $chkdata = false){
  3975. if (self::$__log_mode)
  3976. $this->logger("Checking logical order at $ini...");
  3977. if ($chkdata) {
  3978. $rang = $this->getRanges(DIV_TAG_TPLVAR_BEGIN, DIV_TAG_TPLVAR_END, null, true);
  3979. if (count($rang) > 0)
  3980. if ($rang[0][0] < $ini)
  3981. return $ini + 1;
  3982. }
  3983. if ($chkloops) {
  3984. if ($var != "")
  3985. $prev_use = strpos($this->__src, DIV_TAG_LOOP_BEGIN_PREFIX . $var . DIV_TAG_LOOP_BEGIN_SUFFIX);
  3986. else
  3987. $prev_use = $this->searchPreviousLoops($ini);
  3988. if ($prev_use !== false && $prev_use < $ini)
  3989. return $ini + 1;
  3990. }
  3991. if ($chkmatchs)
  3992. foreach ( self::$__modifiers as $m ) {
  3993. $prev_use = strpos($this->__src, DIV_TAG_REPLACEMENT_PREFIX . $m . $var);
  3994. if ($prev_use !== false && $prev_use < $ini)
  3995. return $ini + 1;
  3996. }
  3997. if ($chkformats) {
  3998. $prev_use = strpos($this->__src, DIV_TAG_NUMBER_FORMAT_PREFIX . $var);
  3999. if ($prev_use !== false && $prev_use < $ini)
  4000. return $ini + 1;
  4001. $prev_use = strpos($this->__src, DIV_TAG_DATE_FORMAT_PREFIX . $var);
  4002. if ($prev_use !== false && $prev_use < $ini)
  4003. return $ini + 1;
  4004. }
  4005. return false;
  4006. }
  4007. /**
  4008. * Parsing the macros
  4009. *
  4010. * @param mixed $items
  4011. */
  4012. final public function parseMacros(&$items = null){
  4013. if (self::$__log_mode)
  4014. $this->logger("Parsing macros...");
  4015. if (is_null($items))
  4016. $items = &$this->__items;
  4017. // Free the macro's scope and protect the scope of this method
  4018. $this->__temp = array();
  4019. $this->__temp['p'] = 0;
  4020. $l1 = strlen(DIV_TAG_MACRO_BEGIN);
  4021. $l2 = strlen(DIV_TAG_MACRO_END);
  4022. while ( true ) {
  4023. $classname = get_class($this);
  4024. $this->__temp['ranges'] = $this->getRanges(DIV_TAG_MACRO_BEGIN, DIV_TAG_MACRO_END, null, true, $this->__temp['p']);
  4025. if (count($this->__temp['ranges']) < 1)
  4026. break;
  4027. $this->__temp['ini'] = $this->__temp['ranges'][0][0];
  4028. $this->__temp['fin'] = $this->__temp['ranges'][0][1];
  4029. $this->__temp['r'] = $this->checkLogicalOrder($this->__temp['ini'], "", true, true, true, false);
  4030. if ($this->searchInListRanges($this->__temp['ini'])) {
  4031. $this->__temp['p'] = $this->__temp['ini'] + 1;
  4032. continue;
  4033. }
  4034. if ($this->__temp['r'] !== false) {
  4035. $this->__temp['p'] = $this->__temp['r'];
  4036. continue;
  4037. }
  4038. $this->__temp['code'] = trim(substr($this->__src, $this->__temp['ini'] + $l1, $this->__temp['fin'] - $this->__temp['ini'] - $l1));
  4039. $this->__temp['temp'] = uniqid();
  4040. $this->__src = substr($this->__src, 0, $this->__temp['ini']) . '{' . $this->__temp['temp'] . '}' . substr($this->__src, $this->__temp['fin'] + $l2);
  4041. if (substr($this->__temp['code'], 0, 3) == "php")
  4042. $__code = substr($this->__temp['code'], 3);
  4043. ob_start();
  4044. $this->__temp['invalid_macro'] = false;
  4045. if (self::isValidMacro($this->__temp['code'])) {
  4046. // Preparing methods
  4047. $this->__temp['validmethods'] = implode(',', self::$__allowed_methods);
  4048. $this->__temp['validmethods'] = str_replace(',', '(,' . $classname . '::', $classname . '::' . $this->__temp['validmethods']);
  4049. $this->__temp['methods'] = explode(',', str_replace($classname . '::', '', $this->__temp['validmethods']));
  4050. $this->__temp['methodsx'] = explode(',', $this->__temp['validmethods']);
  4051. $this->__temp['code'] = str_replace($this->__temp['methods'], $this->__temp['methodsx'], $this->__temp['code']);
  4052. // Preparing variables
  4053. foreach ( $items as $key => $value ) {
  4054. if (strpos($key, '.') !== false) {
  4055. self::setVarValue($key, $value, $items);
  4056. unset($items[$key]);
  4057. }
  4058. }
  4059. $this->__temp['codevars'] = '';
  4060. foreach ( $items as $key => $value ) {
  4061. if (self::isValidVarName($key))
  4062. $this->__temp['codevars'] .= '$' . $key . ' = $items["' . $key . '"];';
  4063. }
  4064. $this->__temp['items'] = $items;
  4065. unset($key);
  4066. unset($value);
  4067. unset($classname);
  4068. if ($this->__temp['codevars'] != '')
  4069. eval($this->__temp['codevars']);
  4070. unset($items);
  4071. // Executing the macro
  4072. eval($this->__temp['code']);
  4073. $vars = get_defined_vars();
  4074. $items = $this->__temp['items'];
  4075. foreach ( $vars as $var => $value ) {
  4076. if ($var == 'this')
  4077. continue; // Very very important!!
  4078. if (! isset($items[$var]) || isset(self::$__globals_design[$var]))
  4079. self::$__globals_design[$var] = $value;
  4080. $items[$var] = $value;
  4081. }
  4082. } else {
  4083. $this->__temp['invalid_macro'] = true;
  4084. }
  4085. $this->__src = str_replace('{' . $this->__temp['temp'] . '}', ob_get_contents(), $this->__src);
  4086. ob_end_clean();
  4087. if ($this->__temp['invalid_macro']) {
  4088. self::error("Invalid macro: \n\n" . $this->__temp['code']);
  4089. }
  4090. $this->__temp['p'] = $this->__temp['ini'] + 1;
  4091. }
  4092. // Free all temporal vars
  4093. $this->__temp = array();
  4094. return $items;
  4095. }
  4096. /**
  4097. * Making that remembered
  4098. *
  4099. * @param integer $checksum
  4100. */
  4101. final private function makeItAgain($checksum, &$items){
  4102. if (self::$__log_mode === true)
  4103. $this->logger("Making again some remembered tasks...");
  4104. $simple = DIV_TAG_REPLACEMENT_PREFIX . DIV_TAG_MODIFIER_SIMPLE;
  4105. foreach ( self::$__remember[$checksum] as $params ) {
  4106. switch ($params['o']) {
  4107. case 'replace_submatch_teaser' :
  4108. $value = self::getVarValue($params['key'], $items);
  4109. $value = self::anyToStr($value);
  4110. if (is_null($value))
  4111. continue;
  4112. $value = self::teaser("{$value}", intval($params['param']));
  4113. $search = DIV_TAG_REPLACEMENT_PREFIX . $params['modifier'] . $params['key'] . DIV_TAG_SUBMATCH_SEPARATOR . $params['param'] . DIV_TAG_REPLACEMENT_SUFFIX;
  4114. $this->__src = str_replace($search, $value, $this->__src);
  4115. break;
  4116. case 'replace_submatch_substr' :
  4117. $value = self::getVarValue($params['key'], $items);
  4118. if (is_null($value))
  4119. continue;
  4120. $value = self::anyToStr($value);
  4121. $this->__src = str_replace($simple . $params['key'] . DIV_TAG_SUBMATCH_SEPARATOR . $params['param'] . DIV_TAG_REPLACEMENT_SUFFIX, substr($value, $params['from'], $params['for']), $this->__src);
  4122. break;
  4123. case 'replace_submatch_wordwrap' :
  4124. $value = self::getVarValue($params['key'], $items);
  4125. if (is_null($value))
  4126. continue;
  4127. $value = self::anyToStr($value);
  4128. $this->__src = str_replace($simple . $params['key'] . DIV_TAG_SUBMATCH_SEPARATOR . $params['param'] . DIV_TAG_REPLACEMENT_SUFFIX, wordwrap("{$value}", intval(substr($params['param'], strlen(DIV_TAG_MODIFIER_WORDWRAP))), "\n", 1), $this->__src);
  4129. break;
  4130. case 'replace_submatch_sprintf' :
  4131. $value = self::getVarValue($params['key'], $items);
  4132. if (is_null($value))
  4133. continue;
  4134. $value = self::anyToStr($value);
  4135. $this->__src = str_replace($simple . $params['key'] . DIV_TAG_SUBMATCH_SEPARATOR . $params['param'] . DIV_TAG_REPLACEMENT_SUFFIX, sprintf($params['param'], $value), $this->__src);
  4136. break;
  4137. case 'json_encode' :
  4138. $value = self::getVarValue($params['key'], $items);
  4139. if (is_null($value))
  4140. continue;
  4141. $this->__src = str_replace(DIV_TAG_REPLACEMENT_PREFIX . DIV_TAG_MODIFIER_ENCODE_JSON . $params['key'] . DIV_TAG_REPLACEMENT_SUFFIX, self::jsonEncode($value), $this->__src);
  4142. break;
  4143. case 'simple_replacement' :
  4144. $value = self::getVarValue($params['key'], $items);
  4145. if (is_null($value))
  4146. continue;
  4147. $value = self::anyToStr($value);
  4148. switch ($params['modifier']) {
  4149. case DIV_TAG_MODIFIER_CAPITALIZE_FIRST :
  4150. $value = ucfirst($value);
  4151. break;
  4152. case DIV_TAG_MODIFIER_CAPITALIZE_WORDS :
  4153. $value = ucwords($value);
  4154. break;
  4155. case DIV_TAG_MODIFIER_UPPERCASE :
  4156. $value = strtoupper($value);
  4157. break;
  4158. case DIV_TAG_MODIFIER_LENGTH :
  4159. $value = strlen($value);
  4160. break;
  4161. case DIV_TAG_MODIFIER_COUNT_WORDS :
  4162. $value = self::getCountOfWords($value);
  4163. break;
  4164. case DIV_TAG_MODIFIER_COUNT_SENTENCES :
  4165. $value = self::getCountOfSentences($value);
  4166. break;
  4167. case DIV_TAG_MODIFIER_COUNT_PARAGRAPHS :
  4168. $value = self::getCountOfParagraphs($value);
  4169. break;
  4170. case DIV_TAG_MODIFIER_ENCODE_URL :
  4171. $value = urlencode($value);
  4172. break;
  4173. case DIV_TAG_MODIFIER_ENCODE_RAW_URL :
  4174. $value = rawurlencode($value);
  4175. break;
  4176. }
  4177. if ($params['before'] === false) {
  4178. $this->__src = str_replace(DIV_TAG_REPLACEMENT_PREFIX . $params['modifier'] . $params['key'] . DIV_TAG_REPLACEMENT_SUFFIX, $value, $this->__src);
  4179. } else {
  4180. $substr = substr($this->__src, 0, $params['before']);
  4181. $substr = str_replace(DIV_TAG_REPLACEMENT_PREFIX . $params['modifier'] . $params['key'] . DIV_TAG_REPLACEMENT_SUFFIX, $value, $substr);
  4182. $this->__src = $substr . substr($this->__src, $params['before']);
  4183. }
  4184. break;
  4185. }
  4186. }
  4187. }
  4188. /**
  4189. * Return the template's properties
  4190. *
  4191. * @param string $src
  4192. * @return string
  4193. */
  4194. final public function getTemplateProperties(&$src = null){
  4195. $update = false;
  4196. if (is_null($src)) {
  4197. $src = &$this->__src;
  4198. $update = true;
  4199. }
  4200. $properties = array();
  4201. if (strpos($src, '@_') !== false) {
  4202. $src = str_replace("\n\r", "\n", $src);
  4203. $lines = explode("\n", $src);
  4204. $nsrc = '';
  4205. $engine = self::getAuxiliaryEngineClone($this->__memory);
  4206. foreach ( $lines as $line ) {
  4207. $line = trim($line);
  4208. if (substr($line, 0, 2) == '@_') {
  4209. $s = substr($line, 2);
  4210. $s = trim($s);
  4211. if ($s !== "") {
  4212. $arr = explode('=', $s);
  4213. if (count($arr) > 1) {
  4214. $var = strtoupper(trim($arr[0]));
  4215. if (! isset($properties[$var])) {
  4216. array_shift($arr);
  4217. $value = implode('=', $arr);
  4218. $engine->__src = $value;
  4219. $engine->parse(false);
  4220. $value = $engine->__src;
  4221. $vvalue = self::jsonDecode($value, $this->__memory);
  4222. if (! is_null($vvalue))
  4223. $value = $vvalue;
  4224. else
  4225. $value = trim($value);
  4226. $properties[$var] = $value;
  4227. $line = '';
  4228. }
  4229. }
  4230. }
  4231. }
  4232. $nsrc .= $line . ($line == '' ? '' : "\n");
  4233. }
  4234. $src = $nsrc;
  4235. }
  4236. if ($update)
  4237. $this->__src = $src;
  4238. if (self::$__docs_on) {
  4239. $section = trim($this->__path);
  4240. if ($section !== '') {
  4241. if (substr($section, 0, 2) == './')
  4242. $section = substr($this->__path, 2);
  4243. if ($section !== '')
  4244. self::$__docs[$section]['properties'] = $properties;
  4245. }
  4246. }
  4247. return $properties;
  4248. }
  4249. /**
  4250. * Load properties from template code
  4251. */
  4252. final private function loadTemplateProperties(){
  4253. $this->__properties = $this->getTemplateProperties();
  4254. }
  4255. /**
  4256. * Preparing template's dialect
  4257. *
  4258. * @param string $src
  4259. * @param array $properties
  4260. */
  4261. final public function prepareDialect($src = null, $properties = null){
  4262. if (is_null($src))
  4263. $src = $this->__src;
  4264. if (is_null($properties))
  4265. $properties = $this->__properties;
  4266. if (isset($properties['DIALECT'])) {
  4267. $f = trim($properties['DIALECT']);
  4268. if (self::$__log_mode === true)
  4269. $this->logger("Preparing the dialect...");
  4270. $json = DIV_DEFAULT_DIALECT;
  4271. if (self::fileExists($f) && $f !== '') {
  4272. $json = self::getFileContents($f);
  4273. }
  4274. if (! is_null($json)) {
  4275. $src = $this->translateFrom($json, $src);
  4276. } else if (self::$__log_mode)
  4277. $this->log('The dialect ' . $f . ' is corrupt or invalid');
  4278. }
  4279. return $src;
  4280. }
  4281. /**
  4282. * Parse the template
  4283. *
  4284. * @param boolean $from_original
  4285. * @return string
  4286. */
  4287. final public function parse($from_original = true, $index_item = null){
  4288. self::createAuxiliarEngine($this);
  4289. self::$__parse_level ++;
  4290. if (self::$__log_mode)
  4291. $this->logger("Parsing all...");
  4292. $time_start = microtime(true);
  4293. self::repairSubparsers();
  4294. // Calling the beforeParse hook
  4295. $this->beforeParse();
  4296. if ($from_original == true) {
  4297. if (self::$__log_mode)
  4298. $this->logger("Parsing from the original source");
  4299. if (is_null($this->__src_original)) {
  4300. $this->__src_original = $this->__src;
  4301. } else
  4302. $this->__src = $this->__src_original;
  4303. }
  4304. $subparsers_restore = array();
  4305. if (trim($this->__src) != "") {
  4306. if (! is_null($index_item)) {
  4307. if (self::$__log_mode)
  4308. $this->logger("Parsing with '$index_item' index of __items");
  4309. $items = $this->__items[$index_item];
  4310. } else
  4311. $items = $this->__items;
  4312. // Add global vars (self::$globals)
  4313. foreach ( self::$__globals as $var => $value )
  4314. if (! isset($items[$var]))
  4315. $items[$var] = $value;
  4316. $items = array_merge($items, self::$__globals_design);
  4317. $items = array_merge($items, self::getSystemData());
  4318. // Add properties
  4319. $props = get_object_vars($this);
  4320. foreach ( $props as $prop => $value )
  4321. if (substr($prop, 0, 2) != "__")
  4322. $items[$prop] = $value;
  4323. // Reserved vars
  4324. if (! isset($items['_empty']))
  4325. $items['_empty'] = array();
  4326. if (! isset($items['_']))
  4327. $items['_'] = array();
  4328. if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false)
  4329. $this->parseSubParsers($items, array(
  4330. 'moment' => DIV_MOMENT_BEFORE_PARSE
  4331. ));
  4332. // Template's properties
  4333. $this->loadTemplateProperties();
  4334. // Preparing dialect
  4335. $this->__src = $this->prepareDialect();
  4336. if (strpos($this->__src, DIV_TAG_IGNORE_BEGIN) !== false)
  4337. $this->parseIgnore();
  4338. if (strpos($this->__src, DIV_TAG_COMMENT_BEGIN) !== false)
  4339. $this->parseComments();
  4340. if (strpos($this->__src, DIV_TAG_FRIENDLY_BEGIN) !== false)
  4341. $this->parseFriendly();
  4342. $cycles2 = 0;
  4343. $this->memory($items);
  4344. $msg_infinite_cycle = 'Too many iterations of the parser: possible infinite cycle. Review your template code.';
  4345. do {
  4346. $cycles1 = 0;
  4347. $cycles2 ++;
  4348. if ($cycles2 > DIV_MAX_PARSE_CYCLES)
  4349. $this->error($msg_infinite_cycle, "FATAL");
  4350. do {
  4351. $checksum = crc32($this->__src);
  4352. $this->__crc = $checksum;
  4353. if (self::$__log_mode === true) {
  4354. $this->logger('Template | size: ' . strlen($this->__src));
  4355. if (isset($this->__src[100]))
  4356. $this->logger('Template [checksum=' . $checksum . ']:' . htmlentities(str_replace("\n", " ", substr($this->__src, 0, 100)) . "..." . substr($this->__src, strlen($this->__src) - 100)));
  4357. else
  4358. $this->logger('Template [checksum=' . $checksum . ']: ' . htmlentities($this->__src));
  4359. }
  4360. $cycles1 ++;
  4361. if ($cycles1 > DIV_MAX_PARSE_CYCLES)
  4362. $this->error($msg_infinite_cycle, "FATAL");
  4363. $this->memory($items);
  4364. // Conditional
  4365. if (strpos($this->__src, DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX) !== false || strpos($this->__src, DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX) !== false)
  4366. $this->parseConditional($items);
  4367. // Conditions
  4368. if (strpos($this->__src, DIV_TAG_CONDITIONS_BEGIN_PREFIX) !== false)
  4369. $this->parseConditions($items);
  4370. // Include
  4371. if (strpos($this->__src, DIV_TAG_INCLUDE_BEGIN) !== false) {
  4372. $this->parseInclude($items);
  4373. if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false)
  4374. $this->parseSubParsers($items, array(
  4375. 'moment' => DIV_MOMENT_AFTER_INCLUDE
  4376. ));
  4377. if (strpos($this->__src, DIV_TAG_IGNORE_BEGIN) !== false)
  4378. $this->parseIgnore();
  4379. if (strpos($this->__src, DIV_TAG_COMMENT_BEGIN) !== false)
  4380. $this->parseComments();
  4381. if (strpos($this->__src, DIV_TAG_FRIENDLY_BEGIN) !== false)
  4382. $this->parseFriendly();
  4383. $this->memory($items);
  4384. }
  4385. // Multiple variable's modifiers
  4386. if (strpos($this->__src, DIV_TAG_MULTI_MODIFIERS_PREFIX) !== false && strpos($this->__src, DIV_TAG_MULTI_MODIFIERS_SUFFIX) !== false)
  4387. $this->parseMultipleModifiers();
  4388. // Data in templates
  4389. if (strpos($this->__src, DIV_TAG_TPLVAR_BEGIN) !== false)
  4390. if (strpos($this->__src, DIV_TAG_TPLVAR_END) !== false) {
  4391. $this->parseData($items);
  4392. $this->memory($items);
  4393. }
  4394. // Number format
  4395. if (strpos($this->__src, DIV_TAG_NUMBER_FORMAT_PREFIX) !== false)
  4396. $this->parseNumberFormat($items);
  4397. // Preprocessed
  4398. if (strpos($this->__src, DIV_TAG_PREPROCESSED_BEGIN) !== false) {
  4399. $this->parsePreprocessed($items);
  4400. $this->memory($items);
  4401. }
  4402. $items = array_merge($items, self::$__globals_design);
  4403. // Default values in templates
  4404. if (strpos($this->__src, DIV_TAG_DEFAULT_REPLACEMENT_BEGIN) !== false)
  4405. $this->parseDefaults($items);
  4406. // Macros
  4407. if (strpos($this->__src, DIV_TAG_MACRO_BEGIN) !== false) {
  4408. $items = array_merge($this->__memory, $items);
  4409. $items = $this->parseMacros($items);
  4410. $this->memory($items);
  4411. }
  4412. // Lists
  4413. if (strpos($this->__src, DIV_TAG_LOOP_BEGIN_PREFIX) !== false)
  4414. if (strpos($this->__src, DIV_TAG_LOOP_END_PREFIX) !== false)
  4415. if (strpos($this->__src, DIV_TAG_LOOP_END_SUFFIX) !== false)
  4416. $this->parseList($items);
  4417. $items = array_merge($items, self::$__globals_design);
  4418. // Capsules
  4419. if (strpos($this->__src, DIV_TAG_CAPSULE_BEGIN_PREFIX) !== false)
  4420. if (strpos($this->__src, DIV_TAG_CAPSULE_END_SUFFIX) !== false)
  4421. $this->parseCapsules($items);
  4422. $items = array_merge($items, self::$__globals_design);
  4423. // Make it again
  4424. if (isset(self::$__remember[$checksum])) {
  4425. $this->makeItAgain($checksum, $items);
  4426. if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false)
  4427. $this->parseSubParsers($items, array(
  4428. 'moment' => DIV_MOMENT_AFTER_REPLACE
  4429. ));
  4430. }
  4431. // Sub-Matches
  4432. if (self::atLeastOneString($this->__src, self::$__modifiers))
  4433. $this->parseSubmatches($items);
  4434. // Matches
  4435. 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))
  4436. $this->parseMatches($items);
  4437. // Subparse: after replace
  4438. if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false)
  4439. $this->parseSubParsers($items, array(
  4440. 'moment' => DIV_MOMENT_AFTER_REPLACE
  4441. ));
  4442. // Iterations
  4443. if (strpos($this->__src, DIV_TAG_ITERATION_BEGIN_PREFIX) !== false)
  4444. if (strpos($this->__src, DIV_TAG_ITERATION_END) !== false)
  4445. $this->parseIterations($items);
  4446. } while ( $checksum != crc32($this->__src) );
  4447. // Computing
  4448. if (strpos($this->__src, DIV_TAG_FORMULA_BEGIN) !== false)
  4449. if (strpos($this->__src, DIV_TAG_FORMULA_END) !== false)
  4450. $this->parseFormulas($items);
  4451. // Date format
  4452. if (strpos($this->__src, DIV_TAG_DATE_FORMAT_PREFIX) !== false)
  4453. if (strpos($this->__src, DIV_TAG_DATE_FORMAT_SUFFIX) !== false)
  4454. $this->parseDateFormat($items);
  4455. // Multiple replacements
  4456. if (strpos($this->__src, DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX) !== false)
  4457. if (strpos($this->__src, DIV_TAG_MULTI_REPLACEMENT_END_PREFIX) !== false)
  4458. if (strpos($this->__src, DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX) !== false)
  4459. $this->parseMultiReplace($items);
  4460. // Searching orphan parts (conditions)
  4461. if (strpos($this->__src, DIV_TAG_CONDITIONS_BEGIN_PREFIX) !== false)
  4462. $this->parseConditions($items, true);
  4463. } while ( $checksum != crc32($this->__src) );
  4464. // Searching orphan parts (conditionals)
  4465. if (strpos($this->__src, DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX) !== false || strpos($this->__src, DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX) !== false)
  4466. $this->parseOrphanParts();
  4467. if (strpos($this->__src, DIV_TAG_IGNORE_BEGIN) !== false)
  4468. $this->parseIgnore();
  4469. if (strpos($this->__src, DIV_TAG_COMMENT_BEGIN) !== false)
  4470. $this->parseComments();
  4471. if (strpos($this->__src, DIV_TAG_FRIENDLY_BEGIN) !== false)
  4472. $this->parseFriendly();
  4473. // Locations
  4474. if (strpos($this->__src, DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX) !== false)
  4475. if (strpos($this->__src, DIV_TAG_LOCATION_BEGIN) !== false)
  4476. $this->parseLocations();
  4477. // Clear location's tags
  4478. if (strpos($this->__src, DIV_TAG_LOCATION_BEGIN) !== false)
  4479. $this->clearLocations();
  4480. // Restoring parsers requests
  4481. foreach ( $this->__restore as $restore_id => $rest )
  4482. $this->__src = str_replace('{' . $restore_id . '}', $rest, $this->__src);
  4483. $this->clean();
  4484. // Restoring ignored parts
  4485. if (self::$__parse_level == 1) {
  4486. $this->parseSpecialChars();
  4487. foreach ( self::$__ignored_parts as $id => $ignore ) {
  4488. foreach ( self::$__sub_parsers as $subparser => $function ) {
  4489. $tempunique = uniqid();
  4490. $rcount = 0;
  4491. $tagsearch = DIV_TAG_SUBPARSER_BEGIN_PREFIX . $subparser . DIV_TAG_SUBPARSER_BEGIN_SUFFIX;
  4492. $tagreplace = DIV_TAG_SUBPARSER_BEGIN_PREFIX . $tempunique . DIV_TAG_SUBPARSER_BEGIN_SUFFIX;
  4493. $ignore = str_replace($tagsearch, $tagreplace, $ignore, $rcount);
  4494. if ($rcount > 0)
  4495. $subparsers_restore[$tagsearch] = $tagreplace;
  4496. }
  4497. $this->__src = str_replace('{' . $id . '}', $ignore, $this->__src);
  4498. }
  4499. self::$__ignored_parts = array();
  4500. self::$__globals_design = array();
  4501. }
  4502. }
  4503. $this->txt();
  4504. if (strpos($this->__src, DIV_TAG_SUBPARSER_BEGIN_PREFIX) !== false) {
  4505. $items = array_merge($this->__memory, $items);
  4506. $this->parseSubParsers($items, array(
  4507. 'moment' => DIV_MOMENT_AFTER_PARSE,
  4508. 'level' => self::$__parse_level
  4509. ));
  4510. $this->memory($items);
  4511. }
  4512. // Restore subparsers ignored
  4513. foreach ( $subparsers_restore as $tagsearch => $tag_replace ) {
  4514. $this->__src = str_replace($tagreplace, $tagsearch);
  4515. }
  4516. $time_end = microtime(true);
  4517. if (self::$__log_mode)
  4518. $this->logger("Parser duration: " . number_format($time_end - $time_start, 5) . " secs");
  4519. self::$__parse_duration = $time_end - $time_start;
  4520. self::$__parse_level --;
  4521. // Calling the afterParse hook
  4522. $this->afterParse();
  4523. }
  4524. /**
  4525. * Parsing SpecialChars
  4526. */
  4527. final public function parseSpecialChars(){
  4528. $this->__src = str_replace(DIV_TAG_SPECIAL_REPLACE_NEW_LINE . "\n\n", DIV_TAG_SPECIAL_REPLACE_NEW_LINE . "\n", $this->__src);
  4529. $this->__src = str_replace(DIV_TAG_SPECIAL_REPLACE_NEW_LINE, "\n", $this->__src);
  4530. $this->__src = str_replace(DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB, "\t", $this->__src);
  4531. $this->__src = str_replace(DIV_TAG_SPECIAL_REPLACE_CAR_RETURN, "\r", $this->__src);
  4532. $this->__src = str_replace(DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB, "\v", $this->__src);
  4533. $this->__src = str_replace(DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE, "\f", $this->__src);
  4534. $this->__src = str_replace(DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL, "\$", $this->__src);
  4535. }
  4536. /**
  4537. * Multiple replacement
  4538. *
  4539. * @param array $items
  4540. */
  4541. final public function parseMultiReplace(&$items = null){
  4542. if (is_null($items))
  4543. $items = $this->__items;
  4544. if (is_array($items))
  4545. foreach ( $items as $key => $value ) {
  4546. if (self::isArrayOfArray($value)) {
  4547. $pos = 0;
  4548. while ( true ) {
  4549. $ranges = $this->getRanges("{:$key}", "{:/$key}", null, true, $pos);
  4550. if (count($ranges) < 1)
  4551. break;
  4552. $l = strlen($key) + 4;
  4553. $ini = $ranges[0][0];
  4554. $fin = $ranges[0][1];
  4555. $subsrc = substr($this->__src, $ini + $l - 1, $fin - $ini - $l + 1);
  4556. $engine = self::getAuxiliaryEngineClone($items);
  4557. $engine->__src = $subsrc;
  4558. $engine->parse(false);
  4559. $subsrc = $engine->__src;
  4560. foreach ( $value as $vv ) {
  4561. if (isset($vv[0]) && isset($vv[1])) {
  4562. $regexp = false;
  4563. if (isset($vv[2]))
  4564. if ($vv[2] == true)
  4565. $regexp = true;
  4566. if ($regexp) {
  4567. $subsrc = preg_replace($vv[0], $vv[1], $subsrc);
  4568. } else {
  4569. $subsrc = str_replace($vv[0], $vv[1], $subsrc);
  4570. }
  4571. }
  4572. }
  4573. $this->__src = substr($this->__src, 0, $ini) . $subsrc . substr($this->__src, $fin + $l);
  4574. }
  4575. }
  4576. }
  4577. }
  4578. /**
  4579. * Clean the output: parsing the strip tags
  4580. */
  4581. final public function clean(){
  4582. $restore = array();
  4583. $this->__src = preg_replace("/\015\012|\015|\012/", "\n", $this->__src);
  4584. $l1 = strlen(DIV_TAG_STRIP_BEGIN);
  4585. $l2 = strlen(DIV_TAG_STRIP_END);
  4586. while ( true ) {
  4587. $ranges = $this->getRanges(DIV_TAG_STRIP_BEGIN, DIV_TAG_STRIP_END, null, true);
  4588. if (count($ranges) < 1)
  4589. break;
  4590. $ini = $ranges[0][0];
  4591. $fin = $ranges[0][1];
  4592. $subsrc = substr($this->__src, $ini + $l1, $fin - $ini - $l1);
  4593. while ( strpos($subsrc, "\n\n") !== false )
  4594. $subsrc = str_replace("\n\n", "\n", $subsrc);
  4595. $lines = explode("\n", $subsrc);
  4596. $subsrc = "";
  4597. foreach ( $lines as $line ) {
  4598. $line = trim($line);
  4599. if ($line == "")
  4600. continue;
  4601. $subsrc .= $line . "\n";
  4602. }
  4603. $subsrc = trim($subsrc);
  4604. $this->__src = substr($this->__src, 0, $ini) . $subsrc . substr($this->__src, $fin + $l2);
  4605. }
  4606. }
  4607. /**
  4608. * Parse txt tags and convert HTML to readable text
  4609. */
  4610. final public function txt(){
  4611. $l1 = strlen(DIV_TAG_TXT_BEGIN);
  4612. $l2 = strlen(DIV_TAG_TXT_END);
  4613. $lsep = strlen(DIV_TAG_TXT_WIDTH_SEPARATOR);
  4614. while ( true ) {
  4615. $ranges = $this->getRanges(DIV_TAG_TXT_BEGIN, DIV_TAG_TXT_END, null, true);
  4616. if (count($ranges) < 1)
  4617. break;
  4618. $ini = $ranges[0][0];
  4619. $fin = $ranges[0][1];
  4620. $subsrc = substr($this->__src, $ini + $l1, $fin - $ini - $l1);
  4621. $width = 100;
  4622. $p = strpos($subsrc, DIV_TAG_TXT_WIDTH_SEPARATOR);
  4623. if ($p !== false) {
  4624. $width = intval(trim(substr($subsrc, 0, $p)));
  4625. $subsrc = substr($subsrc, $p + $lsep);
  4626. }
  4627. $subsrc = self::htmlToText($subsrc, $width);
  4628. $this->__src = substr($this->__src, 0, $ini) . $subsrc . substr($this->__src, $fin + $l2);
  4629. }
  4630. }
  4631. /**
  4632. * Translate and change de original template
  4633. *
  4634. * @param mixed $dialectFrom
  4635. * @param string $src
  4636. * @param mixed $items
  4637. * @return string
  4638. */
  4639. final public function translateAndChange($dialectFrom, $src = null, $items = null){
  4640. $translation = $this->translateFrom($dialectFrom, $src, $items);
  4641. $this->changeTemplate($translation);
  4642. return $translation;
  4643. }
  4644. /**
  4645. * Translate simple blocks
  4646. *
  4647. * @param string $src
  4648. * @param string $begin
  4649. * @param string $end
  4650. * @param string $tbegin
  4651. * @param string $end
  4652. */
  4653. final private function translateSimpleBlocks($src, $begin, $end, $tbegin, $tend, $separator = "", $tseparator = "", $first = true){
  4654. $lbegin = strlen($begin);
  4655. $lend = strlen($end);
  4656. $lsep = strlen(trim("$separator"));
  4657. $p = 0;
  4658. while ( true ) {
  4659. $r = $this->getRanges($begin, $end, $src, true, $p);
  4660. if (count($r) < 1)
  4661. break;
  4662. $ini = $r[0][0];
  4663. $end = $r[0][1];
  4664. $subsrc = substr($src, $ini + $lbegin, $end - $ini - $lbegin);
  4665. if ($lsep > 0) {
  4666. if ($first)
  4667. $po = strpos($subsrc, $separator);
  4668. else
  4669. $po = strrpos($subsrc, $separator);
  4670. if ($po !== false)
  4671. $subsrc = substr($subsrc, 0, $po) . $tseparator . substr($subsrc, $po + $lsep);
  4672. }
  4673. $src = substr($src, 0, $ini) . $tbegin . $subsrc . $tend . substr($src, $end + $lend);
  4674. $p = $ini + 1;
  4675. }
  4676. return $src;
  4677. }
  4678. /**
  4679. * Translate key blocks
  4680. *
  4681. * @param string $src
  4682. * @param string $begin_prefix
  4683. * @param string $begin_suffix
  4684. * @param string $end_prefix
  4685. * @param string $end_suffix
  4686. * @param string $tbegin_prefix
  4687. * @param string $tbegin_suffix
  4688. * @param string $tend_prefix
  4689. * @param string $tend_suffix
  4690. */
  4691. final private function translateKeyBlocks($src, $begin_prefix, $begin_suffix, $end_prefix, $end_suffix, $tbegin_prefix, $tbegin_suffix, $tend_prefix, $tend_suffix){
  4692. $p = 0;
  4693. while ( true ) {
  4694. $r = $this->getBlockRanges($src, $begin_prefix, $begin_suffix, $end_prefix, $end_suffix, $p, null, true);
  4695. if (count($r) < 1)
  4696. break;
  4697. $ini = $r[0][0];
  4698. $end = $r[0][1];
  4699. $key = $r[0][2];
  4700. $subsrc = $r[0][3];
  4701. $prefix = $begin_prefix . $key . $begin_suffix;
  4702. $suffix = $end_prefix . $key . $end_suffix;
  4703. $lprefix = strlen($prefix);
  4704. $lsuffix = strlen($suffix);
  4705. $src = substr($src, 0, $ini) . $tbegin_prefix . $key . $tbegin_suffix . $subsrc . $tend_prefix . $key . $tend_suffix . substr($src, $end + $lsuffix);
  4706. $p = $ini + 1;
  4707. }
  4708. return $src;
  4709. }
  4710. /**
  4711. * Translate dialects
  4712. *
  4713. * @param string $src
  4714. * @param mixed $dialectFrom
  4715. * @param mixed $dialectTo
  4716. * @return string
  4717. */
  4718. final public function translateFrom($dialectFrom, $src = null, $items = null){
  4719. if (self::$__log_mode === true)
  4720. $this->logger("Translating to current dialect...");
  4721. $update = false;
  4722. if (is_null($src)) {
  4723. $src = &$this->__src;
  4724. $update = true;
  4725. }
  4726. if (is_null($items))
  4727. $items = &$this->__items;
  4728. $constants = get_defined_constants(true);
  4729. $constants = $constants['user'];
  4730. $nconst = array();
  4731. foreach ( $constants as $c => $v )
  4732. if (substr($c, 0, 8) == 'DIV_TAG_')
  4733. $nconst[$c] = $v;
  4734. $constants = $nconst;
  4735. // Preparing dialect from ...
  4736. if (is_string($dialectFrom))
  4737. $dialectFrom = self::jsonDecode($dialectFrom);
  4738. if (is_object($dialectFrom))
  4739. $dialectFrom = get_object_vars($dialectFrom);
  4740. if (! is_array($dialectFrom))
  4741. return false;
  4742. foreach ( $constants as $c => $v )
  4743. if (! isset($dialectFrom[$c]))
  4744. $dialectFrom[$c] = $v;
  4745. foreach ( $dialectFrom as $c => $v )
  4746. eval('$' . $c . ' = $v;');
  4747. // Searching differences
  4748. $different = false;
  4749. foreach ( $dialectFrom as $c => $v ) {
  4750. if ($v !== constant($c)) {
  4751. $different = true;
  4752. break;
  4753. }
  4754. }
  4755. if (! $different)
  4756. return $src; // The dialects are equals
  4757. $order = array(
  4758. 'replacement' => strlen($DIV_TAG_REPLACEMENT_PREFIX),
  4759. 'multimodifiers' => strlen($DIV_TAG_MULTI_MODIFIERS_PREFIX),
  4760. 'dateformat' => strlen($DIV_TAG_DATE_FORMAT_PREFIX),
  4761. 'numberformat' => strlen($DIV_TAG_NUMBER_FORMAT_PREFIX),
  4762. 'formulas' => strlen($DIV_TAG_FORMULA_BEGIN),
  4763. 'subparsers' => strlen($DIV_TAG_SUBPARSER_BEGIN_PREFIX),
  4764. 'ignore' => strlen($DIV_TAG_IGNORE_BEGIN),
  4765. 'comment' => strlen($DIV_TAG_COMMENT_BEGIN),
  4766. 'html2txt' => strlen($DIV_TAG_TXT_BEGIN),
  4767. 'strip' => strlen($DIV_TAG_STRIP_BEGIN),
  4768. 'loops' => strlen($DIV_TAG_LOOP_BEGIN_PREFIX),
  4769. 'iterations' => strlen($DIV_TAG_ITERATION_BEGIN_PREFIX),
  4770. 'conditionals' => strlen($DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX),
  4771. 'conditions' => strlen($DIV_TAG_CONDITIONS_BEGIN_PREFIX),
  4772. 'tplvars' => strlen($DIV_TAG_TPLVAR_BEGIN),
  4773. 'defaultreplace' => strlen($DIV_TAG_DEFAULT_REPLACEMENT_BEGIN),
  4774. 'include' => strlen($DIV_TAG_IGNORE_BEGIN),
  4775. 'preprocessed' => strlen($DIV_TAG_PREPROCESSED_BEGIN),
  4776. 'capsules' => strlen($DIV_TAG_CAPSULE_BEGIN_PREFIX),
  4777. 'multireplace' => strlen($DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX),
  4778. 'friendlytags' => strlen($DIV_TAG_FRIENDLY_BEGIN),
  4779. 'macros' => strlen($DIV_TAG_MACRO_BEGIN),
  4780. 'location' => strlen($DIV_TAG_LOCATION_BEGIN),
  4781. 'locontent' => strlen($DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX)
  4782. );
  4783. arsort($order);
  4784. $modifiers = array(
  4785. 'DIV_TAG_MODIFIER_SIMPLE',
  4786. 'DIV_TAG_MODIFIER_CAPITALIZE_FIRST',
  4787. 'DIV_TAG_MODIFIER_CAPITALIZE_WORDS',
  4788. 'DIV_TAG_MODIFIER_UPPERCASE',
  4789. 'DIV_TAG_MODIFIER_LOWERCASE',
  4790. 'DIV_TAG_MODIFIER_LENGTH',
  4791. 'DIV_TAG_MODIFIER_COUNT_WORDS',
  4792. 'DIV_TAG_MODIFIER_COUNT_SENTENCES',
  4793. 'DIV_TAG_MODIFIER_COUNT_PARAGRAPHS',
  4794. 'DIV_TAG_MODIFIER_ENCODE_URL',
  4795. 'DIV_TAG_MODIFIER_ENCODE_RAW_URL',
  4796. 'DIV_TAG_MODIFIER_HTML_ENTITIES',
  4797. 'DIV_TAG_MODIFIER_NL2BR',
  4798. 'DIV_TAG_MODIFIER_ENCODE_JSON',
  4799. 'DIV_TAG_MODIFIER_SINGLE_QUOTES',
  4800. 'DIV_TAG_MODIFIER_JS'
  4801. );
  4802. $xmod = array();
  4803. $ymod = array();
  4804. foreach ( $modifiers as $mod ) {
  4805. $xmod[$mod] = array();
  4806. eval('$xmod[$mod][0] = $' . $mod . ';');
  4807. eval('$xmod[$mod][1] = ' . $mod . ';');
  4808. $ymod[$xmod[$mod][0]] = $xmod[$mod][1];
  4809. }
  4810. $temp = $DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR;
  4811. $agfuncs = array(
  4812. DIV_TAG_AGGREGATE_FUNCTION_COUNT . $temp => $DIV_TAG_AGGREGATE_FUNCTION_COUNT . $temp,
  4813. DIV_TAG_AGGREGATE_FUNCTION_MAX . $temp => $DIV_TAG_AGGREGATE_FUNCTION_MAX . $temp,
  4814. DIV_TAG_AGGREGATE_FUNCTION_MIN . $temp => $DIV_TAG_AGGREGATE_FUNCTION_MIN . $temp,
  4815. DIV_TAG_AGGREGATE_FUNCTION_SUM . $temp => $DIV_TAG_AGGREGATE_FUNCTION_SUM . $temp,
  4816. DIV_TAG_AGGREGATE_FUNCTION_AVG . $temp => $DIV_TAG_AGGREGATE_FUNCTION_AVG . $temp
  4817. );
  4818. asort($agfuncs);
  4819. $agfuncs_keys = array_keys($agfuncs);
  4820. foreach ( $order as $o => $priority ) {
  4821. switch ($o) {
  4822. case 'replacement' :
  4823. foreach ( $xmod as $modifier => $values ) {
  4824. $lprefix = strlen($DIV_TAG_REPLACEMENT_PREFIX . $values[0]);
  4825. $lsuffix = strlen($DIV_TAG_REPLACEMENT_SUFFIX);
  4826. $p = 0;
  4827. while ( true ) {
  4828. $r = $this->getRanges($DIV_TAG_REPLACEMENT_PREFIX . $values[0], $DIV_TAG_REPLACEMENT_SUFFIX, $src, true, $p);
  4829. if (count($r) < 1)
  4830. break;
  4831. $ini = $r[0][0];
  4832. $end = $r[0][1];
  4833. $subsrc = substr($src, $ini + $lprefix, $end - $ini - $lprefix);
  4834. if (strpos($subsrc, "\n") !== false) {
  4835. $p = $ini + 1;
  4836. continue;
  4837. }
  4838. if (strpos($subsrc, "\t") !== false) {
  4839. $p = $ini + 1;
  4840. continue;
  4841. }
  4842. if (strpos($subsrc, "\r") !== false) {
  4843. $p = $ini + 1;
  4844. continue;
  4845. }
  4846. if (strpos($subsrc, " ") !== false) {
  4847. $p = $ini + 1;
  4848. continue;
  4849. }
  4850. // Aggregate functions
  4851. $subsrc = str_replace($DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR, DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR, $subsrc);
  4852. $subsrc = str_replace($agfuncs, $agfuncs_keys, $subsrc);
  4853. // Teaser or truncate
  4854. $subsrc = str_replace($DIV_TAG_SUBMATCH_SEPARATOR . $DIV_TAG_MODIFIER_TRUNCATE, DIV_TAG_SUBMATCH_SEPARATOR . DIV_TAG_MODIFIER_TRUNCATE, $subsrc);
  4855. // Word wrap
  4856. $subsrc = str_replace($DIV_TAG_SUBMATCH_SEPARATOR . $DIV_TAG_MODIFIER_WORDWRAP, DIV_TAG_SUBMATCH_SEPARATOR . DIV_TAG_MODIFIER_WORDWRAP, $subsrc);
  4857. // Format (sprintf)
  4858. $subsrc = str_replace($DIV_TAG_SUBMATCH_SEPARATOR . $DIV_TAG_MODIFIER_FORMAT, DIV_TAG_SUBMATCH_SEPARATOR . DIV_TAG_MODIFIER_FORMAT, $subsrc);
  4859. // Substring
  4860. $subsrc = str_replace($DIV_TAG_SUBMATCH_SEPARATOR, DIV_TAG_SUBMATCH_SEPARATOR, $subsrc);
  4861. $src = substr($src, 0, $ini) . DIV_TAG_REPLACEMENT_PREFIX . $values[1] . $subsrc . DIV_TAG_REPLACEMENT_SUFFIX . substr($src, $end + $lsuffix);
  4862. $p = $ini + 1; // IMPORTANT!
  4863. }
  4864. }
  4865. break;
  4866. case 'multimodifiers' :
  4867. $lprefix = strlen($DIV_TAG_MULTI_MODIFIERS_PREFIX);
  4868. $lsuffix = strlen($DIV_TAG_MULTI_MODIFIERS_SUFFIX);
  4869. $p = 0;
  4870. while ( true ) {
  4871. $r = $this->getRanges($DIV_TAG_MULTI_MODIFIERS_PREFIX, $DIV_TAG_MULTI_MODIFIERS_SUFFIX, $src, true, $p);
  4872. if (count($r) < 1)
  4873. break;
  4874. $ini = $r[0][0];
  4875. $end = $r[0][1];
  4876. $subsrc = substr($src, $ini + $lprefix, $end - $ini - $lprefix);
  4877. if (strpos($subsrc, "\n") !== false) {
  4878. $p = $ini + 1;
  4879. continue;
  4880. }
  4881. if (strpos($subsrc, "\t") !== false) {
  4882. $p = $ini + 1;
  4883. continue;
  4884. }
  4885. if (strpos($subsrc, "\r") !== false) {
  4886. $p = $ini + 1;
  4887. continue;
  4888. }
  4889. if (strpos($subsrc, " ") !== false) {
  4890. $p = $ini + 1;
  4891. continue;
  4892. }
  4893. $po = strpos($subsrc, $DIV_TAG_MULTI_MODIFIERS_OPERATOR);
  4894. if ($po === false) {
  4895. $p = $ini + 1;
  4896. continue;
  4897. }
  4898. $temp = substr($subsrc, $po + 1);
  4899. $parts = explode($DIV_TAG_MULTI_MODIFIERS_SEPARATOR, $temp);
  4900. foreach ( $parts as $k => $v ) {
  4901. if (isset($ymod[$v]))
  4902. $parts[$k] = $ymod[$v];
  4903. if (isset($ymod[$v . ':']))
  4904. $parts[$k] = $ymod[$v . ':'];
  4905. }
  4906. $temp = implode(DIV_TAG_MULTI_MODIFIERS_SEPARATOR, $parts);
  4907. $subsrc = substr($subsrc, 0, $po) . DIV_TAG_MULTI_MODIFIERS_OPERATOR . $temp;
  4908. $src = substr($src, 0, $ini) . DIV_TAG_MULTI_MODIFIERS_PREFIX . $subsrc . DIV_TAG_MULTI_MODIFIERS_SUFFIX . substr($src, $end + $lsuffix);
  4909. $p = $ini + 1; // IMPORTANT!
  4910. }
  4911. break;
  4912. case 'dateformat' :
  4913. $lprefix = strlen($DIV_TAG_DATE_FORMAT_PREFIX);
  4914. $lsuffix = strlen($DIV_TAG_DATE_FORMAT_SUFFIX);
  4915. $lsep = strlen($DIV_TAG_DATE_FORMAT_SEPARATOR);
  4916. $p = 0;
  4917. while ( true ) {
  4918. $r = $this->getRanges($DIV_TAG_DATE_FORMAT_PREFIX, $DIV_TAG_DATE_FORMAT_SUFFIX, $src, true, $p);
  4919. if (count($r) < 1)
  4920. break;
  4921. $ini = $r[0][0];
  4922. $end = $r[0][1];
  4923. $subsrc = substr($src, $ini + $lprefix, $end - $ini - $lprefix);
  4924. $po = strpos($subsrc, $DIV_TAG_DATE_FORMAT_SEPARATOR);
  4925. if ($po !== false)
  4926. $subsrc = substr($subsrc, 0, $po) . DIV_TAG_DATE_FORMAT_SEPARATOR . substr($subsrc, $po + $lsep);
  4927. $src = substr($src, 0, $ini) . DIV_TAG_DATE_FORMAT_PREFIX . $subsrc . DIV_TAG_DATE_FORMAT_SUFFIX . substr($src, $end + $lsuffix);
  4928. $p = $ini + 1; // IMPORTANT!
  4929. }
  4930. break;
  4931. case 'numberformat' :
  4932. $lprefix = strlen($DIV_TAG_NUMBER_FORMAT_PREFIX);
  4933. $lsuffix = strlen($DIV_TAG_NUMBER_FORMAT_SUFFIX);
  4934. $lsep = strlen($DIV_TAG_NUMBER_FORMAT_SEPARATOR);
  4935. $p = 0;
  4936. while ( true ) {
  4937. $r = $this->getRanges($DIV_TAG_NUMBER_FORMAT_PREFIX, $DIV_TAG_NUMBER_FORMAT_SUFFIX, $src, true, $p);
  4938. if (count($r) < 1)
  4939. break;
  4940. $ini = $r[0][0];
  4941. $end = $r[0][1];
  4942. $subsrc = substr($src, $ini + $lprefix, $end - $ini - $lprefix);
  4943. $po = strpos($subsrc, $DIV_TAG_NUMBER_FORMAT_SEPARATOR);
  4944. if ($po !== false)
  4945. $subsrc = substr($subsrc, 0, $po) . DIV_TAG_NUMBER_FORMAT_SEPARATOR . substr($subsrc, $po + $lsep);
  4946. $src = substr($src, 0, $ini) . DIV_TAG_NUMBER_FORMAT_PREFIX . $subsrc . DIV_TAG_NUMBER_FORMAT_SUFFIX . substr($src, $end + $lsuffix);
  4947. $p = $ini + 1; // IMPORTANT!
  4948. }
  4949. break;
  4950. case 'formulas' :
  4951. $src = $this->translateSimpleBlocks($src, $DIV_TAG_FORMULA_BEGIN, $DIV_TAG_FORMULA_END, DIV_TAG_FORMULA_BEGIN, DIV_TAG_FORMULA_END, $DIV_TAG_FORMULA_FORMAT_SEPARATOR, DIV_TAG_FORMULA_FORMAT_SEPARATOR, false);
  4952. break;
  4953. case 'subparsers' :
  4954. foreach ( self::$__sub_parsers as $subparser => $function ) {
  4955. $src = str_replace($DIV_TAG_SUBPARSER_BEGIN_PREFIX . $subparser . $DIV_TAG_SUBPARSER_BEGIN_SUFFIX, DIV_TAG_SUBPARSER_BEGIN_PREFIX . $subparser . DIV_TAG_SUBPARSER_BEGIN_SUFFIX, $src);
  4956. $src = str_replace($DIV_TAG_SUBPARSER_END_PREFIX . $subparser . $DIV_TAG_SUBPARSER_END_SUFFIX, DIV_TAG_SUBPARSER_END_PREFIX . $subparser . DIV_TAG_SUBPARSER_END_SUFFIX, $src);
  4957. }
  4958. break;
  4959. case 'ignore' :
  4960. $src = $this->translateSimpleBlocks($src, $DIV_TAG_IGNORE_BEGIN, $DIV_TAG_IGNORE_END, DIV_TAG_IGNORE_BEGIN, DIV_TAG_IGNORE_END);
  4961. break;
  4962. case 'comment' :
  4963. $src = $this->translateSimpleBlocks($src, $DIV_TAG_COMMENT_BEGIN, $DIV_TAG_COMMENT_END, DIV_TAG_COMMENT_BEGIN, DIV_TAG_COMMENT_END);
  4964. break;
  4965. case 'html2txt' :
  4966. $lprefix = strlen($DIV_TAG_TXT_BEGIN);
  4967. $lsuffix = strlen($DIV_TAG_TXT_END);
  4968. $lsep = strlen($DIV_TAG_TXT_WIDTH_SEPARATOR);
  4969. $p = 0;
  4970. while ( true ) {
  4971. $r = $this->getRanges($DIV_TAG_TXT_BEGIN, $DIV_TAG_TXT_END, $src, true, $p);
  4972. if (count($r) < 1)
  4973. break;
  4974. $ini = $r[0][0];
  4975. $end = $r[0][1];
  4976. $subsrc = substr($src, $ini + $lprefix, $end - $ini - $lprefix);
  4977. $po = strpos($subsrc, $DIV_TAG_TXT_WIDTH_SEPARATOR);
  4978. if ($po !== false)
  4979. $subsrc = substr($subsrc, 0, $po) . DIV_TAG_TXT_WIDTH_SEPARATOR . substr($subsrc, $po + $lsep);
  4980. $src = substr($src, 0, $ini) . DIV_TAG_TXT_BEGIN . $subsrc . DIV_TAG_TXT_END . substr($src, $end + $lsuffix);
  4981. $p = $ini + 1;
  4982. }
  4983. break;
  4984. case 'strip' :
  4985. $src = $this->translateSimpleBlocks($src, $DIV_TAG_STRIP_BEGIN, $DIV_TAG_STRIP_END, DIV_TAG_STRIP_BEGIN, DIV_TAG_STRIP_END);
  4986. break;
  4987. case 'loops' :
  4988. $lsep = strlen($DIV_TAG_LOOP_VAR_SEPARATOR);
  4989. $p = 0;
  4990. while ( true ) {
  4991. $r = $this->getBlockRanges($src, $DIV_TAG_LOOP_BEGIN_PREFIX, $DIV_TAG_LOOP_BEGIN_SUFFIX, $DIV_TAG_LOOP_END_PREFIX, $DIV_TAG_LOOP_END_SUFFIX, $p, null, true);
  4992. if (count($r) < 1)
  4993. break;
  4994. $ini = $r[0][0];
  4995. $end = $r[0][1];
  4996. $key = $r[0][2];
  4997. $subsrc = $r[0][3];
  4998. $prefix = $DIV_TAG_LOOP_BEGIN_PREFIX . $key . $DIV_TAG_LOOP_BEGIN_SUFFIX;
  4999. $suffix = $DIV_TAG_LOOP_END_PREFIX . $key . $DIV_TAG_LOOP_END_SUFFIX;
  5000. $lprefix = strlen($prefix);
  5001. $lsuffix = strlen($suffix);
  5002. $po = strpos($subsrc, $DIV_TAG_LOOP_VAR_SEPARATOR);
  5003. if ($po !== false)
  5004. $subsrc = substr($subsrc, 0, $po) . DIV_TAG_LOOP_VAR_SEPARATOR . substr($subsrc, $po + $lsep);
  5005. $subsrc = str_replace(array(
  5006. $DIV_TAG_EMPTY,
  5007. $DIV_TAG_BREAK
  5008. ), array(
  5009. DIV_TAG_EMPTY,
  5010. DIV_TAG_BREAK
  5011. ), $subsrc);
  5012. $src = substr($src, 0, $ini) . DIV_TAG_LOOP_BEGIN_PREFIX . $key . DIV_TAG_LOOP_BEGIN_SUFFIX . $subsrc . DIV_TAG_LOOP_END_PREFIX . $key . DIV_TAG_LOOP_END_SUFFIX . substr($src, $end + $lsuffix);
  5013. $p = $ini + 1;
  5014. }
  5015. break;
  5016. case 'iterations' :
  5017. $lprefix = strlen($DIV_TAG_ITERATION_BEGIN_PREFIX);
  5018. $lsuffix = strlen($DIV_TAG_ITERATION_BEGIN_SUFFIX);
  5019. $lend = strlen($DIV_TAG_ITERATION_END);
  5020. $lsep = strlen($DIV_TAG_LOOP_VAR_SEPARATOR);
  5021. $p = 0;
  5022. while ( true ) {
  5023. $ranges = $this->getRanges($DIV_TAG_ITERATION_BEGIN_PREFIX, $DIV_TAG_ITERATION_END, $src, true, $p);
  5024. if (count($ranges) < 1)
  5025. break;
  5026. $ini = $ranges[0][0];
  5027. $end = $ranges[0][1];
  5028. $p1 = strpos($src, $DIV_TAG_ITERATION_BEGIN_SUFFIX, $ini + 1);
  5029. $s = substr($src, $ini + $lprefix, $p1 - ($ini + $lprefix));
  5030. $parts = explode($DIV_TAG_ITERATION_PARAM_SEPARATOR, $s);
  5031. $s = implode(DIV_TAG_ITERATION_PARAM_SEPARATOR, $parts);
  5032. $subsrc = substr($src, $p1 + $lsuffix, $end - ($p1 + $lsuffix));
  5033. $po = strpos($subsrc, $DIV_TAG_LOOP_VAR_SEPARATOR);
  5034. if ($po !== false)
  5035. $subsrc = substr($subsrc, 0, $po) . DIV_TAG_LOOP_VAR_SEPARATOR . substr($subsrc, $po + $lsep);
  5036. $src = substr($src, 0, $ini) . DIV_TAG_ITERATION_BEGIN_PREFIX . $s . DIV_TAG_ITERATION_BEGIN_SUFFIX . $subsrc . DIV_TAG_ITERATION_END . substr($src, $end + $lend);
  5037. $p = $ini + 1;
  5038. }
  5039. break;
  5040. case 'conditionals' :
  5041. // true
  5042. $p = 0;
  5043. while ( true ) {
  5044. $r = $this->getBlockRanges($src, $DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX, $DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX, $DIV_TAG_CONDITIONAL_TRUE_END_PREFIX, $DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX, $p, null, true);
  5045. if (count($r) < 1)
  5046. break;
  5047. $ini = $r[0][0];
  5048. $end = $r[0][1];
  5049. $key = $r[0][2];
  5050. $subsrc = $r[0][3];
  5051. $prefix = $DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX . $key . $DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX;
  5052. $suffix = $DIV_TAG_CONDITIONAL_TRUE_END_PREFIX . $key . $DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX;
  5053. $lprefix = strlen($prefix);
  5054. $lsuffix = strlen($suffix);
  5055. $subsrc = str_replace($DIV_TAG_ELSE, DIV_TAG_ELSE, $subsrc);
  5056. $src = substr($src, 0, $ini) . DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX . $key . DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX . $subsrc . DIV_TAG_CONDITIONAL_TRUE_END_PREFIX . $key . DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX . substr($src, $end + $lsuffix);
  5057. $p = $ini + 1;
  5058. }
  5059. // false
  5060. $p = 0;
  5061. while ( true ) {
  5062. $r = $this->getBlockRanges($src, $DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX, $DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX, $DIV_TAG_CONDITIONAL_FALSE_END_PREFIX, $DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX, $p, null, true);
  5063. if (count($r) < 1)
  5064. break;
  5065. $ini = $r[0][0];
  5066. $end = $r[0][1];
  5067. $key = $r[0][2];
  5068. $subsrc = $r[0][3];
  5069. $prefix = $DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX . $key . $DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX;
  5070. $suffix = $DIV_TAG_CONDITIONAL_FALSE_END_PREFIX . $key . $DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX;
  5071. $lprefix = strlen($prefix);
  5072. $lsuffix = strlen($suffix);
  5073. $subsrc = str_replace($DIV_TAG_ELSE, DIV_TAG_ELSE, $subsrc);
  5074. $src = substr($src, 0, $ini) . DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX . $key . DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX . $subsrc . DIV_TAG_CONDITIONAL_FALSE_END_PREFIX . $key . DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX . substr($src, $end + $lsuffix);
  5075. $p = $ini + 1;
  5076. }
  5077. break;
  5078. case 'conditions' :
  5079. $lprefix = strlen($DIV_TAG_CONDITIONS_BEGIN_PREFIX);
  5080. $lsuffix = strlen($DIV_TAG_CONDITIONS_BEGIN_SUFFIX);
  5081. $lend = strlen($DIV_TAG_CONDITIONS_END);
  5082. $lelse = strlen($DIV_TAG_ELSE);
  5083. $p = 0;
  5084. while ( true ) {
  5085. $r = $this->getRanges($DIV_TAG_CONDITIONS_BEGIN_PREFIX, $DIV_TAG_CONDITIONS_END, $src, true, $p);
  5086. if (count($r) < 1)
  5087. break;
  5088. $ini = $r[0][0];
  5089. $end = $r[0][1];
  5090. $p1 = strpos($src, $DIV_TAG_CONDITIONS_BEGIN_SUFFIX, $ini + 1);
  5091. $s = substr($src, $ini + $lprefix, $p1 - ($ini + $lprefix));
  5092. $subsrc = substr($src, $p1 + $lsuffix, $end - ($p1 + $lsuffix));
  5093. $po = strpos($subsrc, $DIV_TAG_ELSE);
  5094. if ($po !== false)
  5095. $subsrc = substr($subsrc, 0, $po) . DIV_TAG_ELSE . substr($subsrc, $po + $lelse);
  5096. $src = substr($src, 0, $ini) . DIV_TAG_CONDITIONS_BEGIN_PREFIX . $s . DIV_TAG_CONDITIONS_BEGIN_SUFFIX . $subsrc . DIV_TAG_CONDITIONS_END . substr($src, $end + $lend);
  5097. $p = $ini + 1;
  5098. }
  5099. break;
  5100. case 'tplvars' :
  5101. $lbegin = strlen($DIV_TAG_TPLVAR_BEGIN);
  5102. $lend = strlen($DIV_TAG_TPLVAR_END);
  5103. $loperator = strlen($DIV_TAG_TPLVAR_ASSIGN_OPERATOR);
  5104. $lprotector = strlen($DIV_TAG_TPLVAR_PROTECTOR);
  5105. $p = 0;
  5106. while ( true ) {
  5107. $r = $this->getRanges($DIV_TAG_TPLVAR_BEGIN, $DIV_TAG_TPLVAR_END, $src, true, $p);
  5108. if (count($r) < 1)
  5109. break;
  5110. $ini = $r[0][0];
  5111. $end = $r[0][1];
  5112. $p1 = strpos($src, $DIV_TAG_TPLVAR_ASSIGN_OPERATOR, $ini + $lbegin);
  5113. if ($p1 === false) {
  5114. $p = $ini + 1;
  5115. continue;
  5116. }
  5117. $src = substr($src, 0, $ini) . DIV_TAG_TPLVAR_BEGIN . str_replace($DIV_TAG_TPLVAR_PROTECTOR, DIV_TAG_TPLVAR_PROTECTOR, substr($src, $ini + $lbegin, $p1 - ($ini + $lbegin))) . DIV_TAG_TPLVAR_ASSIGN_OPERATOR . substr($src, $p1 + $loperator, $end - ($p1 + $loperator)) . DIV_TAG_TPLVAR_END . substr($src, $end + $lend);
  5118. $p = $ini + 1;
  5119. }
  5120. break;
  5121. case 'defaultreplace' :
  5122. $src = $this->translateSimpleBlocks($src, $DIV_TAG_DEFAULT_REPLACEMENT_BEGIN, $DIV_TAG_DEFAULT_REPLACEMENT_END, DIV_TAG_DEFAULT_REPLACEMENT_BEGIN, DIV_TAG_DEFAULT_REPLACEMENT_END);
  5123. break;
  5124. case 'include' :
  5125. $src = $this->translateSimpleBlocks($src, $DIV_TAG_INCLUDE_BEGIN, $DIV_TAG_INCLUDE_END, DIV_TAG_INCLUDE_BEGIN, DIV_TAG_INCLUDE_END);
  5126. break;
  5127. case 'preprocessed' :
  5128. $src = $this->translateSimpleBlocks($src, $DIV_TAG_PREPROCESSED_BEGIN, $DIV_TAG_PREPROCESSED_END, DIV_TAG_PREPROCESSED_BEGIN, DIV_TAG_PREPROCESSED_END);
  5129. break;
  5130. case 'capsules' :
  5131. $src = $this->translateKeyBlocks($src, $DIV_TAG_CAPSULE_BEGIN_PREFIX, $DIV_TAG_CAPSULE_BEGIN_SUFFIX, $DIV_TAG_CAPSULE_END_PREFIX, $DIV_TAG_CAPSULE_END_SUFFIX, DIV_TAG_CAPSULE_BEGIN_PREFIX, DIV_TAG_CAPSULE_BEGIN_SUFFIX, DIV_TAG_CAPSULE_END_PREFIX, DIV_TAG_CAPSULE_END_SUFFIX);
  5132. break;
  5133. case 'multireplace' :
  5134. $src = $this->translateKeyBlocks($src, $DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX, $DIV_TAG_MULTI_REPLACEMENT_BEGIN_SUFFIX, $DIV_TAG_MULTI_REPLACEMENT_END_PREFIX, $DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX, DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX, DIV_TAG_MULTI_REPLACEMENT_BEGIN_SUFFIX, DIV_TAG_MULTI_REPLACEMENT_END_PREFIX, DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX);
  5135. break;
  5136. case 'friendlytags' :
  5137. $src = $this->translateSimpleBlocks($src, $DIV_TAG_FRIENDLY_BEGIN, $DIV_TAG_FRIENDLY_END, DIV_TAG_FRIENDLY_BEGIN, DIV_TAG_FRIENDLY_END);
  5138. break;
  5139. case 'macros' :
  5140. $src = $this->translateSimpleBlocks($src, $DIV_TAG_MACRO_BEGIN, $DIV_TAG_MACRO_END, DIV_TAG_MACRO_BEGIN, DIV_TAG_MACRO_END);
  5141. break;
  5142. case 'location' :
  5143. $src = $this->translateSimpleBlocks($src, $DIV_TAG_LOCATION_BEGIN, $DIV_TAG_LOCATION_END, DIV_TAG_LOCATION_BEGIN, DIV_TAG_LOCATION_END);
  5144. break;
  5145. case 'locontent' :
  5146. $src = $this->translateKeyBlocks($src, $DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX, $DIV_TAG_LOCATION_CONTENT_BEGIN_SUFFIX, $DIV_TAG_LOCATION_CONTENT_END_PREFIX, $DIV_TAG_LOCATION_CONTENT_END_SUFFIX, DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX, DIV_TAG_LOCATION_CONTENT_BEGIN_SUFFIX, DIV_TAG_LOCATION_CONTENT_END_PREFIX, DIV_TAG_LOCATION_CONTENT_END_SUFFIX);
  5147. break;
  5148. }
  5149. }
  5150. $order = array(
  5151. DIV_TAG_SPECIAL_REPLACE_NEW_LINE => $DIV_TAG_SPECIAL_REPLACE_NEW_LINE,
  5152. DIV_TAG_SPECIAL_REPLACE_CAR_RETURN => $DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB,
  5153. DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB => $DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB,
  5154. DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB => $DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB,
  5155. DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE => $DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE,
  5156. DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL => $DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL,
  5157. DIV_TAG_TEASER_BREAK => $DIV_TAG_TEASER_BREAK
  5158. );
  5159. asort($order);
  5160. $src = str_replace($order, array_keys($order), $src);
  5161. if ($update)
  5162. $this->__src = $src;
  5163. return $src;
  5164. }
  5165. /**
  5166. * Convert div to string | Return the parsed template
  5167. *
  5168. * @return string
  5169. */
  5170. final public function __toString(){
  5171. $this->parse();
  5172. return $this->__src;
  5173. }
  5174. // ------------------------ PREDEFINED SUBPARSERS ---------------------------- //
  5175. /**
  5176. * Parse this
  5177. *
  5178. * @param string $src
  5179. * @param mixed $items
  5180. * @return string
  5181. */
  5182. final private function subParse_parse($src, $items){
  5183. $tpl = self::getAuxiliaryEngineClone($this->__items);
  5184. $tpl->__src = $src;
  5185. $tpl->__src_original = $src;
  5186. $tpl->parse();
  5187. return $tpl->__src;
  5188. }
  5189. /**
  5190. * Convert all chars to HTML entities/codes.
  5191. *
  5192. * @param string $src
  5193. * @param mixed $items
  5194. * @return string
  5195. */
  5196. final private function subParse_html_wysiwyg($src){
  5197. $l = strlen($src);
  5198. $newcode = '';
  5199. for($i = 0; $i < $l; $i ++) {
  5200. if ($src[$i] != "\n" && $src[$i] != "\t" && $src[$i] != "\r")
  5201. $newcode .= '&#' . ord($src[$i]) . ';';
  5202. else
  5203. $newcode .= $src[$i];
  5204. }
  5205. return $newcode;
  5206. }
  5207. // -------------------------------- HOOKS ------------------------------------- //
  5208. /**
  5209. * The hooks
  5210. */
  5211. public function beforeBuild(&$src = null, &$items = null){}
  5212. public function afterBuild(){}
  5213. public function beforeParse(){}
  5214. public function afterParse(){}
  5215. /**
  5216. * Output the parsed template
  5217. *
  5218. * @param string $template
  5219. */
  5220. public function show($template = null){
  5221. if (! is_null($template)) {
  5222. $this->changeTemplate($template);
  5223. }
  5224. $this->parse();
  5225. echo $this->__src;
  5226. }
  5227. // -------------------------------- Functions ------------------------------------- //
  5228. /**
  5229. * Enable documentation
  5230. */
  5231. final static function docsOn(){
  5232. self::$__docs_on = true;
  5233. }
  5234. /**
  5235. * Disable documentation
  5236. */
  5237. final static function docsOff(){
  5238. self::$__docs_off = false;
  5239. }
  5240. /**
  5241. * Get documentation's data
  5242. *
  5243. * @return array
  5244. */
  5245. final static function getDocs(){
  5246. return self::$__docs;
  5247. }
  5248. /**
  5249. * Get a redeable documentation
  5250. *
  5251. * @param string $tpl
  5252. * @param array $items
  5253. * @return string
  5254. */
  5255. final static function getDocsReadable($tpl = null, $items = null){
  5256. $docs = self::$__docs;
  5257. $keys = array_keys($docs);
  5258. asort($keys);
  5259. $docsx = array();
  5260. foreach ( $keys as $key )
  5261. $docsx[$key] = $docs[$key];
  5262. if (is_null($items))
  5263. $items = array(
  5264. 'title' => "Templates's documentation"
  5265. );
  5266. elseif (is_object($items))
  5267. $items = get_object_vars($items);
  5268. $items = array_merge($items, array(
  5269. 'docs' => $docsx
  5270. ));
  5271. if (is_null($tpl))
  5272. $tpl = DIV_TEMPLATE_FOR_DOCS;
  5273. $obj = self::getAuxiliaryEngineClone($items);
  5274. $obj->__src = $tpl;
  5275. $obj->parse(false);
  5276. return $obj->__src;
  5277. }
  5278. /**
  5279. * Clear all empty/null values and return a compact mixed
  5280. *
  5281. * @param mixed $mixed
  5282. * @return mixed
  5283. */
  5284. final static function compact($mixed){
  5285. if (empty($mixed))
  5286. return null;
  5287. if (is_null($mixed))
  5288. return null;
  5289. if (is_scalar($mixed))
  5290. if ("$mixed" == '')
  5291. return null;
  5292. if (is_object($mixed)) {
  5293. $vars = get_object_vars($mixed);
  5294. foreach ( $vars as $var => $value ) {
  5295. $value = self::compact($value);
  5296. if (is_null($value))
  5297. unset($mixed->$var);
  5298. }
  5299. $vars = get_object_vars($mixed);
  5300. if (count($vars) < 1)
  5301. return null;
  5302. }
  5303. if (is_array($mixed)) {
  5304. $arr = array();
  5305. foreach ( $mixed as $var => $value ) {
  5306. $value = self::compact($value);
  5307. if (! is_null($value))
  5308. $arr[$var] = $value;
  5309. }
  5310. if (count($arr) < 1)
  5311. return null;
  5312. $mixed = $arr;
  5313. }
  5314. return $mixed;
  5315. }
  5316. /**
  5317. * Convert any value to string (with Div method)
  5318. *
  5319. * @param mixed $value
  5320. * @return string
  5321. */
  5322. final static function anyToStr($value){
  5323. if (self::isString($value))
  5324. return "$value";
  5325. if (is_bool($value))
  5326. return $value ? 'true' : 'false';
  5327. if (is_numeric($value))
  5328. return "$value";
  5329. if (is_object($value))
  5330. return "" . count(get_object_vars($value));
  5331. if (is_array($value))
  5332. return "" . count($value);
  5333. if (is_null($value))
  5334. return "";
  5335. return "$value";
  5336. }
  5337. /**
  5338. * Complete object/array properties
  5339. *
  5340. * @param mixed $obj
  5341. * @param mixed $prop
  5342. */
  5343. final static function cop(&$source, $complement){
  5344. $null = null;
  5345. if (is_null($source))
  5346. return $complement;
  5347. if (is_null($complement))
  5348. return $source;
  5349. if (is_scalar($complement))
  5350. return $source;
  5351. if (is_object($complement)) {
  5352. $vars = get_object_vars($complement);
  5353. foreach ( $vars as $key => $value ) {
  5354. if (is_object($source)) {
  5355. if (isset($source->$key))
  5356. $source->$key = self::cop($source->$key, $complement->$key);
  5357. else
  5358. $source->$key = self::cop($null, $complement->$key);
  5359. }
  5360. if (is_array($source)) {
  5361. if (isset($source[$key]))
  5362. $source[$key] = self::cop($source[$key], $complement->$key);
  5363. else
  5364. $source[$key] = self::cop($null, $complement->$key);
  5365. }
  5366. }
  5367. }
  5368. if (is_array($complement)) {
  5369. foreach ( $complement as $key => $value ) {
  5370. if (is_object($source)) {
  5371. if (isset($source->$key))
  5372. $source->$key = self::cop($source->$key, $complement[$key]);
  5373. else
  5374. $source->$key = self::cop($null, $complement[$key]);
  5375. }
  5376. if (is_array($source)) {
  5377. if (isset($source[$key]))
  5378. $source[$key] = self::cop($source[$key], $complement[$key]);
  5379. else
  5380. $source[$key] = self::cop($null, $complement[$key]);
  5381. }
  5382. }
  5383. }
  5384. return $source;
  5385. }
  5386. /**
  5387. * Safe substring
  5388. *
  5389. * @param string $string
  5390. * @param integer $max_length
  5391. * @return string
  5392. */
  5393. final static function substr($string, $max_length){
  5394. $max_length = max($max_length, 0);
  5395. if (strlen($string) <= $max_length)
  5396. return $string;
  5397. $string = substr($string, 0, $max_length);
  5398. return $string;
  5399. }
  5400. /**
  5401. * Return the teaser of a text
  5402. *
  5403. * @param string $text
  5404. * @param integer $maxlength
  5405. * @return string
  5406. */
  5407. final static function teaser($text, $maxlength = 600){
  5408. $delimiter = strpos($text, DIV_TAG_TEASER_BREAK);
  5409. if ($maxlength == 0 && $delimiter === FALSE)
  5410. return $text;
  5411. if ($delimiter !== FALSE)
  5412. return substr($text, 0, $delimiter);
  5413. if (strlen($text) <= $maxlength)
  5414. return $text;
  5415. $summary = self::substr($text, $maxlength);
  5416. $max_rpos = strlen($summary);
  5417. $min_rpos = $max_rpos;
  5418. $reversed = strrev($summary);
  5419. $break_points = array();
  5420. $break_points[] = array(
  5421. '</p>' => 0
  5422. );
  5423. $line_breaks = array(
  5424. '<br />' => 6,
  5425. '<br>' => 4
  5426. );
  5427. if (isset($filters['filter_autop']))
  5428. $line_breaks["\n"] = 1;
  5429. $break_points[] = $line_breaks;
  5430. $break_points[] = array(
  5431. '. ' => 1,
  5432. '! ' => 1,
  5433. '? ' => 1,
  5434. '?' => 0,
  5435. '? ' => 1
  5436. );
  5437. foreach ( $break_points as $points ) {
  5438. foreach ( $points as $point => $offset ) {
  5439. $rpos = strpos($reversed, strrev($point));
  5440. if ($rpos !== FALSE)
  5441. $min_rpos = min($rpos + $offset, $min_rpos);
  5442. }
  5443. if ($min_rpos !== $max_rpos) {
  5444. $summary = ($min_rpos === 0) ? $summary : substr($summary, 0, 0 - $min_rpos);
  5445. break;
  5446. }
  5447. }
  5448. return $summary;
  5449. }
  5450. /**
  5451. * UTF utility
  5452. *
  5453. * @param string $utf16
  5454. * @return string
  5455. */
  5456. final static function utf162utf8($utf16){
  5457. if (function_exists('mb_convert_encoding'))
  5458. return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
  5459. $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
  5460. if ((0x7F & $bytes) == $bytes)
  5461. return chr(0x7F & $bytes);
  5462. if ((0x07FF & $bytes) == $bytes)
  5463. return chr(0xC0 | (($bytes >> 6) & 0x1F)) . chr(0x80 | ($bytes & 0x3F));
  5464. if ((0xFFFF & $bytes) == $bytes)
  5465. return chr(0xE0 | (($bytes >> 12) & 0x0F)) . chr(0x80 | (($bytes >> 6) & 0x3F)) . chr(0x80 | ($bytes & 0x3F));
  5466. return '';
  5467. }
  5468. /**
  5469. * JSON Decode
  5470. *
  5471. * @param string $str
  5472. * @return mixed
  5473. */
  5474. final static function jsonDecode($str, $items = array()){
  5475. $str = trim(preg_replace(array(
  5476. '#^\s*//(.+)$#m',
  5477. '#^\s*/\*(.+)\*/#Us',
  5478. '#/\*(.+)\*/\s*$#Us'
  5479. ), '', $str));
  5480. // Syntax specific for div
  5481. if (isset($str[0]))
  5482. if ($str[0] == '$') {
  5483. $str = substr($str, 1);
  5484. $r = self::getVarValue($str, $items);
  5485. return $r;
  5486. }
  5487. switch (strtolower($str)) {
  5488. case 'true' :
  5489. return true;
  5490. case 'false' :
  5491. return false;
  5492. case 'null' :
  5493. return null;
  5494. default :
  5495. $m = array();
  5496. if (is_numeric($str)) {
  5497. return ((float) $str == (integer) $str) ? (integer) $str : (float) $str;
  5498. } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
  5499. $delim = substr($str, 0, 1);
  5500. $chrs = substr($str, 1, - 1);
  5501. $utf8 = '';
  5502. $strlen_chrs = strlen($chrs);
  5503. for($c = 0; $c < $strlen_chrs; ++ $c) {
  5504. $substr_chrs_c_2 = substr($chrs, $c, 2);
  5505. $ord_chrs_c = ord($chrs{$c});
  5506. switch (true) {
  5507. case $substr_chrs_c_2 == '\b' :
  5508. $utf8 .= chr(0x08);
  5509. ++ $c;
  5510. break;
  5511. case $substr_chrs_c_2 == '\t' :
  5512. $utf8 .= chr(0x09);
  5513. ++ $c;
  5514. break;
  5515. case $substr_chrs_c_2 == '\n' :
  5516. $utf8 .= chr(0x0A);
  5517. ++ $c;
  5518. break;
  5519. case $substr_chrs_c_2 == '\f' :
  5520. $utf8 .= chr(0x0C);
  5521. ++ $c;
  5522. break;
  5523. case $substr_chrs_c_2 == '\r' :
  5524. $utf8 .= chr(0x0D);
  5525. ++ $c;
  5526. break;
  5527. case $substr_chrs_c_2 == '\\"' :
  5528. case $substr_chrs_c_2 == '\\\'' :
  5529. case $substr_chrs_c_2 == '\\\\' :
  5530. case $substr_chrs_c_2 == '\\/' :
  5531. if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || ($delim == "'" && $substr_chrs_c_2 != '\\"'))
  5532. $utf8 .= $chrs{++ $c};
  5533. break;
  5534. case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)) :
  5535. $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) . chr(hexdec(substr($chrs, ($c + 4), 2)));
  5536. $utf8 .= self::utf162utf8($utf16);
  5537. $c += 5;
  5538. break;
  5539. case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F) :
  5540. $utf8 .= $chrs{$c};
  5541. break;
  5542. case ($ord_chrs_c & 0xE0) == 0xC0 :
  5543. $utf8 .= substr($chrs, $c, 2);
  5544. ++ $c;
  5545. break;
  5546. case ($ord_chrs_c & 0xF0) == 0xE0 :
  5547. $utf8 .= substr($chrs, $c, 3);
  5548. $c += 2;
  5549. break;
  5550. case ($ord_chrs_c & 0xF8) == 0xF0 :
  5551. $utf8 .= substr($chrs, $c, 4);
  5552. $c += 3;
  5553. break;
  5554. case ($ord_chrs_c & 0xFC) == 0xF8 :
  5555. $utf8 .= substr($chrs, $c, 5);
  5556. $c += 4;
  5557. break;
  5558. case ($ord_chrs_c & 0xFE) == 0xFC :
  5559. $utf8 .= substr($chrs, $c, 6);
  5560. $c += 5;
  5561. break;
  5562. }
  5563. }
  5564. return $utf8;
  5565. } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
  5566. if ($str{0} == '[') {
  5567. $stk = array(
  5568. 3
  5569. );
  5570. $arr = array();
  5571. } else {
  5572. if (true & 16) {
  5573. $stk = array(
  5574. 4
  5575. );
  5576. $obj = array();
  5577. } else {
  5578. $stk = array(
  5579. 4
  5580. );
  5581. $obj = new stdClass();
  5582. }
  5583. }
  5584. array_push($stk, array(
  5585. 'what' => 1,
  5586. 'where' => 0,
  5587. 'delim' => false
  5588. ));
  5589. $chrs = substr($str, 1, - 1);
  5590. $chrs = trim(preg_replace(array(
  5591. '#^\s*//(.+)$#m',
  5592. '#^\s*/\*(.+)\*/#Us',
  5593. '#/\*(.+)\*/\s*$#Us'
  5594. ), '', $chrs));
  5595. if ($chrs == '')
  5596. if (reset($stk) == 3)
  5597. return $arr;
  5598. else
  5599. return $obj;
  5600. $strlen_chrs = strlen($chrs);
  5601. for($c = 0; $c <= $strlen_chrs; ++ $c) {
  5602. $top = end($stk);
  5603. $substr_chrs_c_2 = substr($chrs, $c, 2);
  5604. if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == 1))) {
  5605. $slice = substr($chrs, $top['where'], ($c - $top['where']));
  5606. array_push($stk, array(
  5607. 'what' => 1,
  5608. 'where' => ($c + 1),
  5609. 'delim' => false
  5610. ));
  5611. if (reset($stk) == 3) {
  5612. array_push($arr, self::jsonDecode($slice, $items));
  5613. } elseif (reset($stk) == 4) {
  5614. $parts = array();
  5615. if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
  5616. $key = self::jsonDecode($parts[1], $items);
  5617. $val = self::jsonDecode($parts[2], $items);
  5618. if (true & 16)
  5619. $obj[$key] = $val;
  5620. else
  5621. $obj->$key = $val;
  5622. } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
  5623. $key = $parts[1];
  5624. $val = self::jsonDecode($parts[2], $items);
  5625. if (true & 16) {
  5626. $obj[$key] = $val;
  5627. } else {
  5628. $obj->$key = $val;
  5629. }
  5630. }
  5631. }
  5632. } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != 2)) {
  5633. array_push($stk, array(
  5634. 'what' => 2,
  5635. 'where' => $c,
  5636. 'delim' => $chrs{$c}
  5637. ));
  5638. } elseif (($chrs{$c} == $top['delim']) && ($top['what'] == 2) && ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
  5639. array_pop($stk);
  5640. } elseif (($chrs{$c} == '[') && in_array($top['what'], array(
  5641. 1,
  5642. 3,
  5643. 4
  5644. ))) {
  5645. array_push($stk, array(
  5646. 'what' => 3,
  5647. 'where' => $c,
  5648. 'delim' => false
  5649. ));
  5650. } elseif (($chrs{$c} == ']') && ($top['what'] == 3)) {
  5651. array_pop($stk);
  5652. } elseif (($chrs{$c} == '{') && in_array($top['what'], array(
  5653. 1,
  5654. 3,
  5655. 4
  5656. ))) {
  5657. array_push($stk, array(
  5658. 'what' => 4,
  5659. 'where' => $c,
  5660. 'delim' => false
  5661. ));
  5662. } elseif (($chrs{$c} == '}') && ($top['what'] == 4)) {
  5663. array_pop($stk);
  5664. } elseif (($substr_chrs_c_2 == '/*') && in_array($top['what'], array(
  5665. 1,
  5666. 3,
  5667. 4
  5668. ))) {
  5669. array_push($stk, array(
  5670. 'what' => 5,
  5671. 'where' => $c,
  5672. 'delim' => false
  5673. ));
  5674. $c ++;
  5675. } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == 5)) {
  5676. array_pop($stk);
  5677. $c ++;
  5678. for($i = $top['where']; $i <= $c; ++ $i)
  5679. $chrs = substr_replace($chrs, ' ', $i, 1);
  5680. }
  5681. }
  5682. if (reset($stk) == 3) {
  5683. return $arr;
  5684. } elseif (reset($stk) == 4) {
  5685. return $obj;
  5686. }
  5687. }
  5688. }
  5689. }
  5690. /**
  5691. * JSON Encode
  5692. *
  5693. * @param mixed $data
  5694. * @return string
  5695. */
  5696. final static function jsonEncode($data){
  5697. if (is_array($data) || is_object($data)) {
  5698. $islist = is_array($data) && (empty($data) || array_keys($data) === range(0, count($data) - 1));
  5699. if ($islist)
  5700. $json = '[' . implode(',', array_map('div::jsonEncode', $data)) . ']';
  5701. else {
  5702. $items = array();
  5703. foreach ( $data as $key => $value ) {
  5704. $items[] = self::jsonEncode("$key") . ':' . self::jsonEncode($value);
  5705. }
  5706. $json = '{' . implode(',', $items) . '}';
  5707. }
  5708. } elseif (self::isString($data)) {
  5709. $string = '"' . addcslashes($data, "\\\"\n\r\t/" . chr(8) . chr(12)) . '"';
  5710. $json = '';
  5711. $len = strlen($string);
  5712. for($i = 0; $i < $len; $i ++) {
  5713. $char = $string[$i];
  5714. $c1 = ord($char);
  5715. if ($c1 < 128) {
  5716. $json .= ($c1 > 31) ? $char : sprintf("\\u%04x", $c1);
  5717. continue;
  5718. }
  5719. $c2 = ord($string[++ $i]);
  5720. if (($c1 & 32) === 0) {
  5721. $json .= sprintf("\\u%04x", ($c1 - 192) * 64 + $c2 - 128);
  5722. continue;
  5723. }
  5724. $c3 = ord($string[++ $i]);
  5725. if (($c1 & 16) === 0) {
  5726. $json .= sprintf("\\u%04x", (($c1 - 224) << 12) + (($c2 - 128) << 6) + ($c3 - 128));
  5727. continue;
  5728. }
  5729. $c4 = ord($string[++ $i]);
  5730. if (($c1 & 8) === 0) {
  5731. $u = (($c1 & 15) << 2) + (($c2 >> 4) & 3) - 1;
  5732. $w1 = (54 << 10) + ($u << 6) + (($c2 & 15) << 2) + (($c3 >> 4) & 3);
  5733. $w2 = (55 << 10) + (($c3 & 15) << 6) + ($c4 - 128);
  5734. $json .= sprintf("\\u%04x\\u%04x", $w1, $w2);
  5735. }
  5736. }
  5737. } else
  5738. $json = strtolower(var_export($data, true));
  5739. return $json;
  5740. }
  5741. /**
  5742. * Convert HTML to plain and formated text
  5743. *
  5744. * @param string $html
  5745. * @return string
  5746. */
  5747. static function htmlToText($html, $width = 50){
  5748. // Special strip tags
  5749. $newhtml = '';
  5750. do {
  5751. $p1 = strpos($html, "<style");
  5752. $p2 = strpos($html, "</style>");
  5753. if ($p1 !== false && $p2 !== false) {
  5754. if ($p2 > $p1) {
  5755. $newhtml .= substr($html, 0, $p1);
  5756. $newhtml .= substr($html, $p2 + 8);
  5757. $html = substr($html, $p2 + 8);
  5758. } else
  5759. break;
  5760. }
  5761. } while ( $p1 !== false && $p2 !== false );
  5762. if ($newhtml != '')
  5763. $html = $newhtml;
  5764. // Other stuffs
  5765. $html = str_replace("<br>", "\n", $html);
  5766. $html = str_replace("<br/>", "\n", $html);
  5767. $html = str_replace("<br />", "\n", $html);
  5768. $html = str_replace("</tr>", "\n", $html);
  5769. $html = str_replace("<td", "\t</td", $html);
  5770. $html = str_replace("<th", "\t</th", $html);
  5771. $html = str_replace("</table>", "\n", $html);
  5772. $hr = str_repeat("-", $width) . "\n";
  5773. $html = str_replace("<hr>", $hr, $html);
  5774. $html = str_replace("<hr/>", $hr, $html);
  5775. $html = str_replace("</p>", "\n", $html);
  5776. $html = str_replace("<h1", "- <h1" . $hr, $html);
  5777. $html = str_replace("<h2", "-- <h2" . $hr, $html);
  5778. $html = str_replace("<h3", "--- <h3" . $hr, $html);
  5779. $html = str_replace("<li", "* <li" . $hr, $html);
  5780. for($i = 1; $i < 5; $i ++) {
  5781. $html = str_replace("</h$i>\n", "</h$i>" . $hr, $html);
  5782. $html = str_replace("</h$i>", "</h$i>\n\n" . $hr, $html);
  5783. }
  5784. $html = html_entity_decode($html);
  5785. $html = preg_replace('!<[^>]*?>!', ' ', $html);
  5786. $html = str_replace("\t", ' ', $html);
  5787. // Strip tags
  5788. $html = preg_replace("/\015\012|\015|\012/", "\n", $html);
  5789. $html = strip_tags($html);
  5790. while ( strpos($html, ' ') !== false )
  5791. $html = str_replace(' ', ' ', $html);
  5792. $html = str_replace(' ' . "\n", "\n", $html);
  5793. $html = str_replace("\n ", "\n", $html);
  5794. while ( strpos($html, ' ') !== false )
  5795. $html = str_replace(' ', ' ', $html);
  5796. $html = trim($html);
  5797. if (! is_null($width) && $width !== 0)
  5798. $html = wordwrap($html, $width, "\n");
  5799. return $html;
  5800. }
  5801. /**
  5802. * Return true if at least one needle is contained in the haystack
  5803. *
  5804. * @param string $haystack
  5805. * @param array $needles
  5806. * @return boolean
  5807. */
  5808. final static function atLeastOneString($haystack, $needles = array()){
  5809. foreach ( $needles as $needle ) {
  5810. if (strpos($haystack, $needle) !== false)
  5811. return true;
  5812. }
  5813. return false;
  5814. }
  5815. /**
  5816. * Return the last key of array or null if not exists
  5817. *
  5818. * @param array $arr
  5819. * @return mixed
  5820. */
  5821. final static function getLastKeyOfArray($arr){
  5822. if (is_array($arr)) {
  5823. if (count($arr) > 0) {
  5824. $keys = array_keys($arr);
  5825. $keys = array_reverse($keys);
  5826. return $keys[0];
  5827. }
  5828. }
  5829. }
  5830. /**
  5831. * Return true if var exists in the template's items recursively
  5832. *
  5833. * @param string $var
  5834. * @param mixed $items
  5835. * @return boolean
  5836. */
  5837. final static function varExists($var, &$items = null){
  5838. if (is_null($items))
  5839. return false;
  5840. $subvars = explode(".", $var);
  5841. if (count($subvars) === 1) {
  5842. if (is_array($items))
  5843. return isset($items[$var]);
  5844. if (is_object($items))
  5845. return isset($items->$var);
  5846. } else {
  5847. $l = strlen($subvars[0]);
  5848. if ($l + 1 < strlen($var)) {
  5849. if (is_array($items))
  5850. return self::varExists(substr($var, $l + 1), $items[$subvars[0]]);
  5851. if (is_object($items))
  5852. return self::varExists(substr($var, $l + 1), $items->$subvars[0]);
  5853. }
  5854. }
  5855. return false;
  5856. }
  5857. /**
  5858. * Return the first instance of $this->__packages
  5859. */
  5860. static function getPackagesPath(){
  5861. $class = get_class();
  5862. if (isset(self::$__packages_by_class[$class]))
  5863. return self::$__packages_by_class[$class];
  5864. return PACKAGES;
  5865. }
  5866. /**
  5867. * Secure 'file exists' method
  5868. *
  5869. * @param string $filename
  5870. * @return boolean
  5871. */
  5872. final static function fileExists($filename){
  5873. if (substr(strtolower($filename), 0, 7) == 'http://' || substr(strtolower($filename), 0, 8) == 'https://' || substr(strtolower($filename), 0, 6) == 'ftp://')
  5874. return false;
  5875. if (strlen($filename) > DIV_MAX_FILENAME_SIZE)
  5876. return false;
  5877. if (file_exists($filename))
  5878. if (is_file($filename))
  5879. return true;
  5880. $ipaths = self::getIncludePaths(self::getPackagesPath());
  5881. foreach ( $ipaths as $ipath ) {
  5882. $pathx = str_replace("\\", "/", $ipath . "/" . $filename);
  5883. while ( strpos($pathx, "//") !== false ) {
  5884. $pathx = str_replace("//", "/", $pathx);
  5885. }
  5886. $pathx = str_replace("/./", "/", $pathx);
  5887. if (substr($pathx, 0, 2) == "./")
  5888. $pathx = substr($pathx, 2);
  5889. if (@file_exists($pathx))
  5890. if (@is_file($pathx))
  5891. return true;
  5892. }
  5893. return false;
  5894. }
  5895. /**
  5896. * Secure 'is dir' method
  5897. *
  5898. * @param string $filename
  5899. * @return boolean
  5900. */
  5901. final static function isDir($dirname){
  5902. if (substr(strtolower($dirname), 0, 7) == 'http://' || substr(strtolower($dirname), 0, 8) == 'https://' || substr(strtolower($dirname), 0, 6) == 'ftp://')
  5903. return false;
  5904. if (strlen($dirname) > DIV_MAX_FILENAME_SIZE)
  5905. return false;
  5906. return is_dir($dirname);
  5907. }
  5908. /**
  5909. * Secure 'file get contents' method
  5910. *
  5911. * @param string $filename
  5912. * @return string
  5913. */
  5914. final static function getFileContents($filename){
  5915. if (substr(strtolower($filename), 0, 7) == 'http://' || substr(strtolower($filename), 0, 8) == 'https://' || substr(strtolower($filename), 0, 6) == 'ftp://')
  5916. return $filename;
  5917. if (file_exists($filename))
  5918. return file_get_contents($filename);
  5919. $ipaths = self::getIncludePaths(self::getPackagesPath());
  5920. foreach ( $ipaths as $ipath ) {
  5921. $pathx = str_replace("\\", "/", $ipath . "/" . $filename);
  5922. while ( strpos($pathx, "//") !== false ) {
  5923. $pathx = str_replace("//", "/", $pathx);
  5924. }
  5925. $pathx = str_replace("/./", "/", $pathx);
  5926. if (substr($pathx, 0, 2) == "./")
  5927. $pathx = substr($pathx, 2);
  5928. if (file_exists($pathx))
  5929. if (is_file($pathx))
  5930. return file_get_contents($pathx);
  5931. }
  5932. return null;
  5933. }
  5934. /**
  5935. * Get folder of path/file
  5936. *
  5937. * @param string $filename
  5938. * @return string
  5939. */
  5940. final static function getFolderOf($filename){
  5941. if (is_dir($filename))
  5942. return $filename;
  5943. $p = strrpos($filename, "/");
  5944. if ($p === false)
  5945. return "./";
  5946. $folder = substr($filename, 0, $p);
  5947. return $folder;
  5948. }
  5949. /**
  5950. * Return mixed value as HTML format, (util for debug and fast presentation)
  5951. *
  5952. * @param mixed $mixed
  5953. * @return string
  5954. */
  5955. final static function asThis($mixed){
  5956. $html = "";
  5957. if (is_array($mixed)) {
  5958. if (self::isArrayOfArray($mixed) === true) {
  5959. $html = "<table>";
  5960. // header
  5961. foreach ( $mixed as $key_row => $row ) {
  5962. $html .= "<tr>";
  5963. foreach ( $row as $key_col => $col )
  5964. $html .= "<th>$key_col</th>";
  5965. $html .= "</tr>";
  5966. break;
  5967. }
  5968. // rows
  5969. foreach ( $mixed as $key_row => $row ) {
  5970. $html .= "<tr>";
  5971. foreach ( $row as $key_col => $col ) {
  5972. $html .= "<td>" . self::asThis($col) . "</td>";
  5973. }
  5974. $html .= "</tr>";
  5975. }
  5976. $html .= "</table>";
  5977. } elseif (self::isArrayOfObjects($mixed)) {
  5978. $html = "<table>";
  5979. // header
  5980. foreach ( $mixed as $key_row => $row ) {
  5981. $html .= "<tr>";
  5982. $vars = get_object_vars($row);
  5983. foreach ( $vars as $key_col => $col ) {
  5984. $html .= "<th>$key_col</th>";
  5985. }
  5986. $html .= "</tr>";
  5987. break;
  5988. }
  5989. // rows
  5990. foreach ( $mixed as $key_row => $row ) {
  5991. $vars = get_object_vars($row);
  5992. $html .= "<tr>";
  5993. foreach ( $vars as $key_col => $col ) {
  5994. $html .= "<td>" . self::asThis($col) . "</td>";
  5995. }
  5996. $html .= "</tr>";
  5997. }
  5998. $html .= "</table>";
  5999. } elseif (self::isNumericList($mixed)) {
  6000. $html = "<table class \"numeric-list\">";
  6001. foreach ( $mixed as $key => $v ) {
  6002. $html .= "<td>$v</td>";
  6003. }
  6004. $html .= "</table>";
  6005. } else {
  6006. $html = "<ul class = \"array\">";
  6007. foreach ( $mixed as $key => $value ) {
  6008. $t = "";
  6009. if (! is_numeric($key) && trim("$key") != "" && $key != null)
  6010. $t = "$key: <br>";
  6011. $html .= "<li> " . self::asThis($value) . "</li>";
  6012. }
  6013. $html .= "</ul>";
  6014. }
  6015. } else {
  6016. if (is_object($mixed)) {
  6017. $html = get_class($mixed) . ": <table>";
  6018. $vars = get_object_vars($mixed);
  6019. foreach ( $vars as $var => $value ) {
  6020. $html .= "<li>" . self::asThis($mixed->$var) . "</li>";
  6021. }
  6022. $html .= "</ul>";
  6023. } else {
  6024. if (is_bool($mixed))
  6025. $html = ($mixed === true ? "TRUE" : "FALSE");
  6026. else {
  6027. $html = "<label>$mixed</label>";
  6028. }
  6029. }
  6030. }
  6031. return $html;
  6032. }
  6033. /**
  6034. * Count a number of paragraphs in a text
  6035. *
  6036. * @param string $value
  6037. * @return integer
  6038. */
  6039. static function getCountOfParagraphs($text){
  6040. return count(preg_split('/[\r\n]+/', $text));
  6041. }
  6042. /**
  6043. * Count a number of sentences in a text
  6044. *
  6045. * @param string $value
  6046. * @return integer
  6047. */
  6048. static function getCountOfSentences($text){
  6049. return preg_match_all('/[^\s]\.(?!\w)/', $text, $match);
  6050. }
  6051. /**
  6052. * Count a number of words in a text
  6053. *
  6054. * @param string $value
  6055. * @return integer
  6056. */
  6057. static function getCountOfWords($text){
  6058. $split_array = preg_split('/\s+/', $text);
  6059. $word_count = preg_grep('/[a-zA-Z0-9\\x80-\\xff]/', $split_array);
  6060. return count($word_count);
  6061. }
  6062. /**
  6063. * Return true if $arr is array of array
  6064. *
  6065. * @param array $arr
  6066. * @return boolean
  6067. */
  6068. final static function isArrayOfArray($arr){
  6069. $is = false;
  6070. if (is_array($arr)) {
  6071. $is = true;
  6072. foreach ( $arr as $v ) {
  6073. if (! is_array($v)) {
  6074. $is = false;
  6075. break;
  6076. }
  6077. }
  6078. }
  6079. return $is;
  6080. }
  6081. /**
  6082. * Return true if $arr is array of objects
  6083. *
  6084. * @param array $arr
  6085. * @return boolean
  6086. */
  6087. final static function isArrayOfObjects($arr){
  6088. $is = false;
  6089. if (is_array($arr)) {
  6090. $is = true;
  6091. foreach ( $arr as $v ) {
  6092. if (! is_object($v)) {
  6093. $is = false;
  6094. break;
  6095. }
  6096. }
  6097. }
  6098. return $is;
  6099. }
  6100. /**
  6101. * Return true if $arr is array of numbers
  6102. *
  6103. * @param array $arr
  6104. * @return boolean
  6105. */
  6106. final static function isNumericList($arr){
  6107. $is = false;
  6108. if (is_array($arr)) {
  6109. $is = true;
  6110. foreach ( $arr as $v ) {
  6111. if (! is_numeric($v)) {
  6112. $is = false;
  6113. break;
  6114. }
  6115. }
  6116. }
  6117. return $is;
  6118. }
  6119. /**
  6120. * Return a list of vars from PHP code
  6121. *
  6122. * @param string $code
  6123. * @return array
  6124. */
  6125. final static function getVarsFromCode($code){
  6126. $t = token_get_all("<?php $code ?>");
  6127. $vars = array();
  6128. foreach ( $t as $key => $value ) {
  6129. if (is_array($value)) {
  6130. if ($value[0] == T_VARIABLE) {
  6131. $vars[] = substr($value[1], 1);
  6132. }
  6133. }
  6134. }
  6135. return $vars;
  6136. }
  6137. /**
  6138. * Return true if the PHP code have any var
  6139. *
  6140. * @param string $code
  6141. * @return bool
  6142. */
  6143. final static function haveVarsThisCode($code){
  6144. $vars = self::getVarsFromCode($code);
  6145. if (count($vars) > 0)
  6146. return true;
  6147. return false;
  6148. }
  6149. /**
  6150. * Return true if current dialect is valid
  6151. *
  6152. * @return mixed
  6153. */
  6154. final static function isValidCurrentDialect(){
  6155. // TODO: Improve this syntax checker
  6156. $all_tags = array(
  6157. DIV_TAG_REPLACEMENT_PREFIX,
  6158. DIV_TAG_REPLACEMENT_SUFFIX,
  6159. DIV_TAG_MULTI_MODIFIERS_PREFIX,
  6160. DIV_TAG_MULTI_MODIFIERS_OPERATOR,
  6161. DIV_TAG_MULTI_MODIFIERS_SEPARATOR,
  6162. DIV_TAG_MULTI_MODIFIERS_SUFFIX,
  6163. DIV_TAG_SUBMATCH_SEPARATOR,
  6164. DIV_TAG_MODIFIER_SIMPLE,
  6165. DIV_TAG_MODIFIER_CAPITALIZE_FIRST,
  6166. DIV_TAG_MODIFIER_CAPITALIZE_WORDS,
  6167. DIV_TAG_MODIFIER_UPPERCASE,
  6168. DIV_TAG_MODIFIER_LOWERCASE,
  6169. DIV_TAG_MODIFIER_LENGTH,
  6170. DIV_TAG_MODIFIER_COUNT_WORDS,
  6171. DIV_TAG_MODIFIER_COUNT_SENTENCES,
  6172. DIV_TAG_MODIFIER_COUNT_PARAGRAPHS,
  6173. DIV_TAG_MODIFIER_ENCODE_URL,
  6174. DIV_TAG_MODIFIER_ENCODE_RAW_URL,
  6175. DIV_TAG_MODIFIER_ENCODE_JSON,
  6176. DIV_TAG_MODIFIER_HTML_ENTITIES,
  6177. DIV_TAG_MODIFIER_NL2BR,
  6178. DIV_TAG_MODIFIER_TRUNCATE,
  6179. DIV_TAG_MODIFIER_WORDWRAP,
  6180. DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR,
  6181. DIV_TAG_MODIFIER_SINGLE_QUOTES,
  6182. DIV_TAG_MODIFIER_JS,
  6183. DIV_TAG_MODIFIER_FORMAT,
  6184. DIV_TAG_DATE_FORMAT_PREFIX,
  6185. DIV_TAG_DATE_FORMAT_SUFFIX,
  6186. DIV_TAG_DATE_FORMAT_SEPARATOR,
  6187. DIV_TAG_NUMBER_FORMAT_PREFIX,
  6188. DIV_TAG_NUMBER_FORMAT_SUFFIX,
  6189. DIV_TAG_NUMBER_FORMAT_SEPARATOR,
  6190. DIV_TAG_FORMULA_BEGIN,
  6191. DIV_TAG_FORMULA_END,
  6192. DIV_TAG_FORMULA_FORMAT_SEPARATOR,
  6193. DIV_TAG_SUBPARSER_BEGIN_PREFIX,
  6194. DIV_TAG_SUBPARSER_BEGIN_SUFFIX,
  6195. DIV_TAG_SUBPARSER_END_PREFIX,
  6196. DIV_TAG_SUBPARSER_END_SUFFIX,
  6197. DIV_TAG_IGNORE_BEGIN,
  6198. DIV_TAG_IGNORE_END,
  6199. DIV_TAG_COMMENT_BEGIN,
  6200. DIV_TAG_COMMENT_END,
  6201. DIV_TAG_TXT_BEGIN,
  6202. DIV_TAG_TXT_END,
  6203. DIV_TAG_TXT_WIDTH_SEPARATOR,
  6204. DIV_TAG_STRIP_BEGIN,
  6205. DIV_TAG_STRIP_END,
  6206. DIV_TAG_LOOP_BEGIN_PREFIX,
  6207. DIV_TAG_LOOP_BEGIN_SUFFIX,
  6208. DIV_TAG_LOOP_END_PREFIX,
  6209. DIV_TAG_LOOP_END_SUFFIX,
  6210. DIV_TAG_EMPTY,
  6211. DIV_TAG_BREAK,
  6212. DIV_TAG_LOOP_VAR_SEPARATOR,
  6213. DIV_TAG_ITERATION_BEGIN_PREFIX,
  6214. DIV_TAG_ITERATION_BEGIN_SUFFIX,
  6215. DIV_TAG_ITERATION_END,
  6216. DIV_TAG_ITERATION_PARAM_SEPARATOR,
  6217. DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX,
  6218. DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX,
  6219. DIV_TAG_CONDITIONAL_TRUE_END_PREFIX,
  6220. DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX,
  6221. DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX,
  6222. DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX,
  6223. DIV_TAG_CONDITIONAL_FALSE_END_PREFIX,
  6224. DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX,
  6225. DIV_TAG_ELSE,
  6226. DIV_TAG_CONDITIONS_BEGIN_PREFIX,
  6227. DIV_TAG_CONDITIONS_BEGIN_SUFFIX,
  6228. DIV_TAG_CONDITIONS_END,
  6229. DIV_TAG_TPLVAR_BEGIN,
  6230. DIV_TAG_TPLVAR_END,
  6231. DIV_TAG_TPLVAR_ASSIGN_OPERATOR,
  6232. DIV_TAG_TPLVAR_PROTECTOR,
  6233. DIV_TAG_DEFAULT_REPLACEMENT_BEGIN,
  6234. DIV_TAG_DEFAULT_REPLACEMENT_END,
  6235. DIV_TAG_INCLUDE_BEGIN,
  6236. DIV_TAG_INCLUDE_END,
  6237. DIV_TAG_PREPROCESSED_BEGIN,
  6238. DIV_TAG_PREPROCESSED_END,
  6239. DIV_TAG_CAPSULE_BEGIN_PREFIX,
  6240. DIV_TAG_CAPSULE_BEGIN_SUFFIX,
  6241. DIV_TAG_CAPSULE_END_PREFIX,
  6242. DIV_TAG_CAPSULE_END_SUFFIX,
  6243. DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX,
  6244. DIV_TAG_MULTI_REPLACEMENT_BEGIN_SUFFIX,
  6245. DIV_TAG_MULTI_REPLACEMENT_END_PREFIX,
  6246. DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX,
  6247. DIV_TAG_FRIENDLY_BEGIN,
  6248. DIV_TAG_FRIENDLY_END,
  6249. DIV_TAG_AGGREGATE_FUNCTION_COUNT,
  6250. DIV_TAG_AGGREGATE_FUNCTION_MAX,
  6251. DIV_TAG_AGGREGATE_FUNCTION_MIN,
  6252. DIV_TAG_AGGREGATE_FUNCTION_SUM,
  6253. DIV_TAG_AGGREGATE_FUNCTION_AVG,
  6254. DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR,
  6255. DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR,
  6256. DIV_TAG_LOCATION_BEGIN,
  6257. DIV_TAG_LOCATION_END,
  6258. DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX,
  6259. DIV_TAG_LOCATION_CONTENT_BEGIN_SUFFIX,
  6260. DIV_TAG_LOCATION_CONTENT_END_PREFIX,
  6261. DIV_TAG_LOCATION_CONTENT_END_SUFFIX,
  6262. DIV_TAG_MACRO_BEGIN,
  6263. DIV_TAG_MACRO_END,
  6264. DIV_TAG_SPECIAL_REPLACE_NEW_LINE,
  6265. DIV_TAG_SPECIAL_REPLACE_CAR_RETURN,
  6266. DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB,
  6267. DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB,
  6268. DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE,
  6269. DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL
  6270. );
  6271. // Required tags
  6272. $names = array(
  6273. 'DIV_TAG_REPLACEMENT_PREFIX',
  6274. 'DIV_TAG_REPLACEMENT_SUFFIX',
  6275. 'DIV_TAG_MULTI_MODIFIERS_PREFIX',
  6276. 'DIV_TAG_MULTI_MODIFIERS_OPERATOR',
  6277. 'DIV_TAG_MULTI_MODIFIERS_SEPARATOR',
  6278. 'DIV_TAG_MULTI_MODIFIERS_SUFFIX',
  6279. 'DIV_TAG_SUBMATCH_SEPARATOR',
  6280. 'DIV_TAG_MODIFIER_SIMPLE',
  6281. 'DIV_TAG_MODIFIER_CAPITALIZE_FIRST',
  6282. 'DIV_TAG_MODIFIER_CAPITALIZE_WORDS',
  6283. 'DIV_TAG_MODIFIER_UPPERCASE',
  6284. 'DIV_TAG_MODIFIER_LOWERCASE',
  6285. 'DIV_TAG_MODIFIER_LENGTH',
  6286. 'DIV_TAG_MODIFIER_COUNT_WORDS',
  6287. 'DIV_TAG_MODIFIER_COUNT_SENTENCES',
  6288. 'DIV_TAG_MODIFIER_COUNT_PARAGRAPHS',
  6289. 'DIV_TAG_MODIFIER_ENCODE_URL',
  6290. 'DIV_TAG_MODIFIER_ENCODE_RAW_URL',
  6291. 'DIV_TAG_MODIFIER_ENCODE_JSON',
  6292. 'DIV_TAG_MODIFIER_HTML_ENTITIES',
  6293. 'DIV_TAG_MODIFIER_NL2BR',
  6294. 'DIV_TAG_MODIFIER_TRUNCATE',
  6295. 'DIV_TAG_MODIFIER_WORDWRAP',
  6296. 'DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR',
  6297. 'DIV_TAG_MODIFIER_SINGLE_QUOTES',
  6298. 'DIV_TAG_MODIFIER_JS',
  6299. 'DIV_TAG_DATE_FORMAT_PREFIX',
  6300. 'DIV_TAG_DATE_FORMAT_SUFFIX',
  6301. 'DIV_TAG_DATE_FORMAT_SEPARATOR',
  6302. 'DIV_TAG_NUMBER_FORMAT_PREFIX',
  6303. 'DIV_TAG_NUMBER_FORMAT_SUFFIX',
  6304. 'DIV_TAG_NUMBER_FORMAT_SEPARATOR',
  6305. 'DIV_TAG_FORMULA_BEGIN',
  6306. 'DIV_TAG_FORMULA_END',
  6307. 'DIV_TAG_FORMULA_FORMAT_SEPARATOR',
  6308. 'DIV_TAG_SUBPARSER_BEGIN_PREFIX',
  6309. 'DIV_TAG_SUBPARSER_END_SUFFIX',
  6310. 'DIV_TAG_IGNORE_BEGIN',
  6311. 'DIV_TAG_IGNORE_END',
  6312. 'DIV_TAG_COMMENT_BEGIN',
  6313. 'DIV_TAG_COMMENT_END',
  6314. 'DIV_TAG_TXT_BEGIN',
  6315. 'DIV_TAG_TXT_END',
  6316. 'DIV_TAG_TXT_WIDTH_SEPARATOR',
  6317. 'DIV_TAG_STRIP_BEGIN',
  6318. 'DIV_TAG_STRIP_END',
  6319. 'DIV_TAG_LOOP_BEGIN_PREFIX',
  6320. 'DIV_TAG_LOOP_END_SUFFIX',
  6321. 'DIV_TAG_EMPTY',
  6322. 'DIV_TAG_BREAK',
  6323. 'DIV_TAG_LOOP_VAR_SEPARATOR',
  6324. 'DIV_TAG_ITERATION_BEGIN_PREFIX',
  6325. 'DIV_TAG_ITERATION_BEGIN_SUFFIX',
  6326. 'DIV_TAG_ITERATION_END',
  6327. 'DIV_TAG_ITERATION_PARAM_SEPARATOR',
  6328. 'DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX',
  6329. 'DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX',
  6330. 'DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX',
  6331. 'DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX',
  6332. 'DIV_TAG_ELSE',
  6333. 'DIV_TAG_CONDITIONS_BEGIN_PREFIX',
  6334. 'DIV_TAG_CONDITIONS_BEGIN_SUFFIX',
  6335. 'DIV_TAG_CONDITIONS_END',
  6336. 'DIV_TAG_TPLVAR_BEGIN',
  6337. 'DIV_TAG_TPLVAR_END',
  6338. 'DIV_TAG_TPLVAR_ASSIGN_OPERATOR',
  6339. 'DIV_TAG_TPLVAR_PROTECTOR',
  6340. 'DIV_TAG_DEFAULT_REPLACEMENT_BEGIN',
  6341. 'DIV_TAG_DEFAULT_REPLACEMENT_END',
  6342. 'DIV_TAG_INCLUDE_BEGIN',
  6343. 'DIV_TAG_INCLUDE_END',
  6344. 'DIV_TAG_PREPROCESSED_BEGIN',
  6345. 'DIV_TAG_PREPROCESSED_END',
  6346. 'DIV_TAG_CAPSULE_BEGIN_PREFIX',
  6347. 'DIV_TAG_CAPSULE_END_SUFFIX',
  6348. 'DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX',
  6349. 'DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX',
  6350. 'DIV_TAG_FRIENDLY_BEGIN',
  6351. 'DIV_TAG_FRIENDLY_END',
  6352. 'DIV_TAG_AGGREGATE_FUNCTION_COUNT',
  6353. 'DIV_TAG_AGGREGATE_FUNCTION_MAX',
  6354. 'DIV_TAG_AGGREGATE_FUNCTION_MIN',
  6355. 'DIV_TAG_AGGREGATE_FUNCTION_SUM',
  6356. 'DIV_TAG_AGGREGATE_FUNCTION_AVG',
  6357. 'DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR',
  6358. 'DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR',
  6359. 'DIV_TAG_LOCATION_BEGIN',
  6360. 'DIV_TAG_LOCATION_END',
  6361. 'DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX',
  6362. 'DIV_TAG_LOCATION_CONTENT_END_SUFFIX',
  6363. 'DIV_TAG_MACRO_BEGIN',
  6364. 'DIV_TAG_MACRO_END',
  6365. 'DIV_TAG_SPECIAL_REPLACE_NEW_LINE',
  6366. 'DIV_TAG_SPECIAL_REPLACE_CAR_RETURN',
  6367. 'DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB',
  6368. 'DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB',
  6369. 'DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE',
  6370. 'DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL',
  6371. 'DIV_TAG_TEASER_BREAK'
  6372. );
  6373. $r = array(
  6374. DIV_TAG_REPLACEMENT_PREFIX,
  6375. DIV_TAG_REPLACEMENT_SUFFIX,
  6376. DIV_TAG_MULTI_MODIFIERS_PREFIX,
  6377. DIV_TAG_MULTI_MODIFIERS_OPERATOR,
  6378. DIV_TAG_MULTI_MODIFIERS_SEPARATOR,
  6379. DIV_TAG_MULTI_MODIFIERS_SUFFIX,
  6380. DIV_TAG_SUBMATCH_SEPARATOR,
  6381. DIV_TAG_MODIFIER_SIMPLE,
  6382. DIV_TAG_MODIFIER_CAPITALIZE_FIRST,
  6383. DIV_TAG_MODIFIER_CAPITALIZE_WORDS,
  6384. DIV_TAG_MODIFIER_UPPERCASE,
  6385. DIV_TAG_MODIFIER_LOWERCASE,
  6386. DIV_TAG_MODIFIER_LENGTH,
  6387. DIV_TAG_MODIFIER_COUNT_WORDS,
  6388. DIV_TAG_MODIFIER_COUNT_SENTENCES,
  6389. DIV_TAG_MODIFIER_COUNT_PARAGRAPHS,
  6390. DIV_TAG_MODIFIER_ENCODE_URL,
  6391. DIV_TAG_MODIFIER_ENCODE_RAW_URL,
  6392. DIV_TAG_MODIFIER_ENCODE_JSON,
  6393. DIV_TAG_MODIFIER_HTML_ENTITIES,
  6394. DIV_TAG_MODIFIER_NL2BR,
  6395. DIV_TAG_MODIFIER_TRUNCATE,
  6396. DIV_TAG_MODIFIER_WORDWRAP,
  6397. DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR,
  6398. DIV_TAG_MODIFIER_SINGLE_QUOTES,
  6399. DIV_TAG_MODIFIER_JS,
  6400. DIV_TAG_DATE_FORMAT_PREFIX,
  6401. DIV_TAG_DATE_FORMAT_SUFFIX,
  6402. DIV_TAG_DATE_FORMAT_SEPARATOR,
  6403. DIV_TAG_NUMBER_FORMAT_PREFIX,
  6404. DIV_TAG_NUMBER_FORMAT_SUFFIX,
  6405. DIV_TAG_NUMBER_FORMAT_SEPARATOR,
  6406. DIV_TAG_FORMULA_BEGIN,
  6407. DIV_TAG_FORMULA_END,
  6408. DIV_TAG_FORMULA_FORMAT_SEPARATOR,
  6409. DIV_TAG_SUBPARSER_BEGIN_PREFIX,
  6410. DIV_TAG_SUBPARSER_END_SUFFIX,
  6411. DIV_TAG_IGNORE_BEGIN,
  6412. DIV_TAG_IGNORE_END,
  6413. DIV_TAG_COMMENT_BEGIN,
  6414. DIV_TAG_COMMENT_END,
  6415. DIV_TAG_TXT_BEGIN,
  6416. DIV_TAG_TXT_END,
  6417. DIV_TAG_TXT_WIDTH_SEPARATOR,
  6418. DIV_TAG_STRIP_BEGIN,
  6419. DIV_TAG_STRIP_END,
  6420. DIV_TAG_LOOP_BEGIN_PREFIX,
  6421. DIV_TAG_LOOP_END_SUFFIX,
  6422. DIV_TAG_EMPTY,
  6423. DIV_TAG_BREAK,
  6424. DIV_TAG_LOOP_VAR_SEPARATOR,
  6425. DIV_TAG_ITERATION_BEGIN_PREFIX,
  6426. DIV_TAG_ITERATION_BEGIN_SUFFIX,
  6427. DIV_TAG_ITERATION_END,
  6428. DIV_TAG_ITERATION_PARAM_SEPARATOR,
  6429. DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX,
  6430. DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX,
  6431. DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX,
  6432. DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX,
  6433. DIV_TAG_ELSE,
  6434. DIV_TAG_CONDITIONS_BEGIN_PREFIX,
  6435. DIV_TAG_CONDITIONS_BEGIN_SUFFIX,
  6436. DIV_TAG_CONDITIONS_END,
  6437. DIV_TAG_TPLVAR_BEGIN,
  6438. DIV_TAG_TPLVAR_END,
  6439. DIV_TAG_TPLVAR_ASSIGN_OPERATOR,
  6440. DIV_TAG_TPLVAR_PROTECTOR,
  6441. DIV_TAG_DEFAULT_REPLACEMENT_BEGIN,
  6442. DIV_TAG_DEFAULT_REPLACEMENT_END,
  6443. DIV_TAG_INCLUDE_BEGIN,
  6444. DIV_TAG_INCLUDE_END,
  6445. DIV_TAG_PREPROCESSED_BEGIN,
  6446. DIV_TAG_PREPROCESSED_END,
  6447. DIV_TAG_CAPSULE_BEGIN_PREFIX,
  6448. DIV_TAG_CAPSULE_END_SUFFIX,
  6449. DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX,
  6450. DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX,
  6451. DIV_TAG_FRIENDLY_BEGIN,
  6452. DIV_TAG_FRIENDLY_END,
  6453. DIV_TAG_AGGREGATE_FUNCTION_COUNT,
  6454. DIV_TAG_AGGREGATE_FUNCTION_MAX,
  6455. DIV_TAG_AGGREGATE_FUNCTION_MIN,
  6456. DIV_TAG_AGGREGATE_FUNCTION_SUM,
  6457. DIV_TAG_AGGREGATE_FUNCTION_AVG,
  6458. DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR,
  6459. DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR,
  6460. DIV_TAG_LOCATION_BEGIN,
  6461. DIV_TAG_LOCATION_END,
  6462. DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX,
  6463. DIV_TAG_LOCATION_CONTENT_END_SUFFIX,
  6464. DIV_TAG_MACRO_BEGIN,
  6465. DIV_TAG_MACRO_END,
  6466. DIV_TAG_SPECIAL_REPLACE_NEW_LINE,
  6467. DIV_TAG_SPECIAL_REPLACE_CAR_RETURN,
  6468. DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB,
  6469. DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB,
  6470. DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE,
  6471. DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL,
  6472. DIV_TAG_TEASER_BREAK
  6473. );
  6474. $p = array_search('', $r, true);
  6475. if ($p !== false)
  6476. return $names[$p] . ' is required';
  6477. $p = array_search(null, $r, true);
  6478. if ($p !== false)
  6479. return $names[$p] . ' is required';
  6480. // Unique tags
  6481. $names = array(
  6482. 'DIV_TAG_MODIFIER_SIMPLE',
  6483. 'DIV_TAG_MODIFIER_CAPITALIZE_FIRST',
  6484. 'DIV_TAG_MODIFIER_CAPITALIZE_WORDS',
  6485. 'DIV_TAG_MODIFIER_UPPERCASE',
  6486. 'DIV_TAG_MODIFIER_LOWERCASE',
  6487. 'DIV_TAG_MODIFIER_LENGTH',
  6488. 'DIV_TAG_MODIFIER_COUNT_WORDS',
  6489. 'DIV_TAG_MODIFIER_COUNT_SENTENCES',
  6490. 'DIV_TAG_MODIFIER_COUNT_PARAGRAPHS',
  6491. 'DIV_TAG_MODIFIER_ENCODE_URL',
  6492. 'DIV_TAG_MODIFIER_ENCODE_RAW_URL',
  6493. 'DIV_TAG_MODIFIER_ENCODE_JSON',
  6494. 'DIV_TAG_MODIFIER_HTML_ENTITIES',
  6495. 'DIV_TAG_MODIFIER_NL2BR',
  6496. 'DIV_TAG_MODIFIER_TRUNCATE',
  6497. 'DIV_TAG_MODIFIER_WORDWRAP',
  6498. 'DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR',
  6499. 'DIV_TAG_MODIFIER_SINGLE_QUOTES',
  6500. 'DIV_TAG_MODIFIER_JS',
  6501. 'DIV_TAG_MODIFIER_FORMAT',
  6502. 'DIV_TAG_EMPTY',
  6503. 'DIV_TAG_BREAK',
  6504. 'DIV_TAG_ELSE',
  6505. 'DIV_TAG_AGGREGATE_FUNCTION_COUNT',
  6506. 'DIV_TAG_AGGREGATE_FUNCTION_MAX',
  6507. 'DIV_TAG_AGGREGATE_FUNCTION_MIN',
  6508. 'DIV_TAG_AGGREGATE_FUNCTION_SUM',
  6509. 'DIV_TAG_AGGREGATE_FUNCTION_AVG',
  6510. 'DIV_TAG_SPECIAL_REPLACE_NEW_LINE',
  6511. 'DIV_TAG_SPECIAL_REPLACE_CAR_RETURN',
  6512. 'DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB',
  6513. 'DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB',
  6514. 'DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE',
  6515. 'DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL'
  6516. );
  6517. $r = array(
  6518. DIV_TAG_MODIFIER_SIMPLE,
  6519. DIV_TAG_MODIFIER_CAPITALIZE_FIRST,
  6520. DIV_TAG_MODIFIER_CAPITALIZE_WORDS,
  6521. DIV_TAG_MODIFIER_UPPERCASE,
  6522. DIV_TAG_MODIFIER_LOWERCASE,
  6523. DIV_TAG_MODIFIER_LENGTH,
  6524. DIV_TAG_MODIFIER_COUNT_WORDS,
  6525. DIV_TAG_MODIFIER_COUNT_SENTENCES,
  6526. DIV_TAG_MODIFIER_COUNT_PARAGRAPHS,
  6527. DIV_TAG_MODIFIER_ENCODE_URL,
  6528. DIV_TAG_MODIFIER_ENCODE_RAW_URL,
  6529. DIV_TAG_MODIFIER_ENCODE_JSON,
  6530. DIV_TAG_MODIFIER_HTML_ENTITIES,
  6531. DIV_TAG_MODIFIER_NL2BR,
  6532. DIV_TAG_MODIFIER_TRUNCATE,
  6533. DIV_TAG_MODIFIER_WORDWRAP,
  6534. DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR,
  6535. DIV_TAG_MODIFIER_SINGLE_QUOTES,
  6536. DIV_TAG_MODIFIER_JS,
  6537. DIV_TAG_MODIFIER_FORMAT,
  6538. DIV_TAG_EMPTY,
  6539. DIV_TAG_BREAK,
  6540. DIV_TAG_ELSE,
  6541. DIV_TAG_AGGREGATE_FUNCTION_COUNT,
  6542. DIV_TAG_AGGREGATE_FUNCTION_MAX,
  6543. DIV_TAG_AGGREGATE_FUNCTION_MIN,
  6544. DIV_TAG_AGGREGATE_FUNCTION_SUM,
  6545. DIV_TAG_AGGREGATE_FUNCTION_AVG,
  6546. DIV_TAG_SPECIAL_REPLACE_NEW_LINE,
  6547. DIV_TAG_SPECIAL_REPLACE_CAR_RETURN,
  6548. DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB,
  6549. DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB,
  6550. DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE,
  6551. DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL
  6552. );
  6553. foreach ( $r as $k => $t ) {
  6554. $p = array_search($t, $r);
  6555. if ($p !== false && $p !== $k)
  6556. return $names[$k] . ' must be unique and not equal to ' . $names[$p];
  6557. }
  6558. // Teaser break must be unique
  6559. if (array_search(DIV_TAG_TEASER_BREAK, $all_tags))
  6560. return 'DIV_TAG_TEASER_BREAK must be unique';
  6561. return true;
  6562. }
  6563. /**
  6564. * Return true if $varname is valid PHP var name
  6565. *
  6566. * @param string $varname
  6567. * @return boolean
  6568. */
  6569. final static function isValidVarName($varname){
  6570. $r = preg_replace('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', '', $varname);
  6571. return $r == '$' || $r == '';
  6572. }
  6573. /**
  6574. * Return true if code is not obtrusive
  6575. *
  6576. * @param string $code
  6577. * @param boolean $multi_lines
  6578. * @param mixed $extra_tokens
  6579. * @return boolean
  6580. */
  6581. final static function isValidPHPCode($code, $multi_lines = true, $valid_tokens = null){
  6582. if (is_null($valid_tokens))
  6583. $valid_tokens = DIV_PHP_VALID_TOKENS_FOR_EXPRESSIONS . ',' . DIV_PHP_VALID_TOKENS_FOR_MACROS;
  6584. $t = token_get_all("<?php $code ?>");
  6585. foreach ( $t as $key => $value )
  6586. if (is_array($value))
  6587. $t[$key][0] = token_name($value[0]);
  6588. $count = count($t);
  6589. if (is_string($valid_tokens))
  6590. $valid_tokens = explode(",", $valid_tokens);
  6591. foreach ( $valid_tokens as $kk => $tk ) {
  6592. $tk = strtoupper(trim($tk));
  6593. $valid_tokens[$tk] = $tk;
  6594. }
  6595. if (is_null(self::$__allowed_php_functions)) {
  6596. $keys = explode(",", DIV_PHP_ALLOWED_FUNCTIONS);
  6597. self::$__allowed_php_functions = array_combine($keys, $keys);
  6598. }
  6599. $object_operator = false;
  6600. foreach ( $t as $idx => $token ) {
  6601. if ($token == ';' && $multi_lines == false)
  6602. return false;
  6603. if (is_array($token)) {
  6604. $n = $token[0];
  6605. switch ($n) {
  6606. case 'T_VARIABLE' :
  6607. if (array_search($token[1], array(
  6608. '$this',
  6609. '$_SESSION',
  6610. '$GLOBALS',
  6611. '$_POST',
  6612. '$_GET',
  6613. '$_FILES',
  6614. '$_COOKIE',
  6615. '$_ENV',
  6616. '$_REQUEST'
  6617. )) !== false)
  6618. return false;
  6619. break;
  6620. case 'T_OPEN_TAG' :
  6621. if ($idx > 0)
  6622. return false;
  6623. break;
  6624. case 'T_CLOSE_TAG' :
  6625. if ($idx < $count - 1)
  6626. return false;
  6627. break;
  6628. case 'T_STRING' :
  6629. $f = $token[1];
  6630. $lw = strtolower($f);
  6631. if (! isset(self::$__allowed_methods[$f])) {
  6632. if ($lw != 'true' && $lw != 'false' && $lw != 'null') {
  6633. if (is_callable($f)) {
  6634. if (! isset(self::$__allowed_php_functions[$f])) {
  6635. if (! isset(self::$__allowed_functions[$f]))
  6636. return false;
  6637. if (self::$__allowed_functions[$f] === false)
  6638. return false;
  6639. }
  6640. } else
  6641. return false;
  6642. }
  6643. }
  6644. break;
  6645. default :
  6646. if (! isset($valid_tokens[$n]))
  6647. return false;
  6648. }
  6649. }
  6650. }
  6651. return true;
  6652. }
  6653. /**
  6654. * Check if code is a valid expression
  6655. *
  6656. * @param string $code
  6657. * @return boolean
  6658. */
  6659. final static function isValidExpression($code){
  6660. return self::isValidPHPCode($code, false, DIV_PHP_VALID_TOKENS_FOR_EXPRESSIONS);
  6661. }
  6662. /**
  6663. * Check if code is a valid macro
  6664. *
  6665. * @param string $code
  6666. * @return boolean
  6667. */
  6668. final static function isValidMacro($code){
  6669. return self::isValidPHPCode($code, true, DIV_PHP_VALID_TOKENS_FOR_EXPRESSIONS . ',' . DIV_PHP_VALID_TOKENS_FOR_MACROS);
  6670. }
  6671. /**
  6672. * Return true if the script was executed in the CLI enviroment
  6673. *
  6674. * @return boolean
  6675. */
  6676. final static function isCli(){
  6677. if (is_null(self::$__is_cli)) {
  6678. self::$__is_cli = (! isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)));
  6679. }
  6680. return self::$__is_cli;
  6681. }
  6682. /**
  6683. * Show error and die
  6684. *
  6685. * @param string $errmsg
  6686. * @param string $level
  6687. */
  6688. static function error($errmsg, $level = DIV_ERROR_WARNING){
  6689. self::$__errors[] = array(
  6690. $errmsg,
  6691. $level
  6692. );
  6693. $iscli = self::isCli();
  6694. ob_start();
  6695. $func = 'warn';
  6696. if ($iscli)
  6697. $errmsg = self::htmlToText($errmsg, null);
  6698. if ($iscli === false)
  6699. echo "<div style = \"z-index:9999; position: fixed; top: " . ((count(self::$__errors) - 1) * 50 + 10) . "px; right: 20px; min-width: 60%; font-family: verdana; border-radius: 5px; padding: 10px;";
  6700. switch ($level) {
  6701. case DIV_ERROR_WARNING :
  6702. if (! $iscli)
  6703. echo "background: yellow; border: 1px solid black; color: black;\">[$level] $errmsg</div>";
  6704. else
  6705. echo "$level: $errmsg\n";
  6706. $func = 'warn';
  6707. break;
  6708. case DIV_ERROR_FATAL :
  6709. if (! $iscli)
  6710. echo "background: red; border: 1px solid black; color: white;\">[$level] $errmsg</div>";
  6711. else
  6712. echo "$level: $errmsg\n";
  6713. $func = 'error';
  6714. break;
  6715. }
  6716. $msg = ob_get_contents();
  6717. ob_end_clean();
  6718. if ($iscli)
  6719. echo '[[]]' . self::htmlToText($msg, null) . "\n";
  6720. else
  6721. echo $msg;
  6722. self::log($msg, $level);
  6723. if ($level == DIV_ERROR_FATAL)
  6724. die();
  6725. }
  6726. /**
  6727. * Switch ON the debug mode
  6728. *
  6729. * @param string $log_file
  6730. */
  6731. final static function logOn($log_file = 'div.log'){
  6732. self::$__log_mode = true;
  6733. self::$__log_file = $log_file;
  6734. self::log('Starting div with logs...');
  6735. }
  6736. /**
  6737. * Global logger
  6738. *
  6739. * @param string $msg
  6740. * @param string $level
  6741. */
  6742. static function log($msg, $level = 'INFO'){
  6743. $msg = self::htmlToText($msg, null);
  6744. $msg = str_replace("\n", "\\n", $msg);
  6745. $msg = str_replace("\r", "\\r", $msg);
  6746. $msg = '[' . $level . '] ' . date('Y-m-d h:i:s') . ' - ' . $msg . "\n";
  6747. if (self::$__log_mode) {
  6748. $f = fopen(self::$__log_file, 'a');
  6749. fputs($f, $msg);
  6750. fclose($f);
  6751. }
  6752. $func = 'log';
  6753. if ($level == DIV_ERROR_WARNING)
  6754. $func = 'warn';
  6755. elseif ($level == DIV_ERROR_FATAL)
  6756. $func = 'error';
  6757. if (! self::isCli()) {
  6758. $msg = str_replace("\n\r", " ", $msg);
  6759. $msg = str_replace("\n", ' ', $msg);
  6760. $msg = str_replace(array(
  6761. "\r",
  6762. '"'
  6763. ), "", $msg);
  6764. echo "<script type=\"text/javascript\"> if (typeof console !== 'undefined') console.$func(\"[[]] $msg \");</script>\n";
  6765. }
  6766. }
  6767. /**
  6768. * Logger of instance
  6769. *
  6770. * @param string $msg
  6771. * @param string $level
  6772. */
  6773. public function logger($msg, $level = 'INFO'){
  6774. $msg = "TPL-ID: " . $this->getId() . " > $msg";
  6775. self::log($msg, $level);
  6776. }
  6777. /**
  6778. * Destructor
  6779. */
  6780. public function __destruct(){
  6781. if (self::$__log_mode)
  6782. $this->logger("Destroying the instance #" . $this->getId());
  6783. }
  6784. }