php中提供了token_get_all函数来针对php代码进行词法分析,通过词法分析我们可以做恶意代码分析,安全代码审计等深层次研究。该函数可以直接把php代码分为php tokens,而每个token又包含类型、值、行数这三样。 首先对最简单的代码进行分析(当然不是hello world): [code lang=“php”]code.php <?php echo ‘token’; ?>[/code] [code lang=“php”]token.php <?php print_r(token_get_all(file_get_contents(‘code.php’))); ?>[/code] 看效果,为了效果更明显,建议你测试的时候直接看浏览器源码。 [code lang=“php”]Array ( [0] => Array ( [0] => 366 [1] => <?php
[2] => 1
)
[1] => Array
(
[0] => 315
[1] => echo
[2] => 2
)
[2] => Array
(
[0] => 369
[1] =>
[2] => 2
)
[3] => Array
(
[0] => 314
[1] => 'token'
[2] => 2
)
[4] => ;
[5] => Array
(
[0] => 369
[1] =>
[2] => 2
)
[6] => Array
(
[0] => 368
[1] => ?>
[2] => 3
)
)[/code] 每个token数组中的第一项表示其类型,可以用函数token_name()得到起文字说明,第二项表示其内容,第三项表示在文件中的行数。还不错吧,可以得到这么多有用的信息(至少我第一次从monyer文章中看到的时候很欢喜的)。如果你只关注一些关键函数及其参数,那么你就需要对这些内容进行过滤,借鉴php手册重点的一个例子实现如下: [code lang=“php”]<?php define(’T_NEW_LINE’, -1);
$tokens = token_get_all_nl(file_get_contents(‘code.php’));
foreach ($tokens as $token)
{
if (is_array($token))
{
echo (‘Type:’.token_name_nl($token[0]) .“t”. ‘Code: “’ . htmlspecialchars($token[1]) .”t”.‘“ line:’.$token[2].‘
’);
}
else
{
echo (‘”’ . $token . ‘“
’);
}
}
function token_get_all_nl($source) { $new_tokens = array();
// Get the tokens
$tokens = token_get_all($source);
// Split newlines into their own tokens
foreach ($tokens as $token)
{
$token_name = is_array($token) ? $token[0] : null;
$token_data = is_array($token) ? $token[1] : $token;
$token_number = is_array($token) ? $token[2] : $token;
// Do not split encapsed strings or multiline comments
if ($token_name == T_CONSTANT_ENCAPSED_STRING || substr($token_data, 0, 2) == '/*')
{
$new_tokens[] = array($token_name, $token_data, $token_number);
continue;
}
// Split the data up by newlines
$split_data = preg_split('#(rn|n)#', $token_data, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach ($split_data as $data)
{
if ($data == "rn" || $data == "n")
{
// This is a new line token
$new_tokens[] = array(T_NEW_LINE, $data, $token_number);
}
else
{
// Add the token under the original token name
$new_tokens[] = is_array($token) ? array($token_name, $data, $token_number) : $data;
}
}
}
return $new_tokens;
}
function token_name_nl($token) { if ($token === T_NEW_LINE) { return ’T_NEW_LINE’; }
return token_name($token);
} ?>[/code] 此外,你可以在这个基础上进行一些有目的的开发。 BTW:今天看rips源码才知道也是这么做的,详细的实现要看完了再分享。