OutputBuffering.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <?php
  2. /**
  3. * Output buffering wrapper
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin;
  7. use function defined;
  8. use function flush;
  9. use function function_exists;
  10. use function header;
  11. use function ini_get;
  12. use function ob_end_clean;
  13. use function ob_flush;
  14. use function ob_get_contents;
  15. use function ob_get_length;
  16. use function ob_get_level;
  17. use function ob_get_status;
  18. use function ob_start;
  19. use function register_shutdown_function;
  20. /**
  21. * Output buffering wrapper class
  22. */
  23. class OutputBuffering
  24. {
  25. /** @var self */
  26. private static $instance;
  27. /** @var int */
  28. private $mode;
  29. /** @var string */
  30. private $content;
  31. /** @var bool */
  32. private $on;
  33. /**
  34. * Initializes class
  35. */
  36. private function __construct()
  37. {
  38. $this->mode = $this->getMode();
  39. $this->on = false;
  40. }
  41. /**
  42. * This function could be used eventually to support more modes.
  43. *
  44. * @return int the output buffer mode
  45. */
  46. private function getMode()
  47. {
  48. $mode = 0;
  49. if ($GLOBALS['cfg']['OBGzip'] && function_exists('ob_start')) {
  50. if (ini_get('output_handler') === 'ob_gzhandler') {
  51. // If a user sets the output_handler in php.ini to ob_gzhandler, then
  52. // any right frame file in phpMyAdmin will not be handled properly by
  53. // the browser. My fix was to check the ini file within the
  54. // PMA_outBufferModeGet() function.
  55. $mode = 0;
  56. } elseif (function_exists('ob_get_level') && ob_get_level() > 0) {
  57. // happens when php.ini's output_buffering is not Off
  58. ob_end_clean();
  59. $mode = 1;
  60. } else {
  61. $mode = 1;
  62. }
  63. }
  64. // Zero (0) is no mode or in other words output buffering is OFF.
  65. // Follow 2^0, 2^1, 2^2, 2^3 type values for the modes.
  66. // Useful if we ever decide to combine modes. Then a bitmask field of
  67. // the sum of all modes will be the natural choice.
  68. return $mode;
  69. }
  70. /**
  71. * Returns the singleton OutputBuffering object
  72. *
  73. * @return OutputBuffering object
  74. */
  75. public static function getInstance()
  76. {
  77. if (empty(self::$instance)) {
  78. self::$instance = new OutputBuffering();
  79. }
  80. return self::$instance;
  81. }
  82. /**
  83. * This function will need to run at the top of all pages if output
  84. * output buffering is turned on. It also needs to be passed $mode from
  85. * the PMA_outBufferModeGet() function or it will be useless.
  86. *
  87. * @return void
  88. */
  89. public function start()
  90. {
  91. if ($this->on) {
  92. return;
  93. }
  94. if ($this->mode && function_exists('ob_gzhandler')) {
  95. ob_start('ob_gzhandler');
  96. }
  97. ob_start();
  98. if (! defined('TESTSUITE')) {
  99. header('X-ob_mode: ' . $this->mode);
  100. }
  101. register_shutdown_function(
  102. [
  103. self::class,
  104. 'stop',
  105. ]
  106. );
  107. $this->on = true;
  108. }
  109. /**
  110. * This function will need to run at the bottom of all pages if output
  111. * buffering is turned on. It also needs to be passed $mode from the
  112. * PMA_outBufferModeGet() function or it will be useless.
  113. *
  114. * @return void
  115. */
  116. public static function stop()
  117. {
  118. $buffer = self::getInstance();
  119. if (! $buffer->on) {
  120. return;
  121. }
  122. $buffer->on = false;
  123. $buffer->content = ob_get_contents();
  124. if (ob_get_length() <= 0) {
  125. return;
  126. }
  127. ob_end_clean();
  128. }
  129. /**
  130. * Gets buffer content
  131. *
  132. * @return string buffer content
  133. */
  134. public function getContents()
  135. {
  136. return $this->content;
  137. }
  138. /**
  139. * Flushes output buffer
  140. *
  141. * @return void
  142. */
  143. public function flush()
  144. {
  145. if (ob_get_status() && $this->mode) {
  146. ob_flush();
  147. } else {
  148. flush();
  149. }
  150. }
  151. }