[ Index ]

PHP Cross Reference of Joomla 2.5.4 DE

title

Body

[close]

/plugins/system/debug/ -> debug.php (source)

   1  <?php
   2  /**
   3   * @copyright    Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
   4   * @license        GNU General Public License version 2 or later; see LICENSE.txt
   5   */
   6  
   7  // no direct access
   8  defined('_JEXEC') or die;
   9  
  10  /**
  11   * Joomla! Debug plugin
  12   *
  13   * @package        Joomla.Plugin
  14   * @subpackage    System.debug
  15   */
  16  class plgSystemDebug extends JPlugin
  17  {
  18      protected $linkFormat = '';
  19  
  20      /**
  21       * Constructor.
  22       *
  23       * @param   object  &$subject  The object to observe
  24       * @param   array   $config    An array that holds the plugin configuration
  25       *
  26       * @since 1.5
  27       */
  28  	public function __construct(&$subject, $config)
  29      {
  30          parent::__construct($subject, $config);
  31  
  32          // Log the deprecated API.
  33          if ($this->params->get('log-deprecated'))
  34          {
  35              JLog::addLogger(array('text_file' => 'deprecated.php'), JLog::ALL, array('deprecated'));
  36          }
  37  
  38          // Only if debugging or language debug is enabled
  39          if (JDEBUG || JFactory::getApplication()->getCfg('debug_lang'))
  40          {
  41              JFactory::getConfig()->set('gzip', 0);
  42              ob_start();
  43              ob_implicit_flush(false);
  44          }
  45  
  46          $this->linkFormat = ini_get('xdebug.file_link_format');
  47      }
  48  
  49      /**
  50       * Add the CSS for debug. We can't do this in the constructor because
  51       * stuff breaks.
  52       */
  53  	public function onAfterDispatch()
  54      {
  55          // Only if debugging or language debug is enabled
  56          if (JDEBUG || JFactory::getApplication()->getCfg('debug_lang'))
  57          {
  58              JHtml::_('stylesheet', 'cms/debug.css', array(), true);
  59          }
  60      }
  61  
  62      /**
  63       * Show the debug info
  64       */
  65  	public function __destruct()
  66      {
  67          // Do not render if debugging or language debug is not enabled
  68          if (!JDEBUG
  69          && ! JFactory::getApplication()->getCfg('debug_lang'))
  70          {
  71              return;
  72          }
  73  
  74          // Load the language
  75          $this->loadLanguage();
  76  
  77          // Capture output
  78          $contents = ob_get_contents();
  79          ob_end_clean();
  80  
  81          // No debug for Safari and Chrome redirection
  82          if (strstr(strtolower($_SERVER['HTTP_USER_AGENT']), 'webkit') !== false
  83          && substr($contents, 0, 50) == '<html><head><meta http-equiv="refresh" content="0;')
  84          {
  85              echo $contents;
  86              return;
  87          }
  88  
  89          // Only render for HTML output
  90          if ('html' !== JFactory::getDocument()->getType())
  91          {
  92              echo $contents;
  93              return;
  94          }
  95  
  96          // If the user is not allowed to view the output then end here
  97          $filterGroups = (array) $this->params->get('filter_groups', null);
  98  
  99          if (!empty($filterGroups))
 100          {
 101              $userGroups = JFactory::getUser()->get('groups');
 102  
 103              if (!array_intersect($filterGroups, $userGroups))
 104              {
 105                  echo $contents;
 106                  return;
 107              }
 108          }
 109  
 110          // Load language file
 111          $this->loadLanguage('plg_system_debug');
 112  
 113          $html = '';
 114  
 115          // Some "mousewheel protecting" JS
 116          $html .= "<script>function toggleContainer(name) {
 117              var e = document.getElementById(name);// MooTools might not be available ;)
 118              e.style.display =(e.style.display == 'none') ? 'block' : 'none';
 119          }</script>";
 120  
 121          $html .= '<div id="system-debug" class="profiler">';
 122  
 123          $html .= '<h1>'.JText::_('PLG_DEBUG_TITLE').'</h1>';
 124  
 125          if (JDEBUG)
 126          {
 127              if (JError::getErrors())
 128              {
 129                  $html .= $this->display('errors');
 130              }
 131  
 132              //$html .= print_r($data[$l], 1);
 133  
 134              $html .= $this->display('session');
 135  
 136  
 137              if ($this->params->get('profile', 1))
 138              {
 139                  $html .= $this->display('profile_information');
 140              }
 141  
 142              if ($this->params->get('memory', 1))
 143              {
 144                  $html .= $this->display('memory_usage');
 145              }
 146  
 147              if ($this->params->get('queries', 1))
 148              {
 149                  $html .= $this->display('queries');
 150              }
 151          }
 152  
 153          if (JFactory::getApplication()->getCfg('debug_lang'))
 154          {
 155              if ($this->params->get('language_errorfiles', 1))
 156              {
 157                  $languageErrors = JFactory::getLanguage()->getErrorFiles();
 158                  $html .= $this->display('language_files_in_error', $languageErrors);
 159              }
 160  
 161              if ($this->params->get('language_files', 1))
 162              {
 163                  $html .= $this->display('language_files_loaded');
 164              }
 165  
 166              if ($this->params->get('language_strings'))
 167              {
 168                  $html .= $this->display('untranslated_strings');
 169              }
 170          }
 171  
 172          $html .= '</div>';
 173  
 174          echo str_replace('</body>', $html.'</body>', $contents);
 175      }
 176  
 177      /**
 178       * General display method.
 179       *
 180       * @param   string  $item    The item to display
 181       * @param   array   $errors  Errors occured during execution
 182       *
 183       * @return string
 184       */
 185  	protected function display($item, array $errors = array())
 186      {
 187          $title = JText::_('PLG_DEBUG_'.strtoupper($item));
 188  
 189          $status = '';
 190  
 191          if(count($errors))
 192          {
 193              $status = ' dbgerror';
 194          }
 195  
 196          $fncName = 'display'.ucfirst(str_replace('_', '', $item));
 197  
 198          if ( ! method_exists($this, $fncName))
 199          {
 200              return __METHOD__.' -- Unknown method: '.$fncName.'<br />';
 201          }
 202  
 203          $html = '';
 204  
 205          $js = "toggleContainer('dbgContainer".$item."');";
 206  
 207          $class = 'dbgHeader'.$status;
 208  
 209          $html .= '<div class="'.$class.'" onclick="'.$js.'"><a href="javascript:void(0);"><h3>'.$title.'</h3></a></div>';
 210  
 211          $style = ' style="display: none;"';//@todo set with js.. ?
 212  
 213          $html .= '<div '.$style.' class="dbgContainer" id="dbgContainer'.$item.'">';
 214          $html .= $this->$fncName();
 215          $html .= '</div>';
 216  
 217          return $html;
 218      }
 219  
 220      /**
 221       * Display session information.
 222       *
 223       * Called recursive.
 224       *
 225       * @param  string   $key      A session key
 226       * @param  mixed    $session  The session array, initially null
 227       * @param  integer  $id       The id is used for JS toggling the div
 228       *
 229       * @return string
 230       */
 231  	protected function displaySession($key = '', $session = null, $id = 0)
 232      {
 233          if( ! $session) $session = $_SESSION;
 234  
 235          static $html = '';
 236  
 237          if( ! is_array($session))
 238          {
 239              $html .= $key.' &rArr;'.$session.PHP_EOL;
 240          }
 241          else
 242          {
 243              foreach ($session as $sKey => $entries)
 244              {
 245                  $display = true;
 246  
 247                  if(is_array($entries) && $entries)
 248                  {
 249                      $display = false;
 250                  }
 251  
 252                  if(is_object($entries))
 253                  {
 254                      $o = JArrayHelper::fromObject($entries);
 255  
 256                      if($o)
 257                      {
 258                          $entries = $o;
 259                          $display = false;
 260                      }
 261                  }
 262  
 263                  if( ! $display)
 264                  {
 265                      $js = "toggleContainer('dbgContainer_session".$id."');";
 266  
 267                      $html .= '<div class="dbgHeader" onclick="'.$js.'"><a href="javascript:void(0);"><h3>'.$sKey.'</h3></a></div>';
 268  
 269                      $style = ' style="display: none;"';//@todo set with js.. ?
 270  
 271                      $html .= '<div '.$style.' class="dbgContainer" id="dbgContainer_session'.$id.'">';
 272                      $id ++;
 273  
 274                      // Recurse...
 275                      $this->displaySession($sKey, $entries, $id);
 276  
 277                      $html .= '</div>';
 278  
 279                      continue;
 280                  }
 281  
 282                  $html .= '<code>';
 283                  $html .= $sKey.' &rArr; '.$entries.'<br />';
 284                  $html .= '</code>';
 285              }
 286          }
 287  
 288          return $html;
 289      }
 290  
 291      /**
 292       * Display errors.
 293       *
 294       * @return string
 295       */
 296  	protected function displayErrors()
 297      {
 298          $html = '';
 299  
 300          $html .= '<ol>';
 301  
 302          while ($error = JError::getError(true))
 303          {
 304              $col =(E_WARNING == $error->get('level')) ? 'red' : 'orange';
 305  
 306              $html .= '<li>';
 307              $html .= '<b style="color: '.$col.'">'.$error->getMessage().'</b><br />';
 308  
 309              $info = $error->get('info');
 310  
 311              if ($info)
 312              {
 313                  $html .= '<pre>'.print_r($info, true).'</pre><br />';
 314              }
 315  
 316              $html .= $this->renderBacktrace($error);
 317              $html .= '</li>';
 318          }
 319  
 320          $html .= '</ol>';
 321  
 322          return $html;
 323      }
 324  
 325      /**
 326       * Display profile information.
 327       *
 328       * @return string
 329       */
 330  	protected function displayProfileInformation()
 331      {
 332          $html = '';
 333  
 334          foreach (JProfiler::getInstance('Application')->getBuffer() as $mark)
 335          {
 336              $html .= '<div>'.$mark.'</div>';
 337          }
 338  
 339          return $html;
 340      }
 341  
 342      /**
 343       * Display memory usage
 344       *
 345       * @return string
 346       */
 347  	protected function displayMemoryUsage()
 348      {
 349          $html = '';
 350  
 351          $bytes = JProfiler::getInstance('Application')->getMemory();
 352  
 353          $html .= '<code>';
 354          $html .= JHtml::_('number.bytes', $bytes);
 355          $html .= ' ('.number_format($bytes).' Bytes)';
 356          $html .= '</code>';
 357  
 358          return $html;
 359      }
 360  
 361      /**
 362       * Display logged queries.
 363       *
 364       * @return string
 365       */
 366  	protected function displayQueries()
 367      {
 368          $db    = JFactory::getDbo();
 369  
 370          $log = $db->getLog();
 371  
 372          if ( ! $log)
 373          {
 374              return;
 375          }
 376  
 377          $html = '';
 378  
 379          $html .= '<h4>'.JText::sprintf('PLG_DEBUG_QUERIES_LOGGED',  $db->getCount()).'</h4>';
 380  
 381          $html .= '<ol>';
 382  
 383          $selectQueryTypeTicker = array();
 384          $otherQueryTypeTicker = array();
 385  
 386          foreach ($log as $k => $sql)
 387          {
 388              // Start Query Type Ticker Additions
 389              $fromStart = stripos($sql, 'from');
 390              $whereStart = stripos($sql, 'where', $fromStart);
 391  
 392              if ($whereStart === false)
 393              {
 394                  $whereStart = stripos($sql, 'order by', $fromStart);
 395              }
 396  
 397              if ($whereStart === false)
 398              {
 399                  $whereStart = strlen($sql) - 1;
 400              }
 401  
 402              $fromString = substr($sql, 0, $whereStart);
 403              $fromString = str_replace("\t", " ", $fromString);
 404              $fromString = str_replace("\n", " ", $fromString);
 405              $fromString = trim($fromString);
 406  
 407              // Initialize the select/other query type counts the first time:
 408              if (!isset($selectQueryTypeTicker[$fromString]))
 409              {
 410                  $selectQueryTypeTicker[$fromString] = 0;
 411              }
 412  
 413              if (!isset($otherQueryTypeTicker[$fromString]))
 414              {
 415                  $otherQueryTypeTicker[$fromString] = 0;
 416              }
 417  
 418              // Increment the count:
 419              if (stripos($sql, 'select') === 0)
 420              {
 421                  $selectQueryTypeTicker[$fromString] = $selectQueryTypeTicker[$fromString] + 1;
 422                  unset($otherQueryTypeTicker[$fromString]);
 423              }
 424              else
 425              {
 426                  $otherQueryTypeTicker[$fromString] = $otherQueryTypeTicker[$fromString] + 1;
 427                  unset($selectQueryTypeTicker[$fromString]);
 428              }
 429  
 430              $text = $this->highlightQuery($sql);
 431  
 432              $html .= '<li><code>'.$text.'</code></li>';
 433          }
 434  
 435          $html .= '</ol>';
 436  
 437          if ( ! $this->params->get('query_types', 1))
 438          {
 439              return $html;
 440          }
 441  
 442          // Get the totals for the query types:
 443          $totalSelectQueryTypes = count($selectQueryTypeTicker);
 444          $totalOtherQueryTypes = count($otherQueryTypeTicker);
 445          $totalQueryTypes = $totalSelectQueryTypes + $totalOtherQueryTypes;
 446  
 447          $html .= '<h4>'.JText::sprintf('PLG_DEBUG_QUERY_TYPES_LOGGED', $totalQueryTypes) . '</h4>';
 448  
 449          if ($totalSelectQueryTypes)
 450          {
 451              $html .= '<h5>'.JText::sprintf('PLG_DEBUG_SELECT_QUERIES').'</h5>';
 452  
 453              arsort($selectQueryTypeTicker);
 454  
 455              $html .= '<ol>';
 456  
 457              foreach ($selectQueryTypeTicker as $query => $occurrences)
 458              {
 459                  $html .= '<li><code>'.JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES'
 460                  , $this->highlightQuery($query), $occurrences).'</code></li>';
 461              }
 462  
 463              $html .= '</ol>';
 464          }
 465  
 466          if ($totalOtherQueryTypes)
 467          {
 468              $html .= '<h5>'.JText::sprintf('PLG_DEBUG_OTHER_QUERIES').'</h5>';
 469  
 470              arsort($otherQueryTypeTicker);
 471  
 472              $html .= '<ol>';
 473  
 474              foreach ($otherQueryTypeTicker as $query => $occurrences)
 475              {
 476                  $html .= '<li><code>'.JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES'
 477                  , $this->highlightQuery($query), $occurrences).'</code></li>';
 478              }
 479              $html .= '</ol>';
 480          }
 481  
 482          return $html;
 483      }
 484  
 485      /**
 486       * Displays errors in language files.
 487       *
 488       * @return string
 489       */
 490  	protected function displayLanguageFilesInError()
 491      {
 492          $html = '';
 493  
 494          $errorfiles = JFactory::getLanguage()->getErrorFiles();
 495  
 496          if ( ! count($errorfiles))
 497          {
 498              $html .= '<p>' . JText::_('JNONE') . '</p>';
 499  
 500              return $html;
 501          }
 502  
 503          $html .= '<ul>';
 504  
 505          foreach ($errorfiles as $file => $error)
 506          {
 507              $html .= '<li>'.$this->formatLink($file)
 508              .str_replace($file, '', $error).'</li>';
 509          }
 510  
 511          $html .= '</ul>';
 512  
 513          return $html;
 514      }
 515  
 516      /**
 517       * Display loaded language files.
 518       *
 519       * @return string
 520       */
 521  	protected function displayLanguageFilesLoaded()
 522      {
 523          $html = '';
 524  
 525          $html .= '<ul>';
 526  
 527          foreach (JFactory::getLanguage()->getPaths() as $extension => $files)
 528          {
 529              foreach ($files as $file => $status)
 530              {
 531                  $html .= '<li>';
 532  
 533                  $html .= ($status)
 534                  ? JText::_('PLG_DEBUG_LANG_LOADED')
 535                  : JText::_('PLG_DEBUG_LANG_NOT_LOADED');
 536  
 537                  $html .= ' : ';
 538                  $html .= $this->formatLink($file);
 539                  $html .= '</li>';
 540              }
 541          }
 542  
 543          $html .= '</ul>';
 544  
 545          return $html;
 546      }
 547  
 548      /**
 549       * Display untranslated language strings.
 550       *
 551       * @return string
 552       */
 553  	protected function displayUntranslatedStrings()
 554      {
 555          $stripFirst    = $this->params->get('strip-first');
 556          $stripPref    = $this->params->get('strip-prefix');
 557          $stripSuff    = $this->params->get('strip-suffix');
 558  
 559          $orphans = JFactory::getLanguage()->getOrphans();
 560  
 561          $html = '';
 562  
 563          if ( ! count($orphans))
 564          {
 565              $html .= '<p>' . JText::_('JNONE') . '</p>';
 566  
 567              return $html;
 568          }
 569  
 570          ksort($orphans, SORT_STRING);
 571  
 572          $guesses = array();
 573  
 574          foreach ($orphans as $key => $occurance)
 575          {
 576              if (is_array($occurance) && isset($occurance[0]))
 577              {
 578                  $info = $occurance[0];
 579                  $file = ($info['file']) ? $info['file'] : '';
 580  
 581                  if (!isset($guesses[$file]))
 582                  {
 583                      $guesses[$file] = array();
 584                  }
 585  
 586                  // Prepare the key
 587  
 588                  if (($pos = strpos($info['string'], '=')) > 0)
 589                  {
 590                      $parts    = explode('=', $info['string']);
 591                      $key    = $parts[0];
 592                      $guess    = $parts[1];
 593                  }
 594                  else
 595                  {
 596                      $guess = str_replace('_', ' ', $info['string']);
 597  
 598                      if ($stripFirst)
 599                      {
 600                          $parts = explode(' ', $guess);
 601                          if (count($parts) > 1)
 602                          {
 603                              array_shift($parts);
 604                              $guess = implode(' ', $parts);
 605                          }
 606                      }
 607  
 608                      $guess = trim($guess);
 609  
 610                      if ($stripPref)
 611                      {
 612                          $guess = trim(preg_replace(chr(1).'^'.$stripPref.chr(1).'i', '', $guess));
 613                      }
 614  
 615                      if ($stripSuff)
 616                      {
 617                          $guess = trim(preg_replace(chr(1).$stripSuff.'$'.chr(1).'i', '', $guess));
 618                      }
 619                  }
 620  
 621                  $key = trim(strtoupper($key));
 622                  $key = preg_replace('#\s+#', '_', $key);
 623                  $key = preg_replace('#\W#', '', $key);
 624  
 625                  // Prepare the text
 626                  $guesses[$file][] = $key.'="'.$guess.'"';
 627              }
 628          }
 629  
 630  
 631          foreach ($guesses as $file => $keys)
 632          {
 633              $html .= "\n\n# ".($file ? $this->formatLink($file) : JText::_('PLG_DEBUG_UNKNOWN_FILE'))."\n\n";
 634              $html .= implode("\n", $keys);
 635          }
 636  
 637          return '<pre>'.$html.'</pre>';
 638      }
 639  
 640      /**
 641       * Simple highlight for SQL queries.
 642       *
 643       * @param   string  $sql  The query to highlight
 644       *
 645       * @return string
 646       */
 647  	protected function highlightQuery($sql)
 648      {
 649          $newlineKeywords = '#\b(FROM|LEFT|INNER|OUTER|WHERE|SET|VALUES|ORDER|GROUP|HAVING|LIMIT|ON|AND|CASE)\b#i';
 650  
 651          $sql = htmlspecialchars($sql, ENT_QUOTES);
 652  
 653          $sql = preg_replace($newlineKeywords, '<br />&#160;&#160;\\0', $sql);
 654  
 655          $regex = array(
 656  
 657          // Tables are identified by the prefix
 658          '/(=)/'
 659          => '<b class="dbgOperator">$1</b>',
 660  
 661          // All uppercase words have a special meaning
 662          '/(?<!\w|>)([A-Z_]{2,})(?!\w)/x'
 663          => '<span class="dbgCommand">$1</span>',
 664  
 665          // Tables are identified by the prefix
 666          '/('.JFactory::getDbo()->getPrefix().'[a-z_0-9]+)/'
 667          => '<span class="dbgTable">$1</span>'
 668  
 669          );
 670  
 671          $sql = preg_replace(array_keys($regex), array_values($regex), $sql);
 672  
 673          $sql = str_replace('*', '<b style="color: red;">*</b>', $sql);
 674  
 675          return $sql;
 676      }
 677  
 678      /**
 679       * Render the backtrace.
 680       *
 681       * Stolen from JError to prevent it's removal.
 682       *
 683       * @param   integer  $error  The error
 684       *
 685       * @return  string  Contents of the backtrace
 686       */
 687  	protected function renderBacktrace($error)
 688      {
 689          $backtrace = $error->getTrace();
 690  
 691          $html = '';
 692  
 693          if (is_array($backtrace))
 694          {
 695              $j = 1;
 696  
 697              $html .= '<table cellpadding="0" cellspacing="0">';
 698  
 699              $html .= '<tr>';
 700              $html .= '<td colspan="3"><strong>Call stack</strong></td>';
 701              $html .= '</tr>';
 702  
 703              $html .= '<tr>';
 704              $html .= '<th>#</th>';
 705              $html .= '<th>Function</th>';
 706              $html .= '<th>Location</th>';
 707              $html .= '</tr>';
 708  
 709              for ($i = count($backtrace) - 1; $i >= 0 ; $i--)
 710              {
 711                  $link = '&#160;';
 712  
 713                  if (isset($backtrace[$i]['file']))
 714                  {
 715                      $link = $this->formatLink($backtrace[$i]['file'], $backtrace[$i]['line']);
 716                  }
 717  
 718                  $html .= '<tr>';
 719                  $html .= '<td>'.$j.'</td>';
 720  
 721                  if (isset($backtrace[$i]['class']))
 722                  {
 723                      $html .= '<td>'.$backtrace[$i]['class'].$backtrace[$i]['type'].$backtrace[$i]['function'].'()</td>';
 724                  }
 725                  else
 726                  {
 727                      $html .= '<td>'.$backtrace[$i]['function'].'()</td>';
 728                  }
 729  
 730                  $html .= '<td>'.$link.'</td>';
 731  
 732                  $html .= '</tr>';
 733                  $j++;
 734              }
 735  
 736              $html .= '</table>';
 737          }
 738  
 739          return $html;
 740      }
 741  
 742      /**
 743       * Replaces the Joomla! root with "JROOT" to improve readability.
 744       * Formats a link with a special value xdebug.file_link_format
 745       * from the php.ini file.
 746       *
 747       * @param   string  $file  The full path to the file.
 748       * @param   string  $line  The line number.
 749       *
 750       * @return string
 751       */
 752  	protected function formatLink($file, $line = '')
 753      {
 754          $link = str_replace(JPATH_ROOT, 'JROOT', $file);
 755          $link .=($line) ? ':'.$line : '';
 756  
 757          if ($this->linkFormat)
 758          {
 759              $href = $this->linkFormat;
 760              $href = str_replace('%f', $file, $href);
 761              $href = str_replace('%l', $line, $href);
 762  
 763              $html = '<a href="'.$href.'">'.$link.'</a>';
 764          }
 765          else
 766          {
 767              $html = $link;
 768          }
 769  
 770          return $html;
 771      }
 772  
 773  }


Generated: Tue Apr 3 11:40:28 2012 Cross-referenced by PHPXref 0.7.1