Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/usr/bin/env php
<?php
define( 'DEBUG_RECURSION', false );
if ( $_SERVER['argc'] > 1 ) {
if ( substr( $_SERVER['argv'][1], 0, 1 ) !== "/" ) {
define( 'FUNCTION_MATCH', "/" . preg_quote( $_SERVER['argv'][1] ) . "/" );
} else {
define( 'FUNCTION_MATCH', $_SERVER['argv'][1] );
}
} else {
die( "Usage: " . $_SERVER['argv'][0] . " function_pattern [scan_path]\n" );
}
if ( $_SERVER['argc'] > 2 ) {
define( 'SCAN_BASE', get_real_path_to( $_SERVER['argv'][2] ) );
if ( !SCAN_BASE ) {
die( $_SERVER['argv'][2] . " does not appear to be a directory...\n" );
}
} else {
define( 'SCAN_BASE', get_real_path_to( getcwd() ) );
}
function get_real_path_to( $path ) {
$path = realpath( $path );
while( is_link( $path ) ) {
$path = realpath( readlink( $path ) );
}
return $path;
}
define( 'SCAN_BASE_STRIP', strlen( SCAN_BASE ) + 1 );
function resurse_find_ext_callback( $ext, $dir, $callback ) {
$base = get_real_path_to( $dir );
$d = opendir( $base );
if ( $d !== false ) {
while( false !== ( $entry = readdir( $d ) ) ) {
if ( in_array( $entry, array( ".", "..", ".svn", ".git" ) ) ) {
if ( DEBUG_RECURSION )
fwrite( STDERR, "!valid\t$base/$entry\n" );
continue;
}
$new = get_real_path_to( "$base/$entry" );
if ( $new === $base ) {
// Don't scan if the entry is a link to the self
if ( DEBUG_RECURSION )
fwrite( STDERR, "!loop\t$new\n" );
continue;
}
if ( is_dir( $new ) ) {
if ( strpos( $new, $base ) === 0 ) {
resurse_find_ext_callback( $ext, $new, $callback );
} else {
// Don't scan if we've been linked out of the current directory (eg: an nfs share of user uploads)
if ( DEBUG_RECURSION )
fwrite( STDERR, "!subdir\t$base/$entry -> $new\n" );
}
continue;
}
if ( substr( $new, strrpos( $new, "." ) ) === $ext ) {
$callback( $new );
}
}
} else {
if ( DEBUG_RECURSION )
fwrite( STDERR, "!opendir\t$d\n" );
}
}
function find_prev( $tokens, $from_idx ) {
for( $i = $from_idx - 1; $i >= 0; $i-- ) {
if ( is_string( $tokens[$i] ) ) {
return $i;
} else {
switch( token_name( $tokens[$i][0] ) ) {
case 'T_WHITESPACE':
break;
default:
return $i;
}
}
}
return false;
}
function find_entire_function_call( $tokens ) {
$p_depth = 0;
foreach( $tokens as $idx => $token ) {
if ( !is_string( $token ) ) {
continue;
}
switch( $token ) {
case '(':
$p_depth++;
break;
case ')':
$p_depth--;
break;
}
if ( $p_depth === 0 ) {
return $idx+1;
}
}
return false;
}
function reconstruct( $tokens ) {
$parts = array();
foreach( $tokens as $token ) {
if ( is_string( $token ) ) {
$parts[] = $token;
} else {
$parts[] = $token[1];
}
}
return implode( "", $parts );
}
resurse_find_ext_callback( ".php", SCAN_BASE, function( $file ) {
$tokens = token_get_all( file_get_contents( $file ) );
foreach( $tokens as $token_idx => $token ) {
if ( is_string( $token ) ) {
continue;
} else {
switch( token_name( $token[0] ) ) {
case 'T_STRING':
if ( !preg_match( FUNCTION_MATCH, $token[1] ) ) {
continue;
}
if ( !is_string( $tokens[$token_idx+1] ) ) {
continue;
}
if ( $tokens[$token_idx+1] !== "(" ) {
continue;
}
$prev = find_prev( $tokens, $token_idx );
if ( $prev !== false ) {
$prev = $tokens[$prev];
if ( !is_string( $prev ) && token_name( $prev[0] ) === "T_FUNCTION" ) {
break;
}
}
$len = find_entire_function_call( array_slice( $tokens, $token_idx ) );
if ( $len === false ) {
printf( "Unable to determine function call end for %s in %s on line %d\n", $token[1], $file, $token[2] );
break;
}
printf(
"%s:%d %s\n",
substr( $file, SCAN_BASE_STRIP ),
$token[2],
str_replace(
array( "\n", "\t" ),
array( "\\n", "\\t" ),
reconstruct( array_slice( $tokens, $token_idx, $len ) )
)
);
break;
default:
//printf( "%s: %s\n", token_name($token[0]), $token[1] );
}
}
}
});
@apokalyptik

This comment has been minimized.

Copy link
Owner Author

commented Feb 3, 2017

Recursively scans a directory for .php files and pulls out any calls to the matching function (converting \t, and \n to "\t" and "\n" to keep one call on one line of output.

Just a quick handy utility for auditing...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.