Text output is now tab delimited, one fault per line. Added an html output module. Mantis: 2691

git-svn-id: file:///srv/svn/scanner/trunk@5 a0501263-5b7a-4423-a8ba-1edf086583e7
This commit is contained in:
Correl Roush 2008-02-15 19:05:09 +00:00
parent d0714c149b
commit 2386113895
7 changed files with 210 additions and 33 deletions

109
modules/output_html.php Normal file
View file

@ -0,0 +1,109 @@
<?php
class HTMLOutput extends OutputModule {
function write( $filename ) {
global $faults, $files;
$output = fopen( $filename, 'w' );
if( $output === false ) {
err( "Cannot write to $filename\n" );
return false;
}
fwrite( $output,
'<html>
<head>
<title>Code Scanner Output</title>
<style type="text/css">
.fault {
padding: 5px;
margin-bottom: 5px;
border-style: solid;
border-width: 1px;
}
.fault.level_0 {
color: #3f1c00;
background-color: #cf5c00;
border-color: #8f4000;
}
.fault.level_1 {
color: #3f0000;
background-color: #cf0000;
border-color: #8f0000;
}
.fault.level_2 {
color: #eee;
background-color: #333;
border-color: #999;
}
.fault dt {
cursor: pointer;
}
.fault code {
color: #000;
display: block;
margin-left: 10px;
border: 1px dashed #999;
background-color: #eee;
padding: 5px;
}
</style>
<script type="text/javascript">
function toggleDisplay( id ) {
var e = document.getElementById( "info_" + id );
if( e.style.display == "none" ) {
e.style.display = "block";
} else {
e.style.display = "none";
}
}
</script>
</head>
<body>
<h1>Code Scanner Output</h1>
<h2>Summary</h2>
<p>Found ' . count( $faults ) . ' faults in ' . count( $files ) . ' files</p>
<h2>Faults by file</h2>
<dl>'
);
$current_file = '';
foreach( $faults as $id => $fault ) {
$svn = serialize( $fault['svn'] );
if( $current_file != $fault['object']['file'] ) {
if( $current_file != '' ) {
fwrite( $output, '</ul></dd>' );
}
$current_file = $fault['object']['file'];
fwrite( $output, "<dt>$current_file</dt><dd><ul>" );
}
fprintf( $output,
'<li>
<dl class="fault level_%s">
<dt onclick="toggleDisplay( ' . $id . ')"><strong>%s:</strong> <span class="reason">%s</span></dt>
<dd id="info_' . $id . '" style="display: none;">
<strong>Line:</strong> <span class="line">%d</span><br />
<strong>Author:</strong> <span class="author">%s</span><br />
<strong>Revision:</strong> <span class="revision">%s</span><br />
<strong>Code:</strong>
<code>%s</code>
</dd>
</dl>
</li>',
$fault['level'],
$fault['module'],
$fault['reason'],
$fault['object']['line'],
isset( $fault['svn']['author'] ) ? $fault['svn']['author'] : 'Unknown',
isset( $fault['svn']['revision'] ) ? $fault['svn']['revision'] : 'Unknown',
$fault['object']['context']
);
}
fwrite( $output,
' </dl>
</body>
</html>' . "\n"
);
fclose( $output );
}
}
addModule( new HTMLOutput() );
?>

27
modules/output_text.php Normal file
View file

@ -0,0 +1,27 @@
<?php
class TextOutput extends OutputModule {
function write( $filename ) {
global $faults;
$output = fopen( $filename, 'w' );
if( $output === false ) {
err( "Cannot write to $filename\n" );
return false;
}
foreach( $faults as $fault ) {
$svn = serialize( $fault['svn'] );
fprintf( $output, "%s\t%d\t%s\t%d\t%s\t%d\t%s\n",
$fault['module'],
$fault['level'],
$fault['object']['file'],
$fault['object']['line'],
isset( $fault['svn']['author'] ) ? $fault['svn']['author'] : '?',
isset( $fault['svn']['revision'] ) ? $fault['svn']['revision'] : '0',
$fault['reason']
);
}
fclose( $output );
}
}
addModule( new TextOutput() );
?>

