Oppaitime's version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

debug.class.php 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. <?php
  2. // Debug info for developers
  3. ini_set('max_execution_time', 600);
  4. define('MAX_TIME', 20000); //Maximum execution time in ms
  5. define('MAX_ERRORS', 0); //Maxmimum errors, warnings, notices we will allow in a page
  6. define('MAX_MEMORY', 80 * 1024 * 1024); //Maximum memory used per pageload
  7. define('MAX_QUERIES', 30); //Maxmimum queries
  8. class DEBUG
  9. {
  10. public $Errors = [];
  11. public $Flags = [];
  12. public $Perf = [];
  13. private $LoggedVars = [];
  14. public function profile($Automatic = '')
  15. {
  16. global $ScriptStartTime;
  17. $Reason = [];
  18. if (!empty($Automatic)) {
  19. $Reason[] = $Automatic;
  20. }
  21. $Micro = (microtime(true) - $ScriptStartTime) * 1000;
  22. if ($Micro > MAX_TIME && !defined('TIME_EXCEPTION')) {
  23. $Reason[] = number_format($Micro, 3).' ms';
  24. }
  25. $Errors = count($this->get_errors());
  26. if ($Errors > MAX_ERRORS && !defined('ERROR_EXCEPTION')) {
  27. $Reason[] = $Errors.' PHP errors';
  28. }
  29. /*
  30. $Queries = count($this->get_queries());
  31. if ($Queries > MAX_QUERIES && !defined('QUERY_EXCEPTION')) {
  32. $Reason[] = $Queries.' Queries';
  33. }
  34. */
  35. $Ram = memory_get_usage(true);
  36. if ($Ram > MAX_MEMORY && !defined('MEMORY_EXCEPTION')) {
  37. $Reason[] = Format::get_size($Ram).' RAM used';
  38. }
  39. G::$DB->warnings(); // see comment in MYSQL::query
  40. /*$Queries = $this->get_queries();
  41. $DBWarningCount = 0;
  42. foreach ($Queries as $Query) {
  43. if (!empty($Query[2])) {
  44. $DBWarningCount += count($Query[2]);
  45. }
  46. }
  47. if ($DBWarningCount) {
  48. $Reason[] = $DBWarningCount . ' DB warning(s)';
  49. }*/
  50. $CacheStatus = G::$Cache->server_status();
  51. if (in_array(0, $CacheStatus) && !G::$Cache->get_value('cache_fail_reported')) {
  52. // Limit to max one report every 15 minutes to avoid massive debug spam
  53. G::$Cache->cache_value('cache_fail_reported', true, 900);
  54. $Reason[] = "Cache server error";
  55. }
  56. if (isset($_REQUEST['profile'])) {
  57. $Reason[] = 'Requested by ' . G::$LoggedUser['Username'];
  58. }
  59. $this->Perf['Memory usage'] = (($Ram>>10) / 1024).' MB';
  60. $this->Perf['Page process time'] = number_format($Micro / 1000, 3).' s';
  61. $this->Perf['CPU time'] = number_format($this->get_cpu_time() / 1000000, 3).' s';
  62. if (isset($Reason[0])) {
  63. $this->log_var($CacheStatus, 'Cache server status');
  64. $this->analysis(implode(', ', $Reason));
  65. return true;
  66. }
  67. return false;
  68. }
  69. public function analysis($Message, $Report = '', $Time = 43200)
  70. {
  71. global $Document;
  72. if (empty($Report)) {
  73. $Report = $Message;
  74. }
  75. $Identifier = Users::make_secret(5);
  76. G::$Cache->cache_value(
  77. 'analysis_'.$Identifier,
  78. array(
  79. 'url' => $_SERVER['REQUEST_URI'],
  80. 'message' => $Report,
  81. 'errors' => $this->get_errors(true),
  82. 'queries' => $this->get_queries(),
  83. 'flags' => $this->get_flags(),
  84. 'includes' => $this->get_includes(),
  85. 'cache' => $this->get_cache_keys(),
  86. 'vars' => $this->get_logged_vars(),
  87. 'perf' => $this->get_perf(),
  88. 'ocelot' => $this->get_ocelot_requests()
  89. ),
  90. $Time
  91. );
  92. $RequestURI = !empty($_SERVER['REQUEST_URI']) ? substr($_SERVER['REQUEST_URI'], 1) : '';
  93. send_irc('PRIVMSG '.LAB_CHAN." :{$Message} $Document ".site_url()."tools.php?action=analysis&case=$Identifier ".site_url().$RequestURI);
  94. }
  95. public function get_cpu_time()
  96. {
  97. if (!defined('PHP_WINDOWS_VERSION_MAJOR')) {
  98. global $CPUTimeStart;
  99. $RUsage = getrusage();
  100. $CPUTime = $RUsage['ru_utime.tv_sec'] * 1000000 + $RUsage['ru_utime.tv_usec'] - $CPUTimeStart;
  101. return $CPUTime;
  102. }
  103. return false;
  104. }
  105. public function log_var($Var, $VarName = false)
  106. {
  107. $BackTrace = debug_backtrace();
  108. $ID = Users::make_secret(5);
  109. if (!$VarName) {
  110. $VarName = $ID;
  111. }
  112. $File = array('path' => substr($BackTrace[0]['file'], strlen(SERVER_ROOT)), 'line' => $BackTrace[0]['line']);
  113. $this->LoggedVars[$ID] = array($VarName => array('bt' => $File, 'data' => $Var));
  114. }
  115. public function set_flag($Event)
  116. {
  117. global $ScriptStartTime;
  118. $this->Flags[] = array($Event, (microtime(true) - $ScriptStartTime) * 1000, memory_get_usage(true), $this->get_cpu_time());
  119. }
  120. //This isn't in the constructor because $this is not available, and the function cannot be made static
  121. public function handle_errors()
  122. {
  123. //error_reporting(E_ALL ^ E_STRICT | E_WARNING | E_DEPRECATED | E_ERROR | E_PARSE); //E_STRICT disabled
  124. error_reporting(E_WARNING | E_ERROR | E_PARSE);
  125. set_error_handler(array($this, 'php_error_handler'));
  126. }
  127. protected function format_args($Array)
  128. {
  129. $LastKey = -1;
  130. $Return = [];
  131. foreach ($Array as $Key => $Val) {
  132. $Return[$Key] = '';
  133. if (!is_int($Key) || $Key != $LastKey + 1) {
  134. $Return[$Key] .= "'$Key' => ";
  135. }
  136. if ($Val === true) {
  137. $Return[$Key] .= 'true';
  138. } elseif ($Val === false) {
  139. $Return[$Key] .= 'false';
  140. } elseif (is_string($Val)) {
  141. $Return[$Key] .= "'$Val'";
  142. } elseif (is_int($Val)) {
  143. $Return[$Key] .= $Val;
  144. } elseif (is_object($Val)) {
  145. $Return[$Key] .= get_class($Val);
  146. } elseif (is_array($Val)) {
  147. $Return[$Key] .= 'array('.$this->format_args($Val).')';
  148. }
  149. $LastKey = $Key;
  150. }
  151. return implode(', ', $Return);
  152. }
  153. public function php_error_handler($Level, $Error, $File, $Line)
  154. {
  155. //Who added this, it's still something to pay attention to...
  156. if (stripos('Undefined index', $Error) !== false) {
  157. //return true;
  158. }
  159. $Steps = 1; //Steps to go up in backtrace, default one
  160. $Call = '';
  161. $Args = '';
  162. $Tracer = debug_backtrace();
  163. //This is in case something in this function goes wrong and we get stuck with an infinite loop
  164. if (isset($Tracer[$Steps]['function'], $Tracer[$Steps]['class']) && $Tracer[$Steps]['function'] == 'php_error_handler' && $Tracer[$Steps]['class'] == 'DEBUG') {
  165. return true;
  166. }
  167. //If this error was thrown, we return the function which threw it
  168. if (isset($Tracer[$Steps]['function']) && $Tracer[$Steps]['function'] == 'trigger_error') {
  169. $Steps++;
  170. $File = $Tracer[$Steps]['file'];
  171. $Line = $Tracer[$Steps]['line'];
  172. }
  173. //At this time ONLY Array strict typing is fully supported.
  174. //Allow us to abuse strict typing (IE: function test(Array))
  175. if (preg_match('/^Argument (\d+) passed to \S+ must be an (array), (array|string|integer|double|object) given, called in (\S+) on line (\d+) and defined$/', $Error, $Matches)) {
  176. $Error = 'Type hinting failed on arg '.$Matches[1]. ', expected '.$Matches[2].' but found '.$Matches[3];
  177. $File = $Matches[4];
  178. $Line = $Matches[5];
  179. }
  180. //Lets not be repetative
  181. if (($Tracer[$Steps]['function'] == 'include' || $Tracer[$Steps]['function'] == 'require') && isset($Tracer[$Steps]['args'][0]) && $Tracer[$Steps]['args'][0] == $File) {
  182. unset($Tracer[$Steps]['args']);
  183. }
  184. //Class
  185. if (isset($Tracer[$Steps]['class'])) {
  186. $Call .= $Tracer[$Steps]['class'].'::';
  187. }
  188. //Function & args
  189. if (isset($Tracer[$Steps]['function'])) {
  190. $Call .= $Tracer[$Steps]['function'];
  191. if (isset($Tracer[$Steps]['args'][0])) {
  192. $Args = $this->format_args($Tracer[$Steps]['args']);
  193. }
  194. }
  195. //Shorten the path & we're done
  196. $File = str_replace(SERVER_ROOT, '', $File);
  197. $Error = str_replace(SERVER_ROOT, '', $Error);
  198. if (DEBUG_WARNINGS) {
  199. $this->Errors[] = array($Error, $File.':'.$Line, $Call, $Args);
  200. }
  201. return true;
  202. }
  203. /* Data wrappers */
  204. public function get_perf()
  205. {
  206. if (empty($this->Perf)) {
  207. global $ScriptStartTime;
  208. $PageTime = (microtime(true) - $ScriptStartTime);
  209. $CPUTime = $this->get_cpu_time();
  210. $Perf = array(
  211. 'Memory usage' => Format::get_size(memory_get_usage(true)),
  212. 'Page process time' => number_format($PageTime, 3).' s');
  213. if ($CPUTime) {
  214. $Perf['CPU time'] = number_format($CPUTime / 1000000, 3).' s';
  215. }
  216. return $Perf;
  217. }
  218. return $this->Perf;
  219. }
  220. public function get_flags()
  221. {
  222. return $this->Flags;
  223. }
  224. public function get_errors($Light = false)
  225. {
  226. //Because the cache can't take some of these variables
  227. if ($Light) {
  228. foreach ($this->Errors as $Key => $Value) {
  229. $this->Errors[$Key][3] = '';
  230. }
  231. }
  232. return $this->Errors;
  233. }
  234. public function get_constants()
  235. {
  236. return get_defined_constants(true);
  237. }
  238. public function get_classes()
  239. {
  240. foreach (get_declared_classes() as $Class) {
  241. $Classes[$Class]['Vars'] = get_class_vars($Class);
  242. $Classes[$Class]['Functions'] = get_class_methods($Class);
  243. }
  244. return $Classes;
  245. }
  246. public function get_extensions()
  247. {
  248. foreach (get_loaded_extensions() as $Extension) {
  249. $Extensions[$Extension]['Functions'] = get_extension_funcs($Extension);
  250. }
  251. return $Extensions;
  252. }
  253. public function get_includes()
  254. {
  255. return get_included_files();
  256. }
  257. public function get_cache_time()
  258. {
  259. return G::$Cache->Time;
  260. }
  261. public function get_cache_keys()
  262. {
  263. return array_keys(G::$Cache->CacheHits);
  264. }
  265. public function get_sphinxql_queries()
  266. {
  267. if (class_exists('Sphinxql')) {
  268. return Sphinxql::$Queries;
  269. }
  270. }
  271. public function get_sphinxql_time()
  272. {
  273. if (class_exists('Sphinxql')) {
  274. return Sphinxql::$Time;
  275. }
  276. }
  277. public function get_queries()
  278. {
  279. return G::$DB->Queries;
  280. }
  281. public function get_query_time()
  282. {
  283. return G::$DB->Time;
  284. }
  285. public function get_logged_vars()
  286. {
  287. return $this->LoggedVars;
  288. }
  289. public function get_ocelot_requests()
  290. {
  291. if (class_exists('Tracker')) {
  292. return Tracker::$Requests;
  293. }
  294. }
  295. /* Output Formatting */
  296. public function perf_table($Perf = false)
  297. {
  298. if (!is_array($Perf)) {
  299. $Perf = $this->get_perf();
  300. }
  301. if (empty($Perf)) {
  302. return;
  303. } ?>
  304. <table class="layout">
  305. <tr>
  306. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_perf').gtoggle(); return false;" class="brackets">View</a> Performance Statistics:</strong></td>
  307. </tr>
  308. </table>
  309. <table id="debug_perf" class="debug_table hidden">
  310. <?php
  311. foreach ($Perf as $Stat => $Value) {
  312. ?>
  313. <tr class="valign_top">
  314. <td class="debug_perf_stat"><?=$Stat?></td>
  315. <td class="debug_perf_data"><?=$Value?></td>
  316. </tr>
  317. <?php
  318. } ?>
  319. </table>
  320. <?php
  321. }
  322. public function include_table($Includes = false)
  323. {
  324. if (!is_array($Includes)) {
  325. $Includes = $this->get_includes();
  326. } ?>
  327. <table class="layout">
  328. <tr>
  329. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_include').gtoggle(); return false;" class="brackets">View</a> <?=number_format(count($Includes))?> Includes:</strong></td>
  330. </tr>
  331. </table>
  332. <table id="debug_include" class="debug_table hidden">
  333. <?php
  334. foreach ($Includes as $File) {
  335. ?>
  336. <tr class="valign_top">
  337. <td><?=$File?></td>
  338. </tr>
  339. <?php
  340. } ?>
  341. </table>
  342. <?php
  343. }
  344. public function class_table($Classes = false)
  345. {
  346. if (!is_array($Classes)) {
  347. $Classes = $this->get_classes();
  348. } ?>
  349. <table class="layout">
  350. <tr>
  351. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_classes').gtoggle(); return false;" class="brackets">View</a> Classes:</strong></td>
  352. </tr>
  353. </table>
  354. <table id="debug_classes" class="debug_table hidden">
  355. <tr>
  356. <td>
  357. <pre>
  358. <?php print_r($Classes);
  359. echo "\n"; ?>
  360. </pre>
  361. </td>
  362. </tr>
  363. </table>
  364. <?php
  365. }
  366. public function extension_table()
  367. {
  368. ?>
  369. <table class="layout">
  370. <tr>
  371. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_extensions').gtoggle(); return false;" class="brackets">View</a> Extensions:</strong></td>
  372. </tr>
  373. </table>
  374. <table id="debug_extensions" class="debug_table hidden">
  375. <tr>
  376. <td>
  377. <pre>
  378. <?php print_r($this->get_extensions());
  379. echo "\n"; ?>
  380. </pre>
  381. </td>
  382. </tr>
  383. </table>
  384. <?php
  385. }
  386. public function flag_table($Flags = false)
  387. {
  388. if (!is_array($Flags)) {
  389. $Flags = $this->get_flags();
  390. }
  391. if (empty($Flags)) {
  392. return;
  393. } ?>
  394. <table class="layout">
  395. <tr>
  396. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_flags').gtoggle(); return false;" class="brackets">View</a> Flags:</strong></td>
  397. </tr>
  398. </table>
  399. <table id="debug_flags" class="debug_table hidden">
  400. <tr class="valign_top">
  401. <td class="debug_flags_event"><strong>Event</strong></td>
  402. <td class="debug_flags_time"><strong>Page time</strong></td>
  403. <?php if ($Flags[0][3] !== false) { ?>
  404. <td class="debug_flags_time"><strong>CPU time</strong></td>
  405. <?php } ?>
  406. <td class="debug_flags_memory"><strong>Memory</strong></td>
  407. </tr>
  408. <?php
  409. foreach ($Flags as $Flag) {
  410. list($Event, $MicroTime, $Memory, $CPUTime) = $Flag; ?>
  411. <tr class="valign_top">
  412. <td><?=$Event?></td>
  413. <td><?=number_format($MicroTime, 3)?> ms</td>
  414. <?php if ($CPUTime !== false) { ?>
  415. <td><?=number_format($CPUTime / 1000, 3)?> ms</td>
  416. <?php } ?>
  417. <td><?=Format::get_size($Memory)?></td>
  418. </tr>
  419. <?php
  420. } ?>
  421. </table>
  422. <?php
  423. }
  424. public function constant_table($Constants = false)
  425. {
  426. if (!is_array($Constants)) {
  427. $Constants = $this->get_constants();
  428. } ?>
  429. <table class="layout">
  430. <tr>
  431. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_constants').gtoggle(); return false;" class="brackets">View</a> Constants:</strong></td>
  432. </tr>
  433. </table>
  434. <table id="debug_constants" class="debug_table hidden">
  435. <tr>
  436. <td class="debug_data debug_constants_data">
  437. <pre>
  438. <?= display_str(print_r($Constants, true))?>
  439. </pre>
  440. </td>
  441. </tr>
  442. </table>
  443. <?php
  444. }
  445. public function ocelot_table($OcelotRequests = false)
  446. {
  447. if (!is_array($OcelotRequests)) {
  448. $OcelotRequests = $this->get_ocelot_requests();
  449. }
  450. if (empty($OcelotRequests)) {
  451. return;
  452. } ?>
  453. <table class="layout">
  454. <tr>
  455. <td><strong><a data-toggle-target="#debug_ocelot" class="brackets">View</a> <?=number_format(count($OcelotRequests))?> Ocelot requests:</strong></td>
  456. </tr>
  457. </table>
  458. <table id="debug_ocelot" class="debug_table hidden">
  459. <?php foreach ($OcelotRequests as $i => $Request) { ?>
  460. <tr>
  461. <td class="debug_data debug_ocelot_data">
  462. <a data-toggle-target="#debug_ocelot_<?=$i?>"><?=display_str($Request['path'])?></a>
  463. <pre id="debug_ocelot_<?=$i?>" class="hidden"><?=display_str($Request['response'])?></pre>
  464. </td>
  465. <td class="debug_info" style="width: 100px;">
  466. <?=display_str($Request['status'])?>
  467. </td>
  468. <td class="debug_info debug_timing" style="width: 100px;">
  469. <?=number_format($Request['time'], 5)?> ms
  470. </td>
  471. </tr>
  472. <?php } ?>
  473. </table>
  474. <?php
  475. }
  476. public function cache_table($CacheKeys = false)
  477. {
  478. $Header = 'Cache Keys';
  479. if (!is_array($CacheKeys)) {
  480. $CacheKeys = $this->get_cache_keys();
  481. $Header .= ' ('.number_format($this->get_cache_time(), 5).' ms)';
  482. }
  483. if (empty($CacheKeys)) {
  484. return;
  485. }
  486. $Header = ' '.number_format(count($CacheKeys))." $Header:"; ?>
  487. <table class="layout">
  488. <tr>
  489. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_cache').gtoggle(); return false;" class="brackets">View</a><?=$Header?></strong></td>
  490. </tr>
  491. </table>
  492. <table id="debug_cache" class="debug_table hidden">
  493. <?php foreach ($CacheKeys as $Key) { ?>
  494. <tr>
  495. <td class="label nobr debug_info debug_cache_key">
  496. <a href="#" onclick="$('#debug_cache_<?=$Key?>').gtoggle(); return false;"><?=display_str($Key)?></a>
  497. <a href="tools.php?action=clear_cache&amp;key=<?=$Key?>&amp;type=clear" target="_blank" class="brackets tooltip" title="Clear this cache key">Clear</a>
  498. </td>
  499. <td class="debug_data debug_cache_data">
  500. <pre id="debug_cache_<?=$Key?>" class="hidden">
  501. <?= display_str(print_r(G::$Cache->get_value($Key, true), true))?>
  502. </pre>
  503. </td>
  504. </tr>
  505. <?php } ?>
  506. </table>
  507. <?php
  508. }
  509. public function error_table($Errors = false)
  510. {
  511. if (!is_array($Errors)) {
  512. $Errors = $this->get_errors();
  513. }
  514. if (empty($Errors)) {
  515. return;
  516. } ?>
  517. <table class="layout">
  518. <tr>
  519. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_error').gtoggle(); return false;" class="brackets">View</a> <?=number_format(count($Errors))?> Errors:</strong></td>
  520. </tr>
  521. </table>
  522. <table id="debug_error" class="debug_table hidden">
  523. <?php
  524. foreach ($Errors as $Error) {
  525. list($Error, $Location, $Call, $Args) = $Error; ?>
  526. <tr class="valign_top">
  527. <td class="debug_info debug_error_call">
  528. <?=display_str($Call)?>(<?=display_str($Args)?>)
  529. </td>
  530. <td class="debug_data debug_error_data">
  531. <?=display_str($Error)?>
  532. </td>
  533. <td>
  534. <?=display_str($Location)?>
  535. </td>
  536. </tr>
  537. <?php
  538. } ?>
  539. </table>
  540. <?php
  541. }
  542. public function query_table($Queries = false)
  543. {
  544. $Header = 'Queries';
  545. if (!is_array($Queries)) {
  546. $Queries = $this->get_queries();
  547. $Header .= ' ('.number_format($this->get_query_time(), 5).' ms)';
  548. }
  549. if (empty($Queries)) {
  550. return;
  551. }
  552. $Header = ' '.number_format(count($Queries))." $Header:"; ?>
  553. <table class="layout">
  554. <tr>
  555. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_database').gtoggle(); return false;" class="brackets">View</a><?=$Header?></strong></td>
  556. </tr>
  557. </table>
  558. <table id="debug_database" class="debug_table hidden">
  559. <?php
  560. foreach ($Queries as $Query) {
  561. $SQL = $Query[0] ?? null;
  562. $Time = $Query[1] ?? null;
  563. $Warnings = $Query[2] ?? null;
  564. if ($Warnings !== null) {
  565. $Warnings = implode('<br />', $Warnings);
  566. } ?>
  567. <tr class="valign_top">
  568. <td class="debug_data debug_query_data"><div><?=str_replace("\t", '&nbsp;&nbsp;', nl2br(display_str(trim($SQL))))?></div></td>
  569. <td class="debug_info debug_query_time" style="width: 130px;"><?=number_format($Time, 5)?> ms</td>
  570. <td class="debug_info debug_query_warnings"><?=$Warnings?></td>
  571. </tr>
  572. <?php
  573. } ?>
  574. </table>
  575. <?php
  576. }
  577. public function sphinx_table($Queries = false)
  578. {
  579. $Header = 'Searches';
  580. if (!is_array($Queries)) {
  581. $Queries = $this->get_sphinxql_queries();
  582. $Header .= ' ('.number_format($this->get_sphinxql_time(), 5).' ms)';
  583. }
  584. if (empty($Queries)) {
  585. return;
  586. }
  587. $Header = ' '.number_format(count($Queries))." $Header:"; ?>
  588. <table class="layout">
  589. <tr>
  590. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_sphinx').gtoggle(); return false;" class="brackets">View</a><?=$Header?></strong></td>
  591. </tr>
  592. </table>
  593. <table id="debug_sphinx" class="debug_table hidden">
  594. <?php
  595. foreach ($Queries as $Query) {
  596. list($Params, $Time) = $Query; ?>
  597. <tr class="valign_top">
  598. <td class="debug_data debug_sphinx_data"><pre><?=str_replace("\t", ' ', $Params)?></pre></td>
  599. <td class="debug_info debug_sphinx_time" style="width: 130px;"><?=number_format($Time, 5)?> ms</td>
  600. </tr>
  601. <?php
  602. } ?>
  603. </table>
  604. <?php
  605. }
  606. public function vars_table($Vars = false)
  607. {
  608. $Header = 'Logged Variables';
  609. if (empty($Vars)) {
  610. if (empty($this->LoggedVars)) {
  611. return;
  612. }
  613. $Vars = $this->LoggedVars;
  614. }
  615. $Header = ' '.number_format(count($Vars))." $Header:"; ?>
  616. <table class="layout">
  617. <tr>
  618. <td><strong><a href="#" onclick="$(this).parents('.layout').next('#debug_loggedvars').gtoggle(); return false;" class="brackets">View</a><?=$Header?></strong></td>
  619. </tr>
  620. </table>
  621. <table id="debug_loggedvars" class="debug_table hidden">
  622. <?php
  623. foreach ($Vars as $ID => $Var) {
  624. $Key = key($Var);
  625. $Data = current($Var);
  626. $Size = count($Data['data']); ?>
  627. <tr>
  628. <td class="debug_info debug_loggedvars_name">
  629. <a href="#" onclick="$('#debug_loggedvars_<?=$ID?>').gtoggle(); return false;"><?=display_str($Key)?></a> (<?=$Size . ($Size == 1 ? ' element' : ' elements')?>)
  630. <div><?=$Data['bt']['path'].':'.$Data['bt']['line']; ?></div>
  631. </td>
  632. <td class="debug_data debug_loggedvars_data">
  633. <pre id="debug_loggedvars_<?=$ID?>" class="hidden">
  634. <?= display_str(print_r($Data['data'], true))?>
  635. </pre>
  636. </td>
  637. </tr>
  638. <?php
  639. } ?>
  640. </table>
  641. <?php
  642. }
  643. }