scanner/modules/functions.php

148 lines
5.1 KiB
PHP
Raw Normal View History

<?php
$FunctionsModule_functions = array();
$FunctionsModule_local_functions = array();
$FunctionsModule_instance = new FunctionsModule();
function FunctionsModule_callback_global( $object ) {
global $FunctionsModule_functions;
$FunctionsModule_functions[$object['name']] = array(
'used' => 0,
'file' => $object['file']
);
}
function FunctionsModule_callback_local( $object ) {
global $FunctionsModule_local_functions;
$file = filename( $object['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 ); $lastpct = 0;
foreach( $include_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;
}
}
$parser->parseFile( $file );
}
err( "\n" );
$this->internal_functions = get_defined_functions();
$this->internal_functions = $this->internal_functions['internal'];
}
function parserCallback( $object ) {
global $FunctionsModule_functions;
global $FunctionsModule_local_functions;
switch( $object['type'] ) {
case PHPPARSER_INCLUDE:
$this->included_files[] = $object;
if( $object['name'] == 'global.php' ) {
$object['name'] = 'libs/security/lib_security_input.php';
$this->included_files[] = $object;
$object['name'] = 'libs/get/lib_get_portal.php';
$this->included_files[] = $object;
$object['name'] = 'libs/logging/lib_logging_errors.php';
$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']}'" );
}
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" );
} elseif( $warning === true ) {
$this->fault( $object, FAULT_MEDIUM, "Potentially undefined function '{$object['name']}' $info" );
}
}
break;
}
}
function preScan( $filename ) {
parent::preScan( $filename );
global $FunctionsModule_local_functions;
$FunctionsModule_local_functions = array();
$FunctionsModule_local_functions[filename( $filename)] = array();
$parser = new PHPParser( PHPPARSER_FETCH_FUNCTIONS );
$parser->registerCallback( 'FunctionsModule_callback_local' );
$parser->parseFile( $filename );
$this->included_files = array();
}
}
$modules[] = $FunctionsModule_instance;
?>