View file

@ -143,5 +143,5 @@ class FunctionsModule extends ScannerModule {
}
}
$modules[] = $FunctionsModule_instance;
addModule( $FunctionsModule_instance );
?>

View file

@ -8,13 +8,15 @@ class LintModule extends ScannerModule {
$output = array();
exec( "php -l '$filename' 2>/dev/null", $output, $result );
if( $result != 0 ) {
$file = file( $filename );
foreach( $output as $linterror ) {
$matches = array();
if( preg_match( '/error:.*?on line (\d+)$/i', $linterror, $matches ) == 0 ) { continue; }
$this->fault(
array(
'file' => $filename,
'line' => $matches[1]
'line' => $matches[1],
'context' => $file[$matches[1] - 1]
),
FAULT_MAJOR,
$linterror
@ -24,5 +26,5 @@ class LintModule extends ScannerModule {
}
}
$modules[] = new LintModule();
addModule( new LintModule() );
?>

View file

@ -41,5 +41,5 @@ class PatternModule extends ScannerModule {
}
}
$modules[] = new PatternModule();
addModule( new PatternModule() );
?>

View file

@ -75,7 +75,7 @@ class PHPParser {
function parse( $content ) {
$tokens = token_get_all( $content );
$lines = preg_split( '/\r?(\n|\r)/', $content );
$line = 1;
$depth = 0;
$block = 0;
@ -144,6 +144,7 @@ class PHPParser {
'type' => PHPPARSER_FUNCTION_CALL,
'name' => strtolower( $string ),
'file' => $this->file_name,
'context' => $lines[$line],
'line' => $line,
'block' => $block,
'depth' => $depth,
@ -160,6 +161,7 @@ class PHPParser {
'type' => PHPPARSER_EXPRESSION,
'name' => trim( $expression ),
'file' => $this->file_name,
'context' => $lines[$line],
'line' => $line,
'block' => $block,
'depth' => $depth,
@ -188,6 +190,7 @@ class PHPParser {
'type' => PHPPARSER_CLASS_DEF,
'name' => strtolower( $string ),
'file' => $this->file_name,
'context' => $lines[$line],
'line' => $line,
'block' => $block,
'depth' => $depth,
@ -203,6 +206,7 @@ class PHPParser {
'type' => PHPPARSER_FUNCTION_DEF,
'name' => strtolower( $string ),
'file' => $this->file_name,
'context' => $lines[$line],
'line' => $line,
'block' => $block,
'depth' => $depth,
@ -225,6 +229,7 @@ class PHPParser {
'type' => PHPPARSER_INCLUDE,
'name' => trim( str_replace( '\'', '', $text ) ),
'file' => $this->file_name,
'context' => $lines[$line],
'line' => $line,
'block' => $block,
'depth' => $depth,
@ -275,6 +280,7 @@ class PHPParser {
'type' => PHPPARSER_LANGUAGE_CONSTRUCT,
'name' => $text,
'file' => $this->file_name,
'context' => $lines[$line],
'line' => $line,
'block' => $block,
'depth' => $depth,

View file

@ -5,19 +5,27 @@ define( 'FAULT_MINOR', 0 );
define( 'FAULT_MEDIUM', 1 );
define( 'FAULT_MAJOR', 2 );
$modules = array();
$modules = array(
'scanner' => array(),
'output' => new OutputModule()
);
$stderr = fopen( 'php://stderr', 'w' );
$config = array(
'svn' => false,
'modules' => array(),
'output_format' => 'text',
'output_file' => 'php://stdout',
'quiet' => false,
);
$help = "Usage: {$argv[0]} [options] file|path [file|path ...]
Options:
-b Set the base path for the scan. Useful if you want
--base-path to scan individual files in a code base that don't
-b path Set the base path for the scan. Useful if you want
--base-path path to scan individual files in a code base that don't
live in the project's base directory.
-f format Select the output format. Defaults to text.
--format format
-h Display this usage information
--help
@ -25,11 +33,15 @@ Options:
--module modulename parameter is not specified, all available modules
will be loaded.
-o filename Write output to a file instead of stdout
--output filename
-q Suppresses all progress output
--quiet
--svn Enables SVN integration
";
$faults = array();
class ScannerModule {
var $faults;
@ -41,9 +53,10 @@ class ScannerModule {
err( "Initializing " . get_class( $this ) . "...\n" );
}
function fault( $object, $level, $reason = '' ) {
global $config;
global $config, $faults;
$object['file'] = filename( $object['file'] );
$this->faults[] = array(
$faults[] = $this->faults[] = array(
'module' => get_class( $this ),
'object' => $object,
'level' => $level,
'reason' => $reason,
@ -74,12 +87,28 @@ class ScannerModule {
}
}
class OutputModule {
function display() {
$this->write( 'php://output' );
}
function write( $filename ) {
}
}
function _callback( $object ) {
global $modules;
foreach( $modules as $module ) {
foreach( $modules['scanner'] as $module ) {
$module->parserCallback( $object );
}
}
function addModule( $module_instance ) {
global $modules;
if( $module_instance instanceof ScannerModule ) {
$modules['scanner'][] = $module_instance;
} elseif( $module_instance instanceof OutputModule ) {
$modules['output'] = $module_instance;
}
}
function filename( $filename ) {
global $base_path;
$filename = realpath( $filename );
@ -108,6 +137,10 @@ for( $i = 1; $i < $argc; $i++ ) {
$base_path = realpath( $new_base ) . '/';
}
break;
case '-f':
case '--format':
$config['output_format'] = $argv[++$i];
break;
case '-h':
case '--help':
die( $help );
@ -116,6 +149,10 @@ for( $i = 1; $i < $argc; $i++ ) {
case '--module':
$config['modules'][] = $argv[++$i];
break;
case '-o':
case '--output':
$config['output_file'] = $argv[++$i];
break;
case '-q':
case '--quiet':
$config['quiet'] = true;
@ -144,11 +181,21 @@ $module_files = scandir( 'modules' );
foreach( $module_files as $module_file ) {
if( strtolower( substr( $module_file, -4 ) ) == '.php' ) {
$module = substr( $module_file, 0, strlen( $module_file ) - 4 );
if(
count( $config['modules'] ) == 0
|| ( in_array( $module, $config['modules'] ) )
) {
require_once( "modules/{$module_file}" );
list( $type, $module ) = split( '_', $module );
switch( $type ) {
case 'output':
if( $module == $config['output_format'] ) {
require_once( "modules/{$module_file}" );
}
break;
case 'scanner':
if(
count( $config['modules'] ) == 0
|| in_array( $module, $config['modules'] )
) {
require_once( "modules/{$module_file}" );
}
break;
}
}
}
@ -168,24 +215,10 @@ foreach( $files as $file ) {
$lastpct = $pct;
}
}
foreach( $modules as $module ) { $module->preScan( $file ); }
foreach( $modules['scanner'] as $module ) { $module->preScan( $file ); }
$parser->parseFile( $file );
}
err( "\n" );
foreach( $modules as $module ) {
foreach( $module->faults as $fault ) {
$svn = serialize( $fault['svn'] );
printf( "%s %s - %s\n -- %s:%d, %s r%d\n",
get_class( $module ),
$fault['level'],
$fault['reason'],
$fault['object']['file'],
$fault['object']['line'],
isset( $fault['svn']['author'] ) ? $fault['svn']['author'] : '?',
isset( $fault['svn']['revision'] ) ? $fault['svn']['revision'] : '?'
);
}
}
$modules['output']->write( $config['output_file'] );
err( sprintf( "Found %d faults in %d files.\n", count( $faults ), count( $files ) ) );
?>