Debugging tools/show source
From TestWiki
The WikiDebug extension adds a new tag that allows you to display the contents of a php file within the page. For security reasons it only allows the display of files that are added to an array of allowed files. If an extension that adds a hook for the 'php' tag has been installed (e.g. the GeSHi Syntax Highlighter) then this will be used to wrap the output, otherwise 'pre' tags will be used.
Syntax
<show_source file="{FileName}"></show_source>
- {FileName} is the name of a file residing on the server.
As a security measure this extension will only allow display of tables added to the $wgWikiDebug_ViewableFiles array. Any other files are blocked.
For example, to view the file containing this extension, you would need to add the following to LocalSettings.php:
$wgWikiDebug_ViewableFiles[] = "WikiDebug.php";
Note that paths are relative to the current include path, which includes the extensions directory on this wiki, but which may not on yours.
Example 1: WikiDebug.php
Here is the current (live) contents of WikiDebug.php - the file that contains this extension.
<show_source file="WikiDebug.php"></show_source>
Live sourcecode viewer: WikiDebug.php
Last modified: 2008-10-23 02:12:04
<?php if (!defined('MEDIAWIKI')) die("MediaWiki extensions cannot be run directly."); /** * An extension to implement various useful debugging tools. * * @package MediaWiki * @subpackage Extensions * * @author Mark Clements <mclements at kennel17 dot co dot uk> * @copyright copyright © 2006, Mark Clements * @license http://creativecommons.org/licenses/by-sa/2.5/ cc-by-sa 2.5 or later * @version $Rev: 114 $ */ if (!isset($wgWikiDebug_ViewableTables)) $wgWikiDebug_ViewableTables = array(); if (!isset($wgWikiDebug_ViewableFiles)) $wgWikiDebug_ViewableFiles = array(); $wgExtensionCredits['other'][] = array( 'name' => 'WikiDebug', 'author' => 'Mark Clements', 'description' => "a set of debugging tools for extension developers", 'url' => 'http://www.kennel17.co.uk/testwiki/Debugging%20tools', ); $pWikiDebug_Messages = array( // Messages for wfWikiDebug_DescribeTable() 'debug_table_header' => "Live Table Definition: $1", 'debug_no_table' => "No table specified.", 'debug_table_not_found' => "Table cannot be viewed. It either does not exist, or is protected against viewing.", 'debug_no_fields' => "No fields found.", 'debug_index_header' => "Indexes", 'debug_no_indexes' => "No indexes defined.", 'debug_error_reading_tabledef' => "There was an error reading the table definition!", // Messages for wfWikiDebug_ShowSource() and wfWikiDebug_ShowVersion() 'debug_file_header' => "Live sourcecode viewer: $1", 'debug_last_modified' => "Last modified: $1", 'debug_no_file' => "No file specified.", 'debug_file_blocked' => "File cannot be viewed. It either does not exist, or is protected against viewing.", 'debug_file_blocked_short' => "File not found", 'debug_file_unreadable' => "File cannot be read.", 'debug_no_version' => "version unknown", 'debug_version' => "rev \$1", ); $wgExtensionFunctions[] = "wfWikiDebug"; function wfWikiDebug() { global $wgMessageCache, $wgParser; global $pWikiDebug_Messages; $wgMessageCache->addMessages($pWikiDebug_Messages); // Specific tags to be parsed $wgParser->setHook( "describe_table", "wfWikiDebug_DescribeTable" ); $wgParser->setHook( "show_source", "wfWikiDebug_ShowSource" ); $wgParser->setHook( "show_version", "wfWikiDebug_ShowVersion" ); } function wfWikiDebug_DescribeTable($Input, $Args) { global $wgParser; global $wgWikiDebug_ViewableTables; $wgParser->disableCache(); if (isset($Args['table'])) $TableName = $Args['table']; else $TableName = ""; $Output = "<h3>" . wfMsg('debug_table_header', $TableName) . "</h3>\n"; if ($TableName == "") $Output .= wfMsg('debug_no_table'); elseif (!in_array($TableName, $wgWikiDebug_ViewableTables)) $Output .= wfMsg('debug_table_not_found'); else { $DB =& wfGetDB(DB_MASTER); if ($DB->tableExists($TableName)) { // Get the requested display mode. $Display = "sql"; if (isset($Args['display'])) $Display = strtolower(trim($Args['display'])); // Output the data according to the display mode. switch ($Display) { case "tables": case "table": // Get field data from table $Result = $DB->query("DESCRIBE " . $DB->tableName($TableName) . ";"); $Fields = array(); while ( $row = $DB->fetchObject( $Result ) ) $Fields[] = $row; // If required, get index data from table $ShowIndexes = true; if (isset($Args['showindexes'])) { switch (strtolower(trim($Args['showindexes']))) { case "0": case "false": $ShowIndexes = false; } } $Indexes = array(); if ($ShowIndexes) { $Result = $DB->query("SHOW INDEX FROM " . $DB->tableName($Args['table']) . ";"); while ( $row = $DB->fetchObject( $Result ) ) $Indexes[] = $row; } if (count($Fields) == 0) $Output .= wfMsg('debug_no_fields'); else { $Output .= '<table border="1" cellpadding="5" cellspacing="2"><tr>'; foreach ($Fields[0] as $RowHeader => $Row) $Output .= '<th>' . $RowHeader . '</th>'; foreach ($Fields as $Row) { $Output .= '<tr>'; foreach ($Row as $RowValue) { if ($RowValue === NULL || $RowValue == "") $RowValue = " "; $Output .= '<td>' . $RowValue . '</td>'; } $Output .= '</tr>'; } $Output .= '</table>'; if ($ShowIndexes) { $Output .= "<h3>" . wfMsg('debug_index_header') . "</h3>\n"; if (count($Indexes) > 0) { $Output .= '<table border="1" cellpadding="5" cellspacing="2"><tr>'; foreach ($Indexes[0] as $RowHeader => $Row) { if ($RowHeader != "Table") $Output .= '<th>' . $RowHeader . '</th>'; } foreach ($Indexes as $Row) { $Output .= '<tr>'; foreach ($Row as $RowHeader => $RowValue) { if ($RowHeader != "Table") { if ($RowValue === NULL || $RowValue == "") $RowValue = " "; $Output .= '<td>' . $RowValue . '</td>'; } } $Output .= '</tr>'; } $Output .= '</table>'; } else $Output .= " " . wfMsg('debug_no_indexes'); } } break; case "sql": default: // Get field data from table $Result = $DB->query("SHOW CREATE TABLE " . $DB->tableName($TableName) . ";"); if ( $Result !== false && $row = $DB->fetchObject( $Result ) ) { $SQL = ""; foreach ( $row as $key => $val ) { if ($key = "Create Table") $SQL = htmlspecialchars($val); } $Removables = array( "/character set .* /Ui", "/collate .* /Ui", "/ ?DEFAULT CHARSET=.*( |$)/Ui", "/ ?COLLATE=.*( |$)/Ui", "/ ?AUTO_INCREMENT\s*=\s*([0-9])+/", ); $SQL = preg_replace($Removables, "", $SQL); $Search = array( "/^CREATE TABLE " . $DB->tableName($TableName) . "/i", "/ENGINE=(.*)( |$)/Ui", "/^/m", // Space at the start of the line, to ensure <pre> block works properly. "/([^;])$/", ); $Replace = array( "CREATE TABLE IF NOT EXISTS `" . $TableName . "`", "TYPE=$1$2", " ", "$1;", ); $SQL = preg_replace($Search, $Replace, $SQL); $Output .= $SQL . "\n"; } else $Output .= wfMsg('debug_error_reading_tabledef'); } } else $Output .= wfMsg('debug_table_not_found'); } $Output = '<div style="border: 1px solid #AAAAAA; background-color: #EEEEEE; padding: 1em;">' . $Output . '</div>'; return $Output; } function wfWikiDebug_ShowSource($Input, $Args) { global $wgOut, $wgParser; global $wgWikiDebug_ViewableFiles; $wgParser->disableCache(); $AllowPHPOutput = false; if (isset($Args['file'])) $FileName = $Args['file']; else $FileName = ""; $Header = wfMsg('debug_file_header', $FileName); if ($FileName == "") $Output = wfMsg('debug_no_file'); elseif (!in_array($FileName, $wgWikiDebug_ViewableFiles)) $Output = wfMsg('debug_file_blocked'); else { $FilePath = wfWikiDebug_file_exists_incpath($FileName); if (!$FilePath) $Output = wfMsg('debug_file_blocked'); elseif (($File = fopen($FilePath, "r", true)) === false) $Output = wfMsg('debug_file_unreadable'); else { // Get last modified date $ModDate = date("Y-m-d h:i:s", filemtime($FilePath)); $Header .= "<br><span style=\"font-size: 80%; font-weight: normal;\">" . wfMsg('debug_last_modified', $ModDate) . "</span>"; // Get length of file. fseek($File, 0, SEEK_END); $Length = ftell($File); fseek($File, 0, SEEK_SET); // Get contents of file. $Output = fread($File, $Length); $AllowPHPOutput = true; } } $Header = "<h3>" . $Header . "</h3>\n"; if ($AllowPHPOutput && isset($wgParser->mTagHooks['php'])) { // This can easily use more than the standard available memory, so remove limit. $MemLimit = ini_get('memory_limit'); ini_set('memory_limit', -1); $Output = $Header . call_user_func($wgParser->mTagHooks['php'], $Output, array()); if (preg_match_all('/copyright (.) /i', $Output, $Matches)) { $Matches = array_unique($Matches[1]); foreach ($Matches as $CopyrightSymbol) { $Output = preg_replace('/copyright (' . $CopyrightSymbol . ') /ie', '"copyright " . htmlentities("$1") . " "', $Output); } } ini_set('memory_limit', $MemLimit); } else $Output = "<pre>" . $Header . htmlspecialchars($Output) . "</pre>"; // Some special code to replace the literal copyright symbol with the HTML // © entity, as this might otherwise be displayed as a question-mark, due to // encoding issues. $Output = str_replace("©", "©", $Output); return $Output; } function wfWikiDebug_ShowVersion($Input, $Args) { global $wgOut, $wgParser; global $wgWikiDebug_ViewableFiles; $wgParser->disableCache(); if (isset($Args['file'])) $FileName = $Args['file']; else $FileName = ""; if ($FileName == "") $Output = wfMsg('debug_no_file'); elseif (!in_array($FileName, $wgWikiDebug_ViewableFiles)) $Output = wfMsg('debug_file_blocked_short'); else { $FilePath = wfWikiDebug_file_exists_incpath($FileName); if (!$FilePath) $Output = wfMsg('debug_file_blocked_short'); elseif (($File = fopen($FilePath, "r", true)) === false) $Output = wfMsg('debug_file_unreadable'); else { // Get length of file. fseek($File, 0, SEEK_END); $Length = ftell($File); fseek($File, 0, SEEK_SET); // Get contents of file. $Contents = fread($File, $Length); $VersionRegex = '/(?:\$Rev:|\$LastChangedRevision:|\$Revision:|) ?([0-9]+) ?\$/Ui'; $Result = preg_match($VersionRegex, $Contents, $matches); if (count($matches) > 0) $Output = wfMsg('debug_version', $matches[1]); else $Output = wfMsg('debug_no_version'); } } return "<i>(" . $Output . ")</i>"; } /** * Check if a file exists in the include path * (Renamed to avoid potential naming conflicts) * * @version 1.2.1 (with slight modifications) * @author Aidan Lister <aidan@php.net> (with slight modifications) * @link http://aidanlister.com/repos/v/function.file_exists_incpath.php * @param string $file Name of the file to look for * @return mixed The full path if file exists, FALSE if it does not */ function wfWikiDebug_file_exists_incpath ($file) { $paths = explode(PATH_SEPARATOR, ini_get('include_path')); foreach ($paths as $path) { // Formulate the absolute path $fullpath = $path . DIRECTORY_SEPARATOR . $file; // Check it if (file_exists($fullpath)) return $fullpath; } return false; }
Example 2: Non-viewable file
Here is an attempt to view LocalSettings.php. Because this file is not in the array of allowed files, you are unable to see it's contents:
<show_source file="LocalSettings.php"></show_source>
Live sourcecode viewer: LocalSettings.php
File cannot be viewed. It either does not exist, or is protected against viewing.
