Important: This is a development wiki, so things might be a little unstable. If something doesn't work properly, try refreshing the page. If that fails, come back later!

Debugging tools/show source

From TestWiki

Jump to: navigation, search

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 = "&nbsp;";
									$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 = "&nbsp;";
												$Output .= '<td>' . $RowValue . '</td>';
											}
										}
										$Output .= '</tr>';
									}
									$Output .= '</table>';
								}
								else
									$Output .= "&nbsp;&nbsp;&nbsp;" . 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
	// &copy; entity, as this might otherwise be displayed as a question-mark, due to 
	// encoding issues.
		$Output = str_replace("©", "&copy;", $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.
Personal tools