PHP中有没有办法进行静态代码分析并检测对register_globals主动性的依赖?手动检查文件并查找尚未初始化的变量并从中推断可能依赖于它的变量相对简单,但我需要为数百个脚本执行此操作,因此我正在寻找自动化解决方案.
我的最后一招是设置开发环境,关闭指令并严格报告错误并让QA玩了很长时间,然后修复错误日志捕获的实例,但不能保证找到100%的情况如果存在自动化解决方案,当然也不能很好地利用资源.
Nik*_*kiC 13
我刚刚攻击一个小脚本来检测简单的未定义变量.你需要PHP-Parser:
<?php
error_reporting(E_ALL);
$dir = './foo';
require_once './lib/bootstrap.php';
class Scope {
protected $stack;
protected $pos;
public function __construct() {
$this->stack = array();
$this->pos = -1;
}
public function addVar($name) {
$this->stack[$this->pos][$name] = true;
}
public function hasVar($name) {
return isset($this->stack[$this->pos][$name]);
}
public function pushScope() {
$this->stack[++$this->pos] = array();
}
public function popScope() {
--$this->pos;
}
}
class UndefinedVariableVisitor extends PHPParser_NodeVisitorAbstract {
protected $scope;
protected $parser;
protected $traverser;
public function __construct(Scope $scope, PHPParser_Parser $parser, PHPParser_NodeTraverser $traverser) {
$this->scope = $scope;
$this->parser = $parser;
$this->traverser = $traverser;
}
public function enterNode(PHPParser_Node $node) {
if (($node instanceof PHPParser_Node_Expr_Assign || $node instanceof PHPParser_Node_Expr_AssignRef)
&& $node->var instanceof PHPParser_Node_Expr_Variable
&& is_string($node->var->name)
) {
$this->scope->addVar($node->var->name);
} elseif ($node instanceof PHPParser_Node_Stmt_Global || $node instanceof PHPParser_Node_Stmt_Static) {
foreach ($node->vars as $var) {
if (is_string($var->name)) {
$this->scope->addVar($var->name);
}
}
} elseif ($node instanceof PHPParser_Node_Expr_Variable && is_string($node->name)) {
if (!$this->scope->hasVar($node->name)) {
echo 'Undefined variable $' . $node->name . ' on line ' . $node->getLine() . "\n";
}
} elseif ($node instanceof PHPParser_Node_Stmt_Function || $node instanceof PHPParser_Node_Stmt_ClassMethod) {
$this->scope->pushScope();
// params are always available
foreach ($node->params as $param) {
$this->scope->addVar($param->name);
}
// methods always have $this
if ($node instanceof PHPParser_Node_Stmt_ClassMethod) {
$this->scope->addVar('this');
}
} elseif ($node instanceof PHPParser_Node_Expr_Include && $node->expr instanceof PHPParser_Node_Scalar_String) {
$file = $node->expr->value;
$code = file_get_contents($file);
$stmts = $this->parser->parse($code);
// for includes within the file
$cwd = getcwd();
chdir(dirname($file));
$this->traverser->traverse($stmts);
chdir($cwd);
}
}
public function leaveNode(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Stmt_Function || $node instanceof PHPParser_Node_Stmt_ClassMethod) {
$this->scope->popScope();
}
}
}
$parser = new PHPParser_Parser(new PHPParser_Lexer());
$scope = new Scope;
$traverser = new PHPParser_NodeTraverser;
$traverser->addVisitor(new UndefinedVariableVisitor($scope, $parser, $traverser));
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir),
RecursiveIteratorIterator::LEAVES_ONLY)
as $file
) {
if (!preg_match('/\.php$/', $file)) continue;
echo 'Checking ' . $file . ':', "\n";
$code = file_get_contents($file);
$stmts = $parser->parse($code);
// for includes within the file
$cwd = getcwd();
chdir(dirname($file));
$scope->pushScope();
$traverser->traverse($stmts);
$scope->popScope();
chdir($cwd);
echo "\n";
}
Run Code Online (Sandbox Code Playgroud)
这只是一个非常基本的实现,我没有进行广泛的测试,但它应该为脚本,不走野一起工作$GLOBALS和$$varVars.它基本包括解决方案.