scanner/scanner.php

170 lines
4.2 KiB
PHP

<?php
require_once( 'parser.php' );
define( 'FAULT_MINOR', 0 );
define( 'FAULT_MEDIUM', 1 );
define( 'FAULT_MAJOR', 2 );
$modules = array();
$stderr = fopen( 'php://stderr', 'w' );
$config = array(
'svn' => false,
'modules' => array(),
);
$help = "Usage: {$argv[0]} [options] file|path [file|path ...]
Options:
-h Display this usage information
--help
-m modulename Loads the requested scanning module. If this
--module modulename parameter is not specified, all available modules
will be loaded.
--svn Enables SVN integration
";
class ScannerModule {
var $faults;
var $blame;
function ScannerModule() {
$this->faults = array();
$this->blame = array();
err( "Initializing " . get_class( $this ) . "...\n" );
}
function fault( $object, $level, $reason = '' ) {
global $config;
$object['file'] = filename( $object['file'] );
$this->faults[] = array(
'object' => $object,
'level' => $level,
'reason' => $reason,
'svn' => ( $config['svn'] === true ) ? $this->blame[$object['line']] : ''
);
}
function parserCallback( $object ) {
}
function preScan( $filename ) {
global $config;
if( $config['svn'] === true ) {
$this->blame = array();
$output = array();
exec( "svn blame '$filename' 2>/dev/null", $output, $result );
if( $result == 0 ) {
foreach( $output as $line => $text ) {
$matches = array();
preg_match( '/^\s*(\d+)\s+([^\s]+)/', $text, $matches );
$this->blame[$line + 1] = array(
'author' => $matches[2],
'revision' => $matches[1]
);
}
}
}
}
function postScan( $filename ) {
}
}
function _callback( $object ) {
global $modules;
foreach( $modules as $module ) {
$module->parserCallback( $object );
}
}
function filename( $filename ) {
global $base_path;
$filename = realpath( $filename );
if( strpos( $filename, $base_path ) === 0 ) {
$filename = substr( $filename, strlen( $base_path ) );
}
return $filename;
}
function err( $string ) {
global $stderr;
fputs( $stderr, $string );
}
// Handle application arguments
$files = array();
$base_path = false;
for( $i = 1; $i < $argc; $i++ ) {
switch( $argv[$i] ) {
case '-h':
case '--help':
die( $help );
break;
case '-m':
case '--module':
$config['modules'][] = $argv[++$i];
break;
case '--svn':
$config['svn'] = true;
break;
default:
if( file_exists( $argv[$i] ) && strtolower( substr( $argv[$i], -4 ) ) == '.php' ) {
$base_path = ( $base_path === false ) ? realpath( dirname( $argv[$i] ) ) . '/' : $base_path;
$files[] = $argv[$i];
} else if( is_dir( $argv[$i] ) ) {
$base_path = ( $base_path === false ) ? realpath( $argv[$i] ) . '/' : $base_path;
exec( "find $base_path -iname '*.php' 2>/dev/null", $output, $result );
$files = array_merge( $files, $output );
}
}
}
if( count( $files ) == 0 ) {
die( $help );
}
// Dig into the modules folder and load up what we find
$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( $modules ) == 0
|| ( in_array( $module, $config['modules'] ) )
) {
require_once( "modules/{$module_file}" );
}
}
}
$parser = new PHPParser();
$parser->registerCallback( '_callback' );
err( "Parsing files...\n" );
$counter = 0; $total = count( $files ); $lastpct = 0;
foreach( $files as $file ) {
$counter++;
if( $counter == 1 ) { err( 0 ); }
else {
$pct = intval( $counter / $total * 100 );
if( $pct != $lastpct && $pct % 2 == 0 ) {
err( $pct % 10 == 0 ? $pct : '.' );
$lastpct = $pct;
}
}
foreach( $modules 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'] : '?'
);
}
}
?>