Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
8.0 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php
  2. /*
  3. * This is the old template engine, now deprecated.
  4. * Friendica's default template engine is Smarty3 (see include/friendica_smarty.php)
  5. *
  6. */
  7. require_once 'object/TemplateEngine.php';
  8. define("KEY_NOT_EXISTS", '^R_key_not_Exists^');
  9. class Template implements ITemplateEngine {
  10. static $name ="internal";
  11. var $r;
  12. var $search;
  13. var $replace;
  14. var $stack = array();
  15. var $nodes = array();
  16. var $done = false;
  17. var $d = false;
  18. var $lang = null;
  19. var $debug = false;
  20. private function _preg_error() {
  21. switch (preg_last_error()) {
  22. case PREG_INTERNAL_ERROR: echo('PREG_INTERNAL_ERROR');
  23. break;
  24. case PREG_BACKTRACK_LIMIT_ERROR: echo('PREG_BACKTRACK_LIMIT_ERROR');
  25. break;
  26. case PREG_RECURSION_LIMIT_ERROR: echo('PREG_RECURSION_LIMIT_ERROR');
  27. break;
  28. case PREG_BAD_UTF8_ERROR: echo('PREG_BAD_UTF8_ERROR');
  29. break;
  30. // This is only valid for php > 5.3, not certain how to code around it for unit tests
  31. // case PREG_BAD_UTF8_OFFSET_ERROR: echo('PREG_BAD_UTF8_OFFSET_ERROR'); break;
  32. default:
  33. //die("Unknown preg error.");
  34. return;
  35. }
  36. echo "<hr><pre>";
  37. debug_print_backtrace();
  38. die();
  39. }
  40. private function _push_stack() {
  41. $this->stack[] = array($this->r, $this->nodes);
  42. }
  43. private function _pop_stack() {
  44. list($this->r, $this->nodes) = array_pop($this->stack);
  45. }
  46. private function _get_var($name, $retNoKey = false) {
  47. $keys = array_map('trim', explode(".", $name));
  48. if ($retNoKey && !array_key_exists($keys[0], $this->r))
  49. return KEY_NOT_EXISTS;
  50. $val = $this->r;
  51. foreach ($keys as $k) {
  52. $val = (isset($val[$k]) ? $val[$k] : null);
  53. }
  54. return $val;
  55. }
  56. /**
  57. * IF node
  58. *
  59. * {{ if <$var> }}...[{{ else }} ...] {{ endif }}
  60. * {{ if <$var>==<val|$var> }}...[{{ else }} ...]{{ endif }}
  61. * {{ if <$var>!=<val|$var> }}...[{{ else }} ...]{{ endif }}
  62. */
  63. private function _replcb_if($args) {
  64. if (strpos($args[2], "==") > 0) {
  65. list($a, $b) = array_map("trim", explode("==", $args[2]));
  66. $a = $this->_get_var($a);
  67. if ($b[0] == "$")
  68. $b = $this->_get_var($b);
  69. $val = ($a == $b);
  70. } else if (strpos($args[2], "!=") > 0) {
  71. list($a, $b) = array_map("trim", explode("!=", $args[2]));
  72. $a = $this->_get_var($a);
  73. if ($b[0] == "$")
  74. $b = $this->_get_var($b);
  75. $val = ($a != $b);
  76. } else {
  77. $val = $this->_get_var($args[2]);
  78. }
  79. $x = preg_split("|{{ *else *}}|", $args[3]);
  80. return ( $val ? $x[0] : (isset($x[1]) ? $x[1] : ""));
  81. }
  82. /**
  83. * FOR node
  84. *
  85. * {{ for <$var> as $name }}...{{ endfor }}
  86. * {{ for <$var> as $key=>$name }}...{{ endfor }}
  87. */
  88. private function _replcb_for($args) {
  89. $m = array_map('trim', explode(" as ", $args[2]));
  90. $x = explode("=>", $m[1]);
  91. if (count($x) == 1) {
  92. $varname = $x[0];
  93. $keyname = "";
  94. } else {
  95. list($keyname, $varname) = $x;
  96. }
  97. if ($m[0] == "" || $varname == "" || is_null($varname))
  98. die("template error: 'for " . $m[0] . " as " . $varname . "'");
  99. //$vals = $this->r[$m[0]];
  100. $vals = $this->_get_var($m[0]);
  101. $ret = "";
  102. if (!is_array($vals))
  103. return $ret;
  104. foreach ($vals as $k => $v) {
  105. $this->_push_stack();
  106. $r = $this->r;
  107. $r[$varname] = $v;
  108. if ($keyname != '')
  109. $r[$keyname] = (($k === 0) ? '0' : $k);
  110. $ret .= $this->replace($args[3], $r);
  111. $this->_pop_stack();
  112. }
  113. return $ret;
  114. }
  115. /**
  116. * INC node
  117. *
  118. * {{ inc <templatefile> [with $var1=$var2] }}{{ endinc }}
  119. */
  120. private function _replcb_inc($args) {
  121. if (strpos($args[2], "with")) {
  122. list($tplfile, $newctx) = array_map('trim', explode("with", $args[2]));
  123. } else {
  124. $tplfile = trim($args[2]);
  125. $newctx = null;
  126. }
  127. if ($tplfile[0] == "$")
  128. $tplfile = $this->_get_var($tplfile);
  129. $this->_push_stack();
  130. $r = $this->r;
  131. if (!is_null($newctx)) {
  132. list($a, $b) = array_map('trim', explode("=", $newctx));
  133. $r[$a] = $this->_get_var($b);
  134. }
  135. $this->nodes = Array();
  136. $tpl = get_markup_template($tplfile);
  137. $ret = $this->replace($tpl, $r);
  138. $this->_pop_stack();
  139. return $ret;
  140. }
  141. /**
  142. * DEBUG node
  143. *
  144. * {{ debug $var [$var [$var [...]]] }}{{ enddebug }}
  145. *
  146. * replace node with <pre>var_dump($var, $var, ...);</pre>
  147. */
  148. private function _replcb_debug($args) {
  149. $vars = array_map('trim', explode(" ", $args[2]));
  150. $vars[] = $args[1];
  151. $ret = "<pre>";
  152. foreach ($vars as $var) {
  153. $ret .= htmlspecialchars(var_export($this->_get_var($var), true));
  154. $ret .= "\n";
  155. }
  156. $ret .= "</pre>";
  157. return $ret;
  158. }
  159. private function _replcb_node($m) {
  160. $node = $this->nodes[$m[1]];
  161. if (method_exists($this, "_replcb_" . $node[1])) {
  162. $s = call_user_func(array($this, "_replcb_" . $node[1]), $node);
  163. } else {
  164. $s = "";
  165. }
  166. $s = preg_replace_callback('/\|\|([0-9]+)\|\|/', array($this, "_replcb_node"), $s);
  167. return $s;
  168. }
  169. private function _replcb($m) {
  170. //var_dump(array_map('htmlspecialchars', $m));
  171. $this->done = false;
  172. $this->nodes[] = (array) $m;
  173. return "||" . (count($this->nodes) - 1) . "||";
  174. }
  175. private function _build_nodes($s) {
  176. $this->done = false;
  177. while (!$this->done) {
  178. $this->done = true;
  179. $s = preg_replace_callback('|{{ *([a-z]*) *([^}]*)}}([^{]*({{ *else *}}[^{]*)?){{ *end\1 *}}|', array($this, "_replcb"), $s);
  180. if ($s == Null)
  181. $this->_preg_error();
  182. }
  183. //({{ *else *}}[^{]*)?
  184. krsort($this->nodes);
  185. return $s;
  186. }
  187. private function var_replace($s) {
  188. $m = array();
  189. /** regexp:
  190. * \$ literal $
  191. * (\[)? optional open square bracket
  192. * ([a-zA-Z0-9-_]+\.?)+ var name, followed by optional
  193. * dot, repeated at least 1 time
  194. * (|[a-zA-Z0-9-_:]+)* pipe followed by filter name and args, zero or many
  195. * (?(1)\]) if there was opened square bracket
  196. * (subgrup 1), match close bracket
  197. */
  198. if (preg_match_all('/\$(\[)?([a-zA-Z0-9-_]+\.?)+(\|[a-zA-Z0-9-_:]+)*(?(1)\])/', $s, $m)) {
  199. foreach ($m[0] as $var) {
  200. $exp = str_replace(array("[", "]"), array("", ""), $var);
  201. $exptks = explode("|", $exp);
  202. $varn = $exptks[0];
  203. unset($exptks[0]);
  204. $val = $this->_get_var($varn, true);
  205. if ($val != KEY_NOT_EXISTS) {
  206. /* run filters */
  207. /*
  208. * Filter are in form of:
  209. * filtername:arg:arg:arg
  210. *
  211. * "filtername" is function name
  212. * "arg"s are optional, var value is appended to the end
  213. * if one "arg"==='x' , is replaced with var value
  214. *
  215. * examples:
  216. * $item.body|htmlspecialchars // escape html chars
  217. * $item.body|htmlspecialchars|strtoupper // escape html and uppercase result
  218. * $item.created|date:%Y %M %j // format date (created is a timestamp)
  219. * $item.body|str_replace:cat:dog // replace all "cat" with "dog"
  220. * $item.body|str_replace:cat:dog:x:1 // replace one "cat" with "dog"
  221. */
  222. foreach ($exptks as $filterstr) {
  223. $filter = explode(":", $filterstr);
  224. $filtername = $filter[0];
  225. unset($filter[0]);
  226. $valkey = array_search("x", $filter);
  227. if ($valkey === false) {
  228. $filter[] = $val;
  229. } else {
  230. $filter[$valkey] = $val;
  231. }
  232. if (function_exists($filtername)) {
  233. $val = call_user_func_array($filtername, $filter);
  234. }
  235. }
  236. $s = str_replace($var, $val, $s);
  237. }
  238. }
  239. }
  240. return $s;
  241. }
  242. // TemplateEngine interface
  243. public function replace_macros($s, $r) {
  244. $this->r = $r;
  245. // remove comments block
  246. $s = preg_replace('/{#(.*?\s*?)*?#}/', "", $s);
  247. $s = $this->_build_nodes($s);
  248. $s = preg_replace_callback('/\|\|([0-9]+)\|\|/', array($this, "_replcb_node"), $s);
  249. if ($s == Null)
  250. $this->_preg_error();
  251. // replace strings recursively (limit to 10 loops)
  252. $os = "";
  253. $count = 0;
  254. while ($os != $s && $count < 10) {
  255. $os = $s;
  256. $count++;
  257. $s = $this->var_replace($s);
  258. }
  259. return template_unescape($s);
  260. }
  261. public function get_template_file($file, $root='') {
  262. $a = get_app();
  263. $template_file = get_template_file($a, $file, $root);
  264. $content = file_get_contents($template_file);
  265. return $content;
  266. }
  267. }
  268. function template_escape($s) {
  269. return str_replace(array('$', '{{'), array('!_Doll^Ars1Az_!', '!_DoubLe^BraceS4Rw_!'), $s);
  270. }
  271. function template_unescape($s) {
  272. return str_replace(array('!_Doll^Ars1Az_!', '!_DoubLe^BraceS4Rw_!'), array('$', '{{'), $s);
  273. }