Response.class.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Manages the rendering of pages in PMA
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. require_once 'libraries/OutputBuffering.class.php';
  12. require_once 'libraries/Header.class.php';
  13. require_once 'libraries/Footer.class.php';
  14. /**
  15. * Singleton class used to manage the rendering of pages in PMA
  16. *
  17. * @package PhpMyAdmin
  18. */
  19. class PMA_Response
  20. {
  21. /**
  22. * PMA_Response instance
  23. *
  24. * @access private
  25. * @static
  26. * @var object
  27. */
  28. private static $_instance;
  29. /**
  30. * PMA_Header instance
  31. *
  32. * @access private
  33. * @var object
  34. */
  35. private $_header;
  36. /**
  37. * HTML data to be used in the response
  38. *
  39. * @access private
  40. * @var string
  41. */
  42. private $_HTML;
  43. /**
  44. * An array of JSON key-value pairs
  45. * to be sent back for ajax requests
  46. *
  47. * @access private
  48. * @var array
  49. */
  50. private $_JSON;
  51. /**
  52. * PMA_Footer instance
  53. *
  54. * @access private
  55. * @var object
  56. */
  57. private $_footer;
  58. /**
  59. * Whether we are servicing an ajax request.
  60. * We can't simply use $GLOBALS['is_ajax_request']
  61. * here since it may have not been initialised yet.
  62. *
  63. * @access private
  64. * @var bool
  65. */
  66. private $_isAjax;
  67. /**
  68. * Whether response object is disabled
  69. *
  70. * @access private
  71. * @var bool
  72. */
  73. private $_isDisabled;
  74. /**
  75. * Whether we are servicing an ajax request for a page
  76. * that was fired using the generic page handler in JS.
  77. *
  78. * @access private
  79. * @var bool
  80. */
  81. private $_isAjaxPage;
  82. /**
  83. * Whether there were any errors druing the processing of the request
  84. * Only used for ajax responses
  85. *
  86. * @access private
  87. * @var bool
  88. */
  89. private $_isSuccess;
  90. /**
  91. * Workaround for PHP bug
  92. *
  93. * @access private
  94. * @var bool
  95. */
  96. private $_CWD;
  97. /**
  98. * Creates a new class instance
  99. *
  100. * @return new PMA_Response object
  101. */
  102. private function __construct()
  103. {
  104. if (! defined('TESTSUITE')) {
  105. $buffer = PMA_OutputBuffering::getInstance();
  106. $buffer->start();
  107. }
  108. $this->_header = new PMA_Header();
  109. $this->_HTML = '';
  110. $this->_JSON = array();
  111. $this->_footer = new PMA_Footer();
  112. $this->_isSuccess = true;
  113. $this->_isAjax = false;
  114. $this->_isAjaxPage = false;
  115. $this->_isDisabled = false;
  116. if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true) {
  117. $this->_isAjax = true;
  118. }
  119. if (isset($_REQUEST['ajax_page_request'])
  120. && $_REQUEST['ajax_page_request'] == true
  121. ) {
  122. $this->_isAjaxPage = true;
  123. }
  124. $this->_header->setAjax($this->_isAjax);
  125. $this->_footer->setAjax($this->_isAjax);
  126. $this->_CWD = getcwd();
  127. }
  128. /**
  129. * Returns the singleton PMA_Response object
  130. *
  131. * @return PMA_Response object
  132. */
  133. public static function getInstance()
  134. {
  135. if (empty(self::$_instance)) {
  136. self::$_instance = new PMA_Response();
  137. }
  138. return self::$_instance;
  139. }
  140. /**
  141. * Set the status of an ajax response,
  142. * whether it is a success or an error
  143. *
  144. * @param bool $state Whether the request was successfully processed
  145. *
  146. * @return void
  147. */
  148. public function isSuccess($state)
  149. {
  150. $this->_isSuccess = ($state == true);
  151. }
  152. /**
  153. * Returns true or false depending on whether
  154. * we are servicing an ajax request
  155. *
  156. * @return bool
  157. */
  158. public function isAjax()
  159. {
  160. return $this->_isAjax;
  161. }
  162. /**
  163. * Returns the path to the current working directory
  164. * Necessary to work around a PHP bug where the CWD is
  165. * reset after the initial script exits
  166. *
  167. * @return string
  168. */
  169. public function getCWD()
  170. {
  171. return $this->_CWD;
  172. }
  173. /**
  174. * Disables the rendering of the header
  175. * and the footer in responses
  176. *
  177. * @return void
  178. */
  179. public function disable()
  180. {
  181. $this->_header->disable();
  182. $this->_footer->disable();
  183. $this->_isDisabled = true;
  184. }
  185. /**
  186. * Returns a PMA_Header object
  187. *
  188. * @return object
  189. */
  190. public function getHeader()
  191. {
  192. return $this->_header;
  193. }
  194. /**
  195. * Returns a PMA_Footer object
  196. *
  197. * @return object
  198. */
  199. public function getFooter()
  200. {
  201. return $this->_footer;
  202. }
  203. /**
  204. * Add HTML code to the response
  205. *
  206. * @param string $content A string to be appended to
  207. * the current output buffer
  208. *
  209. * @return void
  210. */
  211. public function addHTML($content)
  212. {
  213. if ($content instanceof PMA_Message) {
  214. $this->_HTML .= $content->getDisplay();
  215. } else {
  216. $this->_HTML .= $content;
  217. }
  218. }
  219. /**
  220. * Add JSON code to the response
  221. *
  222. * @param mixed $json Either a key (string) or an
  223. * array or key-value pairs
  224. * @param mixed $value Null, if passing an array in $json otherwise
  225. * it's a string value to the key
  226. *
  227. * @return void
  228. */
  229. public function addJSON($json, $value = null)
  230. {
  231. if (is_array($json)) {
  232. foreach ($json as $key => $value) {
  233. $this->addJSON($key, $value);
  234. }
  235. } else {
  236. if ($value instanceof PMA_Message) {
  237. $this->_JSON[$json] = $value->getDisplay();
  238. } else {
  239. $this->_JSON[$json] = $value;
  240. }
  241. }
  242. }
  243. /**
  244. * Renders the HTML response text
  245. *
  246. * @return string
  247. */
  248. private function _getDisplay()
  249. {
  250. // The header may contain nothing at all,
  251. // if it's content was already rendered
  252. // and, in this case, the header will be
  253. // in the content part of the request
  254. $retval = $this->_header->getDisplay();
  255. $retval .= $this->_HTML;
  256. $retval .= $this->_footer->getDisplay();
  257. return $retval;
  258. }
  259. /**
  260. * Sends an HTML response to the browser
  261. *
  262. * @return void
  263. */
  264. private function _htmlResponse()
  265. {
  266. echo $this->_getDisplay();
  267. }
  268. /**
  269. * Sends a JSON response to the browser
  270. *
  271. * @return void
  272. */
  273. private function _ajaxResponse()
  274. {
  275. /* Avoid wrapping in case we're disabled */
  276. if ($this->_isDisabled) {
  277. echo $this->_getDisplay();
  278. return;
  279. }
  280. if (! isset($this->_JSON['message'])) {
  281. $this->_JSON['message'] = $this->_getDisplay();
  282. } else if ($this->_JSON['message'] instanceof PMA_Message) {
  283. $this->_JSON['message'] = $this->_JSON['message']->getDisplay();
  284. }
  285. if ($this->_isSuccess) {
  286. $this->_JSON['success'] = true;
  287. } else {
  288. $this->_JSON['success'] = false;
  289. $this->_JSON['error'] = $this->_JSON['message'];
  290. unset($this->_JSON['message']);
  291. }
  292. if ($this->_isAjaxPage && $this->_isSuccess) {
  293. $this->addJSON('_title', $this->getHeader()->getTitleTag());
  294. $menuHash = $this->getHeader()->getMenu()->getHash();
  295. $this->addJSON('_menuHash', $menuHash);
  296. $hashes = array();
  297. if (isset($_REQUEST['menuHashes'])) {
  298. $hashes = explode('-', $_REQUEST['menuHashes']);
  299. }
  300. if (! in_array($menuHash, $hashes)) {
  301. $this->addJSON('_menu', $this->getHeader()->getMenu()->getDisplay());
  302. }
  303. $this->addJSON('_scripts', $this->getHeader()->getScripts()->getFiles());
  304. $this->addJSON('_selflink', $this->getFooter()->getSelfUrl('unencoded'));
  305. $this->addJSON('_displayMessage', $this->getHeader()->getMessage());
  306. $errors = $this->_footer->getErrorMessages();
  307. if (strlen($errors)) {
  308. $this->addJSON('_errors', $errors);
  309. }
  310. if (empty($GLOBALS['error_message'])) {
  311. // set current db, table and sql query in the querywindow
  312. $query = '';
  313. if (isset($GLOBALS['sql_query'])
  314. && strlen($GLOBALS['sql_query']) < $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']
  315. ) {
  316. $query = PMA_escapeJsString($GLOBALS['sql_query']);
  317. }
  318. $this->addJSON(
  319. '_reloadQuerywindow',
  320. array(
  321. 'db' => PMA_ifSetOr($GLOBALS['db'], ''),
  322. 'table' => PMA_ifSetOr($GLOBALS['table'], ''),
  323. 'sql_query' => $query
  324. )
  325. );
  326. if (! empty($GLOBALS['focus_querywindow'])) {
  327. $this->addJSON('_focusQuerywindow', $query);
  328. }
  329. if (! empty($GLOBALS['reload'])) {
  330. $this->addJSON('_reloadNavigation', 1);
  331. }
  332. $this->addJSON('_params', $this->getHeader()->getJsParams());
  333. }
  334. }
  335. // Set the Content-Type header to JSON so that jQuery parses the
  336. // response correctly.
  337. if (! defined('TESTSUITE')) {
  338. header('Cache-Control: no-cache');
  339. header('Content-Type: application/json');
  340. }
  341. echo json_encode($this->_JSON);
  342. }
  343. /**
  344. * Sends an HTML response to the browser
  345. *
  346. * @static
  347. * @return void
  348. */
  349. public static function response()
  350. {
  351. $response = PMA_Response::getInstance();
  352. chdir($response->getCWD());
  353. $buffer = PMA_OutputBuffering::getInstance();
  354. if (empty($response->_HTML)) {
  355. $response->_HTML = $buffer->getContents();
  356. }
  357. if ($response->isAjax()) {
  358. $response->_ajaxResponse();
  359. } else {
  360. $response->_htmlResponse();
  361. }
  362. $buffer->flush();
  363. exit;
  364. }
  365. }
  366. ?>