PageRenderTime 35ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/assets/tvs/multitv/includes/phx.parser.class.inc.php

https://github.com/good-web-master/modx.evo.custom
PHP | 558 lines | 498 code | 17 blank | 43 comment | 16 complexity | 9b0e417e82ae82b3db827217981263ca MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, GPL-2.0, MIT, BSD-3-Clause
  1. <?php
  2. /*####
  3. #
  4. # Name: PHx (Placeholders Xtended)
  5. # Version: 2.1.3
  6. # Modified by Nick to include external files
  7. # Author: Armand "bS" Pondman (apondman@zerobarrier.nl)
  8. # Date: July 13, 2007
  9. #
  10. ####*/
  11. class PHxParser {
  12. var $placeholders = array();
  13. function PHxParser($debug = 0, $maxpass = 50) {
  14. global $modx;
  15. $this->name = "PHx";
  16. $this->version = "2.1.3";
  17. $this->user["mgrid"] = intval($_SESSION['mgrInternalKey']);
  18. $this->user["usrid"] = intval($_SESSION['webInternalKey']);
  19. $this->user["id"] = ($this->user["usrid"] > 0) ? (-$this->user["usrid"]) : $this->user["mgrid"];
  20. $this->cache["cm"] = array();
  21. $this->cache["ui"] = array();
  22. $this->cache["mo"] = array();
  23. $this->safetags[0][0] = '~(?<![\[]|^\^)\[(?=[^\+\*\(\[]|$)~s';
  24. $this->safetags[0][1] = '~(?<=[^\+\*\)\]]|^)\](?=[^\]]|$)~s';
  25. $this->safetags[1][0] = '&_PHX_INTERNAL_091_&';
  26. $this->safetags[1][1] = '&_PHX_INTERNAL_093_&';
  27. $this->safetags[2][0] = '[';
  28. $this->safetags[2][1] = ']';
  29. $this->console = array();
  30. $this->debug = ($debug != '') ? $debug : 0;
  31. $this->debugLog = false;
  32. $this->curPass = 0;
  33. $this->maxPasses = ($maxpass != '') ? $maxpass : 50;
  34. $this->swapSnippetCache = array();
  35. $modx->setPlaceholder("phx", "&_PHX_INTERNAL_&");
  36. }
  37. // Plugin event hook for MODx
  38. function OnParseDocument() {
  39. global $modx;
  40. // Get document output from MODx
  41. $template = $modx->documentOutput;
  42. // To the parse cave .. let's go! *insert batman tune here*
  43. $template = $this->Parse($template);
  44. // Set processed document output in MODx
  45. $modx->documentOutput = $template;
  46. }
  47. // Parser: Preparation, cleaning and checkup
  48. function Parse($template = '') {
  49. global $modx;
  50. // If we already reached max passes don't get at it again.
  51. if ($this->curPass == $this->maxPasses)
  52. return $template;
  53. // Set template pre-process hash
  54. $st = md5($template);
  55. // Replace non-call characters in the template: [, ]
  56. $template = preg_replace($this->safetags[0], $this->safetags[1], $template);
  57. // To the parse mobile.. let's go! *insert batman tune here*
  58. $template = $this->ParseValues($template);
  59. // clean up unused placeholders that have modifiers attached (MODx can't clean them)
  60. preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $template, $matches);
  61. if ($matches[0]) {
  62. $template = str_replace($matches[0], '', $template);
  63. $this->Log("Cleaning unsolved tags: \n".implode("\n", $matches[2]));
  64. }
  65. // Restore non-call characters in the template: [, ]
  66. $template = str_replace($this->safetags[1], $this->safetags[2], $template);
  67. // Set template post-process hash
  68. $et = md5($template);
  69. // If template has changed, parse it once more...
  70. if ($st != $et)
  71. $template = $this->Parse($template);
  72. // Write an event log if debugging is enabled and there is something to log
  73. if ($this->debug && $this->debugLog) {
  74. $modx->logEvent($this->curPass, 1, $this->createEventLog(), $this->name.' '.$this->version);
  75. $this->debugLog = false;
  76. }
  77. // Return the processed template
  78. return $template;
  79. }
  80. // Parser: Tag detection and replacements
  81. function ParseValues($template = '') {
  82. global $modx;
  83. $this->curPass = $this->curPass + 1;
  84. $st = md5($template);
  85. //$this->LogSource($template);
  86. $this->LogPass();
  87. // MODx Chunks
  88. $this->Log("MODx Chunks -> Merging all chunk tags");
  89. $template = $modx->mergeChunkContent($template);
  90. // MODx Snippets
  91. // if (preg_match_all('~\[(\[|!)([^\[]*?)(!|\])\]~s', $template, $matches)) {
  92. if (preg_match_all('~\[(\[)([^\[]*?)(\])\]~s', $template, $matches)) {
  93. $count = count($matches[0]);
  94. $var_search = array();
  95. $var_replace = array();
  96. // for each detected snippet
  97. for ($i = 0; $i < $count; $i++) {
  98. $snippet = $matches[2][$i]; // snippet call
  99. $this->Log("MODx Snippet -> ".$snippet);
  100. // Let MODx evaluate snippet
  101. $replace = $modx->evalSnippets("[[".$snippet."]]");
  102. $this->LogSnippet($replace);
  103. // Replace values
  104. $var_search[] = $matches[0][$i];
  105. $var_replace[] = $replace;
  106. }
  107. $template = str_replace($var_search, $var_replace, $template);
  108. }
  109. // PHx / MODx Tags
  110. if (preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $template, $matches)) {
  111. //$matches[0] // Complete string that's need to be replaced
  112. //$matches[1] // Type
  113. //$matches[2] // The placeholder(s)
  114. //$matches[3] // The modifiers
  115. //$matches[4] // Type (end character)
  116. $count = count($matches[0]);
  117. $var_search = array();
  118. $var_replace = array();
  119. for ($i = 0; $i < $count; $i++) {
  120. $replace = NULL;
  121. $match = $matches[0][$i];
  122. $type = $matches[1][$i];
  123. $type_end = $matches[4][$i];
  124. $input = $matches[2][$i];
  125. $modifiers = $matches[3][$i];
  126. $var_search[] = $match;
  127. switch ($type) {
  128. // Document / Template Variable eXtended
  129. case "*": {
  130. $this->Log("MODx TV/DV: ".$input);
  131. $input = $modx->mergeDocumentContent("[*".$input."*]");
  132. $replace = $this->Filter($input, $modifiers);
  133. break;
  134. }
  135. // MODx Setting eXtended
  136. case "(": {
  137. $this->Log("MODx Setting variable: ".$input);
  138. $input = $modx->mergeSettingsContent("[(".$input.")]");
  139. $replace = $this->Filter($input, $modifiers);
  140. break;
  141. }
  142. // MODx Placeholder eXtended
  143. default: {
  144. $this->Log("MODx / PHx placeholder variable: ".$input);
  145. // Check if placeholder is set
  146. if (!array_key_exists($input, $this->placeholders) && !array_key_exists($input, $modx->placeholders)) {
  147. // not set so try again later.
  148. $replace = $match;
  149. $this->Log(" |--- Skipping - hasn't been set yet.");
  150. } else {
  151. // is set, get value and run filter
  152. $input = $this->getPHxVariable($input);
  153. $replace = $this->Filter($input, $modifiers);
  154. }
  155. break;
  156. }
  157. }
  158. $var_replace[] = $replace;
  159. }
  160. $template = str_replace($var_search, $var_replace, $template);
  161. }
  162. // Post-process template hash
  163. $et = md5($template);
  164. // Log an event if this was the maximum pass
  165. if ($this->curPass == $this->maxPasses)
  166. $this->Log("Max passes reached. infinite loop protection so exiting.\n If you need the extra passes set the max passes to the highest count of nested tags in your template.");
  167. // If this pass is not at maximum passes and the template hash is not the same, get at it again.
  168. if (($this->curPass < $this->maxPasses) && ($st != $et))
  169. $template = $this->ParseValues($template);
  170. return $template;
  171. }
  172. // Parser: modifier detection and eXtended processing if needed
  173. function Filter($input, $modifiers) {
  174. global $modx;
  175. $output = $input;
  176. $this->Log(" |--- Input = '".$output."'");
  177. if (preg_match_all('~:([^:=]+)(?:=`(.*?)`(?=:[^:=]+|$))?~s', $modifiers, $matches)) {
  178. $modifier_cmd = $matches[1]; // modifier command
  179. $modifier_value = $matches[2]; // modifier value
  180. $count = count($modifier_cmd);
  181. $condition = array();
  182. for ($i = 0; $i < $count; $i++) {
  183. $output = trim($output);
  184. $this->Log(" |--- Modifier = '".$modifier_cmd[$i]."'");
  185. if ($modifier_value[$i] != '')
  186. $this->Log(" |--- Options = '".$modifier_value[$i]."'");
  187. switch ($modifier_cmd[$i]) {
  188. ##### Conditional Modifiers
  189. case "input":
  190. case "if": {
  191. $output = $modifier_value[$i];
  192. break;
  193. }
  194. case "equals":
  195. case "is":
  196. case "eq": {
  197. $condition[] = intval(($output == $modifier_value[$i]));
  198. break;
  199. }
  200. case "notequals":
  201. case "isnot":
  202. case "isnt":
  203. case "ne": {
  204. $condition[] = intval(($output != $modifier_value[$i]));
  205. break;
  206. }
  207. case "isgreaterthan":
  208. case "isgt":
  209. case "eg": {
  210. $condition[] = intval(($output >= $modifier_value[$i]));
  211. break;
  212. }
  213. case "islowerthan":
  214. case "islt":
  215. case "el": {
  216. $condition[] = intval(($output <= $modifier_value[$i]));
  217. break;
  218. }
  219. case "greaterthan":
  220. case "gt": {
  221. $condition[] = intval(($output > $modifier_value[$i]));
  222. break;
  223. }
  224. case "lowerthan":
  225. case "lt": {
  226. $condition[] = intval(($output < $modifier_value[$i]));
  227. break;
  228. }
  229. // Is Member Of (same as inrole but this one can be stringed as a conditional)
  230. case "isinrole":
  231. case "ir":
  232. case "memberof":
  233. case "mo": {
  234. if ($output == "&_PHX_INTERNAL_&")
  235. $output = $this->user["id"];
  236. $grps = (strlen($modifier_value) > 0) ? explode(",", $modifier_value[$i]) : array();
  237. $condition[] = intval($this->isMemberOfWebGroupByUserId($output, $grps));
  238. break;
  239. }
  240. case "or": {
  241. $condition[] = "||";
  242. break;
  243. }
  244. case "and": {
  245. $condition[] = "&&";
  246. break;
  247. }
  248. case "show": {
  249. $conditional = implode(' ', $condition);
  250. $isvalid = intval(eval("return (".$conditional.");"));
  251. if (!$isvalid) {
  252. $output = NULL;
  253. }
  254. }
  255. case "then": {
  256. $conditional = implode(' ', $condition);
  257. $isvalid = intval(eval("return (".$conditional.");"));
  258. if ($isvalid) {
  259. $output = $modifier_value[$i];
  260. } else {
  261. $output = NULL;
  262. }
  263. break;
  264. }
  265. case "else": {
  266. $conditional = implode(' ', $condition);
  267. $isvalid = intval(eval("return (".$conditional.");"));
  268. if (!$isvalid) {
  269. $output = $modifier_value[$i];
  270. }
  271. break;
  272. }
  273. case "select": {
  274. $raw = explode("&", $modifier_value[$i]);
  275. $map = array();
  276. for ($m = 0; $m < (count($raw)); $m++) {
  277. $mi = explode("=", $raw[$m]);
  278. $map[$mi[0]] = $mi[1];
  279. }
  280. $output = $map[$output];
  281. break;
  282. }
  283. ##### End of Conditional Modifiers
  284. ##### String Modifiers
  285. case "lcase": {
  286. $output = strtolower($output);
  287. break;
  288. }
  289. case "ucase": {
  290. $output = strtoupper($output);
  291. break;
  292. }
  293. case "ucfirst": {
  294. $output = ucfirst($output);
  295. break;
  296. }
  297. case "htmlent": {
  298. $output = htmlentities($output, ENT_QUOTES, $modx->config['etomite_charset']);
  299. break;
  300. }
  301. case "esc": {
  302. $output = preg_replace("/&amp;(#[0-9]+|[a-z]+);/i", "&$1;", htmlspecialchars($output));
  303. $output = str_replace(array("[", "]", "`"), array("&#91;", "&#93;", "&#96;"), $output);
  304. break;
  305. }
  306. case "strip": {
  307. $output = preg_replace("~([\n\r\t\s]+)~", " ", $output);
  308. break;
  309. }
  310. case "notags": {
  311. $output = strip_tags($output);
  312. break;
  313. }
  314. case "length":
  315. case "len": {
  316. $output = strlen($output);
  317. break;
  318. }
  319. case "reverse": {
  320. $output = strrev($output);
  321. break;
  322. }
  323. case "wordwrap": { // default: 70
  324. $wrapat = intval($modifier_value[$i]) ? intval($modifier_value[$i]) : 70;
  325. $output = preg_replace("~(\b\w+\b)~e", "wordwrap('\\1',\$wrapat,' ',1)", $output);
  326. break;
  327. }
  328. case "limit": { // default: 100
  329. $limit = intval($modifier_value[$i]) ? intval($modifier_value[$i]) : 100;
  330. $output = substr($output, 0, $limit);
  331. break;
  332. }
  333. ##### Special functions
  334. case "math": {
  335. $filter = preg_replace("~([a-zA-Z\n\r\t\s])~", "", $modifier_value[$i]);
  336. $filter = str_replace("?", $output, $filter);
  337. $output = eval("return ".$filter.";");
  338. break;
  339. }
  340. case "ifempty": {
  341. if ( empty($output))
  342. $output = $modifier_value[$i];
  343. break;
  344. }
  345. case "nl2br": {
  346. $output = nl2br($output);
  347. break;
  348. }
  349. case "date": {
  350. $output = strftime($modifier_value[$i], 0 + $output);
  351. break;
  352. }
  353. case "set": {
  354. $c = $i + 1;
  355. if ($count > $c && $modifier_cmd[$c] == "value")
  356. $output = preg_replace("~([^a-zA-Z0-9])~", "", $modifier_value[$i]);
  357. break;
  358. }
  359. case "value": {
  360. if ($i > 0 && $modifier_cmd[$i - 1] == "set") {
  361. $modx->SetPlaceholder("phx.".$output, $modifier_value[$i]);
  362. }
  363. $output = NULL;
  364. break;
  365. }
  366. case "md5": {
  367. $output = md5($output);
  368. break;
  369. }
  370. case "userinfo": {
  371. if ($output == "&_PHX_INTERNAL_&")
  372. $output = $this->user["id"];
  373. $output = $this->ModUser($output, $modifier_value[$i]);
  374. break;
  375. }
  376. case "inrole": { // deprecated
  377. if ($output == "&_PHX_INTERNAL_&")
  378. $output = $this->user["id"];
  379. $grps = (strlen($modifier_value) > 0) ? explode(",", $modifier_value[$i]) : array();
  380. $output = intval($this->isMemberOfWebGroupByUserId($output, $grps));
  381. break;
  382. }
  383. default: {
  384. if (!array_key_exists($modifier_cmd[$i], $this->cache["cm"])) {
  385. $sql = "SELECT snippet FROM ".$modx->getFullTableName("site_snippets")." WHERE ".$modx->getFullTableName("site_snippets").".name='phx:".$modifier_cmd[$i]."';";
  386. $result = $modx->dbQuery($sql);
  387. if ($modx->recordCount($result) == 1) {
  388. $row = $modx->fetchRow($result);
  389. $cm = $this->cache["cm"][$modifier_cmd[$i]] = $row["snippet"];
  390. $this->Log(" |--- DB -> Custom Modifier");
  391. } else if ($modx->recordCount($result) == 0) { // If snippet not found, look in the modifiers folder
  392. $filename = $modx->config['rb_base_dir'].'plugins/phx/modifiers/'.$modifier_cmd[$i].'.phx.php';
  393. //add by Bruno
  394. $filename = ($GLOBALS['blox_path']) ? $modx->config['base_path'].$GLOBALS['blox_path'].'chunkie/modifiers/'.$modifier_cmd[$i].'.phx.php' : $filename;
  395. //echo $filename;
  396. if (@file_exists($filename)) {
  397. $file_contents = @file_get_contents($filename);
  398. $file_contents = str_replace('<?php', '', $file_contents);
  399. $file_contents = str_replace('?'.'>', '', $file_contents);
  400. $file_contents = str_replace('<'.'?', '', $file_contents);
  401. $cm = $this->cache["cm"][$modifier_cmd[$i]] = $file_contents;
  402. $this->Log(" |--- File ($filename) -> Custom Modifier");
  403. }
  404. }
  405. } else {
  406. $cm = $this->cache["cm"][$modifier_cmd[$i]];
  407. $this->Log(" |--- Cache -> Custom Modifier");
  408. }
  409. ob_start();
  410. $options = $modifier_value[$i];
  411. $custom = eval($cm);
  412. $msg = ob_get_contents();
  413. $output = $msg.$custom;
  414. ob_end_clean();
  415. break;
  416. }
  417. }
  418. if (count($condition))
  419. $this->Log(" |--- Condition = '".$condition[count($condition) - 1]."'");
  420. $this->Log(" |--- Output = '".$output."'");
  421. }
  422. }
  423. return $output;
  424. }
  425. // Event logging (debug)
  426. function createEventLog() {
  427. if ($this->console) {
  428. $console = implode("\n", $this->console);
  429. $this->console = array();
  430. return ' < pre style = "overflow: auto;" > '.$console.' < / pre > ';
  431. }
  432. }
  433. // Returns a cleaned string escaping the HTML and special MODx characters
  434. function LogClean($string) {
  435. $string = preg_replace("/&amp;(#[0-9]+|[a-z]+);/i", "&$1;", htmlspecialchars($string));
  436. $string = str_replace(array("[", "]", "`"), array("&#91;", "&#93;", "&#96;"), $string);
  437. return $string;
  438. }
  439. // Simple log entry
  440. function Log($string) {
  441. if ($this->debug) {
  442. $this->debugLog = true;
  443. $this->console[] = (count($this->console) + 1 - $this->curPass)." [".strftime("%H:%M:%S", time())."] ".$this->LogClean($string);
  444. }
  445. }
  446. // Log snippet output
  447. function LogSnippet($string) {
  448. if ($this->debug) {
  449. $this->debugLog = true;
  450. $this->console[] = (count($this->console) + 1 - $this->curPass)." [".strftime("%H:%M:%S", time())."] "." |--- Returns: <div style='margin: 10px;'>".$this->LogClean($string)."</div>";
  451. }
  452. }
  453. // Log pass
  454. function LogPass() {
  455. $this->console[] = "<div style='margin: 2px; margin-top: 5px; border-bottom: 1px solid black;'>Pass ".$this->curPass."</div>";
  456. }
  457. // Log pass
  458. function LogSource($string) {
  459. $this->console[] = "<div style='margin: 2px; margin-top: 5px; border-bottom: 1px solid black;'>Source:</div>".$this->LogClean($string);
  460. }
  461. // Returns the specified field from the user record
  462. // positive userid = manager, negative integer = webuser
  463. function ModUser($userid, $field) {
  464. global $modx;
  465. if (!array_key_exists($userid, $this->cache["ui"])) {
  466. if (intval($userid) < 0) {
  467. $user = $modx->getWebUserInfo(-($userid));
  468. } else {
  469. $user = $modx->getUserInfo($userid);
  470. }
  471. $this->cache["ui"][$userid] = $user;
  472. } else {
  473. $user = $this->cache["ui"][$userid];
  474. }
  475. return $user[$field];
  476. }
  477. // Returns true if the user id is in one the specified webgroups
  478. function isMemberOfWebGroupByUserId($userid = 0, $groupNames = array()) {
  479. global $modx;
  480. // if $groupNames is not an array return false
  481. if (!is_array($groupNames))
  482. return false;
  483. // if the user id is a negative number make it positive
  484. if (intval($userid) < 0) {
  485. $userid = -($userid);
  486. }
  487. // Creates an array with all webgroups the user id is in
  488. if (!array_key_exists($userid, $this->cache["mo"])) {
  489. $tbl = $modx->getFullTableName("webgroup_names");
  490. $tbl2 = $modx->getFullTableName("web_groups");
  491. $sql = "SELECT wgn.name FROM $tbl wgn INNER JOIN $tbl2 wg ON wg.webgroup=wgn.id AND wg.webuser='".$userid."'";
  492. $this->cache["mo"][$userid] = $grpNames = $modx->db->getColumn("name", $sql);
  493. } else {
  494. $grpNames = $this->cache["mo"][$userid];
  495. }
  496. // Check if a supplied group matches a webgroup from the array we just created
  497. foreach ($groupNames as $k=>$v)
  498. if (in_array(trim($v), $grpNames))
  499. return true;
  500. // If we get here the above logic did not find a match, so return false
  501. return false;
  502. }
  503. // Returns the value of a PHx/MODx placeholder.
  504. function getPHxVariable($name) {
  505. global $modx;
  506. // Check if this variable is created by PHx
  507. if (array_key_exists($name, $this->placeholders)) {
  508. // Return the value from PHx
  509. return $this->placeholders[$name];
  510. } else {
  511. // Return the value from MODx
  512. return $modx->getPlaceholder($name);
  513. }
  514. }
  515. // Sets a placeholder variable which can only be access by PHx
  516. function setPHxVariable($name, $value) {
  517. if ($name != "phx")
  518. $this->placeholders[$name] = $value;
  519. }
  520. }
  521. ?>