Importing code scanner
git-svn-id: file:///srv/svn/scanner/trunk@1 a0501263-5b7a-4423-a8ba-1edf086583e7
This commit is contained in:
commit
4244ed6d8b
3 changed files with 694 additions and 0 deletions
305
flist2.php
Normal file
305
flist2.php
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once( 'parser.php' );
|
||||||
|
|
||||||
|
function microtime_float()
|
||||||
|
{
|
||||||
|
list($usec, $sec) = explode(" ", microtime());
|
||||||
|
return ((float)$usec + (float)$sec);
|
||||||
|
}
|
||||||
|
$stderr = fopen( 'php://stderr', 'w' );
|
||||||
|
function err( $string ) {
|
||||||
|
global $stderr;
|
||||||
|
fputs( $stderr, $string );
|
||||||
|
}
|
||||||
|
|
||||||
|
$time_start = microtime_float();
|
||||||
|
|
||||||
|
$CODE_PATH = !empty( $argv[1] ) ? $argv[1] : '/home/correlr/code/correl';
|
||||||
|
$SCAN_PATH = !empty( $argv[2] ) ? trim( $argv[2] ) : '';
|
||||||
|
if( !empty( $SCAN_PATH ) ) { $SCAN_PATH = "/$SCAN_PATH"; }
|
||||||
|
if( !file_exists( "{$CODE_PATH}{$SCAN_PATH}" ) ) { die( "Bad scan path\n" ); }
|
||||||
|
|
||||||
|
$php_files = `find $CODE_PATH -name '*.php'`;
|
||||||
|
$php_files = split( "\n", $php_files );
|
||||||
|
|
||||||
|
$parser = new PHPParser( PHPPARSER_FETCH_FUNCTIONS );
|
||||||
|
$local_parser = new PHPParser( PHPPARSER_FETCH_FUNCTIONS );
|
||||||
|
|
||||||
|
err( "Parsing Libs\n" );
|
||||||
|
$counter = 0; $total = count( $php_files ); $lastpct = 0;
|
||||||
|
foreach( $php_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" );
|
||||||
|
|
||||||
|
$functions = array();
|
||||||
|
$all_local_functions = array();
|
||||||
|
foreach( $parser->parsed_objects as $function ) {
|
||||||
|
$file = str_replace( "$CODE_PATH/", '', $function['file'] );
|
||||||
|
if( strpos( $file, 'libs/' ) === 0 ) {
|
||||||
|
$functions[$function['name']] = array( 'used' => 0, 'file' => $function['file'] );
|
||||||
|
}
|
||||||
|
if( !is_array( $all_local_functions[$file] ) ) { $all_local_functions[$file] = array(); }
|
||||||
|
$all_local_functions[$file][] = $function['name'];
|
||||||
|
}
|
||||||
|
$functions['eval'] = array( 'used' => 0, 'file' => 'Evil Eval' );
|
||||||
|
|
||||||
|
$php_files = `find {$CODE_PATH}{$SCAN_PATH} -name '*.php'`;
|
||||||
|
$php_files = split( "\n", $php_files );
|
||||||
|
|
||||||
|
$counters = array( 'files' => 0, 'errors' => 0, 'warnings' => 0, 'failed' => 0 );
|
||||||
|
$file_requires = array();
|
||||||
|
err( "Parsing Files\n" );
|
||||||
|
$parser->reset( PHPPARSER_FETCH_INCLUDES + PHPPARSER_FETCH_CALLS + PHPPARSER_FETCH_INTERNAL );
|
||||||
|
$counter = 0; $total = count( $php_files ); $lastpct = 0;
|
||||||
|
foreach( $php_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = trim( $file );
|
||||||
|
if( empty( $file ) ) { continue; }
|
||||||
|
$filename = $file;
|
||||||
|
$file = str_replace( "$CODE_PATH/", '', $file );
|
||||||
|
$file_requires[$file] = array( 'parsed' => false, 'bad' => 0, 'warning' => 0, 'libs' => array(), 'errors' => array() );
|
||||||
|
|
||||||
|
// If the file has bad syntax, don't even bother with it
|
||||||
|
$output = array();
|
||||||
|
exec( "php -l '$filename'", $output, $result );
|
||||||
|
if( $result != 0 ) {
|
||||||
|
$counters['failed']++;
|
||||||
|
foreach( $output as $linterror ) {
|
||||||
|
$matches = array();
|
||||||
|
if( preg_match( '/error:.*?on line (\d+)$/i', $linterror, $matches ) == 0 ) { continue; }
|
||||||
|
$file_requires[$file]['errors'][] = array( 'line' => $matches[1], 'message' => $matches[0] );
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$file_requires[$file]['parsed'] = true;
|
||||||
|
|
||||||
|
$local_functions = isset( $all_local_functions[$file] ) ? $all_local_functions[$file] : array();
|
||||||
|
$includes = array();
|
||||||
|
$parser->reset();
|
||||||
|
$parser->parseFile( $filename );
|
||||||
|
//echo "<pre>", print_r( $parser->parsed_objects ), '</pre>';
|
||||||
|
foreach( $parser->parsed_objects as $object ) {
|
||||||
|
switch( $object['type'] ) {
|
||||||
|
case PHPPARSER_INCLUDE:
|
||||||
|
$includes[] = $object;
|
||||||
|
$current_dir = dirname( $file );
|
||||||
|
if( $object['name'] == 'global.php' ) {
|
||||||
|
$object['name'] = 'libs/security/lib_security_input.php';
|
||||||
|
$includes[] = $object;
|
||||||
|
$object['name'] = 'libs/get/lib_get_portal.php';
|
||||||
|
$includes[] = $object;
|
||||||
|
$object['name'] = 'libs/logging/lib_logging_errors.php';
|
||||||
|
$includes[] = $object;
|
||||||
|
}
|
||||||
|
$local_functions = array_merge( $local_functions, isset( $all_local_functions[$object['name']] ) ? $all_local_functions[$object['name']] : array() );
|
||||||
|
break;
|
||||||
|
case PHPPARSER_FUNCTION_CALL:
|
||||||
|
if( !in_array( $object['name'], array_keys( $functions ) ) ) {
|
||||||
|
if(
|
||||||
|
!in_array( $object['name'], $parser->internal_functions )
|
||||||
|
&& !in_array( $object['name'], $local_functions )
|
||||||
|
) {
|
||||||
|
$file_requires[$file]['errors'][] = array( 'line' => $object['line'], 'message' => "Undefined function '{$object['name']}'" );
|
||||||
|
$file_requires[$file]['warnings']++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$include = $functions[$object['name']]['file'];
|
||||||
|
$include = str_replace( "$CODE_PATH/", '', $include );
|
||||||
|
if( $include == $file ) { break; }
|
||||||
|
$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( $includes as $libinc ) {
|
||||||
|
if( $libinc['name'] != $include || !in_array( $libinc['in_function'], array( '', $object['in_function'] ) ) ) { continue; }
|
||||||
|
$inc = $libinc;
|
||||||
|
$bad = false;
|
||||||
|
/* Holy shit, what a fucked up check this used to be...
|
||||||
|
$warning = !$bad && $libinc['depth'] > ( empty( $object['in_function'] ) ? 0 : 1 ) && (
|
||||||
|
$object['depth'] < $libinc['depth']
|
||||||
|
|| (
|
||||||
|
$object['depth'] >= $libinc['depth']
|
||||||
|
&& ( $object['block'] - ( $object['depth'] - $libinc['depth'] ) ) != $libinc['block']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
$warning = !$bad && !in_array( $libinc['block'], $object['open_blocks'] );
|
||||||
|
if( !$bad && !$warning ) { break; }
|
||||||
|
}
|
||||||
|
$open_blocks = is_array( $object['open_blocks'] ) ? implode( ',', $object['open_blocks'] ) : '';
|
||||||
|
$object['bad'] = $bad;
|
||||||
|
$object['warning'] = $warning;
|
||||||
|
$object['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}]" : '' );
|
||||||
|
$lib['lines'][] = $object['line'];
|
||||||
|
$lib['calls'][] = $object;
|
||||||
|
$file_requires[$file]['bad'] += $bad ? 1 : 0;
|
||||||
|
$file_requires[$file]['warning'] += $warning ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$counters['files']++;
|
||||||
|
if( $file_requires[$file]['bad'] > 0 ) { $counters['errors']++; }
|
||||||
|
if( $file_requires[$file]['warning'] > 0 ) { $counters['warnings']++; }
|
||||||
|
if( !$file_requires[$file]['parsed'] ) { $counters['failed']++; }
|
||||||
|
} err( "\n" );
|
||||||
|
fclose( $stderr );
|
||||||
|
|
||||||
|
$files =& $php_files;
|
||||||
|
foreach( $files as $key => $value ) { $files[$key] = str_replace( "$CODE_PATH/", '', $value ); }
|
||||||
|
function ispath( $string ) { return strpos( $string, '/' ) === false ? false: true; }
|
||||||
|
function notpath( $string ) { return strpos( $string, '/' ) === false ? true: false; }
|
||||||
|
sort( $files );
|
||||||
|
$files1 = array_filter( $files, 'notpath' ); sort( $files1 );
|
||||||
|
$files2 = array_filter( $files, 'ispath' ); sort( $files2 );
|
||||||
|
$files = array_merge( $files1, $files2 );
|
||||||
|
?>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>PayQuik Library Function Calls</title>
|
||||||
|
<style>
|
||||||
|
.expander {
|
||||||
|
display: none;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
color: #000;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #ddffdd;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
div.bad, dt.bad {
|
||||||
|
display: block;
|
||||||
|
background-color: #ffdddd;
|
||||||
|
}
|
||||||
|
div.warning, dt.warning {
|
||||||
|
display: block;
|
||||||
|
background-color: #ffca9f;
|
||||||
|
}
|
||||||
|
dt.good {
|
||||||
|
background-color: #ddffdd;
|
||||||
|
}
|
||||||
|
div.failed, dt.failed {
|
||||||
|
display: block;
|
||||||
|
background-color: #000;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.expand {
|
||||||
|
padding-left: 1em;
|
||||||
|
font-size: small;
|
||||||
|
}
|
||||||
|
.code {
|
||||||
|
font-family: monospace,courier;
|
||||||
|
background-color: #eee;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
}
|
||||||
|
.line, .offset {
|
||||||
|
color: #990000;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.scope {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.function {
|
||||||
|
font-weight: bold;
|
||||||
|
font-family: monospace,courier;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
color: #999;
|
||||||
|
font-variant: small-caps;
|
||||||
|
}
|
||||||
|
span.bad {
|
||||||
|
color: #990000;
|
||||||
|
}
|
||||||
|
span.warning {
|
||||||
|
color: #df6300;
|
||||||
|
}
|
||||||
|
#footer {
|
||||||
|
font-size: x-small;
|
||||||
|
font-style: italic;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function expand( id ) {
|
||||||
|
var e = document.getElementById( "expand_" + id );
|
||||||
|
if( e.style.display == "none" ) {
|
||||||
|
e.style.display = "block";
|
||||||
|
} else {
|
||||||
|
e.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Library Function calls by file</h1>
|
||||||
|
<?=$counters['files']?> files, of which <?=$counters['errors']?> contain errors, <?=$counters['warnings']?> contain warnings and <?=$counters['failed']?> failed to parse<br />
|
||||||
|
Last updated: <?=date( 'Y-m-d H:i:s' )?>
|
||||||
|
<h2>Legend</h2>
|
||||||
|
<dl>
|
||||||
|
<dt class="good">Good files</dt>
|
||||||
|
<dd>File parsed ok, no warnings or errors</dd>
|
||||||
|
<dt class="warning">Warnings</dt>
|
||||||
|
<dd>File contains potentially undefined function calls</dd>
|
||||||
|
<dt class="bad">Errors</dt>
|
||||||
|
<dd>File contains undefined function calls</dd>
|
||||||
|
<dt class="failed">Failed</dt>
|
||||||
|
<dd>File failed to parse (checked with <code>php -l <var>filename</var></code>)</dd>
|
||||||
|
</dl>
|
||||||
|
<h2>Files:</h2>
|
||||||
|
<?
|
||||||
|
foreach( $files as $key => $file ) {
|
||||||
|
if( !isset( $file_requires[$file] ) ) { continue; }
|
||||||
|
$failed = !$file_requires[$file]['parsed'];
|
||||||
|
$bad = $file_requires[$file]['bad'];
|
||||||
|
$warning = $file_requires[$file]['warning'];
|
||||||
|
$requires = array_keys( $file_requires[$file]['libs'] );
|
||||||
|
ksort( $requires );
|
||||||
|
?>
|
||||||
|
<div class="expander<?=( $failed ? ' failed' : ( $bad > 0 ? ' bad' : ( $warning > 0 ? ' warning' : '' ) ) )?>" id="link_<?=$key?>" onclick="expand(<?=$key?>)"><?=$file?></div>
|
||||||
|
<div id="expand_<?=$key?>" class="expand" style="display: none">
|
||||||
|
<ul>
|
||||||
|
<? foreach( $file_requires[$file]['errors'] as $error ):?>
|
||||||
|
<li><span class="line"><?=$error['line']?>: <span class="info"><?=$error['message']?></span></li>
|
||||||
|
<? endforeach;?>
|
||||||
|
</ul>
|
||||||
|
<dl>
|
||||||
|
<? foreach( $requires as $require ): ?>
|
||||||
|
<dt class="code">require_once( '<?=$require?>' );</dt>
|
||||||
|
<dd>
|
||||||
|
<ul>
|
||||||
|
<? foreach( $file_requires[$file]['libs'][$require]['calls'] as $call ): ?>
|
||||||
|
<li><span class="line"><?=$call['line']?></span>:<span class="offset"><?=$call['block']?></span>:<span class="scope"><?=$call['in_function']?></span>: <span class="function<?=( $call['bad'] ? ' bad' : ( $call['warning'] ? ' warning' : '' ) )?>"><?=$call['name']?></span> <span class="info"><?=$call['info']?></span></li>
|
||||||
|
<? endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
<? endforeach; ?>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<?
|
||||||
|
}
|
||||||
|
$time_end = microtime_float();
|
||||||
|
?>
|
||||||
|
<div id="footer">Generated in <?=$time_end - $time_start?> seconds.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
330
parser.php
Normal file
330
parser.php
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
<?php
|
||||||
|
define( 'PHPPARSER_FETCH_CLASSES', 1 );
|
||||||
|
define( 'PHPPARSER_FETCH_FUNCTIONS', 2 );
|
||||||
|
define( 'PHPPARSER_FETCH_CALLS', 4 );
|
||||||
|
define( 'PHPPARSER_FETCH_INCLUDES', 8 );
|
||||||
|
define( 'PHPPARSER_FETCH_INTERNAL', 16 );
|
||||||
|
define( 'PHPPARSER_FETCH_CONSTRUCTS', 32 );
|
||||||
|
define( 'PHPPARSER_FETCH_EXPRESSIONS', 64 );
|
||||||
|
|
||||||
|
define( 'PHPPARSER_FETCH_ALL', 65535 );
|
||||||
|
|
||||||
|
define( 'PHPPARSER_CLASS_DEF', 1 );
|
||||||
|
define( 'PHPPARSER_FUNCTION_DEF', 2 );
|
||||||
|
define( 'PHPPARSER_FUNCTION_CALL', 3 );
|
||||||
|
define( 'PHPPARSER_INCLUDE', 4 );
|
||||||
|
define( 'PHPPARSER_EXPRESSION', 5 );
|
||||||
|
define( 'PHPPARSER_LANGUAGE_CONSTRUCT', 6 );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PHPParser {
|
||||||
|
|
||||||
|
var $fetch_mode;
|
||||||
|
var $file_name;
|
||||||
|
var $internal_functions;
|
||||||
|
var $defined_functions;
|
||||||
|
var $parsed_objects;
|
||||||
|
|
||||||
|
function PHPParser( $fetch_mode = PHPPARSER_FETCH_ALL, $functionlist = array() ) {
|
||||||
|
$this->reset( $fetch_mode );
|
||||||
|
$this->internal_functions = get_defined_functions(); $this->internal_functions = $this->internal_functions['internal'];
|
||||||
|
$this->addFunctionDefinitions( $functionlist );
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset( $fetch_mode = null ) {
|
||||||
|
if( $fetch_mode > 0 ) {
|
||||||
|
$this->fetch_mode = $fetch_mode;
|
||||||
|
}
|
||||||
|
$this->file_name = '';
|
||||||
|
$this->defined_functions = array();
|
||||||
|
$this->parsed_objects = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFunctionDefinitions( $functionlist ) {
|
||||||
|
if( is_array( $functionlist ) ) {
|
||||||
|
array_merge( $this->defined_functions, $functionlist );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function parseFile( $file ) {
|
||||||
|
if( !file_exists( $file ) || !is_readable( $file ) ) { return false; }
|
||||||
|
$this->file_name = $file;
|
||||||
|
$this->parse( file_get_contents( $file ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse( $content ) {
|
||||||
|
$tokens = token_get_all( $content );
|
||||||
|
|
||||||
|
$line = 1;
|
||||||
|
$depth = 0;
|
||||||
|
$block = 0;
|
||||||
|
$block_count = 0;
|
||||||
|
|
||||||
|
$class = $classname = null;
|
||||||
|
$function = $functionname = null;
|
||||||
|
$switch = array();
|
||||||
|
$expression = '';
|
||||||
|
$line_text = '';
|
||||||
|
|
||||||
|
$internal_functions = get_defined_functions(); $internal_functions = $internal_functions['internal'];
|
||||||
|
$local_functions = array();
|
||||||
|
$local_classes = array();
|
||||||
|
$open_blocks = array( 0 );
|
||||||
|
$in_string = false;
|
||||||
|
foreach( $tokens as $token ) {
|
||||||
|
//echo ( is_string( $token ) ? 'CHAR: ' . $token : token_name( $token[0] ) . ': ' . $token[1] ) . "\n";
|
||||||
|
if( !in_array( 0, $open_blocks ) ) {
|
||||||
|
echo "PARSER ERROR: LOST ZERO BLOCK AT FILE {$this->file_name} LINE $line\n";
|
||||||
|
$open_blocks = array_merge( array(0), $open_blocks );
|
||||||
|
}
|
||||||
|
$classname = isset( $class['name'] ) ? $class['name'] : '';
|
||||||
|
$functionname = isset( $function['name'] ) ? $function['name'] : '';
|
||||||
|
if( $token == '"' ) {
|
||||||
|
$in_string = !$in_string;
|
||||||
|
}
|
||||||
|
if( $in_string ) {
|
||||||
|
$expression .= is_string( $token ) ? $token : $token[1];
|
||||||
|
$count = preg_match_all( '/\r?(\n|\r)/', is_string( $token ) ? $token : $token[1], $m );
|
||||||
|
$line += $count;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if( is_string( $token ) ) {
|
||||||
|
// Single character token
|
||||||
|
$text = $token;
|
||||||
|
switch( $token ) {
|
||||||
|
case '{':
|
||||||
|
$block_count++;
|
||||||
|
$block = $block_count;
|
||||||
|
array_push( $open_blocks, $block );
|
||||||
|
$depth = count( $open_blocks ) - 1;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
array_pop( $open_blocks );
|
||||||
|
$depth = count( $open_blocks ) - 1;
|
||||||
|
$block = $depth == 0 ? 0 : $open_blocks[$depth];
|
||||||
|
if( !empty( $class ) && $class['block'] == $block ) { $class = $functionname = null; }
|
||||||
|
if( !empty( $function ) && $function['block'] == $block ) { $function = $functionname = null; }
|
||||||
|
if( in_array( $block, $switch ) ) {
|
||||||
|
array_pop( $open_blocks );
|
||||||
|
$depth = count( $open_blocks ) - 1;
|
||||||
|
$block = $depth == 0 ? 0 : $open_blocks[$depth-1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
if(
|
||||||
|
(bool)($this->fetch_mode & PHPPARSER_FETCH_CALLS)
|
||||||
|
&& !empty( $string )
|
||||||
|
&& $last_token != T_FUNCTION
|
||||||
|
&& $last_token != T_OBJECT_OPERATOR
|
||||||
|
&& $last_token != T_NEW
|
||||||
|
//&& ( (bool)($this->fetch_mode & PHPPARSER_FETCH_INTERNAL) && !in_array( $string, $this->internal_functions ) )
|
||||||
|
) {
|
||||||
|
$this->parsed_objects[] = array(
|
||||||
|
'type' => PHPPARSER_FUNCTION_CALL,
|
||||||
|
'name' => strtolower( $string ),
|
||||||
|
'file' => $this->file_name,
|
||||||
|
'line' => $line,
|
||||||
|
'block' => $block,
|
||||||
|
'depth' => $depth,
|
||||||
|
'in_class' => $classname,
|
||||||
|
'in_function' => $functionname,
|
||||||
|
'open_blocks' => $open_blocks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( !in_array( $token, array( '(', ')' ) ) ) { $last_token = null; }
|
||||||
|
if( (bool)($this->fetch_mode & PHPPARSER_FETCH_EXPRESSIONS) && in_array( $token, array( '{', '}', ';', '=', '?', ':' ) ) && strlen( trim( $expression ) ) > 0 ) {
|
||||||
|
$this->parsed_objects[] = array(
|
||||||
|
'type' => PHPPARSER_EXPRESSION,
|
||||||
|
'name' => trim( $expression ),
|
||||||
|
'file' => $this->file_name,
|
||||||
|
'line' => $line,
|
||||||
|
'block' => $block,
|
||||||
|
'depth' => $depth,
|
||||||
|
'in_class' => $classname,
|
||||||
|
'in_function' => $functionname,
|
||||||
|
'open_blocks' => $open_blocks
|
||||||
|
);
|
||||||
|
$expression = '';
|
||||||
|
} else { $expression .= $token; }
|
||||||
|
} else {
|
||||||
|
list($id, $text) = $token;
|
||||||
|
switch( $id ) {
|
||||||
|
case T_CURLY_OPEN:
|
||||||
|
case T_DOLLAR_OPEN_CURLY_BRACES:
|
||||||
|
$block_count++;
|
||||||
|
$block = $block_count;
|
||||||
|
array_push( $open_blocks, $block );
|
||||||
|
$depth = count( $open_blocks ) - 1;
|
||||||
|
break;
|
||||||
|
case T_STRING:
|
||||||
|
$string = $text;
|
||||||
|
switch( $last_token ) {
|
||||||
|
case T_CLASS:
|
||||||
|
if( (bool)($this->fetch_mode & PHPPARSER_FETCH_CLASSES) ) {
|
||||||
|
$this->parsed_objects[] = array(
|
||||||
|
'type' => PHPPARSER_CLASS_DEF,
|
||||||
|
'name' => strtolower( $string ),
|
||||||
|
'file' => $this->file_name,
|
||||||
|
'line' => $line,
|
||||||
|
'block' => $block,
|
||||||
|
'depth' => $depth,
|
||||||
|
'in_class' => $classname,
|
||||||
|
'in_function' => $functionname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$class = array( 'name' => $text, 'block' => $block );
|
||||||
|
break;
|
||||||
|
case T_FUNCTION:
|
||||||
|
if( (bool)($this->fetch_mode & PHPPARSER_FETCH_FUNCTIONS) && empty( $classname ) ) { // Not interested in member function definitions
|
||||||
|
$this->parsed_objects[] = array(
|
||||||
|
'type' => PHPPARSER_FUNCTION_DEF,
|
||||||
|
'name' => strtolower( $string ),
|
||||||
|
'file' => $this->file_name,
|
||||||
|
'line' => $line,
|
||||||
|
'block' => $block,
|
||||||
|
'depth' => $depth,
|
||||||
|
'in_class' => $classname,
|
||||||
|
'in_function' => $functionname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$function = array( 'name' => $text, 'block' => $block );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case T_CONSTANT_ENCAPSED_STRING:
|
||||||
|
switch( $last_token ) {
|
||||||
|
case T_INCLUDE:
|
||||||
|
case T_INCLUDE_ONCE:
|
||||||
|
case T_REQUIRE:
|
||||||
|
case T_REQUIRE_ONCE:
|
||||||
|
if( (bool)($this->fetch_mode & PHPPARSER_FETCH_INCLUDES) ) {
|
||||||
|
$this->parsed_objects[] = array(
|
||||||
|
'type' => PHPPARSER_INCLUDE,
|
||||||
|
'name' => trim( str_replace( '\'', '', $text ) ),
|
||||||
|
'file' => $this->file_name,
|
||||||
|
'line' => $line,
|
||||||
|
'block' => $block,
|
||||||
|
'depth' => $depth,
|
||||||
|
'in_class' => $classname,
|
||||||
|
'in_function' => $functionname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
///*
|
||||||
|
case T_SWITCH:
|
||||||
|
$block_count++;
|
||||||
|
$block = $block_count;
|
||||||
|
array_push( $open_blocks, $block );
|
||||||
|
$depth = count( $open_blocks ) - 1;
|
||||||
|
$switch[$block] = $block;
|
||||||
|
break;
|
||||||
|
case T_CASE:
|
||||||
|
case T_DEFAULT:
|
||||||
|
// Each conditional of a switch statement is its own block
|
||||||
|
array_pop( $open_blocks );
|
||||||
|
$block_count++;
|
||||||
|
$block = $block_count;
|
||||||
|
array_push( $open_blocks, $block );
|
||||||
|
$depth = count( $open_blocks ) - 1;
|
||||||
|
break;
|
||||||
|
//*/
|
||||||
|
case T_EVAL:
|
||||||
|
if( (bool)($this->fetch_mode & PHPPARSER_FETCH_INTERNAL) ) {
|
||||||
|
$this->parsed_objects[] = array(
|
||||||
|
'type' => PHPPARSER_FUNCTION_CALL,
|
||||||
|
'name' => $text,
|
||||||
|
'file' => $this->file_name,
|
||||||
|
'line' => $line,
|
||||||
|
'block' => $block,
|
||||||
|
'depth' => $depth,
|
||||||
|
'in_class' => $classname,
|
||||||
|
'in_function' => $functionname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( !in_array( $id, array( T_WHITESPACE, /*T_COMMENT, T_DOC_COMMENT,*/ T_STRING ) ) ) { $string = null; $last_token = $id; }
|
||||||
|
if( (bool)($this->fetch_mode & PHPPARSER_FETCH_CONSTRUCTS) && in_array( $id, array(
|
||||||
|
T_ARRAY,
|
||||||
|
T_ECHO,
|
||||||
|
T_EMPTY,
|
||||||
|
T_EVAL,
|
||||||
|
T_EXIT,
|
||||||
|
T_HALT_COMPILER,
|
||||||
|
T_INCLUDE,
|
||||||
|
T_INCLUDE_ONCE,
|
||||||
|
T_ISSET,
|
||||||
|
T_LIST,
|
||||||
|
T_PRINT,
|
||||||
|
T_REQUIRE,
|
||||||
|
T_REQUIRE_ONCE,
|
||||||
|
T_UNSET
|
||||||
|
) ) ) {
|
||||||
|
$this->parsed_objects[] = array(
|
||||||
|
'type' => PHPPARSER_LANGUAGE_CONSTRUCT,
|
||||||
|
'name' => $text,
|
||||||
|
'file' => $this->file_name,
|
||||||
|
'line' => $line,
|
||||||
|
'block' => $block,
|
||||||
|
'depth' => $depth,
|
||||||
|
'in_class' => $classname,
|
||||||
|
'in_function' => $functionname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$expression .= ( in_array( $id, array(
|
||||||
|
/* Values */
|
||||||
|
T_STRING,
|
||||||
|
T_CHARACTER,
|
||||||
|
T_CONSTANT_ENCAPSED_STRING,
|
||||||
|
T_ENCAPSED_AND_WHITESPACE,
|
||||||
|
T_WHITESPACE,
|
||||||
|
T_DNUMBER,
|
||||||
|
T_LNUMBER,
|
||||||
|
T_NUM_STRING,
|
||||||
|
T_VARIABLE,
|
||||||
|
//T_ARRAY,
|
||||||
|
T_STRING_VARNAME,
|
||||||
|
|
||||||
|
/* Operators */
|
||||||
|
T_BOOLEAN_AND,
|
||||||
|
T_BOOLEAN_OR,
|
||||||
|
T_DEC,
|
||||||
|
T_INC,
|
||||||
|
T_IS_EQUAL,
|
||||||
|
T_IS_GREATER_OR_EQUAL,
|
||||||
|
T_IS_IDENTICAL,
|
||||||
|
T_IS_NOT_EQUAL,
|
||||||
|
T_IS_NOT_IDENTICAL,
|
||||||
|
T_IS_SMALLER_OR_EQUAL,
|
||||||
|
T_LOGICAL_AND,
|
||||||
|
T_LOGICAL_OR,
|
||||||
|
T_LOGICAL_XOR,
|
||||||
|
T_OBJECT_OPERATOR,
|
||||||
|
T_DOUBLE_COLON,
|
||||||
|
T_SL,
|
||||||
|
T_SR,
|
||||||
|
|
||||||
|
/* Casts */
|
||||||
|
T_DOUBLE_CAST,
|
||||||
|
T_INT_CAST,
|
||||||
|
T_OBJECT_CAST,
|
||||||
|
T_STRING_CAST,
|
||||||
|
T_UNSET_CAST,
|
||||||
|
|
||||||
|
/* Constructs */
|
||||||
|
T_ECHO,
|
||||||
|
T_PRINT
|
||||||
|
) ) ) ? $text : ' ';
|
||||||
|
$count = preg_match_all( '/\r?(\n|\r)/', $text, $m );
|
||||||
|
$line += $count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
59
test.php
Normal file
59
test.php
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once( 'parser.php' );
|
||||||
|
|
||||||
|
$filters = array(
|
||||||
|
array(
|
||||||
|
'type' => PHPPARSER_EXPRESSION,
|
||||||
|
'desc' => 'Echoing Sql',
|
||||||
|
'pattern' => '/echo[\(\s].*?\$sql/i'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'type' => PHPPARSER_LANGUAGE_CONSTRUCT,
|
||||||
|
'desc' => 'Evil Eval',
|
||||||
|
'pattern' => '/^eval$/i'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'type' => PHPPARSER_FUNCTION_CALL,
|
||||||
|
'desc' => 'PRINT_R or VAR_DUMP',
|
||||||
|
'pattern' => '/^(print_r|var_dump)$/i'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'type' => PHPPARSER_EXPRESSION,
|
||||||
|
'desc' => 'Developer Email',
|
||||||
|
'pattern' => '/(?<!dev|qa)@payquik\.com/'
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$parser = new PHPParser( PHPPARSER_FETCH_EXPRESSIONS | PHPPARSER_FETCH_CALLS | PHPPARSER_FETCH_INTERNAL | PHPPARSER_FETCH_CONSTRUCTS );
|
||||||
|
$parser->parseFile( __FILE__ );
|
||||||
|
|
||||||
|
foreach( $parser->parsed_objects as $object ) {
|
||||||
|
foreach( $filters as $filter ) {
|
||||||
|
if( $object['type'] == $filter['type'] ) {
|
||||||
|
if( preg_match( $filter['pattern'], $object['name'] ) > 0 ) {
|
||||||
|
echo "Triggered Filter '{$filter['desc']}' at line {$object['line']}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "select * from failure";
|
||||||
|
echo "Here's the $sql!\n";
|
||||||
|
mail( 'correl@payquik.com', 'subject', 'stuffs' );
|
||||||
|
eval( "echo \"here's eval!\n\";" );
|
||||||
|
print_r( $sql );
|
||||||
|
var_dump( $sql );
|
||||||
|
echo "done\n";
|
||||||
|
|
||||||
|
/* OUTPUT:
|
||||||
|
|
||||||
|
Triggered Filter 'Echoing Sql' at line 42
|
||||||
|
Triggered Filter 'Developer Email' at line 43
|
||||||
|
Triggered Filter 'Evil Eval' at line 44
|
||||||
|
Triggered Filter 'PRINT_R or VAR_DUMP' at line 45
|
||||||
|
Triggered Filter 'PRINT_R or VAR_DUMP' at line 46
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
?>
|
Loading…
Reference in a new issue