PageRenderTime 43ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/versionpress/vendor/tracy/tracy/src/Tracy/Dumper.php

https://gitlab.com/vanafroo/landingpage
PHP | 353 lines | 255 code | 53 blank | 45 comment | 35 complexity | ae5f4f18757dda3eddc54283e4f028cc MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Tracy (https://tracy.nette.org)
  4. * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  5. */
  6. namespace Tracy;
  7. use Tracy;
  8. /**
  9. * Dumps a variable.
  10. *
  11. * @author David Grudl
  12. */
  13. class Dumper
  14. {
  15. const DEPTH = 'depth', // how many nested levels of array/object properties display (defaults to 4)
  16. TRUNCATE = 'truncate', // how truncate long strings? (defaults to 150)
  17. COLLAPSE = 'collapse', // always collapse? (defaults to false)
  18. COLLAPSE_COUNT = 'collapsecount', // how big array/object are collapsed? (defaults to 7)
  19. LOCATION = 'location'; // show location string? (defaults to false)
  20. /** @var array */
  21. public static $terminalColors = array(
  22. 'bool' => '1;33',
  23. 'null' => '1;33',
  24. 'number' => '1;32',
  25. 'string' => '1;36',
  26. 'array' => '1;31',
  27. 'key' => '1;37',
  28. 'object' => '1;31',
  29. 'visibility' => '1;30',
  30. 'resource' => '1;37',
  31. 'indent' => '1;30',
  32. );
  33. /** @var array */
  34. public static $resources = array(
  35. 'stream' => 'stream_get_meta_data',
  36. 'stream-context' => 'stream_context_get_options',
  37. 'curl' => 'curl_getinfo',
  38. );
  39. /**
  40. * Dumps variable to the output.
  41. * @return mixed variable
  42. */
  43. public static function dump($var, array $options = NULL)
  44. {
  45. if (PHP_SAPI !== 'cli' && !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list()))) {
  46. echo self::toHtml($var, $options);
  47. } elseif (self::detectColors()) {
  48. echo self::toTerminal($var, $options);
  49. } else {
  50. echo self::toText($var, $options);
  51. }
  52. return $var;
  53. }
  54. /**
  55. * Dumps variable to HTML.
  56. * @return string
  57. */
  58. public static function toHtml($var, array $options = NULL)
  59. {
  60. $options = (array) $options + array(
  61. self::DEPTH => 4,
  62. self::TRUNCATE => 150,
  63. self::COLLAPSE => FALSE,
  64. self::COLLAPSE_COUNT => 7,
  65. self::LOCATION => FALSE,
  66. );
  67. list($file, $line, $code) = $options[self::LOCATION] ? self::findLocation() : NULL;
  68. return '<pre class="tracy-dump"'
  69. . ($file ? Helpers::createHtml(' title="%in file % on line %" data-tracy-href="%"', "$code\n", $file, $line, Helpers::editorUri($file, $line)) . '>' : '>')
  70. . self::dumpVar($var, $options)
  71. . ($file ? '<small>in ' . Helpers::editorLink($file, $line) . '</small>' : '')
  72. . "</pre>\n";
  73. }
  74. /**
  75. * Dumps variable to plain text.
  76. * @return string
  77. */
  78. public static function toText($var, array $options = NULL)
  79. {
  80. return htmlspecialchars_decode(strip_tags(self::toHtml($var, $options)), ENT_QUOTES);
  81. }
  82. /**
  83. * Dumps variable to x-terminal.
  84. * @return string
  85. */
  86. public static function toTerminal($var, array $options = NULL)
  87. {
  88. return htmlspecialchars_decode(strip_tags(preg_replace_callback('#<span class="tracy-dump-(\w+)">|</span>#', function ($m) {
  89. return "\033[" . (isset($m[1], Dumper::$terminalColors[$m[1]]) ? Dumper::$terminalColors[$m[1]] : '0') . 'm';
  90. }, self::toHtml($var, $options))), ENT_QUOTES);
  91. }
  92. /**
  93. * Internal toHtml() dump implementation.
  94. * @param mixed variable to dump
  95. * @param array options
  96. * @param int current recursion level
  97. * @return string
  98. */
  99. private static function dumpVar(& $var, array $options, $level = 0)
  100. {
  101. if (method_exists(__CLASS__, $m = 'dump' . gettype($var))) {
  102. return self::$m($var, $options, $level);
  103. } else {
  104. return "<span>unknown type</span>\n";
  105. }
  106. }
  107. private static function dumpNull()
  108. {
  109. return "<span class=\"tracy-dump-null\">NULL</span>\n";
  110. }
  111. private static function dumpBoolean(& $var)
  112. {
  113. return '<span class="tracy-dump-bool">' . ($var ? 'TRUE' : 'FALSE') . "</span>\n";
  114. }
  115. private static function dumpInteger(& $var)
  116. {
  117. return "<span class=\"tracy-dump-number\">$var</span>\n";
  118. }
  119. private static function dumpDouble(& $var)
  120. {
  121. $var = is_finite($var)
  122. ? ($tmp = json_encode($var)) . (strpos($tmp, '.') === FALSE ? '.0' : '')
  123. : var_export($var, TRUE);
  124. return "<span class=\"tracy-dump-number\">$var</span>\n";
  125. }
  126. private static function dumpString(& $var, $options)
  127. {
  128. return '<span class="tracy-dump-string">"'
  129. . htmlspecialchars(self::encodeString($var, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8')
  130. . '"</span>' . (strlen($var) > 1 ? ' (' . strlen($var) . ')' : '') . "\n";
  131. }
  132. private static function dumpArray(& $var, $options, $level)
  133. {
  134. static $marker;
  135. if ($marker === NULL) {
  136. $marker = uniqid("\x00", TRUE);
  137. }
  138. $out = '<span class="tracy-dump-array">array</span> (';
  139. if (empty($var)) {
  140. return $out . ")\n";
  141. } elseif (isset($var[$marker])) {
  142. return $out . (count($var) - 1) . ") [ <i>RECURSION</i> ]\n";
  143. } elseif (!$options[self::DEPTH] || $level < $options[self::DEPTH]) {
  144. $collapsed = $level ? count($var) >= $options[self::COLLAPSE_COUNT] : $options[self::COLLAPSE];
  145. $out = '<span class="tracy-toggle' . ($collapsed ? ' tracy-collapsed' : '') . '">'
  146. . $out . count($var) . ")</span>\n<div" . ($collapsed ? ' class="tracy-collapsed"' : '') . '>';
  147. $var[$marker] = TRUE;
  148. foreach ($var as $k => & $v) {
  149. if ($k !== $marker) {
  150. $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . htmlspecialchars(self::encodeString($k, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') . '"';
  151. $out .= '<span class="tracy-dump-indent"> ' . str_repeat('| ', $level) . '</span>'
  152. . '<span class="tracy-dump-key">' . $k . '</span> => '
  153. . self::dumpVar($v, $options, $level + 1);
  154. }
  155. }
  156. unset($var[$marker]);
  157. return $out . '</div>';
  158. } else {
  159. return $out . count($var) . ") [ ... ]\n";
  160. }
  161. }
  162. private static function dumpObject(& $var, $options, $level)
  163. {
  164. if ($var instanceof \Closure) {
  165. $rc = new \ReflectionFunction($var);
  166. $fields = array();
  167. foreach ($rc->getParameters() as $param) {
  168. $fields[] = '$' . $param->getName();
  169. }
  170. $fields = array(
  171. 'file' => $rc->getFileName(), 'line' => $rc->getStartLine(),
  172. 'variables' => $rc->getStaticVariables(), 'parameters' => implode(', ', $fields)
  173. );
  174. } elseif ($var instanceof \SplFileInfo) {
  175. $fields = array('path' => $var->getPathname());
  176. } elseif ($var instanceof \SplObjectStorage) {
  177. $fields = array();
  178. foreach (clone $var as $obj) {
  179. $fields[] = array('object' => $obj, 'data' => $var[$obj]);
  180. }
  181. } else {
  182. $fields = (array) $var;
  183. }
  184. static $list = array();
  185. $rc = $var instanceof \Closure ? new \ReflectionFunction($var) : new \ReflectionClass($var);
  186. $out = '<span class="tracy-dump-object"'
  187. . ($options[self::LOCATION] && ($editor = Helpers::editorUri($rc->getFileName(), $rc->getStartLine())) ? ' data-tracy-href="' . htmlspecialchars($editor) . '"' : '')
  188. . '>' . htmlspecialchars(Helpers::getClass($var)) . '</span> <span class="tracy-dump-hash">#' . substr(md5(spl_object_hash($var)), 0, 4) . '</span>';
  189. if (empty($fields)) {
  190. return $out . "\n";
  191. } elseif (in_array($var, $list, TRUE)) {
  192. return $out . " { <i>RECURSION</i> }\n";
  193. } elseif (!$options[self::DEPTH] || $level < $options[self::DEPTH] || $var instanceof \Closure) {
  194. $collapsed = $level ? count($fields) >= $options[self::COLLAPSE_COUNT] : $options[self::COLLAPSE];
  195. $out = '<span class="tracy-toggle' . ($collapsed ? ' tracy-collapsed' : '') . '">'
  196. . $out . "</span>\n<div" . ($collapsed ? ' class="tracy-collapsed"' : '') . '>';
  197. $list[] = $var;
  198. foreach ($fields as $k => & $v) {
  199. $vis = '';
  200. if ($k[0] === "\x00") {
  201. $vis = ' <span class="tracy-dump-visibility">' . ($k[1] === '*' ? 'protected' : 'private') . '</span>';
  202. $k = substr($k, strrpos($k, "\x00") + 1);
  203. }
  204. $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . htmlspecialchars(self::encodeString($k, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') . '"';
  205. $out .= '<span class="tracy-dump-indent"> ' . str_repeat('| ', $level) . '</span>'
  206. . '<span class="tracy-dump-key">' . $k . "</span>$vis => "
  207. . self::dumpVar($v, $options, $level + 1);
  208. }
  209. array_pop($list);
  210. return $out . '</div>';
  211. } else {
  212. return $out . " { ... }\n";
  213. }
  214. }
  215. private static function dumpResource(& $var, $options, $level)
  216. {
  217. $type = get_resource_type($var);
  218. $out = '<span class="tracy-dump-resource">' . htmlSpecialChars($type, ENT_IGNORE, 'UTF-8') . ' resource</span> '
  219. . '<span class="tracy-dump-hash">#' . intval($var) . '</span>';
  220. if (isset(self::$resources[$type])) {
  221. $out = "<span class=\"tracy-toggle tracy-collapsed\">$out</span>\n<div class=\"tracy-collapsed\">";
  222. foreach (call_user_func(self::$resources[$type], $var) as $k => $v) {
  223. $out .= '<span class="tracy-dump-indent"> ' . str_repeat('| ', $level) . '</span>'
  224. . '<span class="tracy-dump-key">' . htmlSpecialChars($k, ENT_IGNORE, 'UTF-8') . '</span> => ' . self::dumpVar($v, $options, $level + 1);
  225. }
  226. return $out . '</div>';
  227. }
  228. return "$out\n";
  229. }
  230. /**
  231. * @internal
  232. * @return string UTF-8
  233. */
  234. public static function encodeString($s, $maxLength = NULL)
  235. {
  236. static $table;
  237. if ($table === NULL) {
  238. foreach (array_merge(range("\x00", "\x1F"), range("\x7F", "\xFF")) as $ch) {
  239. $table[$ch] = '\x' . str_pad(dechex(ord($ch)), 2, '0', STR_PAD_LEFT);
  240. }
  241. $table['\\'] = '\\\\';
  242. $table["\r"] = '\r';
  243. $table["\n"] = '\n';
  244. $table["\t"] = '\t';
  245. }
  246. if (preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $s) || preg_last_error()) {
  247. if ($maxLength && strlen($s) > $maxLength) {
  248. $s = substr($s, 0, $maxLength) . ' ... ';
  249. }
  250. $s = strtr($s, $table);
  251. } elseif ($maxLength && strlen(utf8_decode($s)) > $maxLength) {
  252. $s = iconv_substr($s, 0, $maxLength, 'UTF-8') . ' ... ';
  253. }
  254. return $s;
  255. }
  256. /**
  257. * Finds the location where dump was called.
  258. * @return array [file, line, code]
  259. */
  260. private static function findLocation()
  261. {
  262. foreach (debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE) as $item) {
  263. if (isset($item['class']) && $item['class'] === __CLASS__) {
  264. $location = $item;
  265. continue;
  266. } elseif (isset($item['function'])) {
  267. try {
  268. $reflection = isset($item['class'])
  269. ? new \ReflectionMethod($item['class'], $item['function'])
  270. : new \ReflectionFunction($item['function']);
  271. if ($reflection->isInternal() || preg_match('#\s@tracySkipLocation\s#', $reflection->getDocComment())) {
  272. $location = $item;
  273. continue;
  274. }
  275. } catch (\ReflectionException $e) {
  276. }
  277. }
  278. break;
  279. }
  280. if (isset($location['file'], $location['line']) && is_file($location['file'])) {
  281. $lines = file($location['file']);
  282. $line = $lines[$location['line'] - 1];
  283. return array(
  284. $location['file'],
  285. $location['line'],
  286. trim(preg_match('#\w*dump(er::\w+)?\(.*\)#i', $line, $m) ? $m[0] : $line),
  287. );
  288. }
  289. }
  290. /**
  291. * @return bool
  292. */
  293. private static function detectColors()
  294. {
  295. return self::$terminalColors &&
  296. (getenv('ConEmuANSI') === 'ON'
  297. || getenv('ANSICON') !== FALSE
  298. || (defined('STDOUT') && function_exists('posix_isatty') && posix_isatty(STDOUT)));
  299. }
  300. }