/lib/tinyTemplate.php

https://github.com/dounokouno/TransmitMail · PHP · 318 lines · 199 code · 60 blank · 59 comment · 27 complexity · dd2e3325252951a87fdd159a1cd6b73b MD5 · raw file

  1. <?php
  2. /*--------------------------------------------------------------*\
  3. Description: HTML template class based on bTemplate.
  4. Author: Takayuki Miyauchi (miya@theta.ne.jp)
  5. Modified by: TAGAWA Takao (dounokouno@gmail.com)
  6. License: MIT License
  7. Version: 0.1.2
  8. \*--------------------------------------------------------------*/
  9. if (!class_exists('tinyTemplate')) {
  10. class tinyTemplate {
  11. // Configuration variables
  12. private $base_path = '';
  13. private $reset_vars = false;
  14. // Default Modifier
  15. public $default_modifier = null;
  16. // Delimeters for regular tags
  17. private $ldelim = '{';
  18. private $rdelim = '}';
  19. // Delimeters for beginnings of loops
  20. private $BAldelim = '{';
  21. private $BArdelim = '}';
  22. // Delimeters for ends of loops
  23. private $EAldelim = '{/';
  24. private $EArdelim = '}';
  25. // Internal privateiables
  26. private $scalars = [];
  27. private $arrays = [];
  28. private $carrays = [];
  29. private $ifs = [];
  30. //
  31. // Simply sets the base path (if you don't set the default).
  32. //
  33. function __construct($base_path = null, $reset_vars = false)
  34. {
  35. if ($base_path) $this->base_path = $base_path;
  36. $this->reset_vars = $reset_vars;
  37. $this->default_modifier = [$this, 'modifier'];
  38. }
  39. //
  40. // Sets all types of variables (scalar, loop, hash).
  41. //
  42. public function set($tag, $var, $modifier = false)
  43. {
  44. if (is_array($var)) {
  45. if ($modifier) {
  46. array_walk_recursive($var, $this->default_modifier);
  47. }
  48. $this->arrays[$tag] = $var;
  49. $result = $var ? true : false;
  50. $this->ifs[] = $tag;
  51. $this->scalars[$tag] = $result;
  52. } else {
  53. if ($modifier) {
  54. call_user_func_array($this->default_modifier, [&$var]);
  55. }
  56. $this->scalars[$tag] = $var;
  57. $this->ifs[] = $tag;
  58. }
  59. }
  60. //
  61. // Returns the parsed contents of the specified template.
  62. //
  63. public function fetch($file_name)
  64. {
  65. $file = $this->base_path . $file_name;
  66. $fp = fopen($file, 'rb');
  67. if (!$fp) return false;
  68. $contents = fread($fp, filesize($file));
  69. fclose($fp);
  70. $contents = $this->parse($contents);
  71. $contents = $this->deleteUnusedTags($contents);
  72. return $contents;
  73. }
  74. //
  75. // Parses all variables into the template.
  76. //
  77. public function parse($contents)
  78. {
  79. // Process the ifs
  80. if (!empty($this->ifs)) {
  81. foreach ($this->ifs as $value) {
  82. $contents = $this->parse_if($value, $contents);
  83. }
  84. }
  85. // Process the scalars
  86. foreach ($this->scalars as $key => $value) {
  87. $contents = str_replace($this->get_tag($key), $value, $contents);
  88. }
  89. // Process the arrays
  90. foreach ($this->arrays as $key => $array) {
  91. $contents = $this->parse_loop($key, $array, $contents);
  92. }
  93. // Process the carrays
  94. foreach ($this->carrays as $key => $array) {
  95. $contents = $this->parse_cloop($key, $array, $contents);
  96. }
  97. // Process the includes
  98. $regex = '/' . preg_quote($this->ldelim, '/') . 'include:(.*)' . preg_quote($this->rdelim, '/') . '/';
  99. preg_match_all($regex, $contents, $matches);
  100. foreach ($matches[1] as $index => $value) {
  101. $contents = str_replace($matches[0][$index], rtrim($this->fetch($value)), $contents);
  102. }
  103. // Reset the arrays
  104. if ($this->reset_vars) $this->reset_vars(false, true, true, false);
  105. // Return the contents
  106. return $contents;
  107. }
  108. //
  109. // Set filter function for template output
  110. //
  111. public function setModifier($modifier)
  112. {
  113. if (is_array($modifier)) {
  114. if (method_exists($modifier[0], $modifier[1])) {
  115. $this->default_modifier = $modifier;
  116. }
  117. } elseif (function_exists($modifier)) {
  118. $this->default_modifier = $modifier;
  119. }
  120. }
  121. private function reset_vars($scalars, $arrays, $carrays, $ifs)
  122. {
  123. if ($scalars) $this->scalars = [];
  124. if ($arrays) $this->arrays = [];
  125. if ($carrays) $this->carrays = [];
  126. if ($ifs) $this->ifs = [];
  127. }
  128. private function get_tags($tag, $directive)
  129. {
  130. $tags['b'] = $this->BAldelim . $directive . $tag . $this->BArdelim;
  131. $tags['e'] = $this->EAldelim . $directive . $tag . $this->EArdelim;
  132. return $tags;
  133. }
  134. private function get_tag($tag) {
  135. return $this->ldelim . '$' . $tag . $this->rdelim;
  136. }
  137. private function get_statement($t, &$contents) {
  138. // Locate the statement
  139. $tag_length = strlen($t['b']);
  140. $fpos = strpos($contents, $t['b']) + $tag_length;
  141. $lpos = strpos($contents, $t['e']);
  142. $length = $lpos - $fpos;
  143. // Extract & return the statement
  144. return substr($contents, $fpos, $length);
  145. }
  146. private function parse_if($tag, $contents)
  147. {
  148. // Get the tags
  149. $t = $this->get_tags($tag, 'if:$');
  150. // Get the entire statement
  151. $entire_statement = $this->get_statement($t, $contents);
  152. // Get the else tag
  153. $tags['b'] = null;
  154. $tags['e'] = $this->BAldelim . 'else:$' . $tag . $this->BArdelim;
  155. // See if there's an else statement
  156. if (($else = strpos($entire_statement, $tags['e']))) {
  157. // Get the if statement
  158. $if = $this->get_statement($tags, $entire_statement);
  159. // Get the else statement
  160. $else = substr($entire_statement, $else + strlen($tags['e']));
  161. } else {
  162. $else = null;
  163. $if = $entire_statement;
  164. }
  165. // Process the if statement
  166. $this->scalars[$tag] ? $replace = $if : $replace = $else;
  167. // Parse & return the template
  168. return str_replace(
  169. $t['b'] . $entire_statement . $t['e'],
  170. $replace,
  171. $contents
  172. );
  173. }
  174. private function parse_loop($tag, $array, $contents)
  175. {
  176. // Get the tags & loop
  177. $t = $this->get_tags($tag, 'loop:$');
  178. $loop = $this->get_statement($t, $contents);
  179. $parsed = null;
  180. // Process the loop
  181. foreach ($array as $key => $value) {
  182. if (is_numeric($key) && is_array($value)) {
  183. $i = $loop;
  184. foreach ($value as $key2 => $value2) {
  185. if (!is_array($value2)) {
  186. // Replace associative array tags
  187. $i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
  188. } else {
  189. // Check to see if it's a nested loop
  190. $i = $this->parse_loop($tag . '[].' . $key2, $value2, $i);
  191. }
  192. }
  193. } elseif (is_string($key) && !is_array($value)) {
  194. $contents = str_replace($this->get_tag($tag . '.' . $key), $value, $contents);
  195. } elseif(!is_array($value)) {
  196. $i = str_replace($this->get_tag($tag . '[]'), $value, $loop);
  197. }
  198. // Add the parsed iteration
  199. if (isset($i)) $parsed .= rtrim($i);
  200. }
  201. // Parse & return the final loop
  202. return str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
  203. }
  204. private function parse_cloop($tag, $array, $contents)
  205. {
  206. // Get the tags & loop
  207. $t = $this->get_tags($tag, 'cloop:');
  208. $loop = $this->get_statement($t, $contents);
  209. // Set up the cases
  210. $array['cases'][] = 'default';
  211. $case_content = [];
  212. $parsed = null;
  213. // Get the case strings
  214. foreach ($array['cases'] as $case) {
  215. $ctags[$case] = $this->get_tags($case, 'case:');
  216. $case_content[$case] = $this->get_statement($ctags[$case], $loop);
  217. }
  218. // Process the loop
  219. foreach ($array['array'] as $key => $value) {
  220. if (is_numeric($key) && is_array($value)) {
  221. // Set up the cases
  222. if (isset($value['case'])) $current_case = $value['case'];
  223. else $current_case = 'default';
  224. unset($value['case']);
  225. $i = $case_content[$current_case];
  226. // Loop through each value
  227. foreach ($value as $key2 => $value2) {
  228. $i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
  229. }
  230. }
  231. // Add the parsed iteration
  232. $parsed .= rtrim($i);
  233. }
  234. // Parse & return the final loop
  235. return str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
  236. }
  237. private function modifier(&$str)
  238. {
  239. $str = htmlentities($str, ENT_QUOTES, mb_internal_encoding());
  240. $str = trim($str);
  241. return $str;
  242. }
  243. private function deleteUnusedTags($contents)
  244. {
  245. $multiline_tags = ['if', 'loop'];
  246. $regex_start = '/' . preg_quote($this->BAldelim, '/');
  247. $regex_middle = '.*?' . preg_quote($this->BArdelim, '/') . '.*?' . preg_quote($this->EAldelim, '/');
  248. $regex_end = '.*?' . preg_quote($this->EArdelim, '/') . '/s';
  249. foreach ($multiline_tags as $tag) {
  250. $regex = $regex_start . $tag . $regex_middle . $tag . $regex_end;
  251. $contents = preg_replace($regex, '', $contents);
  252. }
  253. $regex = '/' . preg_quote($this->ldelim, '/') . '\$.*?' . preg_quote($this->rdelim, '/') . '/';
  254. $contents = preg_replace($regex, '', $contents);
  255. return $contents;
  256. }
  257. }
  258. }