scanner/modules/scanner_functions.php

153 lines
5.5 KiB
PHP
Raw Permalink Normal View History

<?php
$FunctionsModule_functions = array();
$FunctionsModule_local_functions = array();
$FunctionsModule_file = '';
$FunctionsModule_instance = new FunctionsModule();
function FunctionsModule_callback_global( $object ) {
global $FunctionsModule_functions, $FunctionsModule_file;
$FunctionsModule_functions[$object['name']] = array(
'used' => 0,
'file' => $object['file']
);
}
function FunctionsModule_callback_local( $object ) {
global $FunctionsModule_local_functions, $FunctionsModule_file;
$file = $FunctionsModule_file;
if( !isset( $FunctionsModule_local_functions[$file] ) ) {
$FunctionsModule_local_functions[$file] = array();
}
$FunctionsModule_local_functions[$file][strtolower( $object['name'] )] = array(
'used' => 0,
'file' => $object['file']
);
}
class FunctionsModule extends ScannerModule {
var $include_paths;
var $internal_functions;
var $included_files;
function FunctionsModule() {
$this->ScannerModule();
// Preload library function declarations
$library_folders = array(
'libs',
'inc',
'incs',
'includes'
);
global $base_path;
$parser = new PHPParser( PHPPARSER_FETCH_FUNCTIONS );
$parser->registerCallback( 'FunctionsModule_callback_global' );
//$parser->registerCallback( 'FunctionsModule_callback_local' );
$this->include_paths = array();
$paths = array();
$path = realpath( $base_path );
if( !in_array( $path, $paths ) ) {
$paths[] = $path;
$contents = scandir( $path );
foreach( $contents as $node ) {
if(
is_dir( "$path/$node" )
&& in_array( strtolower( $node ), $library_folders )
&& !in_array( "$path/$node", $this->include_paths )
) {
$this->include_paths[] = "$path/$node";
}
}
}
$include_files = array();
$functions = array();
foreach( $this->include_paths as $path ) {
exec( "find $path -iname '*.php' 2>/dev/null", $output, $result );
$include_files = array_merge( $include_files, $output );
}
err( "Parsing function libraries...\n" );
$counter = 0; $total = count( $include_files );
foreach( $include_files as $file ) {
$counter++;
scan_progress( $counter, $total, 'Scanning Function Libraries [%d/%d]' );
$parser->parseFile( $file );
}
$this->internal_functions = get_defined_functions();
$this->internal_functions = $this->internal_functions['internal'];
}
function parserCallback( $object ) {
global $FunctionsModule_functions;
global $FunctionsModule_local_functions;
global $FunctionsModule_file;
$FunctionsModule_file = filename( $object['file'] );
switch( $object['type'] ) {
case PHPPARSER_INCLUDE:
$this->included_files[] = $object;
if( $object['name'] == 'global.php' ) {
$global_includes = array(
'libs/security/lib_security_input.php',
'libs/get/lib_get_portal.php',
'libs/logging/lib_logging_errors.php',
);
foreach ($global_includes as $global_include) {
$object['name'] = $global_include;
$this->included_files[] = $object;
}
}
break;
case PHPPARSER_FUNCTION_CALL:
if( !in_array( $object['name'], array_keys( $FunctionsModule_functions ) ) ) {
if(
!in_array( $object['name'], $this->internal_functions )
&& !in_array( $object['name'], array_keys( $FunctionsModule_local_functions[filename( $object['file'] )] ) )
) {
$this->fault( $object, FAULT_MAJOR, "Undefined function '{$object['name']}'", true );
}
continue;
}
$include = filename( $FunctionsModule_functions[$object['name']]['file'] );
if( $include != filename( $object['file'] ) ) {
//$functions[$object['name']]['used']++;
//if( !isset( $file_requires[$file]['libs'][$include] ) ) { $file_requires[$file]['libs'][$include] = array( 'lines' => array(), 'calls' => array() ); }
//$lib =& $file_requires[$file]['libs'][$include];
$bad = $warning = true;
foreach( $this->included_files as $libinc ) {
if( $libinc['name'] != $include || !in_array( $libinc['in_function'], array( '', $object['in_function'] ) ) ) { continue; }
$inc = $libinc;
$bad = false;
$warning = !$bad && !in_array( $libinc['block'], $object['open_blocks'] );
if( !$bad && !$warning ) { break; }
}
$open_blocks = is_array( $object['open_blocks'] ) ? implode( ',', $object['open_blocks'] ) : '';
$info = "called[l={$object['line']};b={$object['block']};d={$object['depth']}]" . ( !$bad ? ", required[l={$inc['line']};b={$inc['block']};d={$inc['depth']}] open[{$open_blocks}]" : '' );
if( $bad === true ) {
$this->fault( $object, FAULT_MAJOR, "Undefined function '{$object['name']}' $info", true );
} elseif( $warning === true ) {
$this->fault( $object, FAULT_MEDIUM, "Potentially undefined function '{$object['name']}' $info", true );
}
}
break;
}
}
function preScan( $file ) {
parent::preScan( $file );
global $FunctionsModule_local_functions, $FunctionsModule_file;
$FunctionsModule_file = filename( $file['filename'] );
$FunctionsModule_local_functions = array();
$FunctionsModule_local_functions[filename( $file['filename'] )] = array();
$parser = new PHPParser( PHPPARSER_FETCH_FUNCTIONS );
$parser->registerCallback( 'FunctionsModule_callback_local' );
if( $file['revision'] > 0 ) {
$file_contents = isset( $file['contents'] ) ? $file['contents'] : shell_exec( "svn cat -r {$file['revision']} {$svn_root}{$svn_base}/{$file['filename']} 2>/dev/null" );
$parser->parse( $file_contents );
} else {
$parser->parseFile( $file['filename'] );
}
$this->included_files = array();
}
}
addModule( $FunctionsModule_instance );
?>