PageRenderTime 62ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/public/external/pydio/core/classes/class.AJXP_Controller.php

https://github.com/antoinemineau/cms
PHP | 579 lines | 365 code | 19 blank | 195 comment | 128 complexity | 000a540a0ca707a739a300aa7561d6f7 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause, BSD-2-Clause, Apache-2.0
  1. <?php
  2. /*
  3. * Copyright 2007-2013 Charles du Jeu - Abstrium SAS <team (at) pyd.io>
  4. * This file is part of Pydio.
  5. *
  6. * Pydio is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Pydio is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with Pydio. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. * The latest code can be found at <http://pyd.io/>.
  20. */
  21. defined('AJXP_EXEC') or die( 'Access not allowed');
  22. /**
  23. * Core controller for dispatching the actions.
  24. * It uses the XML Registry (simple version, not extended) to search all the <action> tags and find the action.
  25. * @package Pydio
  26. * @subpackage Core
  27. */
  28. class AJXP_Controller
  29. {
  30. /**
  31. * @var DOMXPath
  32. */
  33. private static $xPath;
  34. /**
  35. * @var bool
  36. */
  37. public static $lastActionNeedsAuth = false;
  38. /**
  39. * @var array
  40. */
  41. private static $includeHooks = array();
  42. /**
  43. * Initialize the queryable xPath object
  44. * @static
  45. * @return DOMXPath
  46. */
  47. private static function initXPath()
  48. {
  49. if (!isSet(self::$xPath)) {
  50. $registry = AJXP_PluginsService::getXmlRegistry( false );
  51. $changes = self::filterRegistryFromRole($registry);
  52. if($changes) AJXP_PluginsService::updateXmlRegistry($registry);
  53. self::$xPath = new DOMXPath($registry);
  54. }
  55. return self::$xPath;
  56. }
  57. /**
  58. * Check the current user "specificActionsRights" and filter the full registry actions with these.
  59. * @static
  60. * @param DOMDocument $registry
  61. * @return bool
  62. */
  63. public static function filterRegistryFromRole(&$registry)
  64. {
  65. if(!AuthService::usersEnabled()) return false ;
  66. $loggedUser = AuthService::getLoggedUser();
  67. if($loggedUser == null) return false;
  68. $crtRepo = ConfService::getRepository();
  69. $crtRepoId = AJXP_REPO_SCOPE_ALL; // "ajxp.all";
  70. if ($crtRepo != null && is_a($crtRepo, "Repository")) {
  71. $crtRepoId = $crtRepo->getId();
  72. }
  73. $actionRights = $loggedUser->mergedRole->listActionsStatesFor($crtRepo);
  74. $changes = false;
  75. $xPath = new DOMXPath($registry);
  76. foreach ($actionRights as $pluginName => $actions) {
  77. foreach ($actions as $actionName => $enabled) {
  78. if($enabled !== false) continue;
  79. $actions = $xPath->query("actions/action[@name='$actionName']");
  80. if (!$actions->length) {
  81. continue;
  82. }
  83. $action = $actions->item(0);
  84. $action->parentNode->removeChild($action);
  85. $changes = true;
  86. }
  87. }
  88. $parameters = $loggedUser->mergedRole->listParameters();
  89. foreach ($parameters as $scope => $paramsPlugs) {
  90. if ($scope == AJXP_REPO_SCOPE_ALL || $scope == $crtRepoId || ($crtRepo->hasParent() && $scope == AJXP_REPO_SCOPE_SHARED)) {
  91. foreach ($paramsPlugs as $plugId => $params) {
  92. foreach ($params as $name => $value) {
  93. // Search exposed plugin_configs, replace if necessary.
  94. $searchparams = $xPath->query("plugins/*[@id='$plugId']/plugin_configs/property[@name='$name']");
  95. if(!$searchparams->length) continue;
  96. $param = $searchparams->item(0);
  97. $newCdata = $registry->createCDATASection(json_encode($value));
  98. $param->removeChild($param->firstChild);
  99. $param->appendChild($newCdata);
  100. }
  101. }
  102. }
  103. }
  104. return $changes;
  105. }
  106. /**
  107. * @param $actionName
  108. * @param $path
  109. * @return bool
  110. */
  111. public static function findRestActionAndApply($actionName, $path)
  112. {
  113. $xPath = self::initXPath();
  114. $actions = $xPath->query("actions/action[@name='$actionName']");
  115. if (!$actions->length) {
  116. self::$lastActionNeedsAuth = true;
  117. return false;
  118. }
  119. $action = $actions->item(0);
  120. $restPathList = $xPath->query("processing/serverCallback/@restParams", $action);
  121. if (!$restPathList->length) {
  122. self::$lastActionNeedsAuth = true;
  123. return false;
  124. }
  125. $restPath = $restPathList->item(0)->nodeValue;
  126. $paramNames = explode("/", trim($restPath, "/"));
  127. $path = array_shift(explode("?", $path));
  128. $paramValues = array_map("urldecode", explode("/", trim($path, "/"), count($paramNames)));
  129. foreach ($paramNames as $i => $pName) {
  130. if (strpos($pName, "+") !== false) {
  131. $paramNames[$i] = str_replace("+", "", $pName);
  132. $paramValues[$i] = "/" . $paramValues[$i];
  133. }
  134. }
  135. if (count($paramValues) < count($paramNames)) {
  136. $paramNames = array_slice($paramNames, 0, count($paramValues));
  137. }
  138. $httpVars = array_merge($_GET, $_POST, array_combine($paramNames, $paramValues));
  139. return self::findActionAndApply($actionName, $httpVars, $_FILES, $action);
  140. }
  141. /**
  142. * @static
  143. * @param Array $parameters
  144. * @param DOMNode $callbackNode
  145. * @param DOMXPath $xPath
  146. * @throws Exception
  147. */
  148. public static function checkParams(&$parameters, $callbackNode, $xPath)
  149. {
  150. if (!$callbackNode->attributes->getNamedItem('checkParams') || $callbackNode->attributes->getNamedItem('checkParams')->nodeValue != "true") {
  151. return;
  152. }
  153. $inputParams = $xPath->query("input_param", $callbackNode);
  154. $declaredParams = array();
  155. foreach ($inputParams as $param) {
  156. $name = $param->attributes->getNamedItem("name")->nodeValue;
  157. $type = $param->attributes->getNamedItem("type")->nodeValue;
  158. $defaultNode = $param->attributes->getNamedItem("default");
  159. $mandatory = ($param->attributes->getNamedItem("mandatory")->nodeValue == "true");
  160. if ($mandatory && !isSet($parameters[$name])) {
  161. throw new Exception("Missing parameter '".$name."' of type '$type'");
  162. }
  163. if ($defaultNode != null && !isSet($parameters[$name])) {
  164. $parameters[$name] = $defaultNode->nodeValue;
  165. }
  166. $declaredParams[] = $name;
  167. }
  168. foreach ($parameters as $k => $n) {
  169. if(!in_array($k, $declaredParams)) unset($parameters[$k]);
  170. }
  171. }
  172. /**
  173. * Main method for querying the XML registry, find an action and all its associated processors,
  174. * and apply all the callbacks.
  175. * @static
  176. * @param String $actionName
  177. * @param array $httpVars
  178. * @param array $fileVars
  179. * @param DOMNode $action
  180. * @return bool
  181. */
  182. public static function findActionAndApply($actionName, $httpVars, $fileVars, &$action = null)
  183. {
  184. $actionName = AJXP_Utils::sanitize($actionName, AJXP_SANITIZE_EMAILCHARS);
  185. if ($actionName == "cross_copy") {
  186. $pService = AJXP_PluginsService::getInstance();
  187. $actives = $pService->getActivePlugins();
  188. $accessPlug = $pService->getPluginsByType("access");
  189. if (count($accessPlug)) {
  190. foreach ($accessPlug as $key=>$objbect) {
  191. if ($actives[$objbect->getId()] === true) {
  192. call_user_func(array($pService->getPluginById($objbect->getId()), "crossRepositoryCopy"), $httpVars);
  193. break;
  194. }
  195. }
  196. }
  197. self::$lastActionNeedsAuth = true;
  198. return ;
  199. }
  200. $xPath = self::initXPath();
  201. if ($action == null) {
  202. $actions = $xPath->query("actions/action[@name='$actionName']");
  203. if (!$actions->length) {
  204. self::$lastActionNeedsAuth = true;
  205. return false;
  206. }
  207. $action = $actions->item(0);
  208. }
  209. //Check Rights
  210. if (AuthService::usersEnabled()) {
  211. $loggedUser = AuthService::getLoggedUser();
  212. if( AJXP_Controller::actionNeedsRight($action, $xPath, "adminOnly") &&
  213. ($loggedUser == null || !$loggedUser->isAdmin())){
  214. $mess = ConfService::getMessages();
  215. AJXP_XMLWriter::header();
  216. AJXP_XMLWriter::sendMessage(null, $mess[207]);
  217. AJXP_XMLWriter::requireAuth();
  218. AJXP_XMLWriter::close();
  219. exit(1);
  220. }
  221. if( AJXP_Controller::actionNeedsRight($action, $xPath, "read") &&
  222. ($loggedUser == null || !$loggedUser->canRead(ConfService::getCurrentRepositoryId().""))){
  223. AJXP_XMLWriter::header();
  224. if($actionName == "ls" & $loggedUser!=null
  225. && $loggedUser->canWrite(ConfService::getCurrentRepositoryId()."")){
  226. // Special case of "write only" right : return empty listing, no auth error.
  227. AJXP_XMLWriter::close();
  228. exit(1);
  229. }
  230. $mess = ConfService::getMessages();
  231. AJXP_XMLWriter::sendMessage(null, $mess[208]);
  232. AJXP_XMLWriter::requireAuth();
  233. AJXP_XMLWriter::close();
  234. exit(1);
  235. }
  236. if( AJXP_Controller::actionNeedsRight($action, $xPath, "write") &&
  237. ($loggedUser == null || !$loggedUser->canWrite(ConfService::getCurrentRepositoryId().""))){
  238. $mess = ConfService::getMessages();
  239. AJXP_XMLWriter::header();
  240. AJXP_XMLWriter::sendMessage(null, $mess[207]);
  241. AJXP_XMLWriter::requireAuth();
  242. AJXP_XMLWriter::close();
  243. exit(1);
  244. }
  245. }
  246. $preCalls = self::getCallbackNode($xPath, $action, 'pre_processing/serverCallback', $actionName, $httpVars, $fileVars, true);
  247. $postCalls = self::getCallbackNode($xPath, $action, 'post_processing/serverCallback[not(@capture="true")]', $actionName, $httpVars, $fileVars, true);
  248. $captureCalls = self::getCallbackNode($xPath, $action, 'post_processing/serverCallback[@capture="true"]', $actionName, $httpVars, $fileVars, true);
  249. $mainCall = self::getCallbackNode($xPath, $action, "processing/serverCallback",$actionName, $httpVars, $fileVars, false);
  250. if ($mainCall != null) {
  251. self::checkParams($httpVars, $mainCall, $xPath);
  252. }
  253. if ($captureCalls !== false) {
  254. // Make sure the ShutdownScheduler has its own OB started BEFORE, as it will presumabily be
  255. // executed AFTER the end of this one.
  256. AJXP_ShutdownScheduler::getInstance();
  257. ob_start();
  258. $params = array("pre_processor_results" => array(), "post_processor_results" => array());
  259. }
  260. if ($preCalls !== false) {
  261. foreach ($preCalls as $preCall) {
  262. // A Preprocessing callback can modify its input arguments (passed by ref)
  263. $preResult = self::applyCallback($xPath, $preCall, $actionName, $httpVars, $fileVars);
  264. if (isSet($params)) {
  265. $params["pre_processor_results"][$preCall->getAttribute("pluginId")] = $preResult;
  266. }
  267. }
  268. }
  269. if ($mainCall) {
  270. $result = self::applyCallback($xPath, $mainCall, $actionName, $httpVars, $fileVars);
  271. if (isSet($params)) {
  272. $params["processor_result"] = $result;
  273. }
  274. }
  275. if ($postCalls !== false) {
  276. foreach ($postCalls as $postCall) {
  277. // A Preprocessing callback can modify its input arguments (passed by ref)
  278. $postResult = self::applyCallback($xPath, $postCall, $actionName, $httpVars, $fileVars);
  279. if (isSet($params)) {
  280. $params["post_processor_results"][$postCall->getAttribute("pluginId")] = $postResult;
  281. }
  282. }
  283. }
  284. if ($captureCalls !== false) {
  285. $params["ob_output"] = ob_get_contents();
  286. ob_end_clean();
  287. foreach ($captureCalls as $captureCall) {
  288. self::applyCallback($xPath, $captureCall, $actionName, $httpVars, $params);
  289. }
  290. } else {
  291. if(isSet($result)) return $result;
  292. }
  293. }
  294. /**
  295. * Launch a command-line version of the framework by passing the actionName & parameters as arguments.
  296. * @static
  297. * @param String $currentRepositoryId
  298. * @param String $actionName
  299. * @param Array $parameters
  300. * @param string $user
  301. * @param string $statusFile
  302. * @return null|UnixProcess
  303. */
  304. public static function applyActionInBackground($currentRepositoryId, $actionName, $parameters, $user ="", $statusFile = "")
  305. {
  306. $token = md5(time());
  307. $logDir = AJXP_CACHE_DIR."/cmd_outputs";
  308. if(!is_dir($logDir)) mkdir($logDir, 0755);
  309. $logFile = $logDir."/".$token.".out";
  310. if (empty($user)) {
  311. if(AuthService::usersEnabled() && AuthService::getLoggedUser() !== null) $user = AuthService::getLoggedUser()->getId();
  312. else $user = "shared";
  313. }
  314. if (AuthService::usersEnabled()) {
  315. $user = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($token."\1CDAFx¨op#"), $user, MCRYPT_MODE_ECB));
  316. }
  317. $robustInstallPath = str_replace("/", DIRECTORY_SEPARATOR, AJXP_INSTALL_PATH);
  318. $cmd = ConfService::getCoreConf("CLI_PHP")." ".$robustInstallPath.DIRECTORY_SEPARATOR."cmd.php -u=$user -t=$token -a=$actionName -r=$currentRepositoryId";
  319. /* Inserted next 3 lines to quote the command if in windows - rmeske*/
  320. if (PHP_OS == "WIN32" || PHP_OS == "WINNT" || PHP_OS == "Windows") {
  321. $cmd = ConfService::getCoreConf("CLI_PHP")." ".chr(34).$robustInstallPath.DIRECTORY_SEPARATOR."cmd.php".chr(34)." -u=$user -t=$token -a=$actionName -r=$currentRepositoryId";
  322. }
  323. if ($statusFile != "") {
  324. $cmd .= " -s=".$statusFile;
  325. }
  326. foreach ($parameters as $key=>$value) {
  327. if($key == "action" || $key == "get_action") continue;
  328. if(is_array($value)){
  329. $index = 0;
  330. foreach($value as $v){
  331. $cmd .= " --file_".$index."=".escapeshellarg($v);
  332. $index++;
  333. }
  334. }else{
  335. $cmd .= " --$key=".escapeshellarg($value);
  336. }
  337. }
  338. return self::runCommandInBackground($cmd, $logFile);
  339. /*
  340. if (PHP_OS == "WIN32" || PHP_OS == "WINNT" || PHP_OS == "Windows") {
  341. if(AJXP_SERVER_DEBUG) $cmd .= " > ".$logFile;
  342. if (class_exists("COM") && ConfService::getCoreConf("CLI_USE_COM")) {
  343. $WshShell = new COM("WScript.Shell");
  344. $oExec = $WshShell->Run("cmd /C $cmd", 0, false);
  345. } else {
  346. $tmpBat = implode(DIRECTORY_SEPARATOR, array( $robustInstallPath, "data","tmp", md5(time()).".bat"));
  347. $cmd .= "\n DEL ".chr(34).$tmpBat.chr(34);
  348. AJXP_Logger::debug("Writing file $cmd to $tmpBat");
  349. file_put_contents($tmpBat, $cmd);
  350. pclose(popen('start /b "CLI" "'.$tmpBat.'"', 'r'));
  351. }
  352. } else {
  353. $process = new UnixProcess($cmd, (AJXP_SERVER_DEBUG?$logFile:null));
  354. AJXP_Logger::debug("Starting process and sending output dev null");
  355. return $process;
  356. }
  357. */
  358. }
  359. /**
  360. * @param $cmd
  361. * @param $logFile
  362. * @return UnixProcess|null
  363. */
  364. public static function runCommandInBackground($cmd, $logFile)
  365. {
  366. if (PHP_OS == "WIN32" || PHP_OS == "WINNT" || PHP_OS == "Windows") {
  367. if(AJXP_SERVER_DEBUG) $cmd .= " > ".$logFile;
  368. if (class_exists("COM") && ConfService::getCoreConf("CLI_USE_COM")) {
  369. $WshShell = new COM("WScript.Shell");
  370. $oExec = $WshShell->Run("cmd /C $cmd", 0, false);
  371. } else {
  372. $basePath = str_replace("/", DIRECTORY_SEPARATOR, AJXP_INSTALL_PATH);
  373. $tmpBat = implode(DIRECTORY_SEPARATOR, array( $basePath, "data","tmp", md5(time()).".bat"));
  374. $cmd .= "\n DEL ".chr(34).$tmpBat.chr(34);
  375. AJXP_Logger::debug("Writing file $cmd to $tmpBat");
  376. file_put_contents($tmpBat, $cmd);
  377. pclose(popen('start /b "CLI" "'.$tmpBat.'"', 'r'));
  378. }
  379. } else {
  380. $process = new UnixProcess($cmd, (AJXP_SERVER_DEBUG?$logFile:null));
  381. AJXP_Logger::debug("Starting process and sending output dev null");
  382. return $process;
  383. }
  384. }
  385. /**
  386. * Find a callback node by its xpath query, filtering with the applyCondition if the xml attribute exists.
  387. * @static
  388. * @param DOMXPath $xPath
  389. * @param DOMNode $actionNode
  390. * @param string $query
  391. * @param string $actionName
  392. * @param array $httpVars
  393. * @param array $fileVars
  394. * @param bool $multiple
  395. * @return DOMNode|bool
  396. */
  397. private static function getCallbackNode($xPath, $actionNode, $query ,$actionName, $httpVars, $fileVars, $multiple = true)
  398. {
  399. $callbacks = $xPath->query($query, $actionNode);
  400. if(!$callbacks->length) return false;
  401. if ($multiple) {
  402. $cbArray = array();
  403. foreach ($callbacks as $callback) {
  404. if (self::appliesCondition($callback, $actionName, $httpVars, $fileVars)) {
  405. $cbArray[] = $callback;
  406. }
  407. }
  408. if(!count($cbArray)) return false;
  409. return $cbArray;
  410. } else {
  411. $callback=$callbacks->item(0);
  412. if(!self::appliesCondition($callback, $actionName, $httpVars, $fileVars)) return false;
  413. return $callback;
  414. }
  415. }
  416. /**
  417. * Check in the callback node if an applyCondition XML attribute exists, and eval its content.
  418. * The content must set an $apply boolean as result
  419. * @static
  420. * @param DOMNode $callback
  421. * @param string $actionName
  422. * @param array $httpVars
  423. * @param array $fileVars
  424. * @return bool
  425. */
  426. private static function appliesCondition($callback, $actionName, $httpVars, $fileVars)
  427. {
  428. if ($callback->getAttribute("applyCondition")!="") {
  429. $apply = false;
  430. eval($callback->getAttribute("applyCondition"));
  431. if(!$apply) return false;
  432. }
  433. return true;
  434. }
  435. /**
  436. * Applies a callback node
  437. * @static
  438. * @param DOMXPath $xPath
  439. * @param DOMNode $callback
  440. * @param String $actionName
  441. * @param Array $httpVars
  442. * @param Array $fileVars
  443. * @param null $variableArgs
  444. * @throw AJXP_Exception
  445. * @return void
  446. */
  447. private static function applyCallback($xPath, $callback, &$actionName, &$httpVars, &$fileVars, &$variableArgs = null, $defer = false)
  448. {
  449. //Processing
  450. $plugId = $xPath->query("@pluginId", $callback)->item(0)->value;
  451. $methodName = $xPath->query("@methodName", $callback)->item(0)->value;
  452. $plugInstance = AJXP_PluginsService::findPluginById($plugId);
  453. //return call_user_func(array($plugInstance, $methodName), $actionName, $httpVars, $fileVars);
  454. // Do not use call_user_func, it cannot pass parameters by reference.
  455. if (method_exists($plugInstance, $methodName)) {
  456. if ($variableArgs == null) {
  457. return $plugInstance->$methodName($actionName, $httpVars, $fileVars);
  458. } else {
  459. if ($defer == true) {
  460. AJXP_ShutdownScheduler::getInstance()->registerShutdownEventArray(array($plugInstance, $methodName), $variableArgs);
  461. } else {
  462. call_user_func_array(array($plugInstance, $methodName), $variableArgs);
  463. }
  464. }
  465. } else {
  466. throw new AJXP_Exception("Cannot find method $methodName for plugin $plugId!");
  467. }
  468. }
  469. /**
  470. * Find all callbacks registered for a given hook and apply them
  471. * @static
  472. * @param string $hookName
  473. * @param array $args
  474. * @return
  475. */
  476. public static function applyHook($hookName, $args, $forceNonDefer = false)
  477. {
  478. $xPath = self::initXPath();
  479. $callbacks = $xPath->query("hooks/serverCallback[@hookName='$hookName']");
  480. if(!$callbacks->length) return ;
  481. $callback = new DOMNode();
  482. foreach ($callbacks as $callback) {
  483. if ($callback->getAttribute("applyCondition")!="") {
  484. $apply = false;
  485. eval($callback->getAttribute("applyCondition"));
  486. if(!$apply) continue;
  487. }
  488. //$fake1; $fake2; $fake3;
  489. $defer = ($callback->attributes->getNamedItem("defer") != null && $callback->attributes->getNamedItem("defer")->nodeValue == "true");
  490. if($defer && $forceNonDefer) $defer = false;
  491. self::applyCallback($xPath, $callback, $fake1, $fake2, $fake3, $args, $defer);
  492. }
  493. }
  494. /**
  495. * Find the statically defined callbacks for a given hook and apply them
  496. * @static
  497. * @param $hookName
  498. * @param $args
  499. * @return
  500. */
  501. public static function applyIncludeHook($hookName, &$args)
  502. {
  503. if(!isSet(self::$includeHooks[$hookName])) return;
  504. foreach (self::$includeHooks[$hookName] as $callback) {
  505. call_user_func_array($callback, $args);
  506. }
  507. }
  508. /**
  509. * Register a hook statically when it must be defined before the XML registry construction.
  510. * @static
  511. * @param $hookName
  512. * @param $callback
  513. * @return void
  514. */
  515. public static function registerIncludeHook($hookName, $callback)
  516. {
  517. if (!isSet(self::$includeHooks[$hookName])) {
  518. self::$includeHooks[$hookName] = array();
  519. }
  520. self::$includeHooks[$hookName][] = $callback;
  521. }
  522. /**
  523. * Check the rightsContext node of an action.
  524. * @static
  525. * @param DOMNode $actionNode
  526. * @param DOMXPath $xPath
  527. * @param string $right
  528. * @return bool
  529. */
  530. public static function actionNeedsRight($actionNode, $xPath, $right)
  531. {
  532. $rights = $xPath->query("rightsContext", $actionNode);
  533. if(!$rights->length) return false;
  534. $rightNode = $rights->item(0);
  535. $rightAttr = $xPath->query("@".$right, $rightNode);
  536. if ($rightAttr->length && $rightAttr->item(0)->value == "true") {
  537. self::$lastActionNeedsAuth = true;
  538. return true;
  539. }
  540. return false;
  541. }
  542. /**
  543. * Utilitary used by the postprocesors to forward previously computed data
  544. * @static
  545. * @param array $postProcessData
  546. * @return void
  547. */
  548. public static function passProcessDataThrough($postProcessData)
  549. {
  550. if (isSet($postProcessData["pre_processor_results"]) && is_array($postProcessData["pre_processor_results"])) {
  551. print(implode("", $postProcessData["pre_processor_results"]));
  552. }
  553. if (isSet($postProcessData["processor_result"])) {
  554. print($postProcessData["processor_result"]);
  555. }
  556. if(isSet($postProcessData["ob_output"])) print($postProcessData["ob_output"]);
  557. }
  558. }