PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/manager/includes/document.parser.class.inc.php

https://github.com/garryn/evolution
PHP | 2829 lines | 2372 code | 212 blank | 245 comment | 579 complexity | 4ee03fedd56977f867addd2714f4aa53 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * MODx Document Parser
  4. * Function: This class contains the main document parsing functions
  5. *
  6. */
  7. class DocumentParser {
  8. var $db; // db object
  9. var $event, $Event; // event object
  10. var $pluginEvent;
  11. var $config= null;
  12. var $rs, $result, $sql, $table_prefix, $debug, $documentIdentifier, $documentMethod, $documentGenerated, $documentContent, $tstart, $minParserPasses, $maxParserPasses, $documentObject, $templateObject, $snippetObjects, $stopOnNotice, $executedQueries, $queryTime, $currentSnippet, $documentName, $aliases, $visitor, $entrypage, $documentListing, $dumpSnippets, $chunkCache, $snippetCache, $contentTypes, $dumpSQL, $queryCode, $virtualDir, $placeholders, $sjscripts, $jscripts, $loadedjscripts, $documentMap;
  13. var $forwards= 3;
  14. // constructor
  15. function DocumentParser() {
  16. $this->loadExtension('DBAPI') or die('Could not load DBAPI class.'); // load DBAPI class
  17. $this->dbConfig= & $this->db->config; // alias for backward compatibility
  18. $this->jscripts= array ();
  19. $this->sjscripts= array ();
  20. $this->loadedjscripts= array ();
  21. // events
  22. $this->event= new SystemEvent();
  23. $this->Event= & $this->event; //alias for backward compatibility
  24. $this->pluginEvent= array ();
  25. // set track_errors ini variable
  26. @ ini_set("track_errors", "1"); // enable error tracking in $php_errormsg
  27. }
  28. // loads an extension from the extenders folder
  29. function loadExtension($extname) {
  30. global $database_type;
  31. switch ($extname) {
  32. // Database API
  33. case 'DBAPI' :
  34. if (!include_once MODX_BASE_PATH . 'manager/includes/extenders/dbapi.' . $database_type . '.class.inc.php')
  35. return false;
  36. $this->db= new DBAPI;
  37. return true;
  38. break;
  39. // Manager API
  40. case 'ManagerAPI' :
  41. if (!include_once MODX_BASE_PATH . 'manager/includes/extenders/manager.api.class.inc.php')
  42. return false;
  43. $this->manager= new ManagerAPI;
  44. return true;
  45. break;
  46. default :
  47. return false;
  48. }
  49. }
  50. function getMicroTime() {
  51. list ($usec, $sec)= explode(' ', microtime());
  52. return ((float) $usec + (float) $sec);
  53. }
  54. function sendRedirect($url, $count_attempts= 0, $type= '', $responseCode= '') {
  55. if (empty ($url)) {
  56. return false;
  57. } else {
  58. if ($count_attempts == 1) {
  59. // append the redirect count string to the url
  60. $currentNumberOfRedirects= isset ($_REQUEST['err']) ? $_REQUEST['err'] : 0;
  61. if ($currentNumberOfRedirects > 3) {
  62. $this->messageQuit('Redirection attempt failed - please ensure the document you\'re trying to redirect to exists. <p>Redirection URL: <i>' . $url . '</i></p>');
  63. } else {
  64. $currentNumberOfRedirects += 1;
  65. if (strpos($url, "?") > 0) {
  66. $url .= "&err=$currentNumberOfRedirects";
  67. } else {
  68. $url .= "?err=$currentNumberOfRedirects";
  69. }
  70. }
  71. }
  72. if ($type == 'REDIRECT_REFRESH') {
  73. $header= 'Refresh: 0;URL=' . $url;
  74. }
  75. elseif ($type == 'REDIRECT_META') {
  76. $header= '<META HTTP-EQUIV="Refresh" CONTENT="0; URL=' . $url . '" />';
  77. echo $header;
  78. exit;
  79. }
  80. elseif ($type == 'REDIRECT_HEADER' || empty ($type)) {
  81. // check if url has /$base_url
  82. global $base_url, $site_url;
  83. if (substr($url, 0, strlen($base_url)) == $base_url) {
  84. // append $site_url to make it work with Location:
  85. $url= $site_url . substr($url, strlen($base_url));
  86. }
  87. if (strpos($url, "\n") === false) {
  88. $header= 'Location: ' . $url;
  89. } else {
  90. $this->messageQuit('No newline allowed in redirect url.');
  91. }
  92. }
  93. if ($responseCode && (strpos($responseCode, '30') !== false)) {
  94. header($responseCode);
  95. }
  96. header($header);
  97. exit();
  98. }
  99. }
  100. function sendForward($id, $responseCode= '') {
  101. if ($this->forwards > 0) {
  102. $this->forwards= $this->forwards - 1;
  103. $this->documentIdentifier= $id;
  104. $this->documentMethod= 'id';
  105. $this->documentObject= $this->getDocumentObject('id', $id);
  106. if ($responseCode) {
  107. header($responseCode);
  108. }
  109. $this->prepareResponse();
  110. exit();
  111. } else {
  112. header('HTTP/1.0 500 Internal Server Error');
  113. die('<h1>ERROR: Too many forward attempts!</h1><p>The request could not be completed due to too many unsuccessful forward attempts.</p>');
  114. }
  115. }
  116. function sendErrorPage() {
  117. // invoke OnPageNotFound event
  118. $this->invokeEvent('OnPageNotFound');
  119. // $this->sendRedirect($this->makeUrl($this->config['error_page'], '', '&refurl=' . urlencode($_SERVER['PHP_SELF'] . '?' . $_SERVER['QUERY_STRING'])), 1);
  120. $this->sendForward($this->config['error_page'] ? $this->config['error_page'] : $this->config['site_start'], 'HTTP/1.0 404 Not Found');
  121. exit();
  122. }
  123. function sendUnauthorizedPage() {
  124. // invoke OnPageUnauthorized event
  125. $_REQUEST['refurl'] = $this->documentIdentifier;
  126. $this->invokeEvent('OnPageUnauthorized');
  127. if ($this->config['unauthorized_page']) {
  128. $unauthorizedPage= $this->config['unauthorized_page'];
  129. } elseif ($this->config['error_page']) {
  130. $unauthorizedPage= $this->config['error_page'];
  131. } else {
  132. $unauthorizedPage= $this->config['site_start'];
  133. }
  134. $this->sendForward($unauthorizedPage, 'HTTP/1.1 401 Unauthorized');
  135. exit();
  136. }
  137. // function to connect to the database
  138. // - deprecated use $modx->db->connect()
  139. function dbConnect() {
  140. $this->db->connect();
  141. $this->rs= $this->db->conn; // for compatibility
  142. }
  143. // function to query the database
  144. // - deprecated use $modx->db->query()
  145. function dbQuery($sql) {
  146. return $this->db->query($sql);
  147. }
  148. // function to count the number of rows in a record set
  149. function recordCount($rs) {
  150. return $this->db->getRecordCount($rs);
  151. }
  152. // - deprecated, use $modx->db->getRow()
  153. function fetchRow($rs, $mode= 'assoc') {
  154. return $this->db->getRow($rs, $mode);
  155. }
  156. // - deprecated, use $modx->db->getAffectedRows()
  157. function affectedRows($rs) {
  158. return $this->db->getAffectedRows($rs);
  159. }
  160. // - deprecated, use $modx->db->getInsertId()
  161. function insertId($rs) {
  162. return $this->db->getInsertId($rs);
  163. }
  164. // function to close a database connection
  165. // - deprecated, use $modx->db->disconnect()
  166. function dbClose() {
  167. $this->db->disconnect();
  168. }
  169. function getSettings() {
  170. if (!is_array($this->config) || empty ($this->config)) {
  171. if ($included= file_exists(MODX_BASE_PATH . 'assets/cache/siteCache.idx.php')) {
  172. $included= include_once (MODX_BASE_PATH . 'assets/cache/siteCache.idx.php');
  173. }
  174. if (!$included) {
  175. $result= $this->dbQuery('SELECT setting_name, setting_value FROM ' . $this->getFullTableName('system_settings'));
  176. while ($row= $this->fetchRow($result, 'both')) {
  177. $this->config[$row[0]]= $row[1];
  178. }
  179. }
  180. // added for backwards compatibility - garry FS#104
  181. $this->config['etomite_charset'] = & $this->config['modx_charset'];
  182. // store base_url and base_path inside config array
  183. $this->config['base_url']= MODX_BASE_URL;
  184. $this->config['base_path']= MODX_BASE_PATH;
  185. $this->config['site_url']= MODX_SITE_URL;
  186. // load user setting if user is logged in
  187. $usrSettings= array ();
  188. if ($id= $this->getLoginUserID()) {
  189. $usrType= $this->getLoginUserType();
  190. if (isset ($usrType) && $usrType == 'manager')
  191. $usrType= 'mgr';
  192. if ($usrType == 'mgr' && $this->isBackend()) {
  193. // invoke the OnBeforeManagerPageInit event, only if in backend
  194. $this->invokeEvent("OnBeforeManagerPageInit");
  195. }
  196. if (isset ($_SESSION[$usrType . 'UsrConfigSet'])) {
  197. $usrSettings= & $_SESSION[$usrType . 'UsrConfigSet'];
  198. } else {
  199. if ($usrType == 'web')
  200. $query= $this->getFullTableName('web_user_settings') . ' WHERE webuser=\'' . $id . '\'';
  201. else
  202. $query= $this->getFullTableName('user_settings') . ' WHERE user=\'' . $id . '\'';
  203. $result= $this->dbQuery('SELECT setting_name, setting_value FROM ' . $query);
  204. while ($row= $this->fetchRow($result, 'both'))
  205. $usrSettings[$row[0]]= $row[1];
  206. if (isset ($usrType))
  207. $_SESSION[$usrType . 'UsrConfigSet']= $usrSettings; // store user settings in session
  208. }
  209. }
  210. if ($this->isFrontend() && $mgrid= $this->getLoginUserID('mgr')) {
  211. $musrSettings= array ();
  212. if (isset ($_SESSION['mgrUsrConfigSet'])) {
  213. $musrSettings= & $_SESSION['mgrUsrConfigSet'];
  214. } else {
  215. $query= $this->getFullTableName('user_settings') . ' WHERE user=\'' . $mgrid . '\'';
  216. if ($result= $this->dbQuery('SELECT setting_name, setting_value FROM ' . $query)) {
  217. while ($row= $this->fetchRow($result, 'both')) {
  218. $usrSettings[$row[0]]= $row[1];
  219. }
  220. $_SESSION['mgrUsrConfigSet']= $musrSettings; // store user settings in session
  221. }
  222. }
  223. if (!empty ($musrSettings)) {
  224. $usrSettings= array_merge($musrSettings, $usrSettings);
  225. }
  226. }
  227. $this->config= array_merge($this->config, $usrSettings);
  228. }
  229. }
  230. function getDocumentMethod() {
  231. // function to test the query and find the retrieval method
  232. if (isset ($_REQUEST['q'])) {
  233. return "alias";
  234. }
  235. elseif (isset ($_REQUEST['id'])) {
  236. return "id";
  237. } else {
  238. return "none";
  239. }
  240. }
  241. function getDocumentIdentifier($method) {
  242. // function to test the query and find the retrieval method
  243. $docIdentifier= $this->config['site_start'];
  244. switch ($method) {
  245. case 'alias' :
  246. $docIdentifier= $this->db->escape($_REQUEST['q']);
  247. break;
  248. case 'id' :
  249. if (!is_numeric($_REQUEST['id'])) {
  250. $this->sendErrorPage();
  251. } else {
  252. $docIdentifier= intval($_REQUEST['id']);
  253. }
  254. break;
  255. }
  256. return $docIdentifier;
  257. }
  258. // check for manager login session
  259. function checkSession() {
  260. if (isset ($_SESSION['mgrValidated'])) {
  261. return true;
  262. } else {
  263. return false;
  264. }
  265. }
  266. function checkPreview() {
  267. if ($this->checkSession() == true) {
  268. if (isset ($_REQUEST['z']) && $_REQUEST['z'] == 'manprev') {
  269. return true;
  270. } else {
  271. return false;
  272. }
  273. } else {
  274. return false;
  275. }
  276. }
  277. // check if site is offline
  278. function checkSiteStatus() {
  279. $siteStatus= $this->config['site_status'];
  280. if ($siteStatus == 1) {
  281. // site online
  282. return true;
  283. }
  284. elseif ($siteStatus == 0 && $this->checkSession()) {
  285. // site offline but launched via the manager
  286. return true;
  287. } else {
  288. // site is offline
  289. return false;
  290. }
  291. }
  292. function cleanDocumentIdentifier($qOrig) {
  293. (!empty($qOrig)) or $qOrig = $this->config['site_start'];
  294. $q= $qOrig;
  295. /* First remove any / before or after */
  296. if ($q[strlen($q) - 1] == '/')
  297. $q= substr($q, 0, -1);
  298. if ($q[0] == '/')
  299. $q= substr($q, 1);
  300. /* Save path if any */
  301. /* FS#476 and FS#308: only return virtualDir if friendly paths are enabled */
  302. if ($this->config['use_alias_path'] == 1) {
  303. $this->virtualDir= dirname($q);
  304. $this->virtualDir= ($this->virtualDir == '.' ? '' : $this->virtualDir);
  305. $q= basename($q);
  306. } else {
  307. $this->virtualDir= '';
  308. }
  309. $q= str_replace($this->config['friendly_url_prefix'], "", $q);
  310. $q= str_replace($this->config['friendly_url_suffix'], "", $q);
  311. if (is_numeric($q) && !$this->documentListing[$q]) { /* we got an ID returned, check to make sure it's not an alias */
  312. /* FS#476 and FS#308: check that id is valid in terms of virtualDir structure */
  313. if ($this->config['use_alias_path'] == 1) {
  314. if ((($this->virtualDir != '' && !$this->documentListing[$this->virtualDir . '/' . $q]) || ($this->virtualDir == '' && !$this->documentListing[$q])) && (($this->virtualDir != '' && in_array($q, $this->getChildIds($this->documentListing[$this->virtualDir], 1))) || ($this->virtualDir == '' && in_array($q, $this->getChildIds(0, 1))))) {
  315. $this->documentMethod= 'id';
  316. return $q;
  317. } else { /* not a valid id in terms of virtualDir, treat as alias */
  318. $this->documentMethod= 'alias';
  319. return $q;
  320. }
  321. } else {
  322. $this->documentMethod= 'id';
  323. return $q;
  324. }
  325. } else { /* we didn't get an ID back, so instead we assume it's an alias */
  326. if ($this->config['friendly_alias_urls'] != 1) {
  327. $q= $qOrig;
  328. }
  329. $this->documentMethod= 'alias';
  330. return $q;
  331. }
  332. }
  333. function checkCache($id) {
  334. $cacheFile= "assets/cache/docid_" . $id . ".pageCache.php";
  335. if (file_exists($cacheFile)) {
  336. $this->documentGenerated= 0;
  337. $flContent= implode("", file($cacheFile));
  338. $flContent= substr($flContent, 37); // remove php header
  339. $a= explode("<!--__MODxCacheSpliter__-->", $flContent, 2);
  340. if (count($a) == 1)
  341. return $a[0]; // return only document content
  342. else {
  343. $docObj= unserialize($a[0]); // rebuild document object
  344. // check page security
  345. if ($docObj['privateweb'] && isset ($docObj['__MODxDocGroups__'])) {
  346. $pass= false;
  347. $usrGrps= $this->getUserDocGroups();
  348. $docGrps= explode(",", $docObj['__MODxDocGroups__']);
  349. // check is user has access to doc groups
  350. if (is_array($usrGrps)) {
  351. foreach ($usrGrps as $k => $v)
  352. if (in_array($v, $docGrps)) {
  353. $pass= true;
  354. break;
  355. }
  356. }
  357. // diplay error pages if user has no access to cached doc
  358. if (!$pass) {
  359. if ($this->config['unauthorized_page']) {
  360. // check if file is not public
  361. $tbldg= $this->getFullTableName("document_groups");
  362. $secrs= $this->dbQuery("SELECT id FROM $tbldg WHERE document = '" . $id . "' LIMIT 1;");
  363. if ($secrs)
  364. $seclimit= mysql_num_rows($secrs);
  365. }
  366. if ($seclimit > 0) {
  367. // match found but not publicly accessible, send the visitor to the unauthorized_page
  368. $this->sendUnauthorizedPage();
  369. exit; // stop here
  370. } else {
  371. // no match found, send the visitor to the error_page
  372. $this->sendErrorPage();
  373. exit; // stop here
  374. }
  375. }
  376. }
  377. // Grab the Scripts
  378. if (isset($docObj['__MODxSJScripts__'])) $this->sjscripts = $docObj['__MODxSJScripts__'];
  379. if (isset($docObj['__MODxJScripts__'])) $this->jscripts = $docObj['__MODxJScripts__'];
  380. // Remove intermediate variables
  381. unset($docObj['__MODxDocGroups__'], $docObj['__MODxSJScripts__'], $docObj['__MODxJScripts__']);
  382. $this->documentObject= $docObj;
  383. return $a[1]; // return document content
  384. }
  385. } else {
  386. $this->documentGenerated= 1;
  387. return "";
  388. }
  389. }
  390. function outputContent($noEvent= false) {
  391. $this->documentOutput= $this->documentContent;
  392. if ($this->documentGenerated == 1 && $this->documentObject['cacheable'] == 1 && $this->documentObject['type'] == 'document' && $this->documentObject['published'] == 1) {
  393. if (!empty($this->sjscripts)) $this->documentObject['__MODxSJScripts__'] = $this->sjscripts;
  394. if (!empty($this->jscripts)) $this->documentObject['__MODxJScripts__'] = $this->jscripts;
  395. }
  396. // check for non-cached snippet output
  397. if (strpos($this->documentOutput, '[!') > -1) {
  398. $this->documentOutput= str_replace('[!', '[[', $this->documentOutput);
  399. $this->documentOutput= str_replace('!]', ']]', $this->documentOutput);
  400. // Parse document source
  401. $this->documentOutput= $this->parseDocumentSource($this->documentOutput);
  402. }
  403. // Moved from prepareResponse() by sirlancelot
  404. // Insert Startup jscripts & CSS scripts into template - template must have a <head> tag
  405. if ($js= $this->getRegisteredClientStartupScripts()) {
  406. // change to just before closing </head>
  407. // $this->documentContent = preg_replace("/(<head[^>]*>)/i", "\\1\n".$js, $this->documentContent);
  408. $this->documentOutput= preg_replace("/(<\/head>)/i", $js . "\n\\1", $this->documentOutput);
  409. }
  410. // Insert jscripts & html block into template - template must have a </body> tag
  411. if ($js= $this->getRegisteredClientScripts()) {
  412. $this->documentOutput= preg_replace("/(<\/body>)/i", $js . "\n\\1", $this->documentOutput);
  413. }
  414. // End fix by sirlancelot
  415. // remove all unused placeholders
  416. if (strpos($this->documentOutput, '[+') > -1) {
  417. $matches= array ();
  418. preg_match_all('~\[\+(.*?)\+\]~', $this->documentOutput, $matches);
  419. if ($matches[0])
  420. $this->documentOutput= str_replace($matches[0], '', $this->documentOutput);
  421. }
  422. $this->documentOutput= $this->rewriteUrls($this->documentOutput);
  423. // send out content-type and content-disposition headers
  424. if (IN_PARSER_MODE == "true") {
  425. $type= !empty ($this->contentTypes[$this->documentIdentifier]) ? $this->contentTypes[$this->documentIdentifier] : "text/html";
  426. header('Content-Type: ' . $type . '; charset=' . $this->config['modx_charset']);
  427. // if (($this->documentIdentifier == $this->config['error_page']) || $redirect_error)
  428. // header('HTTP/1.0 404 Not Found');
  429. if (!$this->checkPreview() && $this->documentObject['content_dispo'] == 1) {
  430. if ($this->documentObject['alias'])
  431. $name= $this->documentObject['alias'];
  432. else {
  433. // strip title of special characters
  434. $name= $this->documentObject['pagetitle'];
  435. $name= strip_tags($name);
  436. $name= strtolower($name);
  437. $name= preg_replace('/&.+?;/', '', $name); // kill entities
  438. $name= preg_replace('/[^\.%a-z0-9 _-]/', '', $name);
  439. $name= preg_replace('/\s+/', '-', $name);
  440. $name= preg_replace('|-+|', '-', $name);
  441. $name= trim($name, '-');
  442. }
  443. $header= 'Content-Disposition: attachment; filename=' . $name;
  444. header($header);
  445. }
  446. }
  447. $totalTime= ($this->getMicroTime() - $this->tstart);
  448. $queryTime= $this->queryTime;
  449. $phpTime= $totalTime - $queryTime;
  450. $queryTime= sprintf("%2.4f s", $queryTime);
  451. $totalTime= sprintf("%2.4f s", $totalTime);
  452. $phpTime= sprintf("%2.4f s", $phpTime);
  453. $source= $this->documentGenerated == 1 ? "database" : "cache";
  454. $queries= isset ($this->executedQueries) ? $this->executedQueries : 0;
  455. $out =& $this->documentOutput;
  456. if ($this->dumpSQL) {
  457. $out .= $this->queryCode;
  458. }
  459. $out= str_replace("[^q^]", $queries, $out);
  460. $out= str_replace("[^qt^]", $queryTime, $out);
  461. $out= str_replace("[^p^]", $phpTime, $out);
  462. $out= str_replace("[^t^]", $totalTime, $out);
  463. $out= str_replace("[^s^]", $source, $out);
  464. //$this->documentOutput= $out;
  465. // invoke OnWebPagePrerender event
  466. if (!$noEvent) {
  467. $this->invokeEvent("OnWebPagePrerender");
  468. }
  469. echo $this->documentOutput;
  470. ob_end_flush();
  471. }
  472. function checkPublishStatus() {
  473. $cacheRefreshTime= 0;
  474. @include $this->config["base_path"] . "assets/cache/sitePublishing.idx.php";
  475. $timeNow= time() + $this->config['server_offset_time'];
  476. if ($cacheRefreshTime <= $timeNow && $cacheRefreshTime != 0) {
  477. // now, check for documents that need publishing
  478. $sql = "UPDATE ".$this->getFullTableName("site_content")." SET published=1, publishedon=".time()." WHERE ".$this->getFullTableName("site_content").".pub_date <= $timeNow AND ".$this->getFullTableName("site_content").".pub_date!=0 AND published=0";
  479. if (@ !$result= $this->dbQuery($sql)) {
  480. $this->messageQuit("Execution of a query to the database failed", $sql);
  481. }
  482. // now, check for documents that need un-publishing
  483. $sql= "UPDATE " . $this->getFullTableName("site_content") . " SET published=0, publishedon=0 WHERE " . $this->getFullTableName("site_content") . ".unpub_date <= $timeNow AND " . $this->getFullTableName("site_content") . ".unpub_date!=0 AND published=1";
  484. if (@ !$result= $this->dbQuery($sql)) {
  485. $this->messageQuit("Execution of a query to the database failed", $sql);
  486. }
  487. // clear the cache
  488. $basepath= $this->config["base_path"] . "assets/cache/";
  489. if ($handle= opendir($basepath)) {
  490. $filesincache= 0;
  491. $deletedfilesincache= 0;
  492. while (false !== ($file= readdir($handle))) {
  493. if ($file != "." && $file != "..") {
  494. $filesincache += 1;
  495. if (preg_match("/\.pageCache/", $file)) {
  496. $deletedfilesincache += 1;
  497. while (!unlink($basepath . "/" . $file));
  498. }
  499. }
  500. }
  501. closedir($handle);
  502. }
  503. // update publish time file
  504. $timesArr= array ();
  505. $sql= "SELECT MIN(pub_date) AS minpub FROM " . $this->getFullTableName("site_content") . " WHERE pub_date>$timeNow";
  506. if (@ !$result= $this->dbQuery($sql)) {
  507. $this->messageQuit("Failed to find publishing timestamps", $sql);
  508. }
  509. $tmpRow= $this->fetchRow($result);
  510. $minpub= $tmpRow['minpub'];
  511. if ($minpub != NULL) {
  512. $timesArr[]= $minpub;
  513. }
  514. $sql= "SELECT MIN(unpub_date) AS minunpub FROM " . $this->getFullTableName("site_content") . " WHERE unpub_date>$timeNow";
  515. if (@ !$result= $this->dbQuery($sql)) {
  516. $this->messageQuit("Failed to find publishing timestamps", $sql);
  517. }
  518. $tmpRow= $this->fetchRow($result);
  519. $minunpub= $tmpRow['minunpub'];
  520. if ($minunpub != NULL) {
  521. $timesArr[]= $minunpub;
  522. }
  523. if (count($timesArr) > 0) {
  524. $nextevent= min($timesArr);
  525. } else {
  526. $nextevent= 0;
  527. }
  528. $basepath= $this->config["base_path"] . "assets/cache";
  529. $fp= @ fopen($basepath . "/sitePublishing.idx.php", "wb");
  530. if ($fp) {
  531. @ flock($fp, LOCK_EX);
  532. @ fwrite($fp, "<?php \$cacheRefreshTime=$nextevent; ?>");
  533. @ flock($fp, LOCK_UN);
  534. @ fclose($fp);
  535. }
  536. }
  537. }
  538. function postProcess() {
  539. // if the current document was generated, cache it!
  540. if ($this->documentGenerated == 1 && $this->documentObject['cacheable'] == 1 && $this->documentObject['type'] == 'document' && $this->documentObject['published'] == 1) {
  541. $basepath= $this->config["base_path"] . "assets/cache";
  542. // invoke OnBeforeSaveWebPageCache event
  543. $this->invokeEvent("OnBeforeSaveWebPageCache");
  544. if ($fp= @ fopen($basepath . "/docid_" . $this->documentIdentifier . ".pageCache.php", "w")) {
  545. // get and store document groups inside document object. Document groups will be used to check security on cache pages
  546. $sql= "SELECT document_group FROM " . $this->getFullTableName("document_groups") . " WHERE document='" . $this->documentIdentifier . "'";
  547. $docGroups= $this->db->getColumn("document_group", $sql);
  548. // Attach Document Groups and Scripts
  549. if (is_array($docGroups)) $this->documentObject['__MODxDocGroups__'] = implode(",", $docGroups);
  550. $docObjSerial= serialize($this->documentObject);
  551. $cacheContent= $docObjSerial . "<!--__MODxCacheSpliter__-->" . $this->documentContent;
  552. fputs($fp, "<?php die('Unauthorized access.'); ?>$cacheContent");
  553. fclose($fp);
  554. }
  555. }
  556. // Useful for example to external page counters/stats packages
  557. $this->invokeEvent('OnWebPageComplete');
  558. // end post processing
  559. }
  560. function mergeDocumentMETATags($template) {
  561. if ($this->documentObject['haskeywords'] == 1) {
  562. // insert keywords
  563. $keywords = $this->getKeywords();
  564. if (is_array($keywords) && count($keywords) > 0) {
  565. $keywords = implode(", ", $keywords);
  566. $metas= "\t<meta name=\"keywords\" content=\"$keywords\" />\n";
  567. }
  568. // Don't process when cached
  569. $this->documentObject['haskeywords'] = '0';
  570. }
  571. if ($this->documentObject['hasmetatags'] == 1) {
  572. // insert meta tags
  573. $tags= $this->getMETATags();
  574. foreach ($tags as $n => $col) {
  575. $tag= strtolower($col['tag']);
  576. $tagvalue= $col['tagvalue'];
  577. $tagstyle= $col['http_equiv'] ? 'http-equiv' : 'name';
  578. $metas .= "\t<meta $tagstyle=\"$tag\" content=\"$tagvalue\" />\n";
  579. }
  580. // Don't process when cached
  581. $this->documentObject['hasmetatags'] = '0';
  582. }
  583. if ($metas) $template = preg_replace("/(<head>)/i", "\\1\n\t" . trim($metas), $template);
  584. return $template;
  585. }
  586. // mod by Raymond
  587. function mergeDocumentContent($template) {
  588. $replace= array ();
  589. preg_match_all('~\[\*(.*?)\*\]~', $template, $matches);
  590. $variableCount= count($matches[1]);
  591. $basepath= $this->config["base_path"] . "manager/includes";
  592. for ($i= 0; $i < $variableCount; $i++) {
  593. $key= $matches[1][$i];
  594. $key= substr($key, 0, 1) == '#' ? substr($key, 1) : $key; // remove # for QuickEdit format
  595. $value= $this->documentObject[$key];
  596. if (is_array($value)) {
  597. include_once $basepath . "/tmplvars.format.inc.php";
  598. include_once $basepath . "/tmplvars.commands.inc.php";
  599. $w= "100%";
  600. $h= "300";
  601. $value= getTVDisplayFormat($value[0], $value[1], $value[2], $value[3], $value[4]);
  602. }
  603. $replace[$i]= $value;
  604. }
  605. $template= str_replace($matches[0], $replace, $template);
  606. return $template;
  607. }
  608. function mergeSettingsContent($template) {
  609. $replace= array ();
  610. $matches= array ();
  611. if (preg_match_all('~\[\(([a-z\_]*?)\)\]~', $template, $matches)) {
  612. $settingsCount= count($matches[1]);
  613. for ($i= 0; $i < $settingsCount; $i++) {
  614. if (array_key_exists($matches[1][$i], $this->config))
  615. $replace[$i]= $this->config[$matches[1][$i]];
  616. }
  617. $template= str_replace($matches[0], $replace, $template);
  618. }
  619. return $template;
  620. }
  621. function mergeChunkContent($content) {
  622. $replace= array ();
  623. $matches= array ();
  624. if (preg_match_all('~{{(.*?)}}~', $content, $matches)) {
  625. $settingsCount= count($matches[1]);
  626. for ($i= 0; $i < $settingsCount; $i++) {
  627. if (isset ($this->chunkCache[$matches[1][$i]])) {
  628. $replace[$i]= $this->chunkCache[$matches[1][$i]];
  629. } else {
  630. $sql= "SELECT * FROM " . $this->getFullTableName("site_htmlsnippets") . " WHERE " . $this->getFullTableName("site_htmlsnippets") . ".name='" . $this->db->escape($matches[1][$i]) . "';";
  631. $result= $this->dbQuery($sql);
  632. $limit= $this->recordCount($result);
  633. if ($limit < 1) {
  634. $this->chunkCache[$matches[1][$i]]= "";
  635. $replace[$i]= "";
  636. } else {
  637. $row= $this->fetchRow($result);
  638. $this->chunkCache[$matches[1][$i]]= $row['snippet'];
  639. $replace[$i]= $row['snippet'];
  640. }
  641. }
  642. }
  643. $content= str_replace($matches[0], $replace, $content);
  644. }
  645. return $content;
  646. }
  647. // Added by Raymond
  648. function mergePlaceholderContent($content) {
  649. $replace= array ();
  650. $matches= array ();
  651. if (preg_match_all('~\[\+(.*?)\+\]~', $content, $matches)) {
  652. $cnt= count($matches[1]);
  653. for ($i= 0; $i < $cnt; $i++) {
  654. $v= '';
  655. $key= $matches[1][$i];
  656. if (is_array($this->placeholders) && array_key_exists($key, $this->placeholders))
  657. $v= $this->placeholders[$key];
  658. if ($v === '')
  659. unset ($matches[0][$i]); // here we'll leave empty placeholders for last.
  660. else
  661. $replace[$i]= $v;
  662. }
  663. $content= str_replace($matches[0], $replace, $content);
  664. }
  665. return $content;
  666. }
  667. // evalPlugin
  668. function evalPlugin($pluginCode, $params) {
  669. $etomite= $modx= & $this;
  670. $modx->event->params= & $params; // store params inside event object
  671. if (is_array($params)) {
  672. extract($params, EXTR_SKIP);
  673. }
  674. ob_start();
  675. eval ($pluginCode);
  676. $msg= ob_get_contents();
  677. ob_end_clean();
  678. if ($msg && isset ($php_errormsg)) {
  679. if (!strpos($php_errormsg, 'Deprecated')) { // ignore php5 strict errors
  680. // log error
  681. $this->logEvent(1, 3, "<b>$php_errormsg</b><br /><br /> $msg", $this->Event->activePlugin . " - Plugin");
  682. if ($this->isBackend())
  683. $this->Event->alert("An error occurred while loading. Please see the event log for more information.<p />$msg");
  684. }
  685. } else {
  686. echo $msg;
  687. }
  688. unset ($modx->event->params);
  689. }
  690. function evalSnippet($snippet, $params) {
  691. $etomite= $modx= & $this;
  692. $modx->event->params= & $params; // store params inside event object
  693. if (is_array($params)) {
  694. extract($params, EXTR_SKIP);
  695. }
  696. ob_start();
  697. $snip= eval ($snippet);
  698. $msg= ob_get_contents();
  699. ob_end_clean();
  700. if ($msg && isset ($php_errormsg)) {
  701. if (!strpos($php_errormsg, 'Deprecated')) { // ignore php5 strict errors
  702. // log error
  703. $this->logEvent(1, 3, "<b>$php_errormsg</b><br /><br /> $msg", $this->currentSnippet . " - Snippet");
  704. if ($this->isBackend())
  705. $this->Event->alert("An error occurred while loading. Please see the event log for more information<p />$msg");
  706. }
  707. }
  708. unset ($modx->event->params);
  709. return $msg . $snip;
  710. }
  711. function evalSnippets($documentSource) {
  712. preg_match_all('~\[\[(.*?)\]\]~ms', $documentSource, $matches);
  713. $etomite= & $this;
  714. if ($matchCount= count($matches[1])) {
  715. for ($i= 0; $i < $matchCount; $i++) {
  716. $spos= strpos($matches[1][$i], '?', 0);
  717. if ($spos !== false) {
  718. $params= substr($matches[1][$i], $spos, strlen($matches[1][$i]));
  719. } else {
  720. $params= '';
  721. }
  722. $matches[1][$i]= str_replace($params, '', $matches[1][$i]);
  723. $snippetParams[$i]= $params;
  724. }
  725. $nrSnippetsToGet= $matchCount;
  726. for ($i= 0; $i < $nrSnippetsToGet; $i++) { // Raymond: Mod for Snippet props
  727. if (isset ($this->snippetCache[$matches[1][$i]])) {
  728. $snippets[$i]['name']= $matches[1][$i];
  729. $snippets[$i]['snippet']= $this->snippetCache[$matches[1][$i]];
  730. if (array_key_exists($matches[1][$i] . "Props", $this->snippetCache))
  731. $snippets[$i]['properties']= $this->snippetCache[$matches[1][$i] . "Props"];
  732. } else {
  733. // get from db and store a copy inside cache
  734. $sql= "SELECT * FROM " . $this->getFullTableName("site_snippets") . " WHERE " . $this->getFullTableName("site_snippets") . ".name='" . $this->db->escape($matches[1][$i]) . "';";
  735. $result= $this->dbQuery($sql);
  736. if ($this->recordCount($result) == 1) {
  737. $row= $this->fetchRow($result);
  738. $snippets[$i]['name']= $row['name'];
  739. $snippets[$i]['snippet']= $this->snippetCache[$row['name']]= $row['snippet'];
  740. $snippets[$i]['properties']= $this->snippetCache[$row['name'] . "Props"]= $row['properties'];
  741. } else {
  742. $snippets[$i]['name']= $matches[1][$i];
  743. $snippets[$i]['snippet']= $this->snippetCache[$matches[1][$i]]= "return false;";
  744. $snippets[$i]['properties']= '';
  745. }
  746. }
  747. }
  748. for ($i= 0; $i < $nrSnippetsToGet; $i++) {
  749. $parameter= array ();
  750. $snippetName= $this->currentSnippet= $snippets[$i]['name'];
  751. // FIXME Undefined index: properties
  752. if (array_key_exists('properties', $snippets[$i])) {
  753. $snippetProperties= $snippets[$i]['properties'];
  754. } else {
  755. $snippetProperties= '';
  756. }
  757. // load default params/properties - Raymond
  758. // FIXME Undefined variable: snippetProperties
  759. $parameter= $this->parseProperties($snippetProperties);
  760. // current params
  761. $currentSnippetParams= $snippetParams[$i];
  762. if (!empty ($currentSnippetParams)) {
  763. $tempSnippetParams= str_replace("?", "", $currentSnippetParams);
  764. $splitter= "&";
  765. if (strpos($tempSnippetParams, "&amp;") > 0)
  766. $tempSnippetParams= str_replace("&amp;", "&", $tempSnippetParams);
  767. //$tempSnippetParams = html_entity_decode($tempSnippetParams, ENT_NOQUOTES, $this->config['etomite_charset']); //FS#334 and FS#456
  768. $tempSnippetParams= explode($splitter, $tempSnippetParams);
  769. $snippetParamCount= count($tempSnippetParams);
  770. for ($x= 0; $x < $snippetParamCount; $x++) {
  771. if (strpos($tempSnippetParams[$x], '=', 0)) {
  772. if ($parameterTemp= explode("=", $tempSnippetParams[$x])) {
  773. $parameterTemp[0] = trim($parameterTemp[0]);
  774. $parameterTemp[1] = trim($parameterTemp[1]);
  775. $fp= strpos($parameterTemp[1], '`');
  776. $lp= strrpos($parameterTemp[1], '`');
  777. if (!($fp === false && $lp === false))
  778. $parameterTemp[1]= substr($parameterTemp[1], $fp +1, $lp -1);
  779. $parameter[$parameterTemp[0]]= $parameterTemp[1];
  780. }
  781. }
  782. }
  783. }
  784. $executedSnippets[$i]= $this->evalSnippet($snippets[$i]['snippet'], $parameter);
  785. if ($this->dumpSnippets == 1) {
  786. echo "<fieldset><legend><b>$snippetName</b></legend><textarea style='width:60%; height:200px'>" . htmlentities($executedSnippets[$i]) . "</textarea></fieldset><br />";
  787. }
  788. $documentSource= str_replace("[[" . $snippetName . $currentSnippetParams . "]]", $executedSnippets[$i], $documentSource);
  789. }
  790. }
  791. return $documentSource;
  792. }
  793. function makeFriendlyURL($pre, $suff, $alias) {
  794. $Alias = explode('/',$alias);
  795. $alias = array_pop($Alias);
  796. $dir = implode('/', $Alias);
  797. unset($Alias);
  798. return ($dir != '' ? "$dir/" : '') . $pre . $alias . $suff;
  799. }
  800. function rewriteUrls($documentSource) {
  801. // rewrite the urls
  802. if ($this->config['friendly_urls'] == 1) {
  803. $aliases= array ();
  804. foreach ($this->aliasListing as $item) {
  805. $aliases[$item['id']]= (strlen($item['path']) > 0 ? $item['path'] . '/' : '') . $item['alias'];
  806. }
  807. $in= '!\[\~([0-9]+)\~\]!ise'; // Use preg_replace with /e to make it evaluate PHP
  808. $isfriendly= ($this->config['friendly_alias_urls'] == 1 ? 1 : 0);
  809. $pref= $this->config['friendly_url_prefix'];
  810. $suff= $this->config['friendly_url_suffix'];
  811. $thealias= '$aliases[\\1]';
  812. $found_friendlyurl= "\$this->makeFriendlyURL('$pref','$suff',$thealias)";
  813. $not_found_friendlyurl= "\$this->makeFriendlyURL('$pref','$suff','" . '\\1' . "')";
  814. $out= "({$isfriendly} && isset({$thealias}) ? {$found_friendlyurl} : {$not_found_friendlyurl})";
  815. $documentSource= preg_replace($in, $out, $documentSource);
  816. } else {
  817. $in= '!\[\~([0-9]+)\~\]!is';
  818. $out= "index.php?id=" . '\1';
  819. $documentSource= preg_replace($in, $out, $documentSource);
  820. }
  821. return $documentSource;
  822. }
  823. /**
  824. * name: getDocumentObject - used by parser
  825. * desc: returns a document object - $method: alias, id
  826. */
  827. function getDocumentObject($method, $identifier) {
  828. $tblsc= $this->getFullTableName("site_content");
  829. $tbldg= $this->getFullTableName("document_groups");
  830. // get document groups for current user
  831. if ($docgrp= $this->getUserDocGroups())
  832. $docgrp= implode(",", $docgrp);
  833. // get document
  834. $access= ($this->isFrontend() ? "sc.privateweb=0" : "1='" . $_SESSION['mgrRole'] . "' OR sc.privatemgr=0") .
  835. (!$docgrp ? "" : " OR dg.document_group IN ($docgrp)");
  836. $sql= "SELECT sc.*
  837. FROM $tblsc sc
  838. LEFT JOIN $tbldg dg ON dg.document = sc.id
  839. WHERE sc." . $method . " = '" . $identifier . "'
  840. AND ($access) LIMIT 1;";
  841. $result= $this->db->query($sql);
  842. $rowCount= $this->recordCount($result);
  843. if ($rowCount < 1) {
  844. if ($this->config['unauthorized_page']) {
  845. // Fix for FS #375 - netnoise 2006/08/14
  846. if ($method != 'id')
  847. $identifier= $this->cleanDocumentIdentifier($identifier);
  848. if (!is_numeric($identifier) && array_key_exists($identifier, $this->documentListing)) {
  849. $identifier= $this->documentListing[$identifier];
  850. $method= 'id';
  851. }
  852. // check if file is not public
  853. $secrs= $this->dbQuery("SELECT id FROM $tbldg WHERE document = '" . $identifier . "' LIMIT 1;");
  854. if ($secrs)
  855. $seclimit= mysql_num_rows($secrs);
  856. }
  857. if ($seclimit > 0) {
  858. // match found but not publicly accessible, send the visitor to the unauthorized_page
  859. $this->sendUnauthorizedPage();
  860. exit; // stop here
  861. } else {
  862. $this->sendErrorPage();
  863. exit;
  864. }
  865. }
  866. # this is now the document :) #
  867. $documentObject= $this->fetchRow($result);
  868. // load TVs and merge with document - Orig by Apodigm - Docvars
  869. $sql= "SELECT tv.*, IF(tvc.value!='',tvc.value,tv.default_text) as value ";
  870. $sql .= "FROM " . $this->getFullTableName("site_tmplvars") . " tv ";
  871. $sql .= "INNER JOIN " . $this->getFullTableName("site_tmplvar_templates")." tvtpl ON tvtpl.tmplvarid = tv.id ";
  872. $sql .= "LEFT JOIN " . $this->getFullTableName("site_tmplvar_contentvalues")." tvc ON tvc.tmplvarid=tv.id AND tvc.contentid = '" . $documentObject['id'] . "' ";
  873. $sql .= "WHERE tvtpl.templateid = '" . $documentObject['template'] . "'";
  874. $rs= $this->dbQuery($sql);
  875. $rowCount= $this->recordCount($rs);
  876. if ($rowCount > 0) {
  877. for ($i= 0; $i < $rowCount; $i++) {
  878. $row= $this->fetchRow($rs);
  879. $tmplvars[$row['name']]= array (
  880. $row['name'],
  881. $row['value'],
  882. $row['display'],
  883. $row['display_params'],
  884. $row['type']
  885. );
  886. }
  887. $documentObject= array_merge($documentObject, $tmplvars);
  888. }
  889. return $documentObject;
  890. }
  891. /**
  892. * name: parseDocumentSource - used by parser
  893. * desc: return document source aftering parsing tvs, snippets, chunks, etc.
  894. */
  895. function parseDocumentSource($source) {
  896. // set the number of times we are to parse the document source
  897. $this->minParserPasses= empty ($this->minParserPasses) ? 2 : $this->minParserPasses;
  898. $this->maxParserPasses= empty ($this->maxParserPasses) ? 10 : $this->maxParserPasses;
  899. $passes= $this->minParserPasses;
  900. for ($i= 0; $i < $passes; $i++) {
  901. // get source length if this is the final pass
  902. if ($i == ($passes -1))
  903. $st= strlen($source);
  904. if ($this->dumpSnippets == 1) {
  905. echo "<fieldset><legend><b style='color: #821517;'>PARSE PASS " . ($i +1) . "</b></legend>The following snippets (if any) were parsed during this pass.<div style='width:100%' align='center'>";
  906. }
  907. // invoke OnParseDocument event
  908. $this->documentOutput= $source; // store source code so plugins can
  909. $this->invokeEvent("OnParseDocument"); // work on it via $modx->documentOutput
  910. $source= $this->documentOutput;
  911. // combine template and document variables
  912. $source= $this->mergeDocumentContent($source);
  913. // replace settings referenced in document
  914. $source= $this->mergeSettingsContent($source);
  915. // replace HTMLSnippets in document
  916. $source= $this->mergeChunkContent($source);
  917. // insert META tags & keywords
  918. $source= $this->mergeDocumentMETATags($source);
  919. // find and merge snippets
  920. $source= $this->evalSnippets($source);
  921. // find and replace Placeholders (must be parsed last) - Added by Raymond
  922. $source= $this->mergePlaceholderContent($source);
  923. if ($this->dumpSnippets == 1) {
  924. echo "</div></fieldset><br />";
  925. }
  926. if ($i == ($passes -1) && $i < ($this->maxParserPasses - 1)) {
  927. // check if source length was changed
  928. $et= strlen($source);
  929. if ($st != $et)
  930. $passes++; // if content change then increase passes because
  931. } // we have not yet reached maxParserPasses
  932. }
  933. return $source;
  934. }
  935. function executeParser() {
  936. //error_reporting(0);
  937. if (version_compare(phpversion(), "5.0.0", ">="))
  938. set_error_handler(array (
  939. & $this,
  940. "phpError"
  941. ), E_ALL);
  942. else
  943. set_error_handler(array (
  944. & $this,
  945. "phpError"
  946. ));
  947. $this->db->connect();
  948. // get the settings
  949. if (empty ($this->config)) {
  950. $this->getSettings();
  951. }
  952. // IIS friendly url fix
  953. if ($this->config['friendly_urls'] == 1 && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false) {
  954. $url= $_SERVER['QUERY_STRING'];
  955. $err= substr($url, 0, 3);
  956. if ($err == '404' || $err == '405') {
  957. $k= array_keys($_GET);
  958. unset ($_GET[$k[0]]);
  959. unset ($_REQUEST[$k[0]]); // remove 404,405 entry
  960. $_SERVER['QUERY_STRING']= $qp['query'];
  961. $qp= parse_url(str_replace($this->config['site_url'], '', substr($url, 4)));
  962. if (!empty ($qp['query'])) {
  963. parse_str($qp['query'], $qv);
  964. foreach ($qv as $n => $v)
  965. $_REQUEST[$n]= $_GET[$n]= $v;
  966. }
  967. $_SERVER['PHP_SELF']= $this->config['base_url'] . $qp['path'];
  968. $_REQUEST['q']= $_GET['q']= $qp['path'];
  969. }
  970. }
  971. // check site settings
  972. if (!$this->checkSiteStatus()) {
  973. header('HTTP/1.0 503 Service Unavailable');
  974. if (!$this->config['site_unavailable_page']) {
  975. // display offline message
  976. $this->documentContent= $this->config['site_unavailable_message'];
  977. $this->outputContent();
  978. exit; // stop processing here, as the site's offline
  979. } else {
  980. // setup offline page document settings
  981. $this->documentMethod= "id";
  982. $this->documentIdentifier= $this->config['site_unavailable_page'];
  983. }
  984. } else {
  985. // make sure the cache doesn't need updating
  986. $this->checkPublishStatus();
  987. // find out which document we need to display
  988. $this->documentMethod= $this->getDocumentMethod();
  989. $this->documentIdentifier= $this->getDocumentIdentifier($this->documentMethod);
  990. }
  991. if ($this->documentMethod == "none") {
  992. $this->documentMethod= "id"; // now we know the site_start, change the none method to id
  993. }
  994. if ($this->documentMethod == "alias") {
  995. $this->documentIdentifier= $this->cleanDocumentIdentifier($this->documentIdentifier);
  996. }
  997. if ($this->documentMethod == "alias") {
  998. // Check use_alias_path and check if $this->virtualDir is set to anything, then parse the path
  999. if ($this->config['use_alias_path'] == 1) {
  1000. $alias= (strlen($this->virtualDir) > 0 ? $this->virtualDir . '/' : '') . $this->documentIdentifier;
  1001. if (array_key_exists($alias, $this->documentListing)) {
  1002. $this->documentIdentifier= $this->documentListing[$alias];
  1003. } else {
  1004. $this->sendErrorPage();
  1005. }
  1006. } else {
  1007. $this->documentIdentifier= $this->documentListing[$this->documentIdentifier];
  1008. }
  1009. $this->documentMethod= 'id';
  1010. }
  1011. // invoke OnWebPageInit event
  1012. $this->invokeEvent("OnWebPageInit");
  1013. // invoke OnLogPageView event
  1014. if ($this->config['track_visitors'] == 1) {
  1015. $this->invokeEvent("OnLogPageHit");
  1016. }
  1017. $this->prepareResponse();
  1018. }
  1019. function prepareResponse() {
  1020. // we now know the method and identifier, let's check the cache
  1021. $this->documentContent= $this->checkCache($this->documentIdentifier);
  1022. if ($this->documentContent != "") {
  1023. // invoke OnLoadWebPageCache event
  1024. $this->invokeEvent("OnLoadWebPageCache");
  1025. } else {
  1026. // get document object
  1027. $this->documentObject= $this->getDocumentObject($this->documentMethod, $this->documentIdentifier);
  1028. // write the documentName to…

Large files files are truncated, but you can click here to view the full file